Понимание нотации создания таблицы Hive

Я столкнулся с таблицами Hive, которые мне нужно преобразовать в эквивалент Redshift / MySql. У меня проблемы с пониманием структуры запроса Hive, и я был бы признателен за помощь:

CREATE TABLE IF NOT EXISTS table_1 (
    id BIGINT,
    price DOUBLE,
    asset string
)
PARTITIONED BY (
    pt STRING
);
ALTER TABLE table_1 DROP IF EXISTS PARTITION (pt== '${yyyymmdd}');

INSERT OVERWRITE TABLE table_1 PARTITION (pt= '${yyyymmdd}') 
select aa.id,aa.price,aa.symbol from
...
...
from
 table_2 table 

Мне не удается понять предложение PARTITIONED BY. Это, если я правильно понимаю, отличается от разделов таблиц MySQL и является динамическим разделом, специфичным для Hive. Раздел не определяет столбец или ключ, а разделы по текущей дате.

Означает ли это, что таблица_1 разбита по дате? Каждый день имеет отдельный раздел?

Далее в коде есть обозначения, похожие на

inner join table_new table on table.pt = '${yyyymmdd}' and ...

В этом контексте означает ли это, что для объединения выбираются только строки, вставленные на yyyymmdd?

Спасибо.


person madu    schedule 04.06.2020    source источник
comment
раздел в Hive - это просто папка HDFS   -  person mangusta    schedule 04.06.2020


Ответы (2)


Раздел в Hive - это папка в HDFS по умолчанию с именем key=value + метаданные в хранилище метаданных Hive. Вы можете изменить расположение раздела и создать его поверх любой папки.

Этот PARTITIONED BY (pt STRING) определяет pt столбца раздела типа строка, а не дату. Значения разделов хранятся в метаданных. Столбец pt отсутствует в файлах данных таблицы, он определен только в PARTITIONED BY, все значения разделов хранятся в метаданных. Если вы загружаете раздел динамически, создается папка раздела с именем pt = 'value'.

Это предложение динамически создает раздел:

INSERT OVERWRITE TABLE table_1 PARTITION (pt) 
select id, price, symbol
       coln as pt            --partition column should be the last one
  from ...

И это предложение загружает один статический раздел:

INSERT OVERWRITE TABLE table_1 PARTITION (pt= '${yyyymmdd}') 
select aa.id,aa.price,aa.symbol 
  from

Столбец раздела не выбран, значение раздела указано в

PARTITION  (pt= '${yyyymmdd}')

'${yyyymmdd}' это параметр с именем yyyymmdd, который передается в сценарий с использованием --hivevar следующим образом:

 hive --hivevar yyyymmdd=20200604 -f myscript.sql 

В этом случае вы можете передать ЛЮБУЮ строку в качестве значения раздела, хотя имя параметра yyyymmdd предполагает его формат.

Кстати, формат даты в кусте - 'yyyy-MM-dd'. Строки в формате 'yyyy-MM-dd' могут быть неявно преобразованы в DATE.

person leftjoin    schedule 04.06.2020
comment
Большое спасибо @leftjoin. Я не могу понять, что INSERT OVERWRITE TABLE table_1 PARTITION (pt = '20200604') создает новую таблицу с папкой 20200604 HDFS. Что произойдет, если я сделаю еще одну INSERT OVERWRITE ... (pt = 20200605)? Создает ли он новую таблицу в новой папке 20200605? Может предыдущая таблица еще существует в папке 20200604? - person madu; 04.06.2020
comment
Таким образом, раздел Hive - это способ иметь несколько таблиц одной и той же схемы, разделенных ключом / значением раздела? - person madu; 04.06.2020
comment
Он не создает новую таблицу. Он создает новый раздел в той же таблице. Папки разделов по умолчанию находятся внутри папки таблицы. Но вы можете изменить раздел и изменить местоположение на любое другое. - person leftjoin; 04.06.2020
comment
Означает ли это, что INSERT OVERWRITE TABLE table_1 PARTITION (pt = 20200605) перезаписывает данные, созданные в INSERT OVERWRITE TABLE table_1 PARTITION (pt = 20200604)? Предполагая, что pt - это даты? - person madu; 04.06.2020
comment
В чем будет разница между INSERT OVERWRITE TABLE table_1 PARTITION (pt = 20200605) и ALTER TABLE table_1 DROP IF EXISTS PARTITION (pt = 20200605)? Спасибо. - person madu; 04.06.2020
comment
@madu нет, потому что раздел другой. первый будет перезаписывать данные в pt = 20200605, а второй - в pt = 20200604 - person leftjoin; 04.06.2020
comment
Спасибо. Теперь я использую INSERT OVERWRITE .... - person madu; 04.06.2020
comment
разница очевидна: INSERT OVERWRITE - загружает новые данные (удаляя старые данные, если раздел существовал). И DROP - удаляет раздел (и его местоположение, если таблица управляемая) - person leftjoin; 04.06.2020
comment
Это означает, что если для таблицы определен раздел, операции влияют только на этот конкретный раздел. - person madu; 04.06.2020

