Apache Iceberg. Кластеризация
Z‑ordering и умная организация данных
Содержание
Давайте поговорим о кластеризации. Технически она не является частью спецификации Iceberg, но каждый вендор и каждый подход её поддерживает, поэтому стоит разобраться.
Что делает кластеризация?
Вы уже знаете, что партицирование делит ваши данные на отдельные куски — физические части в blob‑хранилище, примерно как организация книг по жанрам в библиотеке: одна полка для ужасов, другая для фэнтези, третья для поэзии и так далее. Всего, скажем, 50 полок.
Но что, если вы ищете автора, который работает в нескольких жанрах, например Стивена Кинга? Вы можете считать его автором ужасов, но он заходил и в десяток других жанров. Теперь вам придётся пройтись по всем 50 полкам — не очень удобно.
Кластеризация пытается решить эту проблему. Самый распространённый подход — Z‑ordering (Z‑упорядочивание).
Z‑ordering: комбинирование атрибутов
Вместо организации книг по одному атрибуту Z‑ordering комбинирует несколько атрибутов — например, жанр и имя автора — и вычисляет так называемое z‑значение на основе этих входных значений. Это z‑значение определяет, куда попадёт книга, и становится скалярной величиной (скажем, числом от 1 до 10 000), которую мы получаем хэшированием входных колонок.
Книги сортируются по этому вычисленному z‑значению и размещаются на гораздо более узких полках. Каждая полка покрывает небольшой диапазон значений (например, по 10 значений на полку, всего до 10 000 полок).
Самое интересное: книги с одинаковым жанром или одним автором будут стремиться кластеризоваться в одной области. Это работает вероятностно — нам нужно, чтобы это срабатывало хотя бы часть времени, и это действительно происходит.
Благодаря такой организации книги Стивена Кинга окажутся всего на четырёх соседних полках. И это работает в обе стороны: если вам нужны все книги фэнтези независимо от автора, они будут находиться примерно на полках 61–130.
Таким образом, Z‑ordering даёт эффективные диапазоны для множества шаблонов запросов или нескольких предикатов, участвующих в кластеризации.
В Iceberg z‑значение получается переплетением битов значений каждой колонки. Математика здесь довольно изящна — если вам интересно, можете изучить её отдельно.
Пример: таблица продаж с 100 миллионами строк
Представьте таблицу продаж, партицированную по месяцам. Проблема в том, что данные имеют выраженную сезонность: например, декабрь — пиковый месяц шопинга для этого бизнеса. В результате одна партиция раздувается до 50 миллионов строк, распределённых по десяткам больших файлов.
Внутри этой декабрьской партиции данные не организованы автоматически по датам. Разные дни перемешаны между файлами, диапазоны перекрываются, и эффективное отсечение (pruning) становится очень сложным.
Если вам нужны продажи региона EMEA за конец декабря, вы будете читать гораздо больше данных, чем необходимо, потому что большинство декабрьских файлов содержат перекрывающиеся диапазоны дат и смешанные регионы.
Как помогает кластеризация?
При переходе на кластеризацию ваши файлы физически реорганизуются: похожие значения кластеризуются вместе. Например, продажи EMEA за 17–19 декабря оказываются в одном файле, за 20–22 декабря — в другом. Диапазоны становятся узкими, отсечение работает хорошо, сканирование эффективно.
Вы получаете лучшую локальность данных, более высокое сжатие и более быстрые запросы. Тот же запрос, что и раньше, теперь сканирует горстку файлов вместо сотен.
Что выбрать: партицирование или кластеризацию?
Как всегда, здесь есть компромиссы, и нет универсального ответа.
Партицирование лучше всего работает, когда:
- У вас колонки с низкой кардинальностью (регион, месяц).
- Запросы последовательно фильтруют по этим измерениям.
- Хорошо спроектированное бакетирование (bucketing) тоже помогает — сохраняйте бакеты крупными, чтобы избежать сильного перекоса.
- Баланс между значениями бакетов важен для предсказуемой производительности (хотя заранее это сложно оценить, потому что бакет проходит через хэш‑функцию).
Ещё одно преимущество партицирования — простота. Оно сохраняет слой метаданных лёгким и требует меньше обслуживания. Если вы используете open‑source Iceberg без платформы вендора, партицирование — фактически ваш единственный вариант.
Кластеризация подходит, когда:
- У вас высококардинальные колонки (миллионы клиентов, миллионы ID товаров).
- Запросы часто фильтруют по разным колонкам.
- Нужны диапазонные сканирования или соединения между таблицами.
- Вы хотите получить тонкое отсечение без взрыва количества партиций и проблемы мелких файлов.
Итог
- Низкая кардинальность + предсказуемые предикаты → партицирование. Просто и работает везде.
- Миллионы уникальных значений + разнообразные шаблоны запросов + поддержка вендора → кластеризация.
Оба варианта остаются на столе. Нужно понимать компромиссы и знать, что доступно в вашем стеке, чтобы построить максимально производительную систему.
«Кластеризация — это как умный гардероб: если разложить футболки по цветам, а джинсы по фасонам, вы найдёте нужный комплект за секунды. Если скинуть всё в одну кучу — придётся перерыть весь шкаф.»
На этом пока всё
Вы завершили третью часть курса Apache Iceberg! Вы изучили партицирование, эволюцию партиций и кластеризацию — ключевые техники оптимизации данных для эффективных запросов. Отличный прогресс!
Что будет дальше? В четвёртой части курса мы перейдём к Time Travel и откату изменений:
- Time Travel — работа со снапшотами, запросы к прошлым версиям таблицы.
- Откат изменений — как безопасно отменить ошибочные операции.
- Практика — упражнение по Time Travel для закрепления навыков.
Четвёртая часть уже доступна — переходите к следующему уроку!
Чтобы не пропустить выход новых уроков:
- Подпишитесь на канал SubQuery в Telegram — там мы анонсируем все обновления курса.
- А чтобы ТОЧНО не пропустить, присоединяйтесь к каналу в MAX 🤭
Спасибо, что учитесь с нами! 🚀