Формат Apache Arrow

Данные возвращаются в колоночном формате Apache Arrow (стандарт IPC версии 5.0) и не преобразуются на стороне SDK, что позволяет эффективно обрабатывать большие объёмы данных.

Этот формат рекомендуется для:

  • Аналитических (OLAP) задач, где данные обрабатываются колоночно — агрегации, фильтрации, сканирование по нескольким столбцам больших выборок;
  • Систем, которые нативно работают с Apache Arrow;
  • Задач, где важна высокая производительность при передаче больших объёмов данных.

Конвертация YQL-типов

Типы данных YQL конвертируются в типы Apache Arrow по следующим правилам.

Числовые типы

Тип YQL Тип Arrow Примечание
Bool uint8 Значения true/false кодируются как 1/0
Int8 int8
Int16 int16
Int32 int32
Int64 int64
Uint8 uint8
Uint16 uint16
Uint32 uint32
Uint64 uint64
Float float
Double double
Decimal(p, s) fixed_size_binary(16) Используются 120 бит, есть маркеры ±inf и NaN
DyNumber string Строковое представление числа

Строковые типы

Тип YQL Тип Arrow Примечание
String binary
Utf8 string
Json string
JsonDocument string Строковое представление бинарного JSON
Yson binary
Uuid fixed_size_binary(16) 16 байт в mixed-endian порядке

Временные типы

Тип YQL Тип Arrow Примечание
Date uint16 Точность до дня
Date32 int32 Точность до дня
Datetime uint32 Точность до секунды
Datetime64 int64 Точность до секунды
Timestamp uint64 Точность до микросекунды
Timestamp64 int64 Точность до микросекунды
Interval int64 Микросекунды
Interval64 int64 Микросекунды
TzDate struct<datetime: uint16, timezone: string> Включает строковое имя метки таймзоны
TzDate32 struct<datetime: int32, timezone: string> Включает строковое имя метки таймзоны
TzDatetime struct<datetime: uint32, timezone: string> Включает строковое имя метки таймзоны
TzDatetime64 struct<datetime: int64, timezone: string> Включает строковое имя метки таймзоны
TzTimestamp struct<datetime: uint64, timezone: string> Включает строковое имя метки таймзоны
TzTimestamp64 struct<datetime: int64, timezone: string> Включает строковое имя метки таймзоны

Примечание

В формате Arrow базовые временные типы данных представляют собой беззнаковые целочисленные типы, в отличие от расширенных временных типов, которые являются знаковыми.

Контейнерные типы

Тип YQL Тип Arrow Примечание
List<T> list<item: T>
Tuple<T1, T2, ...> struct<field0: T1, field1: T2, ...>
Struct<name: T, ...> struct<name: T, ...>
Dict<K, V> list<struct<key: K, payload: V>>
Set<T> list<struct<key: T, payload: struct<>>> Является Dict<T, Void>
Variant<T1, ..., Tn> dense_union<field0: T1, ...> Для n <= 128
Variant<T1, ..., Tn> dense_union<dense_union<field0: T1, ...>, ...> Для 128 < n <= 16384
Variant<name1: T1, ..., nameN: Tn> dense_union<name1: T1, ...> Для n <= 128
Variant<name1: T1, ..., nameN: Tn> dense_union<dense_union<name1: T1, ...>, ...> Для 128 < n <= 16384

Важно

Типы Variant над кортежем и над структурой не представимы в формате Apache Arrow, если количество дочерних типов превышает 16384 (128 * 128).

Опциональные и специальные типы

Тип YQL Тип Arrow Примечание
Null null Сингулярный тип
Void struct<> Сингулярный тип
EmptyList struct<> Сингулярный тип
EmptyDict struct<> Сингулярный тип
Tagged<T> T Раскрытие с потерей именования
Optional<T> struct<opt: T> Если тип T является Variant, Optional, Pg или сингулярным
Optional<T> T Для остальных типов

Типы семейства pg

Все типы семейства pg представляются типом Arrow string как текстовое представление значений.

Сжатие данных

Для формата Apache Arrow можно настроить сжатие передаваемых данных. Доступны следующие кодеки:

Кодек Описание
Без сжатия (по умолчанию)
ZSTD Сжатие Zstandard. Поддерживает настройку уровня сжатия
LZ4_FRAME Сжатие LZ4. Настройка уровня сжатия не поддерживается

Схема возвращаемых данных

