当我用'stored as avro'子句创建配置单元表时,avro模式存储在哪里?

5ssjco0h  于 2021-06-26  发布在  Hive
关注(0)|答案(2)|浏览(378)

至少有两种不同的方法可以创建以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');

2) 通过使用显式指定配置单元列来创建表 STORED AS AVRO 条款:

CREATE TABLE users_stored_as_avro(
  id INT,
  name STRING
) STORED AS AVRO;

在元数据的第一种情况下,我说的对吗 users_from_avro_schema 表不是存储在配置单元元存储中,而是从读取avro模式文件的serde类推断出来的?或者表元数据存储在metastore中,在创建表时添加,但是同步配置单元元数据和avro模式的策略是什么?我指的是两种情况:更新表元数据(添加/删除列)和通过更改 avro.schema.url 财产。
第二种情况是我打电话的时候 DESCRIBE FORMATTED users_stored_as_avro 根本没有 avro.schema.* 属性定义,所以我不知道哪个avro模式用于读/写数据,它是基于存储在metastore中的表元数据动态生成的吗?
编程hive手册的这个片段说的是从serde类推断关于列的信息,但另一方面hive-4703删除了这个 from deserializer 信息表单列注解。如何检查给定表的列类型源(metastore或avro模式)?

zvokhttg

zvokhttg1#

以下是不涉及模式文件的用例
架构存储在两个位置
1.元商店
2.作为数据文件的一部分
desc/show命令的所有信息都来自metastore。
每个ddl更改只影响元存储。
当您查询数据时,两个模式之间的匹配由列名称完成。
如果列类型不匹配,则会出现错误。

演示

create table mytable 
stored as avro 
as 
select  1               as myint
       ,'Hello'         as mystring
       ,current_date    as mydate
;
select * from mytable
;
+-------+----------+------------+
| myint | mystring |   mydate   |
+-------+----------+------------+
|     1 | Hello    | 2017-05-30 |
+-------+----------+------------+

元存储

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 |
+-------------+-------------+-----------+
| myint       |           0 | int       |
| mystring    |           1 | string    |
| mydate      |           2 | date      |
+-------------+-------------+-----------+

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
  } ]
}
alter table mytable change myint dummy1 int;
select * from mytable;
+--------+----------+------------+
| dummy1 | mystring |   mydate   |
+--------+----------+------------+
| (null) | Hello    | 2017-05-30 |
+--------+----------+------------+
alter table mytable add columns (myint int);
select * from mytable;
+--------+----------+------------+-------+
| dummy1 | mystring |   mydate   | myint |
+--------+----------+------------+-------+
| (null) | Hello    | 2017-05-30 |     1 |
+--------+----------+------------+-------+

元存储

+-------------+-------------+-----------+
| 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
  } ]
}

对该表所做的任何工作都是基于存储在metastore中的元数据来完成的。
当查询表时,会使用其他元数据,即存储在数据文件中的元数据。
查询结果结构是从metastore构造的(在我的示例中,在表被修改后返回4列)。
返回的数据取决于这两种模式—文件模式中具有特定名称的字段将Map到元存储模式中具有相同名称的列。
如果名称匹配但数据类型不匹配,则会出现错误。
如果数据文件中的字段在元存储中没有相应的列名,则不会显示该字段。
metastore中的列如果在数据文件架构中没有相应的字段,则该列将包含空值。

biswetbf

biswetbf2#

我决定发表一个对@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}
  ]
}

我们只是添加了另一个名为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

是啊,酷!但是您是否希望配置单元元存储包含此附加列?
不幸的是,在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)

descripe向我们显示存储在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元存储中的内容不再重要:

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模式定义时 avro.schema.url 属性,但如果我们知道推断模式的配置单元策略,我们就可以接受它。我还没有在hive的源代码中检查我对模式逻辑的怀疑是否正确,但是上面的例子让我确信下面发生了什么。
我扩展了我的回答,以表明即使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文件,我们称之为:

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

相关问题