Big Data від A до Я. Частина 5.2: Просунуті можливості hive

Привіт, Хабр! У цій статті ми продовжимо розглядати можливості hive — рушія, яке транслювало SQL-like запити в MapReduce завдання.

попередній статті ми розглянули базові можливості hive, такі як створення таблиць, завантаження даних, виконання простих SELECT-запитів. Тепер поговоримо про просунутих можливості, які дозволять вичавлювати максимум з Hive.



User Defined Functions
Одним з основних перешкод при роботі з Hive є скутість рамками стандартного SQL. Цю проблему можна вирішити за допомогою використання розширень мови — так званих «User Defined Functions». Досить багато корисних функцій встоено прямо в мову Hive. Наведу кілька найбільш цікавих на мій погляд(інформація взята з оффициальной документації):

Json

Досить частою завданням при роботі з великими данынми є обробка неструктурованих даних, що зберігаються у форматі json. Для роботи з json hive підтримувати спеціальний метод get_json_object, що дозволяє витягувати значення з json-документів. Для отримання значень з об'єкта використовується обмежена версія нотації JSONPath. Підтримуються наступні операції:

  • $: Повертає кореневий об'єкт
  • .: Вовзращает об'єкт-дитина
  • []: Звернення по індексу в масиві
  • *: Wildcard
Приклади роботи з Json з оффициальной документації:

Нехай є таблиця: src_json, состоящаяя з однієї колонки(jsoin) і одного рядка:

{"store":
{"fruit":\[{"weight":8,"type":"apple"},{"weight":9,"type":"pear"}],
"bicycle":{"price":19.95,"color":"red"}
},
"email":"amy@only_for_json_udf_test.net",
"owner":"amy"
}

Приклади запитів до таблиці:

hive> SELECT get_json_object(src_json.json, '$.owner') FROM src_json;
amy

hive> SELECT get_json_object(src_json.json, '$.store.fruit\[0]') FROM src_json;
{"weight":8,"type":"apple"}

hive> SELECT get_json_object(src_json.json, '$.non_exist_key') FROM src_json;
NULL

Xpath

Аналогічно, якщо дані, які необхідно обробляти за допомогою hive зберігаються не в json, а в XML — їх можна обрабатыватывать за допомогою функції xpath, позвоялющей парсити XML за допомогою відповідної мови. Приклад парсингу xml-даних за допомогою xpath:

hive> select xpath('<a><b>b1</b><b>b2</b></a>','a/*/text()') from sample_table limit 1 ;
["b1","b2"]

Інші корисні вбудовані функції:

Вбудована бібліотека містить досить багатий набір вбудованих функцій. Можна виділити кілька груп:

  • Математичні функції sin, cos, log, ...)
  • Функції роботи з часом(from_unix_timestamp, to_date, current date hour(string date), timediff, ...) — дуже багатий вибір функцій для перетворення дат і часу
  • Функції для роботи з рядками. Підтримуються як общеприменимые функції, такі як lengh, reverse, regexp, так і специфічні — типу parse_url або вже розглянутої get_json_object)
  • Багато різних системних функцій — current_user, current_database, ...
  • Криптографічні функції — sha, md5, aes_encrypt, aes_decrypt...
Повний список вбудованих в hive функцій можна знайти на за адресою.

Написання власних UDF
Не завжди буває достатньо вбудованих в hive функцій для рішення поставленої задачі. Якщо вбудованої функції не знайшлося — можна написати свою UDF. Робиться це на мові java.

Розберемо створення власної UDF на прикладі простої функції перетворення рядка в lowercase:

1. Створимо пакет com/example/hive/udf і створимо в ньому клас Lower.java:

mkdir -p com/example/hive/udf
edit com/example/hive/udf/Lower.java

2. Реалізуємо власне клас Lower:

package com.example.hive.udf;

import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

public final Lower class extends UDF {
public Text evaluate(final Text s) {
if (s == null) { return null; }
return new Text(s.toString().toLowerCase());
}
}

3. Додамо необхідні бібліотеки в CLASSPATH (у вашому hadoop-дистрибутиві посилання на jar-файли можуть бути трохи іншими):

export CLASSPATH=/opt/cloudera/parcels/CDH/lib/hive/lib/hive-exec.jar:/opt/cloudera/parcels/CDH/lib/hadoop/hadoop-common.jar

4. Компілюємо нашу UDF-ку і збираємо jar-архів:

javac com/example/hive/udf/Lower.java
jar cvf my_udf.jar *

5. Для того щоб можна було використовувати функцію в hive — потрібно явно її декларувати:

hive> ADD JAR my_udf.jar;

hive> create temporary function my_lower as 'com.example.hive.udf.Lower';

hive> select my_lower('HELLO') from sample_table limit 1;
hello

Трансформація таблиці за допомогою скриптів
Ще одним способом розширення стандартного функціоналу HIVE є використання методу TRANSFORM, який дозволяє перетворювати дані за допомогою кастомних скриптів на будь-якій мові програмування(особливо це підходить тим хто не любить java і не хоче писати на ній udf-ки).

Синтаксис для використання команди наступний:

SELECT TRANSFORM(<columns>) USING <script> as <new_columns>

<script> — у даному випадку це програма, яка отримує дані stdin, перетворює їх і видає на stdout перетворені дані. По суті це дуже схоже на streaming-інтерфейс до запуску map-reduce завдань, про який ми писали в статті Big Data від А до Я. Частина 2: Hadoop

