我决定发布对@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)
Describe 向我们展示了存储在 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.schema.url
属性来更改我们的 avro 模式定义时,但如果我们知道 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