Сопоставление типов данных: SPYT, Spark и YTsaurus

В этой статье описано сопоставление типов данных в YTsaurus и типов данных в Spark при чтении и записи.

Особенности

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

  2. Точность Decimal: YTsaurus ограничивает precision типа decimal значением 35 (не scale). Подробнее про Decimal

  3. Строковые типы: опция конфигурации stringToUtf8 контролирует, сопоставляются ли строки с типами string или utf8 в YTsaurus. Пример:

    import spyt
    from pyspark.sql import Row
    from pyspark.sql.types import StructType, StructField, StringType, BinaryType
    
    spark.createDataFrame(
        spark.sparkContext.parallelize([Row("string", b"binary")]),
        StructType([
            StructField("string", StringType(), nullable=False),
            StructField("binary", BinaryType(), nullable=False),
        ])
    ).write \
    .option("string_to_utf8", "true") \
    .yt("//path/to/table")
    
  4. Составные типы: сложные типы наподобие структур, массивов и словарей рекурсивно сопоставляются с использованием тех же правил для их элементарных типов.

  5. Тип float при чтении сопоставляется по-разному в зависимости от положения в схеме:

    • колонка верхнего уровняFloatType;
    • элемент внутри составного типа (Array, Dict, Struct, Tuple, Variant) → DoubleType.

    Это связано с особенностью формата YSON: в YSON нет 4-байтного float-узла, поэтому float внутри составных типов хранится как 8-байтный double. Чтобы избежать потери данных при чтении, SPYT преобразует его в DoubleType. Колонки верхнего уровня читаются по wire-протоколу, где тип float сохраняется как FloatType.

  6. «Arrow не поддерживается»: для типов с такой пометкой при включённой опции spark.yt.read.arrow.enabled (по умолчанию true) SPYT автоматически переключается на wire-протокол.

    Важно

    Если хотя бы одна колонка схемы содержит тип без поддержки Arrow, вся таблица читается через wire-протокол, включая остальные колонки. При проектировании схемы это стоит учитывать, если важна производительность чтения.

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

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

Тип YTsaurus Тип Spark (Базовый) Тип Spark (Расширенный) Примечания
null NullType NullType
int64 LongType LongType
uint64 DecimalType(20, 0) UInt64Type
float FloatType/DoubleType FloatType/DoubleType Верхний уровень: FloatType; внутри составного типа: DoubleType (см. Особенности п. 5). Arrow не поддерживается
double DoubleType DoubleType
boolean BooleanType BooleanType
string StringType StringType
binary BinaryType BinaryType
any/yson BinaryType YsonType YsonType — кастомный тип SPYT (см. раздел ниже)
int8 ByteType ByteType
uint8 ShortType ShortType
int16 ShortType ShortType
uint16 IntegerType IntegerType
int32 IntegerType IntegerType
uint32 LongType LongType
utf8 StringType StringType
date DateType DateType Arrow не поддерживается
datetime DatetimeType DatetimeType Arrow не поддерживается
timestamp TimestampType TimestampType Arrow не поддерживается
interval LongType LongType Arrow не поддерживается
date32 Date32Type Date32Type Кастомный тип SPYT расширенного диапазона (см. раздел ниже). Arrow не поддерживается
datetime64 Datetime64Type Datetime64Type Кастомный тип SPYT расширенного диапазона (см. раздел ниже). Arrow не поддерживается
timestamp64 Timestamp64Type Timestamp64Type Кастомный тип SPYT расширенного диапазона (см. раздел ниже). Arrow не поддерживается
interval64 Interval64Type Interval64Type Кастомный тип SPYT расширенного диапазона (см. раздел ниже). Arrow не поддерживается
uuid StringType StringType Arrow не поддерживается
json StringType StringType Arrow не поддерживается
void NullType NullType

Составные типы

В обозначениях ниже inner, key, value — типы вложенных элементов. Для каждого из них применяются правила «внутреннего уровня» (например, floatDoubleType).

Тип YTsaurus Сопоставление с типом Spark
Optional(inner) inner тип с nullable = true
Dict(key, value) MapType(key_type, value_type, value.nullable), где key_type и value_type — Spark-типы ключа и значения, определённые по правилам внутреннего уровня
Array(inner) ArrayType(inner_type, inner.nullable), где inner_type — Spark-тип элемента по правилам внутреннего уровня
Struct(fields) StructType с соответствующими сопоставлениями полей
Tuple(elements) StructType с полями, названными _1, _2 и т.д.
VariantOverStruct StructType с полями, префиксованными _v и nullable = true
VariantOverTuple StructType с полями, названными _v_1, _v_2 и т.д. и nullable = true

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

Тип Spark Тип YTsaurus Примечания
NullType null
ByteType int8
ShortType int16 (или uint8 при использовании schema_hint) См. пример ниже
IntegerType int32 (или uint16 при использовании schema_hint)
LongType int64 (или uint32 при использовании schema_hint)
StringType string (или utf8/json/uuid при использовании schema_hint, или utf8 если stringToUtf8 включено)
FloatType float
DoubleType double
BooleanType boolean
DecimalType Decimal(precision, scale) precision ограничена 35
ArrayType Array(inner)
StructType (tuple) Tuple(elements)
StructType (variant) VariantOverStruct/VariantOverTuple
StructType Struct(fields)
MapType Dict(key, value)
BinaryType binary
DateType date
DatetimeType datetime
TimestampType timestamp
Date32Type date32
Datetime64Type datetime64
Timestamp64Type timestamp64
Interval64Type interval64
UInt64Type uint64
YsonType any YsonType — кастомный тип SPYT (см. раздел ниже)

Переопределение типа через schema_hint

Если стандартное сопоставление не подходит, можно явно указать целевой YTsaurus-тип через schema_hint.

df.write.schema_hint({"my_col": "uint8"}).yt("//path/to/table")
df.write.schemaHint(Map("my_col" -> YtLogicalType.Uint8)).yt("//path/to/table")

Кастомные типы SPYT

Перечисленные ниже типы не входят в стандартный Apache Spark — они предоставляются библиотекой SPYT.

Временны́е типы расширенного диапазона

В YTsaurus существуют два набора временны́х типов:

  • Стандартные (date, datetime, timestamp, interval) — беззнаковые целые; диапазон [1970-01-01, 2105-12-31].
  • Широкие (date32, datetime64, timestamp64, interval64) — знаковые целые (int32/int64); диапазон около 145 000 лет в прошлое и в будущее от Unix-эпохи.

Широкие типы появились позже стандартных и являются предпочтительными для данных, выходящих за пределы 1970–2105. В Spark им соответствуют кастомные типы SPYT: Date32Type, Datetime64Type, Timestamp64Type, Interval64Type.

Подробнее про устройство временны́х типов в YTsaurus см. в разделе Временны́е типы.

YsonType

YsonType — кастомный UDT (User Defined Type), хранящий данные в виде YSON-байтов.

  • При чтении из YTsaurus: тип any/ysonYsonType (расширенный режим) или BinaryType (базовый режим).
  • При записи в YTsaurus: YsonType → тип any.

Подробнее про работу с YsonType см. в разделах Python API и Scala API.