Где хранится схема Avro, когда я создаю таблицу кустов с предложением STORED AS AVRO?
Существует как минимум два разных способа создания таблицы кустов с данными 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
таблицы не хранятся в Hive Metastore, а выводятся из класса SERDE, читающего файл схемы avro? Или, может быть, метаданные таблицы хранятся в Metastore, добавляемом при создании таблицы, но какова политика синхронизации метаданных улья со схемой Avro? Я имею в виду оба случая: обновление метаданных таблицы (добавление / удаление столбцов) и обновление схемы Avro путем изменения avro.schema.url
имущество.
Во втором случае, когда я звоню DESCRIBE FORMATTED users_stored_as_avro
здесь нет avro.schema.*
определено свойство, поэтому я не знаю, какая схема Avro используется для чтения / записи данных, генерируется ли она динамически на основе метаданных таблицы, хранящихся в Metastore?
В этом фрагменте книги "Улей программирования" говорится о выводимой информации о столбцах из класса SerDe, но, с другой стороны, HIVE-4703 удаляет это from deserializer
инфо формы колонки комментариев. Как я могу проверить, каков источник типов столбцов для данной таблицы (схема Metastore или Avro)?
3 ответа
Я решил опубликовать дополнительный ответ на вопросы, которые дал @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}
]
}
Мы просто добавили еще одно поле под названием электронная почта.
Теперь мы обновляем свойство таблицы, указывающее на схему 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)
Опишите, показывает нам данные, хранящиеся в 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
Следующее относится к случаю использования, когда файл схемы не задействован
Схема хранится в 2 местах
1. Метастор
2. Как часть файлов данных
Вся информация для команд DESC/SHOW берется из метастаза.
Каждое изменение 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 |
+-------+----------+------------+
Metastore
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 |
+--------+----------+------------+-------+
Metastore
+-------------+-------------+-----------+
| 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 столбца возвращаются после изменения таблицы).
Возвращаемые данные зависят от обеих схем - поле с определенным именем в схеме файла будет сопоставлено столбцу с тем же именем в схеме Metastore.
Если имена совпадают, но типы данных не совпадают, возникнет ошибка.
Поля из файла данных, которые не имеют соответствующего имени столбца в Metastore, не будут представлены.
Столбец в Metastore без соответствующего поля в схеме файла данных будет содержать значения NULL.
Сейчас это может немного устареть, учитывая, что такие форматы таблиц, как таблица Iceberg и Delta, заботятся об изменениях и развитии схемы (что с самого начала было основным преимуществом AVRO).
Объединяя ответы Томека и Дэвида, можно ли с уверенностью заключить, что для таблиц ульев, созданных с использованием «сохраненных как avro», метаданные полей выводятся/ссылаются/извлекаются из трех разных источников
- схема в данных обновляется путем создания файла avro (см. ответ Томека, как создать его из JSON)
- метахранилище Hive обновлено с использованием столбца добавления и удаления
- URL-адрес схемы avsc обновлен с использованием свойства avro.schema.url. Это необязательно
Вот моя интерпретация (я буду обновлять свой ответ по мере того, как узнаю больше) логики, которая используется в коде куста для различных операций:
- выберите: схема в данных имеет приоритет, затем ошибка метахранилища куста возникает только в том случае, если имя совпадает, а тип данных - нет.
- описать/показать: URL-адрес схемы avsc имеет приоритет, затем метахранилище куста
- вставить: очевидно, схема внутри данных; но есть некоторая проверка, выполненная с помощью URL-адреса схемы avsc