Я постараюсь одним кадром объяснить, что такое разбиение на разделы в Hive. В первую очередь было бы

КОГДА ИСПОЛЬЗОВАТЬ РАЗДЕЛЕНИЕ ТАБЛИЦ

  • Таблица разбиения хороша, когда:

    • Reading the entire dataset takes too long
    • Запросы почти всегда фильтруются по столбцам раздела
    • Существует разумное количество различных значений для столбцов раздела.
  • Генерация данных процесса ETL разделяет данные по именам файлов или каталогов

  • Значения столбца раздела не содержатся в самих данных
  • Не разбивайте на столбцы с множеством уникальных значений
  • Пример: разделение клиентов по имени

СОЗДАНИЕ РАЗДЕЛЕННЫХ ТАБЛИЦ

Чтобы создать секционированную таблицу, используйте предложение PARTITIONED BY в операторе CREATE TABLE. Имена и типы столбцов раздела должны быть указаны в предложении PARTITIONED BY и только в предложении PARTITIONED BY. Они также не должны появляться в списке всех других столбцов.

CREATE TABLE customers_by_country 
        (cust_id STRING, name STRING) 
PARTITIONED BY (country STRING)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';

Пример оператора CREATE TABLE, показанный выше, создает таблицу customers_by_country, которая разделена столбцом STRING с именем country. Обратите внимание, что столбец страны появляется только в предложении PARTITIONED BY, а не в списке столбцов над ним. В этом примере указывается только один столбец раздела, но вы можете указать более одного, используя список столбцов, разделенных запятыми, в предложении PARTITIONED BY. Помимо этих конкретных различий, этот оператор CREATE TABLE совпадает с оператором, используемым для создания эквивалентной несекционированной таблицы.

Разделение таблицы реализовано способом, который в основном прозрачен для пользователя, отправляющего запросы с помощью Hive. Столбец раздела - это так называемый виртуальный столбец, поскольку его значения не хранятся в файлах данных. Ниже приведен результат выполнения команды DESCRIBE для customers_by_country; он отображает страну столбца раздела, как если бы это был обычный столбец в таблице. Вы можете ссылаться на столбцы секционирования в любом из обычных предложений оператора SELECT.

name    type    comment

cust_id string   
name    string   
country string   

Вы можете загружать данные в многораздельные таблицы динамически или статически.

ЗАГРУЗКА ДАННЫХ В ДИНАМИЧЕСКИЙ РАЗДЕЛ

Один из способов загрузки данных в многораздельную таблицу - использовать динамическое разбиение, которое автоматически определяет разделы при загрузке данных, используя значения в столбце раздела. (Другой способ - вручную определить разделы с помощью статического разбиения на разделы)

Чтобы использовать динамическое разбиение, вы должны загружать данные с помощью оператора INSERT. В операторе INSERT вы должны использовать предложение PARTITION для перечисления столбцов раздела. Вставляемые данные должны включать значения столбцов раздела. Столбцы раздела должны быть крайними правыми столбцами в данных, которые вы вставляете, и они должны быть в том же порядке, что и в предложении PARTITION.

INSERT OVERWRITE TABLE customers_by_country 
    PARTITION(country)
    SELECT cust_id, name, country FROM customers;

В приведенном выше примере используется оператор INSERT… SELECT для загрузки данных в таблицу customers_by_country с динамическим разделением. Обратите внимание, что столбец раздела, страна, включен в предложение PARTITION и указан последним в списке SELECT.

Когда Hive выполняет этот оператор, он автоматически создает разделы для столбца страны и загружает данные в эти разделы на основе значений в столбце страны. Полученные файлы данных в подкаталогах разделов не содержат значений для столбца страны. Поскольку страна известна на основе того, в каком подкаталоге находится файл данных, было бы излишним включать и значения страны в файлы данных.

Посмотрите содержимое каталога customers_by_country. Теперь в нем должен быть один подкаталог для каждого значения в столбце страны.

  1. Посмотрите на файл в одном из этих каталогов. Обратите внимание, что файл содержит строку для клиента из этой страны, а не других; также обратите внимание, что значение страны не включено.

