Привет, Я DocuDroid!
Оценка ИИ поиска
Спасибо за оценку нашего ИИ поиска!
Мы будем признательны, если вы поделитесь своими впечатлениями, чтобы мы могли улучшить наш ИИ поиск для вас и других читателей.
GitHub

Использование коннекторов PXF object store для чтения и записи JSON-данных между Greengage DB и S3

Антон Монаков

JSON — текстовый формат обмена данными. Данные JSON представляют собой коллекцию объектов, каждый из которых является набором неупорядоченных пар имя/значение. Значением может быть строка, число, логическое значение, null, а также вложенный объект или массив.

Данные JSON обычно хранятся в файле с суффиксом .json или .jsonl (JSON Lines). Подробную информацию о синтаксисе JSON можно найти в статье Introducing JSON. Подробную информацию о синтаксисе JSON Lines можно найти в статье JSON Lines.

С помощью коннекторов PXF object store можно читать и записывать данные, хранящиеся в объектных хранилищах Azure Blob Storage, Azure Data Lake, Google Cloud Storage, Amazon S3, MinIO и других, совместимых с S3.

В этой статье описывается настройка и использование коннектора PXF object store для чтения и записи данных JSON в объектном хранилище с использованием внешних таблиц, а также приводятся практические примеры.

РЕКОМЕНДАЦИЯ

Подробная информация о работе с типом данных JSON напрямую в Greengage DB приведена в статье Работа с данными JSON.

Режимы доступа к данным JSON

PXF поддерживает два режима доступа к данным JSON.

Режим одного объекта на строку (по умолчанию) предполагает одну полную JSON-запись на строку, где каждая строка представляет кортеж базы данных. В этом режиме файлы JSON, читаемые PXF, могут иметь любой суффикс или не иметь его вообще. При записи данных PXF создает файл с суффиксом .jsonl.

Файл данных JSON с одним объектом на строку выглядит подобным образом:

{"id":1,"color":"red"}
{"id":2,"color":"yellow"}
{"id":3,"color":"green"}

Режим одного объекта на файл работает с одним объектом JSON на файл, а записи JSON могут охватывать несколько строк. Файл JSON также может содержать один именованный корневой JSON-объект, значением которого является массив объектов JSON. При чтении данных массив может содержать объекты произвольной сложности и вложенности, а PXF формирует кортежи базы данных из объектов, у которых есть свойство с именем, совпадающим со значением опции IDENTIFIER (описана ниже). При записи данных каждый JSON-объект в массиве представляет собой кортеж базы данных. Файлы JSON этого типа имеют суффикс .json.

ВАЖНО

В файлах данных JSON не должно быть пустых строк.

Образец файла данных JSON для одного объекта на файл выглядит подобным образом. Корневой объект records является массивом из трех объектов (кортежей):

{
  "records": [
    {
      "id": 1,
      "color": "red"
    },
    {
      "id": 2,
      "color": "yellow"
    },
    {
      "id": 3,
      "color": "green"
    }
  ]
}

При записи данных PXF по умолчанию создает файл с суффиксом .jsonl. Если указано свойство ROOT (описано ниже), создается файл с суффиксом .json.

Сопоставление типов данных

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

Сопоставление при чтении

При чтении JSON-данных с помощью PXF используется следующее сопоставление типов данных. Вы можете использовать N-уровневую проекцию для сопоставления элементов вложенных объектов и массивов с примитивными типами данных.

Тип данных JSON Тип данных PXF / Greengage

boolean

BOOLEAN

number

Один из следующих типов: BIGINT, FLOAT8, INTEGER, NUMERIC, REAL, SMALLINT

string

TEXT

string (значение, закодированное в base64)

BYTEA

string (date, time, timestamp, timestamptz в текстовом формате, поддерживаемом Greengage DB)

Один из следующих типов: DATE, TIME, TIMESTAMP, TIMESTAMPTZ. PXF возвращает ошибку, если Greengage DB не удалось конвертировать строку времени или даты в целевой тип

Одномерный массив типа boolean[]

BOOLEAN[]

Одномерный массив типа number[]

Один из следующих типов: BIGINT[], FLOAT8[], INTEGER[], NUMERIC[], REAL[], SMALLINT[]

Одномерный массив типа string[] (значение, закодированное в base64)

