tom*_*mek 6 schema hive avro metastore
创建一个支持Avro数据的配置单元至少有两种不同的方法:
1)基于Avro架构创建表(在此示例中存储在hdfs中):
CREATE TABLE users_from_avro_schema
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
TBLPROPERTIES ('avro.schema.url'='hdfs:///user/root/avro/schema/user.avsc');
Run Code Online (Sandbox Code Playgroud)
2)通过使用STORED AS AVRO子句显式指定hive列来创建表:
CREATE TABLE users_stored_as_avro(
id INT,
name STRING
) STORED AS AVRO;
Run Code Online (Sandbox Code Playgroud)
我是否正确在第一种情况下,users_from_avro_schema表的元数据不存储在Hive Metastore中,而是从SERDE类中推断出读取avro模式文件?或者表元数据存储在Metastore中,添加在表的创建上,但是什么是用于将hive元数据与Avro架构同步的策略?我的意思是两种情况:更新表元数据(添加/删除列)和通过更改avro.schema.url属性更新Avro架构.
在第二种情况下,当我调用时DESCRIBE FORMATTED users_stored_as_avro没有avro.schema.*定义属性,所以我不知道哪个Avro架构用于读/写数据,它是根据存储在Metastore中的表的元数据动态生成的吗?
这个Programming Hive书的片段讲述了关于SerDe类中列的信息,但另一方面,HIVE-4703从from deserializer列注释中删除了这个信息.我如何检查给定表(Metastore或Avro架构)的列类型的来源是什么?
tom*_*mek 11
我决定发布@DuduMarkovitz给出的补充答案.
为了使代码示例更简洁,让我们澄清该STORED AS AVRO子句是这三行的等价物:
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe'
STORED AS INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerInputFormat'
OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.AvroContainerOutputFormat'
Run Code Online (Sandbox Code Playgroud)
让我们看一下当我们创建一个表,该表提供对存储在hdfs中的avro模式的引用时会发生什么.这是架构:
{
"namespace": "io.sqooba",
"name": "user",
"type": "record",
"fields": [
{"name": "id", "type": "int"},
{"name": "name", "type": "string"}
]
}
Run Code Online (Sandbox Code Playgroud)
我们使用以下命令创建表:
CREATE TABLE users_from_avro_schema
STORED AS AVRO
TBLPROPERTIES ('avro.schema.url'='hdfs:///user/tulinski/user.avsc');
Run Code Online (Sandbox Code Playgroud)
Hive已正确推断出架构,我们可以通过调用来看到:
hive> DESCRIBE users_from_avro_schema;
OK
id int
name string
Run Code Online (Sandbox Code Playgroud)
Hive Metastore向我们展示了相同的内容(我使用@ DuduMarkovitz的查询):
+------------------------+-------------+-------------+-----------+
| tbl_name | column_name | integer_idx | type_name |
+------------------------+-------------+-------------+-----------+
| users_from_avro_schema | id | 0 | int |
| users_from_avro_schema | name | 1 | string |
+------------------------+-------------+-------------+-----------+
Run Code Online (Sandbox Code Playgroud)
到目前为止,这么好,一切都按照我们的预期运作.但是让我们看看当我们更新avro.schema.url属性以指向我们的模式的下一个版本(users_v2.avsc)时会发生什么,如下所示:
{
"namespace": "io.sqooba",
"name": "user",
"type": "record",
"fields": [
{"name": "id", "type": "int"},
{"name": "name", "type": "string"},
{"name": "email", "type": ["null", "string"], "default":null}
]
}
Run Code Online (Sandbox Code Playgroud)
我们只是添加了一个名为email的字段.
现在我们更新一个指向hdfs中avro架构的表属性:
ALTER TABLE users_from_avro_schema SET TBLPROPERTIES('avro.schema.url'='hdfs:///user/tulinski/user_v2.avsc');
Run Code Online (Sandbox Code Playgroud)
表格元数据是否已更改?
hive> DESCRIBE users_from_avro_schema;
OK
id int
name string
email string
Run Code Online (Sandbox Code Playgroud)
是的,很酷!但是你认为Hive Metastore包含这个额外的列吗?
不幸的是,Metastore没有改变:
+------------------------+-------------+-------------+-----------+
| tbl_name | column_name | integer_idx | type_name |
+------------------------+-------------+-------------+-----------+
| users_from_avro_schema | id | 0 | int |
| users_from_avro_schema | name | 1 | string |
+------------------------+-------------+-------------+-----------+
Run Code Online (Sandbox Code Playgroud)
我怀疑Hive有以下推断模式的策略:它试图从为给定表指定的SerDe类中获取它.当SerDe无法提供架构时,Hive会查看Metastore.
让我们通过删除avro.schema.url属性来检查:
hive> ALTER TABLE users_from_avro_schema UNSET TBLPROPERTIES ('avro.schema.url');
OK
Time taken: 0.33 seconds
hive> DESCRIBE users_from_avro_schema;
OK
id int
name string
Time taken: 0.363 seconds, Fetched: 2 row(s)
Run Code Online (Sandbox Code Playgroud)
描述向我们展示存储在Metastore中的数据.让我们通过添加一列来修改它们:
ALTER TABLE users_from_avro_schema ADD COLUMNS (phone string);
Run Code Online (Sandbox Code Playgroud)
它当然会改变Hive Metastore:
+------------------------+-------------+-------------+-----------+
| tbl_name | column_name | integer_idx | type_name |
+------------------------+-------------+-------------+-----------+
| users_from_avro_schema | id | 0 | int |
| users_from_avro_schema | name | 1 | string |
| users_from_avro_schema | phone | 2 | string |
+------------------------+-------------+-------------+-----------+
Run Code Online (Sandbox Code Playgroud)
但是,当我们avro.schema.url再次回到user_v2.avscHive Metastore中的内容时,不再重要:
hive> ALTER TABLE users_from_avro_schema SET TBLPROPERTIES('avro.schema.url'='hdfs:///user/tulinski/user_v2.avsc');
OK
Time taken: 0.268 seconds
hive> DESCRIBE users_from_avro_schema;
OK
id int
name string
email string
Run Code Online (Sandbox Code Playgroud)
Avro架构优先于Metastore.
上面的例子表明我们应该避免将hive模式更改与avro模式演变混合在一起,因为否则我们很容易陷入Hive Metastore与读取和写入数据时使用的实际模式之间的混乱和不一致.当我们通过更新avro.schema.url属性来更改我们的avro架构定义时会发生第一个不一致,但是如果我们知道推断架构的Hive策略,我们就可以接受它.我没有检查Hive的源代码是否我对模式逻辑的怀疑是正确的,但上面的例子让我相信下面会发生什么.
我扩展了我的答案,表明即使Avro架构和Hive Metastore之间存在冲突,也可以读取符合Avro架构的数据.请再看看我上面的例子.我们的表定义指向具有三个字段的avro模式:
id int
name string
email string
Run Code Online (Sandbox Code Playgroud)
而在Hive Metastore中有以下列:
id int
name string
phone string
Run Code Online (Sandbox Code Playgroud)
电子邮件与电话
让我们创建一个包含单个用户记录符合user_v2.avsc模式的avro文件.这是它的json表示:
{
"id": 123,
"name": "Tomek",
"email": {"string": "tomek@tomek"}
}
Run Code Online (Sandbox Code Playgroud)
要创建avro文件,我们称之为:
java -jar avro-tools-1.8.2.jar fromjson --schema-file user_v2.avsc user_tomek_v2.json > user_tomek_v2.avro
Run Code Online (Sandbox Code Playgroud)
尽管Hive Metastore不包含email列而且它包含phone列,但我们能够查询我们的表:
hive> set hive.cli.print.header=true;
hive> select * from users_from_avro_schema;
OK
users_from_avro_schema.id users_from_avro_schema.name users_from_avro_schema.email
123 Tomek tomek@tomek
Run Code Online (Sandbox Code Playgroud)
以下是指不涉及模式文件的用例
模式存储在2个位置
1. Metastore
2.作为数据文件的一部分
DESC/SHOW命令的所有信息都来自Metastore.
每个DDL变化仅影响Metastore.
查询数据时,2个模式之间的匹配由列名完成.
如果列类型不匹配,您将收到错误.
create table mytable
stored as avro
as
select 1 as myint
,'Hello' as mystring
,current_date as mydate
;
Run Code Online (Sandbox Code Playgroud)
select * from mytable
;
Run Code Online (Sandbox Code Playgroud)
+-------+----------+------------+
| myint | mystring | mydate |
+-------+----------+------------+
| 1 | Hello | 2017-05-30 |
+-------+----------+------------+
Run Code Online (Sandbox Code Playgroud)
Metastore
select c.column_name
,c.integer_idx
,c.type_name
from metastore.DBS as d
join metastore.TBLS as t on t.db_id = d.db_id
join metastore.SDS as s on s.sd_id = t.sd_id
join metastore.COLUMNS_V2 as c on c.cd_id = s.cd_id
where d.name = 'local_db'
and t.tbl_name = 'mytable'
order by integer_idx
Run Code Online (Sandbox Code Playgroud)
+-------------+-------------+-----------+
| column_name | integer_idx | type_name |
+-------------+-------------+-----------+
| myint | 0 | int |
| mystring | 1 | string |
| mydate | 2 | date |
+-------------+-------------+-----------+
Run Code Online (Sandbox Code Playgroud)
Avro的工具
bash-4.1$ avro-tools getschema 000000_0
{
"type" : "record",
"name" : "mytable",
"namespace" : "local_db",
"fields" : [ {
"name" : "myint",
"type" : [ "null", "int" ],
"default" : null
}, {
"name" : "mystring",
"type" : [ "null", "string" ],
"default" : null
}, {
"name" : "mydate",
"type" : [ "null", {
"type" : "int",
"logicalType" : "date"
} ],
"default" : null
} ]
}
Run Code Online (Sandbox Code Playgroud)
alter table mytable change myint dummy1 int;
Run Code Online (Sandbox Code Playgroud)
select * from mytable;
Run Code Online (Sandbox Code Playgroud)
+--------+----------+------------+
| dummy1 | mystring | mydate |
+--------+----------+------------+
| (null) | Hello | 2017-05-30 |
+--------+----------+------------+
Run Code Online (Sandbox Code Playgroud)
alter table mytable add columns (myint int);
Run Code Online (Sandbox Code Playgroud)
select * from mytable;
Run Code Online (Sandbox Code Playgroud)
+--------+----------+------------+-------+
| dummy1 | mystring | mydate | myint |
+--------+----------+------------+-------+
| (null) | Hello | 2017-05-30 | 1 |
+--------+----------+------------+-------+
Run Code Online (Sandbox Code Playgroud)
Metastore
+-------------+-------------+-----------+
| column_name | integer_idx | type_name |
+-------------+-------------+-----------+
| dummy1 | 0 | int |
| mystring | 1 | string |
| mydate | 2 | date |
| myint | 3 | int |
+-------------+-------------+-----------+
Run Code Online (Sandbox Code Playgroud)
avro-tools
(与原始模式相同的模式)
bash-4.1$ avro-tools getschema 000000_0
{
"type" : "record",
"name" : "mytable",
"namespace" : "local_db",
"fields" : [ {
"name" : "myint",
"type" : [ "null", "int" ],
"default" : null
}, {
"name" : "mystring",
"type" : [ "null", "string" ],
"default" : null
}, {
"name" : "mydate",
"type" : [ "null", {
"type" : "int",
"logicalType" : "date"
} ],
"default" : null
} ]
}
Run Code Online (Sandbox Code Playgroud)
针对该表的任何工作都是基于Metastore中存储的元数据完成的.
在查询表时,正在使用其他元数据,这是存储在数据文件中的元数据.
查询结果结构是从Metastore构建的(参见我的示例,在更改表后返回4列).
返回的数据取决于两种方案 - 文件架构中具有特定名称的字段将映射到Metastore架构中具有相同名称的列.
如果名称匹配但数据类型不匹配,则会出现错误.
将不显示数据文件中Metastore中没有相应列名称的字段.
Metastore中没有数据文件架构中的相应字段的列将保留NULL值.
| 归档时间: |
|
| 查看次数: |
7029 次 |
| 最近记录: |