Примечание. Hive включает функцию безопасности, которая предотвращает случайное создание или перезапись пользователями большого количества разделов. (Для получения дополнительной информации см. «Риски использования секционирования».) По умолчанию Hive устанавливает для свойства hive.exec.dynamic.partition.mode значение strict. Это не позволяет вам использовать динамическое разбиение, хотя вы все равно можете использовать статические разделы.

Вы можете отключить эту функцию безопасности в Hive, установив для свойства hive.exec.dynamic.partition.mode значение nonstrict:

SET hive.exec.dynamic.partition.mode=nonstrict;

Затем вы можете использовать оператор INSERT для динамической загрузки данных.

Свойства Hive, установленные в Beeline, предназначены только для текущего сеанса, поэтому при следующем запуске сеанса Hive для этого свойства будет установлено строгое значение. Но при необходимости вы или ваш системный администратор можете настроить свойства на постоянной основе.

Когда вы запускаете несколько запросов SELECT к многораздельной таблице, если таблица достаточно велика, вы можете заметить значительную разницу во времени, необходимом для выполнения. Обратите внимание, что вы не будете запрашивать таблицу иначе, чем запрашиваете таблицу клиентов.

ЗАГРУЗКА ДАННЫХ С ПОМОЩЬЮ СТАТИЧЕСКОГО РАЗДЕЛЕНИЯ

Один из способов загрузки данных в многораздельную таблицу - использовать статическое разбиение, при котором вы вручную определяете различные разделы.

При статическом разделении вы создаете раздел вручную с помощью оператора ALTER TABLE… ADD PARTITION, а затем загружаете данные в раздел.

Например, этот оператор ALTER TABLE создает раздел для Пакистана (pk):

ALTER TABLE customers_by_country
ADD PARTITION (country='pk');

Обратите внимание, как имя столбца раздела, то есть страна, и конкретное значение, определяющее этот раздел, то есть pk, указаны в предложении ADD PARTITION. Это создает каталог раздела с именем country = pk внутри каталога таблицы customers_by_country.

После создания раздела для Пакистана вы можете добавить данные в раздел с помощью оператора INSERT… SELECT:

INSERT OVERWRITE TABLE customers_by_country 
    PARTITION(country='pk')
    SELECT cust_id, name FROM customers WHERE country='pk'

Обратите внимание, как в предложении PARTITION указываются имя столбца раздела - страна и конкретное значение - pk, как и в команде ADD PARTITION, используемой для создания раздела. Также обратите внимание, что в операторе SELECT столбец раздела не включен в список SELECT. Наконец, обратите внимание, что предложение WHERE в операторе SELECT выбирает только клиентов из Пакистана.

При статическом разделении вам необходимо повторить эти два шага для каждого раздела: сначала создать раздел, а затем добавить данные. Фактически вы можете использовать любой метод для загрузки данных; вам не нужно использовать оператор INSERT. Вместо этого вы можете использовать команды hdfs dfs или команду LOAD DATA INPATH. Но как бы вы ни загружали данные, вы обязаны убедиться, что данные хранятся в правильных подкаталогах раздела. Например, данные для клиентов в Пакистане должны храниться в подкаталоге раздела для Пакистана, а данные для клиентов из других стран должны храниться в подкаталогах разделов этих стран.

Статическое разбиение наиболее полезно, когда данные, загружаемые в таблицу, уже разделены на файлы на основе столбца раздела или когда данные растут таким образом, который совпадает с размером столбца раздела: например, предположим, что ваша компания открывает новое хранилище в другая страна, например, Новая Зеландия (nz), и вам предоставляется файл данных для новых клиентов, все из этой страны. Вы можете легко добавить новый раздел и загрузить в него этот файл.

РИСКИ ПРИ РАЗДЕЛЕНИИ РАЗДЕЛОВ

Главный риск при использовании разбиения - это создание разделов, которые приводят к проблеме с небольшими файлами. Когда это происходит, секционирование таблицы фактически ухудшает производительность запроса (противоположность цели при использовании секционирования), потому что это приводит к созданию слишком большого количества маленьких файлов. Это более вероятно при использовании динамического разделения, но все же может произойти со статическим разделением - например, если вы добавляете новый раздел в таблицу продаж на ежедневной основе, содержащую продажи за предыдущий день, и данные за каждый день не особенно большие. .