Схема содержит два компонента:

  • Список столбцов с YQL-типами — описывает исходные типы данных в терминах YQL. Позволяет приложению понять семантику данных независимо от особенностей Arrow-представления.
  • Сериализованная схема Arrow RecordBatch — описывает структуру полученных бинарных данных в терминах Apache Arrow. Необходима для корректной десериализации RecordBatch на стороне клиента.

Наличие двух схем обусловлено тем, что YQL-типы и Arrow-типы не всегда имеют взаимно однозначное соответствие.

Примеры использования Apache Arrow в SDK

В настройках выполнения запроса задаётся формат результата Arrow, режим включения схемы FirstOnly и (по аналогии с примером на Python) сжатие ZSTD с уровнем 10. Сериализованная схема IPC и бинарные RecordBatch читаются через NYdb::TArrowAccessor — этот API помечен как экспериментальный; дальнейшую десериализацию выполняют средствами Apache Arrow C++. Сессию NYdb::NQuery::TSession обычно получают в колбэке TQueryClient::RetryQuerySync / RetryQuery.

#include <ydb-cpp-sdk/client/arrow/accessor.h>
#include <ydb-cpp-sdk/client/query/client.h>

NYdb::TStatus ExampleArrow(NYdb::NQuery::TSession session) {
    constexpr std::string_view query = "SELECT * FROM example ORDER BY Key LIMIT 100;";

    auto settings = NYdb::NQuery::TExecuteQuerySettings()
        .Format(NYdb::TResultSet::EFormat::Arrow)
        .SchemaInclusionMode(NYdb::NQuery::ESchemaInclusionMode::FirstOnly)
        .ArrowFormatSettings(NYdb::NQuery::TArrowFormatSettings()
            .CompressionCodec(NYdb::NQuery::TArrowFormatSettings::TCompressionCodec()
                .Type(NYdb::NQuery::TArrowFormatSettings::TCompressionCodec::EType::Zstd)
                .Level(10)
            )
        );

    auto queryResult = session.ExecuteQuery(
        query,
        NYdb::NQuery::TTxControl::BeginTx().CommitTx(),
        settings).GetValueSync();

    NYdb::NStatusHelpers::ThrowOnError(queryResult);

    for (const NYdb::TResultSet& resultSet : queryResult.GetResultSets()) {
        const std::string& schema = NYdb::TArrowAccessor::GetArrowSchema(resultSet);
        const std::vector<std::string>& batches = NYdb::TArrowAccessor::GetArrowBatches(resultSet);
        std::cout << "Arrow schema size: " << schema.size() << ", batches: " << batches.size()
                  << std::endl;
    }
}
import pyarrow

pool = ydb.QuerySessionPool(driver)

query = """
    SELECT * FROM example ORDER BY Key LIMIT 100;
"""

format_settings = ydb.ArrowFormatSettings(
    compression_codec=ydb.ArrowCompressionCodec(ydb.ArrowCompressionCodecType.ZSTD, 10)
)

result = pool.execute_with_retries(
    query,
    result_set_format=ydb.QueryResultSetFormat.ARROW,
    schema_inclusion_mode=ydb.QuerySchemaInclusionMode.FIRST_ONLY,
    arrow_format_settings=format_settings,
)

for result_set in result:
    schema = pyarrow.ipc.read_schema(pyarrow.py_buffer(result_set.arrow_format_meta.schema))
    batch = pyarrow.ipc.read_record_batch(pyarrow.py_buffer(result_set.data), schema)
    print(f"Record batch with {batch.num_rows} rows and {batch.num_columns} columns")
String query = "SELECT * FROM example ORDER BY Key LIMIT 100;";

ExecuteQuerySettings settings = ExecuteQuerySettings.newBuilder()
        .useApacheArrowFormat(ApacheArrowFormat.zstd())
        .build();

try (RootAllocator allocator = new RootAllocator()) {
    retryCtx.supplyResult(session -> session
            .createQuery(query, TxMode.SERIALIZABLE_RW, Params.empty(), settings)
            .execute(new ApacheArrowCompressedPartsHandler(allocator) {
                @Override
                public void onNextPart(QueryResultPart part) {
                    ResultSetReader rs = part.getResultSetReader();
                    while (rs.next()) {
                        String key = rs.getColumn("Key").getText();
                        System.out.println("Read row with key " + key);
                    }
                    System.out.printf("Record batch with %d rows and %d columns%n",
                            rs.getRowCount(), rs.getColumnCount());
                }
            })
    ).join().getStatus().expectSuccess("execute query problem");
}

Функциональность на данный момент не поддерживается.

Предыдущая