Hive 使用';创建配置单元表时存储Avro模式的位置;存储为AVRO';条款
至少有两种不同的方法可以创建由Avro数据支持的配置单元表: 1) 基于Avro模式创建表(在本例中存储在hdfs中): 2) 通过使用存储为AVRO的Hive 使用';创建配置单元表时存储Avro模式的位置;存储为AVRO';条款,hive,schema,avro,metastore,Hive,Schema,Avro,Metastore,至少有两种不同的方法可以创建由Avro数据支持的配置单元表: 1) 基于Avro模式创建表(在本例中存储在hdfs中): 2) 通过使用存储为AVRO的子句显式指定配置单元列来创建表: CREATE TABLE users_stored_as_avro( id INT, name STRING ) STORED AS AVRO; 在第一种情况下,avro模式表中的用户的元数据不存储在Hive Metastore中,而是从读取avro模式文件的SERDE类推断出来的,这是正确的吗?或者表
子句显式指定配置单元列来创建表:
CREATE TABLE users_stored_as_avro(
id INT,
name STRING
) STORED AS AVRO;
在第一种情况下,avro模式
表中的用户的元数据不存储在Hive Metastore中,而是从读取avro模式文件的SERDE类推断出来的,这是正确的吗?或者表元数据存储在Metastore中,在创建表时添加,但用于将配置单元元数据与Avro模式同步的策略是什么?我指的是两种情况:更新表元数据(添加/删除列)和通过更改Avro.schema.url
属性来更新Avro模式
在第二种情况下,当我调用descripe FORMATTED users\u storage\u as\u avro
时,没有定义avro.schema.
属性,因此我不知道哪个avro模式用于读/写数据,它是基于存储在元存储中的表元数据动态生成的吗
这本编程配置单元书讲述了如何从SerDe类中推断有关列的信息,但另一方面从反序列化器中删除了此信息表单列注释。如何检查给定表(Metastore或Avro模式)的列类型的来源?以下是不涉及模式文件的用例
架构存储在两个位置
1.元存储
2.作为数据文件的一部分
DESC/SHOW命令的所有信息都取自元存储。
每个DDL更改只影响元存储
查询数据时,两个架构之间的匹配由列名称完成。
如果列类型不匹配,则会出现错误
演示
元存储
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
+-------------+-------------+-----------+
| column_name | integer_idx | type_name |
+-------------+-------------+-----------+
| dummy1 | 0 | int |
| mystring | 1 | string |
| mydate | 2 | date |
| myint | 3 | int |
+-------------+-------------+-----------+
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
} ]
}
元存储
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
+-------------+-------------+-----------+
| column_name | integer_idx | type_name |
+-------------+-------------+-----------+
| dummy1 | 0 | int |
| mystring | 1 | string |
| mydate | 2 | date |
| myint | 3 | int |
+-------------+-------------+-----------+
avro工具
(与原始模式相同)
针对该表的任何工作都是基于存储在Metastore中的元数据完成的。
查询表时,将使用附加的元数据,即存储在数据文件中的元数据。
查询结果结构是从元存储构建的(在我的示例中,请参见表更改后返回的4列)。
返回的数据取决于两个方案-文件架构中具有特定名称的字段将映射到元存储架构中具有相同名称的列。
如果名称匹配但数据类型不匹配,则会出现错误。
数据文件中的字段如果在元存储中没有相应的列名,则不会显示。
数据文件架构中没有相应字段的元存储中的列将包含空值 我决定发表一份对@DuduMarkovitz给出的答案的补充
为了使代码示例更简洁,让我们澄清存储为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'
让我们看看当我们创建一个表来引用存储在hdfs中的avro模式时会发生什么。以下是模式:
{
"namespace": "io.sqooba",
"name": "user",
"type": "record",
"fields": [
{"name": "id", "type": "int"},
{"name": "name", "type": "string"}
]
}
我们使用以下命令创建表:
CREATE TABLE users_from_avro_schema
STORED AS AVRO
TBLPROPERTIES ('avro.schema.url'='hdfs:///user/tulinski/user.avsc');
配置单元已正确推断出架构,我们可以通过调用:
hive> DESCRIBE users_from_avro_schema;
OK
id int
name string
Hive Metastore向我们展示了同样的情况(我使用@DuduMarkovitz的查询):
到目前为止,一切正常,一切正常。
但让我们看看当我们更新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}
]
}
我们只是添加了另一个名为email的字段。
现在,我们更新一个指向hdfs中avro模式的表属性:
ALTER TABLE users_from_avro_schema SET TBLPROPERTIES('avro.schema.url'='hdfs:///user/tulinski/user_v2.avsc');
表元数据是否已更改
hive> DESCRIBE users_from_avro_schema;
OK
id int
name string
email string
是啊,酷!但是您是否希望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 |
+------------------------+-------------+-------------+-----------+
我怀疑Hive有以下推断模式的策略:它试图从为给定表指定的SerDe类中获取模式。当SerDe无法提供架构时,配置单元将查看元存储。
让我们通过删除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)
description向我们显示存储在Metastore中的数据。让我们通过添加列来修改它们:
ALTER TABLE users_from_avro_schema ADD COLUMNS (phone string);
它当然会更改配置单元元存储:
+------------------------+-------------+-------------+-----------+
| 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 |
+------------------------+-------------+-------------+-----------+
但是当我们再次将avro.schema.url
设置回user\u v2.avsc
Hive 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
Avro模式优先于元存储
上面的示例表明,我们应该避免将配置单元模式更改与avro模式演化混合在一起,因为否则我们很容易陷入配置单元元存储与读写数据时使用的实际模式之间的混乱和不一致。第一个不一致发生在我们通过更新avro.schema.url
属性来更改avro模式定义时,但是如果我们知道推断模式的配置单元策略,我们就可以接受这一点。我还没有在Hive的源代码中检查我对模式逻辑的怀疑是否正确,但是上面的例子让我相信下面发生了什么
我扩展了我的答案,以表明即使Avro模式和符合Avro模式的Hive元存储数据之间存在冲突,也可以读取。
请再看看我上面的例子。我们的表定义指向具有三个字段的avro模式:
id int
name string
email string
而在配置单元元存储中,有以下列:
id int
name string
phone string
电子邮件与电话的对比
让我们创建一个avro文件,其中包含符合user\u v2.avsc
schema的单个用户记录。这是它的json表示:
{
"id": 123,
"name": "Tomek",
"email": {"string": "tomek@tomek"}
}
要创建avro文件,我们称之为:
java -jar avro-tools-1.8.2.jar fromjson --schema-file user_v2.avsc user_tomek_v2.json > user_tomek_v2.avro
我们能够查询我们的表,尽管Hive M
ALTER TABLE users_from_avro_schema SET TBLPROPERTIES('avro.schema.url'='hdfs:///user/tulinski/user_v2.avsc');
hive> DESCRIBE users_from_avro_schema;
OK
id int
name string
email string
+------------------------+-------------+-------------+-----------+
| tbl_name | column_name | integer_idx | type_name |
+------------------------+-------------+-------------+-----------+
| users_from_avro_schema | id | 0 | int |
| users_from_avro_schema | name | 1 | string |
+------------------------+-------------+-------------+-----------+
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)
ALTER TABLE users_from_avro_schema ADD COLUMNS (phone string);
+------------------------+-------------+-------------+-----------+
| 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 |
+------------------------+-------------+-------------+-----------+
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
id int
name string
email string
id int
name string
phone string
{
"id": 123,
"name": "Tomek",
"email": {"string": "tomek@tomek"}
}
java -jar avro-tools-1.8.2.jar fromjson --schema-file user_v2.avsc user_tomek_v2.json > user_tomek_v2.avro
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