DEV Community на русском
Подписаться
Тип варианта в Apache Iceberg: как "измельчение" превращает неупорядоченный JSON в быструю аналитику
Каждый инженер данных сталкивается с таблицами с JSON-столбцами — ценной, но болезненной частью ландшафта данных. Эти столбцы содержат сырые данные, но влекут за собой значительные затраты на производительность запросов из-за парсинга строк. Apache Iceberg v3 представляет тип Variant для решения этой проблемы, предлагая гибкость, подобную JSON, с производительностью, близкой к типизированным столбцам. Это достигается с помощью техники, называемой "shredding" (разделение).До появления Variant существовало два плохих варианта. Хранение JSON в виде строки было простым для загрузки, но медленным для чтения, поскольку всю строку приходилось парсить для каждого запроса, а хранение было многословным. Альтернативой было "разворачивание" JSON в типизированные столбцы, что ускоряло запросы, но создавало операционные проблемы из-за нестабильности схемы и частых миграций. Многие команды прибегали к поддержанию обоих вариантов, добавляя сложность без новой информации.Variant объединяет эти варианты в один гибкий, быстрый столбец. Это тип данных для значений, структура которых варьируется от строки к строке, поддерживая объекты, массивы и примитивные типы, такие как даты и десятичные числа. Важно отметить, что значения Variant хранятся в бинарном кодировании, а не в текстовом, используя стандарт Apache Parquet. Это кодирование разделяет значения на раздел метаданных (словарь имен полей) и раздел значений, эффективно храня примитивы и позволяя напрямую переходить к конкретным полям.Хотя бинарное кодирование улучшает хранение строк, оно не обеспечивает полной колоночной производительности, поскольку Parquet рассматривает значения Variant как непрозрачные "блоки". Эта невидимость препятствует критически важным оптимизациям, таким как колоночное чтение, сжатие и отсечение. Shredding решает эту проблему, делая внутреннюю структуру видимой для формата файла.Shredding работает следующим образом: движок определяет постоянно встречающиеся поля в значениях Variant во время записи и сохраняет их как отдельные, типизированные столбцы Parquet. Например, общие поля, такие как user_id и event_type, выносятся в отдельные столбцы, в то время как менее распространенные или варьирующиеся поля остаются в остаточном бинарном столбце. Это похоже на то, как сотрудник почтового отделения отдельно подшивает общие документы (счета, этикетки), а остальные предметы оставляет в исходном конверте.Механически shredding создает пару столбцов для каждого общего поля: typed_value и value. Столбец typed_value содержит поле, когда оно соответствует ожидаемому типу, и выигрывает от всех колоночных оптимизаций. Столбец value действует как запасной вариант, храня поле в бинарной форме Variant, если оно не соответствует ожидаемому типу. Это обеспечивает целостность данных, одновременно значительно ускоряя запросы к общим полям.