Использование коннектора PXF object store для чтения и записи данных в формате Avro между Greengage DB и S3
Apache Avro — фреймворк сериализации данных, предназначенный для эффективного хранения и быстрой обработки. Он предоставляет компактный двоичный формат сериализации и использует JSON для определения как типов данных, так и схем, описывающих их структуру. Схема Avro вместе с данными является полностью самодокументирующейся.
В этой статье описывается настройка и использование коннектора PXF object store для чтения и записи данных Avro в объектном хранилище с использованием внешних таблиц, а также приводятся практические примеры.
Сопоставление типов данных
В спецификации Avro определяются примитивные, составные и логические типы данных. Для представления примитивных типов и массивов примитивных типов Avro в Greengage DB необходимо сопоставить значения данных со столбцами Greengage DB того же типа.
Avro поддерживает составные типы данных, включая массивы непримитивных типов, ассоциативные массивы, записи, перечисления и фиксированные типы. Необходимо сопоставить верхнеуровневые поля этих составных типов данных с текстовым типом Greengage DB. PXF по умолчанию не поддерживает чтение составных типов, но вы можете создать функции Greengage DB или код приложения для извлечения или дальнейшей обработки их компонентов.
Avro поддерживает логические типы данных, такие как date, decimal, duration, time, timestamp и uuid.
Сопоставление при чтении
При чтении данных Avro в PXF используется следующее сопоставление типов данных.
| Тип данных Avro | Тип данных PXF / Greengage DB |
|---|---|
boolean |
BOOLEAN |
bytes |
BYTEA |
double |
DOUBLE |
float |
REAL |
int |
INT |
long |
BIGINT |
string |
TEXT |
Составной тип: массив (любой размерности) типа: |
Массив (любой размерности) типа: |
Составной тип: массив других типов (схема Avro указана) |
Массив типа |
Составной тип: ассоциативный массив, запись, перечисление |
|
Составной тип: фиксированный |
|
Union |
Следует вышеуказанным принципам для примитивных или составных типов данных в зависимости от конкретного объединения; должен содержать 2 элемента, одним из которых должен быть |
Логический тип: Date |
DATE |
Логический тип: Decimal |
|
Логический тип: Duration |
BYTEA |
Логический тип: Time (миллисекундная точность) |
|
Логический тип: Time (микросекундная точность) |
|
Логический тип: Timestamp (миллисекундная точность) |
|
Логический тип: Timestamp (микросекундная точность) |
|
Логический тип: Local Timestamp (миллисекундная точность) |
|
Логический тип: Local Timestamp (микросекундная точность) |
|
Логический тип: UUID |
UUID |
Сопоставление при записи
PXF поддерживает запись данных Avro примитивных типов и массивов примитивных типов, а также запись прочих составных типов в виде строк (string).
При записи данных Avro в PXF используется следующее сопоставление типов данных.
| Тип данных PXF / Greengage DB | Тип данных Avro |
|---|---|
BIGINT |
long |
BOOLEAN |
boolean |
BYTEA |
bytes |
DOUBLE |
double |
CHAR (1) |
string |
ENUM |
string |
INT |
int |
REAL |
float |
SMALLINT (2) |
int |
TEXT |
string |
VARCHAR |
string |
|
string |
Массив (любой размерности) типа: |
Массив (любой размерности) типа: |
Одномерный массив типа: |
Одномерный массив типа: |
Одномерный массив типа: |
Одномерный массив типа |
|
string |
Схемы и данные Avro
Схемы Avro определяются с помощью JSON и состоят из примитивных и составных типов, перечисленных в разделе Сопоставление типов данных. Файлы схем Avro обычно имеют суффикс .avsc. Поля в файле схемы Avro определяются через массив объектов, в каждом из которых указывается имя и тип. Файл данных Avro содержит схему и компактное двоичное представление данных и обычно имеет суффикс .avro. Для операций чтения и записи в объектном хранилище указать схему Avro можно либо в виде двоичного файла *.avro, либо в виде файла схемы JSON-формата *.avsc.
| Тип внешней таблицы | Указана ли схема | Описание |
|---|---|---|
Читающая |
Да |
PXF использует указанную схему, переопределяя схему, встроенную в файл данных Avro |
Читающая |
Нет |
PXF использует схему, встроенную в файл данных Avro |
Пишущая |
Да |
PXF использует указанную схему |
Пишущая |
Нет |
PXF создает схему на базе определения внешней таблицы |
Указанный файл схемы Avro должен находиться либо в одном и том же каталоге на каждом хосте Greengage DB, либо в объектном хранилище. Сначала PXF выполняет поиск по абсолютному пути к файлу на хостах Greengage DB. Если файл схемы не найден, поиск выполняется относительно пути к классам PXF. Если файл схемы не найден локально, выполняется поиск файла в объектном хранилище.
Каталог $PXF_BASE/conf указан в пути к классам PXF. PXF может найти файл схемы Avro, если его поместить в этот каталог на каждом хосте Greengage DB.
Запись данных Avro
При создании внешней таблицы для записи данных Avro вы указываете имя бакета в объектном хранилище. Имена столбцов внешней таблицы становятся именами полей в Avro, и каждая строка таблицы сохраняется как запись Avro. Если не указан файл схемы, PXF генерирует схему для файла Avro на основе определения внешней таблицы Greengage DB.
В Avro есть тип данных null, но внешние таблицы Greengage DB не поддерживают ограничение столбца NOT NULL.
По этой причине PXF оборачивает каждый тип данных в объединение сопоставленного типа Avro и null.
Например, в случае внешней таблицы со столбцом, определенным с текстовым типом данных, PXF генерирует следующий элемент схемы:
["string", "null"]
PXF возвращает ошибку, если в данных встречается поле NULL, а предоставленная схема не включает объединение типа данных поля с null.
PXF поддерживает запись только примитивных типов данных Avro и массивов типов, перечисленных в разделе Сопоставление при записи. PXF не поддерживает запись составных типов в Avro:
-
Схема, указанная в выражении
LOCATIONкомандыCREATE EXTERNAL TABLE, должна содержать только примитивные типы данных. -
Когда PXF генерирует схему, любой составной тип, указанный в определении столбца внешней пишущей таблицы, записывается в файл Avro как строковый тип.
Например, массив числового типа Greengage DB при записи преобразуется в строку, и читать эти данные нужно с помощью столбца Greengage DB типа TEXT.
Создание внешней таблицы с использованием протокола PXF
Чтобы создать внешнюю таблицу Greengage DB для чтения и записи данных Avro в объектном хранилище, используется следующий синтаксис:
CREATE [READABLE | WRITABLE] EXTERNAL TABLE <table_name>
( <column_name> <data_type> [, ...] | LIKE <other_table> )
LOCATION ('pxf://<path_to_data>?PROFILE=<objstore>:avro[&<custom_option>=<value>[...]]')
FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import'|'pxfwritable_export')
[DISTRIBUTED BY (<column_name> [, ... ] ) | DISTRIBUTED RANDOMLY];
| Ключевое слово | Значение |
|---|---|
<table_name> |
Имя создаваемой таблицы |
<column_name> |
Имя создаваемого столбца |
<data_type> |
Тип данных создаваемого столбца |
LIKE <other_table> |
Указывает таблицу, из которой внешняя таблица копирует все имена столбцов, типы данных и политику распределения |
<path_to_data> |
Путь к каталогу или файлу в объектном хранилище.
Если в конфигурации сервера |
PROFILE=<objstore>:avro |
Профиль указывается в виде пары Поддерживаются следующие префиксы
|
FORMAT 'CUSTOM' |
Для чтения и записи данных Avro в объектном хранилище используется кастомный формат с использованием встроенных кастомных функций форматирования для операций чтения ( |
DISTRIBUTED BY |
При загрузке данных из таблицы Greengage DB во внешнюю пишущую таблицу рекомендуется указывать ту же политику распределения или имя столбца в обеих таблицах. Это позволит избежать дополнительного перемещения данных между сегментами при выполнении операции загрузки. Более подробную информацию о распределении таблиц можно получить в статье Распределение данных |
<custom_option> |
Одна из опций, описанных ниже, указываемая в строке |
SERVER=<server_name> |
Имя конфигурации сервера, который используется для доступа к данным.
Если опция опущена, используется конфигурация сервера с именем |
COLLECTION_DELIM |
Символы, используемые в качестве разделителя элементов массива, ассоциативного массива или записи верхнего уровня при сопоставлении составного типа данных Avro и текстового столбца во время чтения данных.
По умолчанию используется символ запятой ( |
MAPKEY_DELIM |
Символы, используемые в качестве разделителя ключа и значения элемента ассоциативного массива при сопоставлении составного типа данных Avro и текстового столбца во время чтения данных.
По умолчанию используется символ двоеточия ( |
RECORDKEY_DELIM |
Символы, используемые в качестве разделителя имени и значения поля элемента записи при сопоставлении составного типа данных Avro и текстового столбца во время чтения данных.
По умолчанию используется символ двоеточия ( |
SCHEMA |
Абсолютный путь к файлу схемы Avro на хосте Greengage DB или в объектном хранилище либо относительный путь к файлу схемы на хосте. Если файл схемы Avro находится в объектном хранилище:
|
IGNORE_MISSING_PATH |
Действие, которое необходимо выполнить, если |
COMPRESSION_CODEC |
Кодек сжатия, используемый при записи данных: |
CODEC_LEVEL |
Уровень сжатия (применяется только для кодеков |
При обращении к объектному хранилищу S3 вы можете предоставить учетные данные S3, указав опции accesskey и secretkey в выражении LOCATION команды CREATE EXTERNAL TABLE.
Примеры
Эти примеры демонстрируют настройку и использование коннектора PXF object store для чтения и записи данных Avro в объектном хранилище с помощью внешних таблиц.
Конфигурирование коннектора PXF S3
Для того чтобы подключиться к объектному хранилищу с помощью PXF, необходимо создать соответствующую конфигурацию сервера, а затем синхронизировать конфигурацию между хостами кластера Greengage DB:
-
На мастер-хосте Greengage DB войдите под пользователем
gpadmin. -
Перейдите в каталог $PXF_BASE/servers и создайте каталог конфигурации сервера S3 с именем s3. Скопируйте необходимый для используемого объектного хранилища файл конфигурации сервера из $PXF_HOME/templates в $PXF_BASE/servers/s3. В примере используется файл конфигурации на основе шаблона minio-site.xml.
$ mkdir $PXF_BASE/servers/s3 $ cd $PXF_BASE/servers/s3 $ cp $PXF_HOME/templates/minio-site.xml .В файле конфигурации укажите необходимые данные для подключения к объектному хранилищу:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <property> <name>fs.s3a.endpoint</name> <value>storage.example.com</value> </property> <property> <name>fs.s3a.access.key</name> <value>${ACCESS_KEY}</value> </property> <property> <name>fs.s3a.secret.key</name> <value>${SECRET_KEY}</value> </property> <property> <name>fs.s3a.fast.upload</name> <value>true</value> </property> <property> <name>fs.s3a.path.style.access</name> <value>true</value> </property> </configuration>ПРИМЕЧАНИЕОбратите внимание, что учетные данные для подключения к объектному хранилищу указываются в виде переменных окружения
ACCESS_KEYиSECRET_KEY.Установить значения этих переменных можно следующим образом:
$ export ACCESS_KEY=<access_key> $ export SECRET_KEY=<secret_key>Учетные данные в файле конфигурации можно указать и в виде обычного текста, но в целях безопасности рекомендуется использовать переменные окружения.
-
Синхронизируйте конфигурацию между хостами кластера Greengage DB:
$ pxf cluster sync
Создание читающей внешней таблицы
-
В каталоге /tmp на локальной машине подготовьте набор тестовых данных.
-
Создайте файл под названием avro_schema.avsc, содержащий схему Avro:
{ "type": "record", "name": "Customer", "fields": [ {"name": "id", "type": "int"}, {"name": "name", "type": "string"}, {"name": "email", "type": "string"}, {"name": "preferredChannels", "type": {"type": "array", "items": "string"}}, { "name": "address", "type": { "type": "record", "name": "Address", "fields": [ {"name": "street", "type": "string"}, {"name": "city", "type": "string"}, {"name": "state", "type": "string"}, {"name": "zipCode", "type": "string"} ] } }, { "name": "preferences", "type": { "type": "map", "values": "string" } } ] }В схеме используются следующие имена полей и типы данных:
-
id—int; -
name—string; -
email—string; -
preferredChannels— массив элементов типаstring(string[]); -
address— запись, состоящая из полей типаstring; -
preferences— ассоциативный массив элементов типаstring.
-
-
Создайте JSON-файл данных Avro с именем customers.json, соответствующий схеме выше. В данных примера в качестве разделителя записей верхнего уровня используется символ запятой (
,), а в качестве разделителя ключей и значений ассоциативного массива и имен и значений записи — символ двоеточия (:):{ "id": 123, "name": "Alice Smith", "email": "alice.smith@example.com", "preferredChannels": ["email", "sms"], "address": { "street": "123 Main St", "city": "Anytown", "state": "CA", "zipCode": "91234" }, "preferences": { "notificationsEnabled": "true", "language": "en-US", "theme": "dark" } } { "id": 456, "name": "Bob Johnson", "email": "bob.johnson@example.com", "preferredChannels": ["push", "in-app"], "address": { "street": "456 Oak Ave", "city": "Springfield", "state": "IL", "zipCode": "62704" }, "preferences": { "notificationsEnabled": "false", "language": "fr-CA", "theme": "light" } } -
Существуют различные способы преобразования текстовых файлов в формат Avro — как программно, так и через командную строку. В данном примере используется Java Avro tools. Загрузите последнюю версию JAR-файла Java Avro tools из Maven Central в каталог /tmp и преобразуйте файл customers.json в двоичный формат Avro:
$ curl -O https://repo1.maven.org/maven2/org/apache/avro/avro-tools/1.12.1/avro-tools-1.12.1.jar $ java -jar ./avro-tools-1.12.1.jar fromjson --schema-file /tmp/avro_schema.avsc /tmp/customers.json > /tmp/customers.avro
-
-
Добавьте сгенерированный файл Avro в бакет customers на хосте S3.
-
На мастер-хосте Greengage DB создайте внешнюю таблицу, ссылающуюся на файл customers.avro. Сопоставьте верхнеуровневые поля примитивных типов данных,
id,nameиemail, с типами данных Greengage DB (INTиTEXT). Сопоставьте поля составных типов (preferredChannels,addressиpreferences) с текстовым массивом Greengage DB (TEXT[]). В выраженииLOCATIONукажите PXF-профильs3:avroи конфигурацию сервера. Установите символы разделителя для записи, ассоциативного массива и коллекции с помощью соответствующих опций. В выраженииFORMATукажитеpxfwritable_import— встроенную кастомную функцию форматирования для операций чтения:CREATE EXTERNAL TABLE customers_r ( id INT, name TEXT, email TEXT, preferredChannels TEXT[], address TEXT[], preferences TEXT[] ) LOCATION ('pxf://customers/customers.avro?PROFILE=s3:avro&SERVER=s3&COLLECTION_DELIM=,&MAPKEY_DELIM=:&RECORDKEY_DELIM=:') FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import'); -
Выполните запрос к созданной внешней таблице:
SELECT * FROM customers_r;Вывод должен выглядеть следующим образом:
id | name | email | preferredchannels | address | preferences -----+-------------+-------------------------+-------------------+----------------------------------------------------------------+------------------- -------------------------------------- 123 | Alice Smith | alice.smith@example.com | {email,sms} | {"street:123 Main St",city:Anytown,state:CA,zipCode:91234} | {theme:dark,notifi cationsEnabled:true,language:en-US} 456 | Bob Johnson | bob.johnson@example.com | {push,in-app} | {"street:456 Oak Ave",city:Springfield,state:IL,zipCode:62704} | {theme:light,notif icationsEnabled:false,language:fr-CA} (2 rows) -
Опционально, выполните запрос к таблице для вывода идентификатора клиента и первых элементов текстовых массивов
preferencesиpreferredchannels:SELECT id, preferences[1], preferredChannels[1] FROM customers_r;Вывод должен выглядеть следующим образом:
id | preferences | preferredchannels -----+-------------+------------------- 123 | theme:dark | email 456 | theme:light | push (2 rows)
Создание пишущей внешней таблицы
-
На мастер-хосте Greengage DB создайте пишущую внешнюю таблицу, сохраняющую данные в каталог customers_w бакета customers на хосте S3. В выражении
LOCATIONукажите PXF-профильs3:avroи конфигурацию сервера. В выраженииFORMATукажитеpxfwritable_export— встроенную кастомную функцию форматирования для операций записи:CREATE WRITABLE EXTERNAL TABLE customers_w( id INT, name TEXT, preferredChannels TEXT[] ) LOCATION ('pxf://customers/customers_w?PROFILE=s3:avro&SERVER=s3') FORMAT 'CUSTOM' (FORMATTER='pxfwritable_export'); -
Вставьте тестовые данные в таблицу
customers_w:INSERT INTO customers_w VALUES (1, 'Alice Smith', ARRAY['email', 'sms']), (2, 'Bob Johnson', ARRAY['push', 'in-app']); -
Скопируйте каталог customers_w из бакета S3 в каталог /tmp на локальной машине и объедините содержащиеся в нем файлы в один файл customers_w.avro:
$ java -jar ./avro-tools-1.12.1.jar concat /tmp/customers_w/ /tmp/customers_w.avro -
Просмотрите содержимое файла:
$ java -jar ./avro-tools-1.12.1.jar tojson /tmp/customers_w.avroВывод должен выглядеть следующим образом:
{"id":{"int":1},"name":{"string":"Alice Smith"},"preferredchannels":{"array":[{"string":"email"},{"string":"sms"}]}} {"id":{"int":2},"name":{"string":"Bob Johnson"},"preferredchannels":{"array":[{"string":"push"},{"string":"in-app"}]}}