BYTEA[]

Одномерный массив типа string[] (date, time, timestamp в текстовом формате, поддерживаемом Greengage DB)

DATE[], TIME[], TIMESTAMP[], TIMESTAMPTZ[]

Одномерный массив типа string[]

TEXT[]

Массив других типов

TEXT[]

Object

Используйте точечную нотацию (.) для указания каждого уровня проекции (вложенности) элемента примитивного типа или массива

Сопоставление при записи

PXF поддерживает запись примитивных типов и одномерных массивов примитивных типов. Другие сложные типы записываются в JSON как строки. PXF использует следующее сопоставление типов данных при записи данных JSON.

Тип данных PXF / Greengage Тип данных JSON

BIGINT, FLOAT8, INTEGER, NUMERIC, REAL, SMALLINT

number

BOOLEAN

boolean

BPCHAR, TEXT, VARCHAR

string

BYTEA

string (значение, закодированное в base64)

DATE, TIME, TIMESTAMP, TIMESTAMPTZ

string

BOOLEAN[]

boolean[]

BIGINT[], FLOAT8[], INT[], NUMERIC[], REAL[], SMALLINT[]

number[]

BYTEA[]

string[] (значение, закодированное в base64)

DATE[], TIME[], TIMESTAMP[], TIMESTAMPTZ[]

string[]

Использование проекции столбцов

В данном примере файла данных JSON объект user содержит поля id и location:

{
  "created_at": "MonSep3004:04:53+00002013",
  "id_str": "384529256681725952",
  "user": {
    "id": 31424214,
    "location": "COLUMBUS"
  },
  "coordinates": {
    "type": "Point",
    "values": [
      13,
      99
    ]
  }
}

Чтобы использовать вложенные поля объекта user в качестве столбцов внешней таблицы Greengage DB, используйте точечную проекцию (.):

user.id
user.location

Объект coordinates состоит из текстового поля type и целочисленного массива values. Чтобы поместить все значения массива values в один столбец, укажите для соответствующего столбца внешней таблицы Greengage DB тип INT[]:

"coordinates.values" INT[]

PXF также поддерживает доступ к конкретным элементам JSON-массива с помощью скобочного синтаксиса [n] в определении таблицы. Обратите внимание, что при использовании этого метода для идентификации конкретных элементов массива PXF предоставляет Greengage DB только эти значения, а не весь массив:

"coordinates.values[0]" INT

При записи данных JSON PXF поддерживает только скалярные значения или одномерные массивы типов данных Greengage DB и не поддерживает проекцию столбцов.

Создание внешней таблицы с использованием протокола PXF

Чтобы создать внешнюю таблицу Greengage DB для чтения и записи данных JSON в объектном хранилище, используется следующий синтаксис:

