Learning Platform
Глоссарий Troubleshooting
Урок 02.03 · 14 мин
Средний
Arrow Type SystemDataTypeSchemaFieldNested TypesExtension Types

Система типов Arrow: от Int32 до вложенных структур

Зачем типовая система в in-memory формате

Arrow определяет не только byte layout, но и полную систему типов. Каждый массив имеет конкретный DataType, определяющий, как интерпретировать байты в буферах. Без типовой информации буфер [1C 00 00 00] — это просто 4 байта. С типом Int32 это число 28, с Float32 — совсем другое значение.

Типовая система Arrow покрывает три уровня:

  • Примитивные типы — числа, строки, бинарные данные, boolean, temporal
  • Вложенные типы — List, Struct, Map, Union
  • Extension types — пользовательские типы поверх базовых

Примитивные типы

Числовые

ТипРазмерДиапазонКогда использовать
Int8 / Int16 / Int32 / Int641 / 2 / 4 / 8 байтзнаковые целыеID, количества, коды
UInt8 / UInt16 / UInt32 / UInt641 / 2 / 4 / 8 байтбеззнаковыеиндексы, размеры
Float16 / Float32 / Float642 / 4 / 8 байтIEEE 754измерения, координаты
Decimal128(precision, scale)16 байтточная арифметикаденьги, финансы
Decimal256(precision, scale)32 байтсверхточная арифметиканаучные вычисления
NOTE

DataFusion по умолчанию использует Int64 для целых литералов и Float64 для дробных. Decimal128 применяется автоматически при работе с SQL DECIMAL типами.

Строковые и бинарные

ТипOffsetsMax размерОписание
Utf8int32~2 GB суммарноUTF-8 строки (основной)
LargeUtf8int64~2^63 байтДля огромных текстовых колонок
Binaryint32~2 GBПроизвольные байты
LargeBinaryint64~2^63 байтБольшие бинарные данные
FixedSizeBinary(N)нетN байт на значениеUUID, хеши, IP-адреса

Temporal типы

Arrow поддерживает точные temporal типы с явным указанием единиц:

ТипЕдиницыПример
Date32дни с epochДата без времени
Date64миллисекунды с epochДата без времени (ms precision)
Time32(unit)секунды / миллисекундыВремя дня
Time64(unit)микросекунды / наносекундыВремя дня (высокая точность)
Timestamp(unit, tz)с/мс/мкс/нс + timezoneПолная метка времени
Duration(unit)с/мс/мкс/нсИнтервал (разность timestamp)
Intervalyear-month / day-time / month-day-nanoКалендарный интервал
use arrow::datatypes::{DataType, TimeUnit};

// Timestamp с наносекундной точностью и UTC timezone
let ts_type = DataType::Timestamp(TimeUnit::Nanosecond, Some("UTC".into()));

// Duration в миллисекундах
let dur_type = DataType::Duration(TimeUnit::Millisecond);

Вложенные типы

Arrow поддерживает вложенные структуры, что критично для работы с JSON, Parquet nested columns и полуструктурированными данными.

List

Массив списков. Каждый элемент — список значений одного типа.

// List<Int32>: [[1, 2], [3], NULL, [4, 5, 6]]
// Внутренне: offset buffer + child Int32 array
List<Int32>: [[1, 2], [3], NULL, [4, 5, 6]]
Validity BitmapБитовая маска для вложенного List: отмечает NULL-элементы среди списков
Offset Buffer (5 x int32)Определяет границы каждого списка в child array. Для NULL — пустой диапазон
Child Array (Int32, 6 значений)Плоский массив всех элементов всех списков. Границы определяются offset buffer

Offset [0, 2] означает, что первый список содержит элементы child array с индекса 0 до 2 (не включая). Offset [3, 3] для NULL-элемента — пустой диапазон.

Struct

Именованная группа полей. Аналог строки в SQL или объекта в JSON.

// Struct { name: Utf8, age: Int32 }
// Два child array одинаковой длины + один validity bitmap для всей структуры
DataType::Struct(vec![
    Field::new("name", DataType::Utf8, false),
    Field::new("age", DataType::Int32, true),
].into())

