当我使用Avro'子句创建一个配置单元表时,Avro模式存储在哪里? [英] Where is an Avro schema stored when I create a hive table with 'STORED AS AVRO' clause?

查看:29
本文介绍了当我使用Avro'子句创建一个配置单元表时,Avro模式存储在哪里?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

创建由Avro数据支持的配置单元表至少有两种不同的方法:

  1. 基于avro架构(在本例中,存储在HDFS中)创建表:

    创建表USERS_FROM_AVRO_SCHEMA 行格式Serde‘org.apache.hadoop.hive.serde2.avro.AvroSerDe’ 存储为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’);

  2. 通过使用STORED AS AVRO子句显式指定配置单元列来创建表:

    创建表USERS_STORED_AS_AVRO( ID int, 名称字符串 )存储为avro;

users_from_avro_schema表的元数据没有存储在配置单元元存储中,而是从读取Avro架构文件的SERDE类推断出来,这对吗?或者,表元数据可能存储在Metastore中,在创建表时添加,但是,将配置单元元数据与Avro模式同步的策略是什么呢?我是说两种情况:

  1. 更新表元数据(添加/删除列)和
  2. 通过更改avro.schema.url属性更新Avro架构。
在第二种情况下,当我调用DESCRIBE FORMATTED users_stored_as_avro时,没有定义avro.schema.*属性,因此我不知道使用哪个avro模式来读/写数据。它是否基于存储在元存储区中的表元数据动态生成?

fragment这本fragment《编程配置单元》一书讨论了从SerDe类推断有关列的信息,但另一方面HIVE-4703删除了此from deserializer信息窗体列注释。那么,我如何检查给定表(Metastore或Avro架构)的列类型来源是什么?

推荐答案

我决定发布一个补充@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'
让我们看一下在创建一个引用存储在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

配置单元Metastore向我们展示了相同的内容(我使用@DuduMarkovitz的查询):

+------------------------+-------------+-------------+-----------+
| tbl_name               | column_name | integer_idx | type_name |
+------------------------+-------------+-------------+-----------+
| users_from_avro_schema | id          |           0 | int       |
| users_from_avro_schema | name        |           1 | string    |
+------------------------+-------------+-------------+-----------+

到目前为止,一切都很好,一切都和我们预期的一样。 但是,让我们看看当我们更新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

是的,酷!但您是否希望配置单元元存储包含此附加列?
遗憾的是,元存储中没有任何更改

+------------------------+-------------+-------------+-----------+
| tbl_name               | column_name | integer_idx | type_name |
+------------------------+-------------+-------------+-----------+
| users_from_avro_schema | id          |           0 | int       |
| users_from_avro_schema | name        |           1 | string    |
+------------------------+-------------+-------------+-----------+

我怀疑配置单元具有以下推断架构的策略:它尝试从为给定表指定的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)
Describe向我们显示存储在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_v2.avsc时,配置单元元存储中的内容就不再重要了:

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模式定义时,第一个不一致发生,但是如果我们知道推断模式的配置单元策略,我们可以接受这一点。我没有检查配置单元的源代码,我对架构逻辑的怀疑是否正确,但上面的示例让我相信下面发生了什么。

我扩展了我的答案,以表明即使在Avro模式和配置单元元存储之间存在冲突时,也可以读取符合Avro模式的数据。 请再看一下我上面的例子。我们的表定义指向具有三个字段的avro架构:

id    int
name  string
email string

而在配置单元元存储区中有以下列:

id    int
name  string
phone string

电子邮件与电话
让我们创建一个avro文件,其中包含符合user_v2.avsc架构单个用户记录。这是它的json表示:

{
  "id": 123,
  "name": "Tomek",
  "email": {"string": "tomek@tomek"}
}

要创建我们称为avro的avro文件:

java -jar avro-tools-1.8.2.jar fromjson --schema-file user_v2.avsc user_tomek_v2.json > user_tomek_v2.avro

尽管配置单元元存储区不包含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

这篇关于当我使用Avro'子句创建一个配置单元表时,Avro模式存储在哪里?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