CREATE [READABLE | WRITABLE] EXTERNAL TABLE <table_name>
    ( <column_name> <data_type> [, ...] | LIKE <other_table> )
    LOCATION ('pxf://<path_to_data>?PROFILE=<objstore>:json[&<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>

Путь к каталогу или файлу в объектном хранилище. Если в конфигурации сервера <server_name> указано свойство pxf.fs.basePath, значение <path_to_data> трактуется как относительный путь к указанному базовому пути. В противном случае путь считается абсолютным. Значение пути не должно содержать символ $

PROFILE=<objstore>:json

Профиль указывается в виде пары <objstore>:json, где <objstore> — префикс объектного хранилища.

Поддерживаются следующие префиксы <objstore> и соответствующие объектные хранилища:

  • wasbs — Azure Blob Storage

  • adl — Azure Data Lake

  • gs — Google Cloud Storage

  • s3 — Amazon S3, MinIO и прочие S3-совместимые объектные хранилища

FORMAT 'CUSTOM'

Для чтения и записи данных JSON в объектном хранилище используется кастомный формат с использованием встроенных кастомных функций форматирования для операций чтения (pxfwritable_import) и записи (pxfwritable_export)

<custom_option>

Одна из опций, описанных ниже, указываемая в строке LOCATION

SERVER=<server_name>

Имя конфигурации сервера, который используется для доступа к данным. Если опция опущена, используется конфигурация сервера с именем default

IDENTIFIER=<value>

Указывается только при обращении к данным JSON с многострочными полями. Значение <value> обозначает имя поля, чей родительский JSON-объект должен быть возвращен в качестве кортежа.

Если во вложенном объекте присутствует поле с тем же именем, что указано в качестве IDENTIFIER, PXF может вернуть неверные данные. Вы можете обойти этот пограничный случай, выполнив сжатие JSON-файла, а затем его чтение с помощью PXF

SPLIT_BY_FILE=<boolean>

Определяет, как разделять файлы, указанные в <path_to_data>. Значение по умолчанию — false: PXF при этом создает несколько разделов для каждого файла и обрабатывает их параллельно. Если установлено значение true, PXF создает и обрабатывает один раздел на файл

IGNORE_MISSING_PATH=<boolean>

Действие, которое необходимо выполнить, если <path_to_data> отсутствует или указан неверно. Если установлено значение false (по умолчанию), возвращается ошибка. Если установлено значение true, PXF игнорирует ошибку и возвращает пустой фрагмент. Применяется только для читающих внешних таблиц; в случае пишущих внешних таблиц игнорируется

ROOT=<value>

При записи данных в один объект указывает имя атрибута корневого уровня

COMPRESSION_CODEC

Кодек сжатия, используемый при записи данных: default, bzip2, gzip или uncompressed (без сжатия). Если значение не указано (или указано uncompressed), сжатие не производится

ПРИМЕЧАНИЕ

При обращении к объектному хранилищу S3 вы можете предоставить учетные данные S3, указав опции accesskey и secretkey в выражении LOCATION команды CREATE EXTERNAL TABLE.

Примеры

Эти примеры демонстрируют настройку и использование коннектора PXF object store для чтения и записи данных JSON в объектном хранилище с помощью внешних таблиц.

Предварительные требования

Для выполнения практических примеров подключитесь к мастер-хосту Greengage DB как gpadmin с помощью psql, как описано в статье Подключение к Greengage DB с использованием psql. Затем создайте тестовую базу данных customers и подключитесь к ней:

DROP DATABASE IF EXISTS customers;
CREATE DATABASE customers;
\c customers

Чтобы создать внешнюю таблицу с использованием протокола PXF, предварительно зарегистрируйте в БД расширение PXF, как описано в разделе Регистрация PXF в БД документации PXF:

CREATE EXTENSION pxf;

Конфигурирование коннектора PXF S3

Для того чтобы подключиться к объектному хранилищу с помощью PXF, необходимо создать соответствующую конфигурацию сервера, а затем синхронизировать конфигурацию между хостами кластера Greengage DB:

  1. На мастер-хосте Greengage DB войдите под пользователем gpadmin.

  2. Перейдите в каталог $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>

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

  3. Синхронизируйте конфигурацию между хостами кластера Greengage DB:

    $ pxf cluster sync

Чтение JSON-файла с однострочными полями

  1. В бакете customers на хосте S3 создайте файл с именем customers.jsonl и следующим содержимым:

    {"customer": {"id": 1,"name": "John Doe"},"ordered_items":["laptop", "monitor"]}
    {"customer": {"id": 2,"name": "Jane Smith"},"ordered_items":["keyboard", "mouse", "pad"]}
    {"customer": {"id": 3,"name": "Bob Brown"},"ordered_items":["headphones"]}
    {"customer": {"id": 4,"name": "Alice Green"},"ordered_items":["webcam", "microphone"]}
  2. На мастер-хосте Greengage DB создайте внешнюю таблицу, ссылающуюся на файл customers.jsonl. При определении столбцов используйте точечную нотацию (.) для доступа к вложенным полям объекта customer. Сопоставьте текстовый массив ordered_items с текстовым столбцом Greengage DB (TEXT). В выражении LOCATION укажите PXF-профиль s3:json и конфигурацию сервера. В выражении FORMAT укажите pxfwritable_import — встроенную кастомную функцию форматирования для операций чтения:

    CREATE EXTERNAL TABLE customers_r_singleline_1 (
            "customer.id" INT,
            "customer.name" TEXT,
            "ordered_items" TEXT
        )
        LOCATION('pxf://customers/customers.jsonl?PROFILE=s3:json&SERVER=s3')
        FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import');
  3. Выполните запрос к созданной внешней таблице:

    SELECT * FROM customers_r_singleline_1;

    Вывод должен выглядеть следующим образом:

     customer.id | customer.name |       ordered_items
    -------------+---------------+----------------------------
               1 | John Doe      | ["laptop","monitor"]
               2 | Jane Smith    | ["keyboard","mouse","pad"]
               3 | Bob Brown     | ["headphones"]
               4 | Alice Green   | ["webcam","microphone"]
    (4 rows)

    JSON-массив ordered_items извлекается в единый столбец текстового типа. Чтобы преобразовать его во встроенный тип массива Greengage DB, можно выполнить следующий запрос, использующий функцию json_array_elements_text():

    SELECT "customer.id",
           "customer.name",
           ARRAY(SELECT json_array_elements_text(ordered_items::json))::text[] AS items
    FROM customers_r_singleline_1;

    Вывод должен выглядеть следующим образом:

     customer.id | customer.name |        items
    -------------+---------------+----------------------
               1 | John Doe      | {laptop,monitor}
               2 | Jane Smith    | {keyboard,mouse,pad}
               3 | Bob Brown     | {headphones}
               4 | Alice Green   | {webcam,microphone}
    (4 rows)
  4. На мастер-хосте Greengage DB создайте еще одну внешнюю таблицу, ссылающуюся на файл customers.jsonl. Сопоставьте текстовый массив ordered_items с текстовым массивом Greengage DB (TEXT[]):

    CREATE EXTERNAL TABLE customers_r_singleline_2 (
            "customer.id" INT,
            "customer.name" TEXT,
            "ordered_items" TEXT[]
        )
        LOCATION('pxf://customers/customers.jsonl?PROFILE=s3:json&SERVER=s3')
        FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import');
  5. Выполните запрос к созданной внешней таблице, используя номер индекса массива в квадратных скобках, чтобы извлечь первый элемент массива ordered_items:

    SELECT "customer.id",
           "customer.name",
           "ordered_items"[1]
    FROM customers_r_singleline_2;

    Вывод должен выглядеть следующим образом:

     customer.id | customer.name | ordered_items
    -------------+---------------+---------------
               1 | John Doe      | laptop
               2 | Jane Smith    | keyboard
               3 | Bob Brown     | headphones
               4 | Alice Green   | webcam
    (4 rows)
  6. На мастер-хосте Greengage DB создайте еще одну внешнюю таблицу, ссылающуюся на файл customers.jsonl. Используйте номер индекса массива в квадратных скобках, чтобы извлечь второй элемент массива ordered_items, и сопоставьте его с текстовым столбцом Greengage DB:

    CREATE EXTERNAL TABLE customers_r_singleline_3 (
            "customer.id" INT,
            "customer.name" TEXT,
            "ordered_items[1]" TEXT
        )
        LOCATION('pxf://customers/customers.jsonl?PROFILE=s3:json&SERVER=s3')
        FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import');
  7. Выполните запрос к созданной внешней таблице:

    SELECT * FROM customers_r_singleline_3;

    Вывод должен выглядеть следующим образом:

     customer.id | customer.name | ordered_items[1]
    -------------+---------------+------------------
               1 | John Doe      | monitor
               2 | Jane Smith    | mouse
               3 | Bob Brown     |
               4 | Alice Green   | microphone
    (4 rows)

Чтение JSON-файла с многострочными полями

  1. В бакете customers на хосте S3 создайте файл с именем customers.json и следующим содержимым:

    {
      "customers": [
        {
          "id": 101,
          "name": "Alice Smith",
          "ordered_items": [
            "laptop",
            "monitor"
          ]
        },
        {
          "id": 102,
          "name": "Bob Johnson",
          "ordered_items": [
            "keyboard",
            "mouse",
            "pad"
          ]
        },
        {
          "id": 103,
          "name": "Charlie Brown",
          "ordered_items": [
            "headphones"
          ]
        }
      ]
    }
  2. На мастер-хосте Greengage DB создайте внешнюю таблицу, ссылающуюся на файл customers.json. Сопоставьте текстовый массив ordered_items с текстовым массивом Greengage DB (TEXT[]). В выражении LOCATION укажите PXF-профиль s3:json, конфигурацию сервера и id в качестве значения IDENTIFIER. В выражении FORMAT укажите pxfwritable_import — встроенную кастомную функцию форматирования для операций чтения:

    CREATE EXTERNAL TABLE customers_r_multiline (
        id INT,
        name TEXT,
        ordered_items TEXT[]
        )
        LOCATION ('pxf://customers/customers.json?PROFILE=s3:json&SERVER=s3&IDENTIFIER=id')
        FORMAT 'CUSTOM' (FORMATTER='pxfwritable_import');
  3. Выполните запрос к созданной внешней таблице:

    SELECT * FROM customers_r_multiline;

    Вывод должен выглядеть следующим образом:

     id  |     name      |    ordered_items
    -----+---------------+----------------------
     101 | Alice Smith   | {laptop,monitor}
     102 | Bob Johnson   | {keyboard,mouse,pad}
     103 | Charlie Brown | {headphones}
    (3 rows)

Запись JSON-файла с однострочными полями

  1. На мастер-хосте Greengage DB создайте пишущую внешнюю таблицу, сохраняющую данные в бакет customers на хосте S3. В выражении LOCATION укажите PXF-профиль s3:json и конфигурацию сервера. В выражении FORMAT укажите pxfwritable_export — встроенную кастомную функцию форматирования для операций записи:

    CREATE WRITABLE EXTERNAL TABLE customers_w_singleline (
            id INT,
            name TEXT, 
            ordered_items TEXT[]    
        )
        LOCATION ('pxf://customers?PROFILE=s3:json&SERVER=s3')
        FORMAT 'CUSTOM' (FORMATTER='pxfwritable_export');
  2. Вставьте тестовые данные в таблицу customers_w_singleline:

    INSERT INTO customers_w_singleline 
    VALUES (1, 'John Doe', ARRAY['laptop', 'monitor']),
           (2, 'Jane Smith', ARRAY['keyboard', 'mouse', 'pad']),
           (3, 'Bob Brown', ARRAY['headphones']),
           (4, 'Alice Green', ARRAY['webcam', 'microphone']);
  3. Просмотрите содержимое файлов, созданных в бакете customers на хосте S3. Вывод должен выглядеть подобным образом:

    {"id":3,"name":"Bob Brown","ordered_items":["headphones"]}
    {"id":4,"name":"Alice Green","ordered_items":["webcam","microphone"]}
    {"id":1,"name":"John Doe","ordered_items":["laptop","monitor"]}
    {"id":2,"name":"Jane Smith","ordered_items":["keyboard","mouse","pad"]}

Запись JSON-файла с многострочными полями

  1. На мастер-хосте Greengage DB создайте пишущую внешнюю таблицу, сохраняющую данные в бакет customers на хосте S3. В выражении LOCATION укажите PXF-профиль s3:json, конфигурацию сервера и customers в качестве значения ROOT. В выражении FORMAT укажите pxfwritable_export — встроенную кастомную функцию форматирования для операций записи:

    CREATE WRITABLE EXTERNAL TABLE customers_w_multiline (
            id INT,
            name TEXT, 
            ordered_items TEXT[]    
        )
        LOCATION ('pxf://customers?PROFILE=s3:json&SERVER=s3&ROOT=customers')
        FORMAT 'CUSTOM' (FORMATTER='pxfwritable_export');
  2. Вставьте тестовые данные в таблицу customers_w_multiline:

    INSERT INTO customers_w_multiline 
    VALUES (1, 'John Doe', ARRAY['laptop', 'monitor']),
           (2, 'Jane Smith', ARRAY['keyboard', 'mouse', 'pad']),
           (3, 'Bob Brown', ARRAY['headphones']),
           (4, 'Alice Green', ARRAY['webcam', 'microphone']);
  3. Просмотрите содержимое файлов, созданных в бакете customers на хосте S3. Вывод должен выглядеть подобным образом:

    {"customers":[
    {"id":3,"name":"Bob Brown","ordered_items":["headphones"]}
    ]}
    {"customers":[
    {"id":1,"name":"John Doe","ordered_items":["laptop","monitor"]}
    ]}
    {"customers":[
    {"id":2,"name":"Jane Smith","ordered_items":["keyboard","mouse","pad"]}
    ,{"id":4,"name":"Alice Green","ordered_items":["webcam","microphone"]}
    ]}