Приклад:

Нехай у нас є таблиця з зарплатами користувачів, які отримують зарплату в різній валюті:

+-------------------+---------------------+-----------------------+
| user_salary.name | user_salary.salary | user_salary.currency |
+-------------------+---------------------+-----------------------+
| alexander | 100000 | RUB |
| yevhen | 4000 | EUR |
| alla | 50000 | RUB |
| elena | 1500 | EUR |
+-------------------+---------------------+-----------------------+

Ми хочемо отримати табличку, в якій будуть рублеві зарплати для всіх користувачів. Для цього напишемо скрипт на python, який виконує перетворення даних:

import sys
EXCHANGE_RATE = 75

for line in sys.stdin:
name, salary, currency = line.rstrip("\n").split('\t')
if currency == 'EUR':
print name + "\t" + str(int(salary) * EXCHANGE_RATE)
else:
print name + "\t" + salary

Скрипт увазі що дані на вхід надходять в tsv-форматі(колонки розділені знаком табуляції). У разі якщо в таблиці зустрінеться значення NULL на вхід скрипта потрапить значення '\N'

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

0: jdbc:hive2://localhost:10000/default> select 
transform(name, salary, currency) 
using 'python transform_to_rub.py' as (name, rub_salary) 
from user_salary;

+------------+-------------+
| name | rub_salary |
+------------+-------------+
| alexander | 100000 |
| yevhen | 300000 |
| alla | 50000 |
| elena | 112500 |
+------------+-------------+

По суті використання операції TRANSFORM дає можливість повністю замінити класичний MapReduce за допомогою hive.

MapJoin

Як ми писали в статті про прийоми і стратегії роботи з MapReduce — для реалізації JOIN'a двох таблиць в загальному необхідно кілька MapReduce завдань. Так як hive працює саме на MapReduce — то JOIN для нього також є дорогою операцією.
Однак якщо одна з двох таблиць, які необхідно сджойнить повністю влазить в оперативну пам'ять какждой ноди — можна обійтися одним MapReduce, завантаживши табличку в пам'ять. Цей патерн називається MapJoin. Для того щоб Hive використовував саме MapJoin — необхідно дати йому підказку(«hint» в термінології Hive).

Приклад:

SELECT /*+ MAPJOIN(time_dim) */ COUNT(*) from
store_sales JOIN time_dim on (ss_sold_time_sk = t_time_sk)

У цьому прикладі мається на увазі що таблиця «store_sales» — більша, а таблиця «time_dim» — маленька і влазить в пам'ять. /*+ MAPJOIN(time_dim) */ — це і є та сама підказка для HIVE про запуск завдання MAPJOIN-завдання

Транзакційна модель
Транзакційна модель ACID передбачає підтримку 4х основних властивостей:

  • Атомарність — операція або цілком виконується повністю змінюючи дані, або падає і не залишає за собою слідів.

  • Консистентним — після того як програма виконує операцію її результат стає доступним для всіх наступних операцій.

  • Ізоляція — операції одних користувачів не мають побічних ефектів на інших користувачів.

  • Довговічність — зміни зроблені в результаті успішної опрации зберігають результат навіть у випадку збою.
Взагалі кажучи Hive не дуже добре підходить для роботи із змінними даними, проте є кілька кейсів, де підтримка змінних даних необхідна. В першу чергу це:

  • Дані, що додаються в потоковому режимі з таких систем, як flume, kafka). Хочеться щоб дані були доступні для аналізу в hive відразу як вони надійшли

  • Оновлення схеми — наприклад, додавання нової колонки у таблицю hive. Хочеться щоб колонка або успішно додалася до кожного запису, або впала і не приєдналася до жодної

  • Іноді все-таки необхідно оновлення окремих записів.
Для цих цілей в hive починаючи з версії 0.14 була реалізована підтримка транзакційний моделі, яка реалізується чотирма операціями — INSERT, UPDATE і DELETE.

Підтримка цих операцій дуже обмежена:

  • На даний момент підтримуються тільки файли формату ORC

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

  • Немає підтримки команд BEGIN, COMMIT, ROLLBACK звичних за реляційних баз даних.
Підтримка транзакцій реалізована за допомогою дельта-файлів. Тобто при виполнеія операції оновлення даних дані у вихідному файлі не оновлюються, а створюється новий файлик де зазначено які рядки були измененеы. Пізніше hive їх об'єднає за допомогою операції compaction(аналогічна використовується в hbase).

В загальному, так як підтримка транзакцій дуже сильно лімітована — варто дуже серйозно подумати перед тим як використовувати цей функціонал в Hive. Можливо варто подивитися в бік HBase або традиційних реляційних баз даних.

Висновок
У цій та предудщей статті циклу ми розглянули основні можливості Hive — потужного інструменту, що полегшує роботу з MapReduce завданнями. Hive чудово підходить аналітикам, які звикли працювати з SQL, може бути легко інтегрований в існуючу інфраструктуру за допомогою підтримки драйвера JDBC, а з урахуванням підтримки User Defined Functions і кастомних трансформацій — дозволяє повністю перевести процесинг даних з класичного MapReduce на себе. Однак hive не є «срібною пігулкою» для часто оновлюваних даних можна подивитися в бік таких інструментів як Hbase і класичні реляционые бази даних.

В наступних статтях циклу ми продовжимо розгляд інструментів для роботи з великими даними і методи їх обробки.
Джерело: Хабрахабр

0 коментарів

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