Где хранится схема Avro, когда я создаю таблицу куста с предложением STORED AS AVRO?

Существует как минимум два разных способа создания таблицы кустов с данными Avro:

  1. Создание таблицы на основе схемы Avro (в этом примере хранящейся в hdfs):

    СОЗДАТЬ ТАБЛИЦУ users_from_avro_schema ФОРМАТ СТРОКИ SERDE 'org.apache.hadoop.hive.serde2.avro.AvroSerDe' СОХРАНЕНО КАК INPUTFORMAT 'org.apache.hadoop.hive.ql.io.avro.Avro.AvroService.Inputdoop.html или O.Format. .ql.io.avro.AvroContainerOutputFormat 'TBLPROPERTIES (' avro.schema.url '=' hdfs: ///user/root/avro/schema/user.avsc ');

  2. Создание таблицы путем явного указания столбцов куста с помощью предложения STORED AS AVRO:

    СОЗДАТЬ ТАБЛИЦУ users_stored_as_avro (идентификатор INT, имя STRING), СОХРАНЕННОЕ КАК AVRO;

Правильно ли я, что в первом случае метаданные таблицы users_from_avro_schema не хранятся в Hive Metastore, а выводятся из класса SERDE, читающего файл схемы avro? Или, может быть, метаданные таблицы хранятся в Metastore, добавляются при создании таблицы, но тогда какова политика синхронизации метаданных улья со схемой Avro? Я имею в виду оба случая:

  1. обновление метаданных таблицы (добавление / удаление столбцов) и
  2. обновление схемы Avro путем изменения свойства avro.schema.url.

Во втором случае, когда я вызываю DESCRIBE FORMATTED users_stored_as_avro, свойство avro.schema.* не определено, поэтому я не знаю, какая схема Avro используется для чтения / записи данных. Создается ли он динамически на основе метаданных таблицы, хранящихся в Metastore?

Это фрагмент книги Programming Hive обсуждает вывод информации о столбцах из класса SerDe, но, с другой стороны, HIVE-4703 удаляет комментарии в from deserializer столбцах информационной формы. Как я могу тогда проверить, что является источником типов столбцов для данной таблицы (Metastore или схема Avro)?


person tomek    schedule 30.05.2017    source источник
comment
просто дополнительный вопрос, для поддержки развития схемы должны использоваться ВНЕШНИЕ таблицы, правильно?   -  person Ashika Umanga Umagiliya    schedule 25.09.2018


Ответы (2)


Я решил опубликовать дополнительный ответ на ответы @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

Следующее относится к варианту использования, в котором не используется файл схемы

Схема хранится в 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 |
+-------+----------+------------+

Хранилище метаданных

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

авро-инструменты

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-tools
(та же схема, что и исходная)

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

Любая работа с этой таблицей выполняется на основе метаданных, хранящихся в хранилище метаданных.
При запросе таблицы используются дополнительные метаданные, которые являются метаданными, хранящимися в файле данных.
Структура результатов запроса создается из хранилища метаданных (в моем примере показано, что 4 столбца возвращаются после изменения таблицы).
Возвращаемые данные зависят от обоих схемы - поле с определенным именем в схеме файла будет сопоставлено столбцу с тем же именем в схеме Metastore.
Если имена совпадают, а типы данных - нет, возникнет ошибка.
A поля из файла данных, у которого нет соответствующего имени столбца в хранилище метаданных, не будут представлены.
Столбец в хранилище метаданных без соответствующего поля в схеме файла данных будет содержать значения NULL.

person David דודו Markovitz    schedule 30.05.2017
comment
Спасибо @DuduMarkovitz за ваш ответ и приведенный вами пример. Я также провел несколько тестов с эволюцией схемы и собираюсь поделиться результатами. - person tomek; 31.05.2017
comment
Ссылаясь на ваш ответ @DuduMarkovitz, правильно ли я понимаю, что в вашем примере схема avro (соответствующая определению таблицы улья) не хранится ни в одном месте, а генерируется на основе метаданных улья каждый раз, когда улей сохраняет данные в hdfs (по порядку чтобы встроить его в выходной файл (ы) avro), верно? А как насчет чтения? Я предполагаю, что улей должен иметь одну схему avro для целей чтения, поэтому единственный способ, который я вижу, - это то, что схема создается на основе текущего определения таблицы, взятого из хранилища метаданных (так же, как и в случае записи). Я прав? - person tomek; 31.05.2017
comment
Я по-прежнему вижу разницу между созданием таблицы со схемой улья (СОХРАНЯЕТСЯ КАК AVRO) и случаем, когда схема улья выводится из файла avro, переданного avro.schema.* свойствами таблицы (который затем может быть обновлен). Я скоро покажу, что я имею в виду, на более конкретном примере. - person tomek; 31.05.2017
comment
Я не могу согласиться с вашими последними двумя утверждениями: поля из файла данных, для которых нет соответствующего имени столбца в Metastore, не будут представлены. Столбец в Metastore без соответствующего поля в схеме файла данных будет содержать значения NULL. Взгляните на мой обновленный пример. - person tomek; 31.05.2017
comment
Мой ответ, как видно из приведенных примеров, относится только ко второму варианту использования, где нет файла схемы. - person David דודו Markovitz; 31.05.2017
comment
Хорошо, @Dudu, но кто-то может понять эти утверждения как общие правила (я имею в виду, что Hive Metastore всегда принимает участие в распознавании схемы, что неверно). Возможно, стоит уточнить это в своем ответе. - person tomek; 31.05.2017
comment
Уточнено. У меня не было времени представить первый вариант использования, но я вижу, что вы реализовали мою методологию, чтобы ответить на него самостоятельно. - person David דודו Markovitz; 31.05.2017