创建支持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');
1.通过使用STORED AS AVRO
子句显式指定配置单元列来创建表:
CREATE TABLE users_stored_as_avro(id INT,name STRING)STORED AS AVRO;
在第一种情况下,users_from_avro_schema
表的元数据没有存储在Hive Metastore中,而是从阅读avro schema文件的SERDE类中推断出来的,我说的对吗?或者,表元数据存储在Metastore中,在创建表时添加,但是将Hive元数据与Avro schema同步的策略是什么?我指的是两种情况:
1.更新表元数据(添加/删除列)和
1.通过更改avro.schema.url
属性更新Avro架构。
在第二种情况下,当我调用DESCRIBE FORMATTED users_stored_as_avro
时,没有定义avro.schema.*
属性,所以我不知道使用哪个Avro模式来读取/写入数据。它是基于存储在Metastore中的表的元数据动态生成的吗?
Programming Hive这本书讨论了从SerDe类中推断列的信息,但另一方面,HIVE-4703从列注解中删除了from deserializer
信息。我如何检查给定表的列类型的来源(Metastore或Avro模式)?
3条答案
按热度按时间rkttyhzu1#
我决定发表一个对@DuduMarkovitz给出的答案的补充。
为了使代码示例更简洁,让我们澄清
STORED AS AVRO
子句是以下三行的等价物:让我们来看看当我们创建一个引用存储在hdfs中的avro schema的表时会发生什么。下面是schema:
我们使用以下命令创建表:
Hive已经正确地推断出了schema,我们可以通过调用来看到:
Hive Metastore向我们展示了同样的情况(我使用@DuduMarkovitz的查询):
到目前为止,一切都很好,一切都如我们所期望的那样。但是让我们看看当我们更新
avro.schema.url
属性以指向模式的下一个版本(users_v2.avsc)时会发生什么,如下所示:我们只是添加了另一个名为电子邮件的字段。
现在我们更新一个指向hdfs中avro模式的表属性:
表元数据是否已更改?
是的,很酷!但是你希望Hive Metastore包含这个额外的列吗?
不幸的是,在Metastore中没有任何变化:
**我怀疑Hive有以下推断schema的策略:**它尝试从为给定表指定的SerDe类中获取schema。当SerDe无法提供schema时,Hive会查看元存储。
让我们通过删除
avro.schema.url
属性来检查:Describe向我们展示了存储在Metastore中的数据。让我们通过添加一列来修改它们:
这当然会改变Hive Metastore:
但是当我们再次将
avro.schema.url
设置回user_v2.avsc
时,Hive Metastore中的内容就不再重要了:Avro架构优先于元存储。
上面的例子表明,我们应该避免将hive模式更改与avro模式演化混合在一起,因为否则我们很容易陷入Hive元存储与阅读数据时使用的实际模式之间的混乱和不一致。第一个不一致发生在我们通过更新
avro.schema.url
属性来更改avro模式定义时,我还没有检查Hive的源代码,我对模式逻辑的怀疑是否正确,但是上面的例子说服了我下面发生了什么。我扩展了我的答案,以表明即使Avro模式和Hive Metastore之间存在冲突,也可以读取符合Avro模式的数据。请再次查看我上面的示例。我们的表定义指向具有三个字段的Avro模式:
而在Hive Metastore中有以下列:
电子邮件vs电话
让我们创建一个avro文件,其中包含一个符合
user_v2.avsc
模式的用户记录。这是它的json表示:要创建avro文件,我们调用:
尽管Hive Metastore不包含
email
列,而是包含phone
列,但我们仍然可以查询我们的表:jv2fixgn2#
以下是不涉及模式文件的用例
架构存储在两个位置
1.元存储
2.作为数据文件的一部分
DESC/SHOW命令的所有信息都取自元存储区。
每个DDL更改都只影响元存储区。
当您查询数据时,两个模式之间的匹配是通过列名完成的。
如果列类型不匹配,您将得到一个错误。
Demo
元数据商店
avro-tools
元数据商店
avro-tools
(same schema作为原始schema)
针对该表的任何工作都是基于存储在Metastore中的元数据完成的。
查询表时,使用的是附加元数据,即数据文件中存储的元数据。
查询结果结构是从Metastore构造的(在我的示例中,表被更改后返回了4列)。
返回的数据取决于两个方案-文件方案中具有特定名称的字段将Map到Metastore方案中具有相同名称的列。
如果名称匹配但数据类型不匹配,则会出现错误。
数据文件中在元存储中没有对应列名的字段将不会显示。
Metastore中的列如果在数据文件模式中没有对应的字段,则将保存NULL值。
hs1rzwqc3#
现在考虑到像Iceberg和Delta表这样的表格式,这可能有点过时了,因为它负责模式的更改和演变(这是AVRO开始的主要卖点)
结合Tomek和大卫的答案,是否可以得出结论,对于使用“存储为avro”创建的hive表,字段元数据是从3个不同的来源推断/引用/提取的
1.通过创建avro文件更新数据中的模式(参见Tomek的回答如何从JSON创建一个)
1.使用添加删除列更新配置单元元存储区
1.使用avro.schema.url属性更新avsc架构URL。这是可选的
以下是我对hive代码中不同操作所遵循的逻辑的解释(我会在了解更多信息时更新我的答案):
1.描述/显示:avsc架构URL优先,然后是配置单元元存储区