Struct в Arrow — это не вложенный RecordBatch. Каждое поле хранится как отдельный child array. Struct-уровневый validity bitmap определяет, является ли вся структура NULL (отдельно от nullable полей внутри).

Map

Ассоциативный массив (key-value). Внутренне Map — это List<Struct<key, value>> с гарантией уникальности ключей.

// Map<Utf8, Int32>: {"a": 1, "b": 2}
DataType::Map(
    Arc::new(Field::new("entries", DataType::Struct(vec![
        Field::new("key", DataType::Utf8, false),
        Field::new("value", DataType::Int32, true),
    ].into()), false)),
    false, // keys_sorted
)

Union

Тип-сумма: каждый элемент может быть одним из нескольких типов. Два варианта:

  • Sparse Union: все child arrays одинаковой длины, type_id указывает активный child
  • Dense Union: child arrays разной длины + offset buffer для маппинга

Union редко используется в DataFusion напрямую, но встречается при чтении Arrow IPC из внешних источников.

Schema, Field, DataType

Schema — упорядоченный набор полей (Field) с необязательными метаданными:

Иерархия: Schema → Field → DataType
SchemaУпорядоченный набор полей с метаданными. Определяет структуру RecordBatch
Field "id"Non-nullable целочисленное поле — идентификатор записи
Field "name"Nullable строковое поле — UTF-8 текст переменной длины
Field "tags"Вложенный тип: список строк. Child array хранит элементы, offset buffer определяет границы
use arrow::datatypes::{Schema, Field, DataType};

let schema = Schema::new(vec![
    Field::new("id", DataType::Int64, false),
    Field::new("name", DataType::Utf8, true),
    Field::new("tags", DataType::List(
        Arc::new(Field::new("item", DataType::Utf8, true))
    ), true),
]);

// Metadata (произвольные key-value пары)
let schema = schema.with_metadata(HashMap::from([
    ("source".to_string(), "kafka".to_string()),
]));

В DataFusion SchemaRef (Arc<Schema>) передаётся между операторами. Каждый оператор знает схему входных и выходных данных до начала выполнения — это позволяет ловить ошибки типов на этапе планирования, а не во время исполнения.

Extension Types

Extension types позволяют добавлять семантику поверх базовых типов без изменения byte layout:

// UUID хранится как FixedSizeBinary(16), но с пометкой "arrow.uuid"
// JSON хранится как Utf8, но с пометкой "arrow.json"
// GeoPoint хранится как Struct{lat: Float64, lon: Float64}

Extension type определяется через metadata поля:

  • ARROW:extension:name — идентификатор типа (например, arrow.uuid)
  • ARROW:extension:metadata — дополнительные параметры

Это позволяет сохранять совместимость: система, не знающая о расширении, видит базовый тип и работает корректно. Система, понимающая расширение, интерпретирует данные точнее.

Сравнение с SQL типами

SQL типArrow DataTypeПримечание
INTEGERInt324 байта
BIGINTInt648 байт
REALFloat32IEEE 754
DOUBLEFloat64IEEE 754
VARCHARUtf8Variable-length UTF-8
BOOLEANBoolean1 бит на значение
DATEDate32Дни с epoch
TIMESTAMPTimestamp(ns, tz)Наносекунды + timezone
DECIMAL(p,s)Decimal128(p,s)16 байт fixed-point
ARRAYList<T>Вложенный тип
ROW / STRUCTStructИменованные поля

DataFusion использует эту таблицу при парсинге SQL: CREATE TABLE t (id INT, name VARCHAR) создаёт схему с Int32 и Utf8.

Итоги

  • Arrow определяет полную типовую систему: примитивные, вложенные, extension типы
  • Примитивные: числа (Int8-Int64, Float16-Float64, Decimal), строки (Utf8), temporal, boolean
  • Вложенные: List (массивы), Struct (записи), Map (словари), Union (суммы)
  • Schema + Field + DataType — иерархия описания данных
  • Extension types добавляют семантику без изменения layout
  • DataFusion маппит SQL типы на Arrow DataType при парсинге запросов

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 5. Какой Arrow DataType следует использовать для хранения денежных сумм с точной арифметикой (без ошибок округления IEEE 754)?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 6