我决定发布对@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 已正确推断模式,我们可以通过调用以下命令来查看:
hive> DESCRIBE users_from_avro_schema;
OK
id int
name string
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 |
+------------------------+-------------+-------------+-----------+
到目前为止,一切都很好,一切都按我们的预期进行。
但让我们看看更新后会发生什么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}
]
}
我们只是添加了另一个名为电子邮件的字段。
现在我们更新指向 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 无法提供架构时,Hive 会查找元存储。
让我们通过删除来检查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)
描述向我们展示存储在 Metastore 中的数据。让我们通过添加一列来修改它们:
ALTER TABLE users_from_avro_schema ADD COLUMNS (phone string);
它当然会改变 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 |
+------------------------+-------------+-------------+-----------+
但是当我们设置avro.schema.url
再次回到user_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 架构优先于 Metastore。
上面的示例表明,我们应该避免将 Hive 模式更改与 avro 模式演变混合在一起,因为否则我们很容易陷入 Hive Metastore 与读写数据时使用的实际模式之间的混乱和不一致。当我们通过更新来更改 avro 架构定义时,就会出现第一个不一致的情况avro.schema.url
属性,但如果我们了解 Hive 推断模式的策略,我们就可以接受这一点。我还没有检查 Hive 的源代码,我对模式逻辑的怀疑是否正确,但上面的示例让我确信下面发生的事情。
我扩展了我的答案,以表明即使 Avro 模式和符合 Avro 模式的 Hive Metastore 数据之间存在冲突,也可以读取。
请再看一下我上面的例子。我们的表定义指向具有三个字段的 avro 模式:
id int
name string
email string
而在 Hive Metastore 中有以下列:
id int
name string
phone string
电子邮件与电话
让我们创建一个包含符合以下条件的单个用户记录的 avro 文件user_v2.avsc
架构。这是它的 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 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