Выбирая разделы, вы хотите найти удачный баланс между слишком большим количеством разделов (вызывающим проблему с небольшими файлами) и слишком небольшим количеством разделов (что дает небольшое преимущество в производительности). Столбец или столбцы раздела должны иметь разумное количество значений для разделов, но то, что вы должны считать разумным, трудно определить количественно.

Использование динамического разделения особенно опасно, потому что, если вы не будете осторожны, легко разделить столбец со слишком большим количеством различных значений. Представьте себе вариант использования, когда вы часто ищете данные, которые попадают в сроки, которые вы укажете в своем запросе. Вы можете подумать, что это хорошая идея - разделить столбец по времени. Но столбец TIMESTAMP может иметь время с точностью до наносекунды, поэтому каждая строка может иметь уникальное значение; это был бы ужасный выбор для колонки перегородок! Даже с точностью до минуты или часа может быть создано слишком много разделов, в зависимости от характера ваших данных; разделение на более крупные единицы времени, такие как день, месяц или даже год, может быть лучшим выбором.

В качестве другого примера рассмотрим таблицу сотрудников. Он состоит из пяти столбцов: empl_id, first_name, last_name, salary и office_id. Прежде чем читать дальше, подумайте на мгновение, какие из них могут быть разумными для разбиения на разделы.

  • Столбец empl_id - это уникальный идентификатор. Если бы это был ваш столбец раздела, у вас был бы отдельный раздел для каждого сотрудника, и каждый имел бы ровно одну строку. Кроме того, маловероятно, что вы будете выполнять много запросов в поисках определенного значения или даже определенного диапазона значений. Это плохой выбор.
  • В столбце first_name не будет одного столбца на каждого сотрудника, но, вероятно, будет много столбцов, в которых будет только одна строка.
  • Это также верно для last_name. Также, как и empl_id, вам вряд ли понадобится фильтровать запросы на основе этих столбцов. Это тоже плохой выбор.
  • Столбец зарплата также будет иметь много делений (и тем более, если ваши зарплаты будут выражаться в процентах, а не в долларах, как в нашей таблице-образце). Хотя может случиться так, что вы иногда захотите запросить диапазоны заработной платы, вряд ли вы захотите использовать индивидуальные зарплаты. Так что зарплата - плохой выбор.
  • Более ограниченная спецификация salary_grades, такая как в таблице salary_grades, может быть разумной, если ваш вариант использования предполагает частый просмотр данных по разряду зарплаты.
  • Столбец office_id определяет офис, в котором работает сотрудник. Это будет иметь гораздо меньшее количество уникальных значений, даже если у вас большая компания с офисами во многих городах. Можно себе представить, что вы можете использовать частую фильтрацию данных о сотрудниках по местоположению офиса. Так что это был бы хороший выбор. Вы также можете использовать несколько столбцов и создавать вложенные разделы. Например, набор данных о клиентах может включать столбцы country и state_or_province. Вы можете разделить по странам, а затем разделить их по state_or_province, так что клиенты из Онтарио, Канада, будут в каталоге country = ca / ​​state_or_province = on / partition. Это может быть чрезвычайно полезно для больших объемов данных, к которым вы хотите получить доступ, по странам, штатам или провинциям. Однако использование нескольких столбцов увеличивает опасность создания слишком большого количества разделов, поэтому при этом следует проявлять особую осторожность.

Риск создания слишком большого количества разделов объясняется тем, что Hive включает свойство hive.exec.dynamic.partition.mode, для которого по умолчанию установлено значение strict, которое необходимо сбросить до нестрогого, прежде чем вы сможете создать раздел.

Вместо того, чтобы автоматически и механически сбрасывать это свойство, когда вы собираетесь загружать данные динамически, используйте это как возможность подумать о столбцах разделения и, возможно, проверить количество уникальных значений, которые вы получите при загрузке данных.

И это все.

person Chema    schedule 04.06.2020
comment
Большое спасибо за подробное объяснение. Это первый раз с Hive, и мне было трудно осмыслить нотации разделов, думая о разделении в MySQL. Теперь я понимаю, что разбиение на разделы в Hive не имеет ничего общего с разбиением на разделы в MySQL. Спасибо. - person madu; 04.06.2020
comment
Пожалуйста :), Ага! но будьте осторожны с разделением в Hive, как я сказал в сообщении. С другой стороны, то, что я пишу в этом посте для Hive, почти то же самое для Impala, поэтому, если вам нужно быстрее выполнять запросы, вы можете создавать секционированные таблицы в Hive или Impala, а затем запускать запросы с Impala. - person Chema; 04.06.2020
comment
Большое спасибо за эту информацию Chema. Ценить это. - person madu; 05.06.2020