Big Data від A до Я. Частина 5.1: Hive — SQL-движок над MapReduce

Привіт, Хабр! Ми продовжуємо наш цикл статей, присвячений інструментам і методам аналізу даних. Наступні 2 статті нашого циклу будуть присвячені Hive — інструменту для любителів SQL. У попередніх статтях ми розглядали парадигму MapReduce, прийоми і стратегії роботи з нею. Можливо багатьом читачам деякі рішення задач за допомогою MapReduce здалися кілька громіздкими. Дійсно, через майже 50 років після винаходу SQL, здається досить дивним писати більше одного рядка коду для вирішення завдань на зразок «порахуй мені суму транзакцій в розбивці по регіонах».

З іншого боку, класичні СУБД, такі як Postgres, MySQL або Oracle не мають такої гнучкості у масштабуванні при обробці великих масивів даних і при досягненні обсягу більшого подальша підтримка стає великою головоной болем.



Власне, Apache Hive був придуманий для того щоб об'єднати два цих переваги:

  • Масштабованість MapReduce
  • Зручність використання SQL для вибірок даних.
Під катом ми розповімо, яким чином це досягається, яким чином почати працювати з Hive, і які є обмеження на його застосування.

Загальна інформація
Hive з'явився в надрах компанії Facebook у 2007 році, а через рік исходники hive були відкриті і передані під управління apache software foundation. Спочатку hive представляв собою набір скриптів поверх hadoop streaming (см 2-ю статтю нашого циклу), пізніше розвинувся в повноцінний фреймворк для виконання запитів до даних поверх MapReduce.

Актуальна версія apache hive(2.0) являє собою просунутий фреймворк, який може працювати не тільки поверх фреймворку Map/Reduce, але й поверх Spark(про спарк у нас будуть окремі статті в циклі), а також Apache Tez.

Apache hive використовують у production такі компанії як Facebook, Grooveshark, Last.Fm і багато інших. Ми в Data-Centric alliance використовуємо HIve в якості основного сховища логів нашої рекламної платформи.

Архітектура

