Я решил опубликовать дополнительный ответ на ответы @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'
Давайте посмотрим, что происходит, когда мы создаем таблицу, содержащую ссылку на схему avro, хранящуюся в hdfs. Вот схема:
{
"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.
Теперь мы обновляем свойство таблицы, указывающее на схему avro в hdfs:
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.
Приведенный выше пример показывает, что нам лучше избегать смешивания изменений схемы улья с эволюцией схемы avro, потому что в противном случае мы можем легко попасть в большой беспорядок и несогласованность между Hive Metastore и фактической схемой, которая используется при чтении и записи данных. Первое несоответствие возникает, когда мы изменяем определение схемы avro, обновляя свойство avro.schema.url
, но мы можем смириться с этим, если знаем о стратегии Hive вывода схемы. Я не проверял в исходном коде Hive, верны ли мои подозрения относительно логики схемы, но приведенный выше пример убеждает меня в том, что происходит под ним.
Я расширил свой ответ, чтобы показать, что даже при конфликте между схемой Avro и данными Hive Metastore, которые соответствуют схеме Avro, можно прочитать. Пожалуйста, взгляните еще раз на мой пример выше. Наше определение таблицы указывает на схему 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
person
tomek
schedule
31.05.2017