Hive представляє із себе движок, який перетворює SQL-запити в ланцюжки map-reduce завдань. Движок включає в себе такі компоненти, як Parser(розбирає входять SQL-запрсоы), Optimimer(оптимізує запит для досягнення більшої ефективності), Planner (планує завдання на виконання) Executor(запускає завдання на фреймворку MapReduce.

Для роботи hive також необхідно сховище метаданих. Справа в тому, що SQL передбачає роботу з такими об'єктами як база даних, таблиця, колонки, рядки, клітинки і тд. Оскільки самі дані, які використовує hive зберігаються просто у вигляді файлів на hdfs — необхідно десь зберігати відповідність між об'єктами hive і реальними файлами.

Як metastorage використовується звичайна реляційна СУБД, така як MySQL, PostgreSQL або Oracle.

Command line interface
Для того щоб спробувати роботу з hive найпростіше скористатися його командним рядком. Сучасна утиліта для роботи з hive називається beeline (привіт нашим партнерам з однойменного оператора :) ) Для цього на будь-якій машині в hadoop-кластері(см наш туторіал по hadoop з встановленим hive достатньо набрати команду.

$beeline

Далі необхідно встановити з'єднання з hive-сервером:

beeline> !connect jdbc:hive2://localhost:10000/default root root
Connecting to jdbc:hive2://localhost:10000/default
Connected to: Apache Hive (version 1.1.0-cdh5.7.0)
Driver: Hive JDBC (version 1.1.0-cdh5.7.0)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://localhost:10000/default>

root root
— в даному контексті це ім'я користувача і пароль. Після цього ви отримаєте командний рядок, у якій можна вводити команди
hive
.

Також іноді буває зручно не вводити sql-запити в командний рядок beeline, а попередньо зберегти та редагувати їх у файлі, а потім виконати всі запити з файлу. Для цього потрібно виконати beeline з параметрами підключення до бази даних і параметром -f вказує ім'я файлу, що містить запити:

beeline -u jdbc:hive2://localhost:10000/default n root -p root -f sorted.sql

Data Units
При роботі з hive можна виділити наступні об'єкти якими оперує hive:

  1. База даних
  2. Таблиця
  3. Партіцій (partition)
  4. Бакет (bucket)
Розглянемо кожен з них детальніше:

База даних
База даних представляє аналог бази даних в реляційних СУБД. База даних являє собою простір імен, що містить таблиці. Команда створення нової бази даних виглядає наступним чином:

CREATE DATABASE|SCHEMA [IF NOT EXISTS] <database name>

Database і Schema в даному контексті це одне і теж. Необов'язкова добавка IF NOT EXISTS як не складно здогадатися створює базу даних тільки в тому випадку, якщо вона ще не існує.

Приклад створення бази даних:

CREATE DATABASE userdb;

Для перемикання на відповідну базу даних використовуємо команду USE:

USE userdb;


Таблиця
Таблиця hive представляє з себе аналог таблиці класичної реляційної БД. Основна відмінність — що дані hive'івських таблиць зберігаються простий у вигляді звичайних файлів на hdfs. Це можуть бути звичайні текстові файли csv, бінарні sequence-файли, більш складні стовпчик paruqet-файли і інші формати. Але в будь-якому випадку дані, над якими налаштована hive-таблиця дуже легко прочитати і не з hive.

Таблиці в hive бувають двох видів:

Класична таблиця, дані в яку додаються за допомогою hive. Ось приклад створення такої таблиці (джерело приклад):

CREATE TABLE IF NOT EXISTS employee ( eid int, name (String
salary String, destination String)
COMMENT 'Employee details'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;

Тут ми створили таблицю, дані в якій будуть зберігатися у вигляді звичайних файлів csv, колонки якої розділені символом табуляції. Після цього дані в таблицю можна завантажити. Нехай у нашого користувача в домашній папці на hdfs є (нагадую, що завантажити файл можна за допомогою hadoop fs -put) файл sample.txt види:

1201 Gopal 45000 Technical manager
1202 Manisha 45000 Proof reader
1203 Masthanvali 40000 Technical writer
1204 Kiran 40000 Hr Admin
1205 Kranthi 30000 Op Admin

Завантажити дані ми зможемо за допомогою наступної команди:

LOAD DATA INPATH '/user/root/sample.txt'
OVERWRITE INTO TABLE employee;

Після hive перемістить дані, що зберігається в нашому файлі в сховище hive. Переконатися в цьому можна прочитавши дані безпосередньо з файлу в сховище hive в hdfs:

[root@quickstart ~]# hadoop fs -text /user/hive/warehouse/userdb.db/employee/*
1201 Gopal 45000 Technical manager
1202 Manisha 45000 Proof reader
1203 Masthanvali 40000 Technical writer
1204 Kiran 40000 Hr Admin
1205 Kranthi 30000 Op Admin

Класичні таблиці також можна створювати як результат select-запиту до інших таблиць:

0: jdbc:hive2://localhost:10000/default> CREATE TABLE big_salary as SELECT * FROM employee WHERE salary > 40000;

0: jdbc:hive2://localhost:10000/default> SELECT * FROM big_salary;
+-----------------+------------------+--------------------+-------------------------+--+
| big_salary.eid | big_salary.name | big_salary.salary | big_salary.destination |
+-----------------+------------------+--------------------+-------------------------+--+
| 1201 | Gopal | 45000 | Technical manager |
| 1202 | Manisha | 45000 | Proof reader |
+-----------------+------------------+--------------------+-------------------------+--+

До речі кажучи, SELECT для створення таблиці у даному випадку вже запустить mapreduce-завдання.

Зовнішня таблиця, дані в яку завантажуються зовнішніми системами, без участі hive. Для роботи із зовнішніми таблицями при створенні таблиці потрібно вказати ключове слово EXTERNAL, а також вказати шлях до папки, по якому зберігаються файли:

CREATE EXTERNAL TABLE IF NOT EXISTS employee_external ( eid int, name (String
salary String, destination String)
COMMENT 'Employee details'
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE
LOCATION '/user/root/external_files/';

Після цього таблицею можна користуватися точно так само, як і звичайними таблицями hive. Найзручніший у цьому, що ви можете просто скопіювати файл в потрібну папку в hdfs, а hive буде автоматом підхоплювати нові файли при запитах до відповідної таблиці. Це дуже зручно при роботі наприклад з логами.

Партіцій (partition)
Так як hive представляє із себе движок для трансляції SQL-запитів в mapreduce-завдання, то зазвичай навіть найпростіші запити до таблиці призводять до повного сканування даних в таблиці. Для того щоб уникнути повного сканування даних за деякими з колонок таблиці можна зробити партиционирование цієї таблиці. Це означає, що дані відносяться до різних значень будуть фізично зберігатися в різних папках на HDFS.

Для створення партиционированной таблиці необхідно вказати за яким колонкам буде вироблено партиционирование:

CREATE TABLE IF NOT EXISTS employee_partitioned ( eid int, name (String
salary String, destination String)
COMMENT 'Employee details'
PARTITIONED BY (birth_year int, birth_month string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;

При заливці даних в таку таблицю необхідно явно вказати, в яку партицию ми заливаємо дані:

LOAD DATA INPATH '/user/root/sample.txt' OVERWRITE
INTO TABLE employee_partitioned
PARTITION (birth_year=1998, birth_month='May');

Подивимося тепер, як виглядає структура директорій:

[root@quickstart ~]# hadoop fs -ls /user/hive/warehouse/employee_partitioned/
Found 1 items
drwxrwxrwx - root supergroup 0 2016-05-08 15:03 /user/hive/warehouse/employee_partitioned/birth_year=1998
[root@quickstart ~]# hadoop fs -ls -R /user/hive/warehouse/employee_partitioned/
drwxrwxrwx - root supergroup 0 2016-05-08 15:03 /user/hive/warehouse/employee_partitioned/birth_year=1998
drwxrwxrwx - root supergroup 0 2016-05-08 15:03 /user/hive/warehouse/employee_partitioned/birth_year=1998/birth_month=May
-rwxrwxrwx 1 root supergroup 161 2016-05-08 15:03 /user/hive/warehouse/employee_partitioned/birth_year=1998/birth_month=May/sample.txt

Видно, що структура директорій виглядає таким чином, що кожній партіціі відповідає окрема папка на hdfs. Тепер, якщо ми будемо запускати будь-які запити, казав в умові WHERE обмеження на значення партіцій — mapreduce візьме вхідні дані лише з відповідних папок.

У разі External таблиць партиционирование працює аналогічним чином, але подібну структуру директорій доведеться створювати вручну.

Партиционирование дуже зручно, наприклад, для поділу логів по датах, так як правило будь-які запити за статистикою містять обмеження по датах. Це дозволяє істотно скоротити час запиту.

Бакет
Партиционирование допомагає скоротити час обробки, якщо зазвичай при запитах відомі обмеження на значення якого-небудь стовпця. Проте воно не завжди доречно. Наприклад — якщо кількість значень у стовпці дуже велике. Наприклад, це може бути ID користувача в системі, що містить кілька мільйонів користувачів.

У цьому випадку на допомогу нам прийде поділ таблиці на бакеты. В один бакет потрапляють рядки таблиці, для яких значення збігається значення хеш-функції обчислене за певною колонці.

При будь-якій роботі з бакетированными таблицями необхідно не забувати включати підтримку бакетов в hive (інакше hive буде працювати з ними як із звичайними таблицями):

set hive.enforce.bucketing=true;

Для створення таблиці розбитою на бакеты використовується конструкція CLUSTERED BY

set hive.enforce.bucketing=true;

CREATE TABLE employee_bucketed ( eid int, String name, salary String, destination String)
CLUSTERED BY(ід) INTO 10 BUCKETS
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
STORED AS TEXTFILE;

Так як команда Load використовується для простого переміщення даних в сховище hive — в даному випадку для завантаження вона не підходить, так як дані необхідно предобработать, правильно розбивши їх на бакеты. Тому їх потрібно буде завантажити за допомогою команди INSERT з іншої таблиці(наприклад зовнішньої таблиці):

set hive.enforce.bucketing=true;
FROM employee_external INSERT OVERWRITE TABLE employee_bucketed SELECT *;

Після виконання команди переконаємося, що дані дійсно розбилися на 10 частин:

[root@quickstart ~]# hadoop fs -ls /user/hive/warehouse/employee_bucketed
Found 10 items
-rwxrwxrwx 1 root supergroup 31555556 2016-05-08 16:04 /user/hive/warehouse/employee_bucketed/000000_0
-rwxrwxrwx 1 root supergroup 31555556 2016-05-08 16:04 /user/hive/warehouse/employee_bucketed/000001_0
-rwxrwxrwx 1 root supergroup 31555556 2016-05-08 16:04 /user/hive/warehouse/employee_bucketed/000002_0
-rwxrwxrwx 1 root supergroup 31555556 2016-05-08 16:04 /user/hive/warehouse/employee_bucketed/000003_0
-rwxrwxrwx 1 root supergroup 31555556 2016-05-08 16:04 /user/hive/warehouse/employee_bucketed/000004_0
-rwxrwxrwx 1 root supergroup 31555556 2016-05-08 16:04 /user/hive/warehouse/employee_bucketed/000005_0
-rwxrwxrwx 1 root supergroup 31555556 2016-05-08 16:04 /user/hive/warehouse/employee_bucketed/000006_0
-rwxrwxrwx 1 root supergroup 31555556 2016-05-08 16:04 /user/hive/warehouse/employee_bucketed/000007_0
-rwxrwxrwx 1 root supergroup 31555556 2016-05-08 16:04 /user/hive/warehouse/employee_bucketed/000008_0
-rwxrwxrwx 1 root supergroup 31555556 2016-05-08 16:04 /user/hive/warehouse/employee_bucketed/000009_0

Тепер при запитах за даними, що відносяться до певного користувача, нам не потрібно буде сканувати всю таблицю, а тільки 1/10 частину цієї таблиці.

Checklist по використанню hive
Тепер ми розібрали всі об'єкти, якими оперує hive. Після того як таблиці створені можна працювати з ними, так як з таблицями звичайних баз даних. Однак не варто забувати про те що hive — це все ж движок по запуску mapreduce завдань над звичайними файлами, і повноцінною заміною класичним СУБД він не є. Необдумане використання таких важких команд, як JOIN може призвести до дуже довгим завдань. Тому перш ніж будувати вашу архітектуру на основі hive — потрібно кілька разів подумати. Наведемо невеликий checklist по використанню hive:

  • Даних які треба обробляти багато і вони не влазять на диск однієї машини (інакше краще подумати над класичними SQL-системами).

  • Дані в основному лише додаються і рідко оновлюються (якщо оновлення часті — можливо варто подумати про використання Hbase наприклад, див наш попередній матеріал.

  • Дані мають добре структуровану структуру і добре розбиваються на колонки.

  • Патерни обробки даних добре описуються декларативним мовою запитів (SQL).

  • Час відповіді на запит не критично(так як hive працює на основі MapReduce — інтерактивності чекати не варто).
Висновок
У даній статті ми розібрали архітектуру hive, data unit-и, якими оперує hive, навели приклади зі створення і заповнення таблиць hive. У наступній статті циклу ми розглянемо просунуті можливості hive, що включають в себе:

  • Транзакционную модель
  • Індекси
  • User-defined функції
  • Інтеграцію hive з сховищами даних, відмінними від hdfs
Посилання на попередні статті циклу:

» Big Data від А до Я. Частина 1: Принципи роботи з великими даними, парадигма MapReduce
» Big Data від А до Я. Частина 2: Hadoop
» Big Data від А до Я. Частина 3: Прийоми і стратегії розробки MapReduce-додатків
» Big Data від А до Я. Частина 4: Hbase

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.