Ни один современный Data Lakehouse не обходится без грамотно устроенного слоя рассорки (staging). Самый чувствительный этап, это «подложить подклад» на уже существующую сущность, не повредив сырые данные и не потеряв целостность схемы. В статье разберёмся, что такое подклад, зачем он нужен, какие бывают стратегии и как применить их на практике.
Содержание
- Что такое «подклад» и «рассорка»
- Что значит «с сущностью»
- Стратегии подкладывания подклада
- Пошаговый алгоритм для Apache Spark / dbt
- Распространённые ошибки и как их избежать
Что такое «подклад» и «рассорка»
Рассорка (staging) — это временная или полу-временная зона, куда попадают сырые данные из источников без трансформаций.
Подклад (overlay) — это тонкий «слой-пластырь» поверх существующей таблицы, содержащий лишь дифф или корректировки, которые нужно применить атомарно.
- Подклад не перезаписывает всю таблицу, а «накладывается» поверх, позволяя оставить оригинальные партиции нетронутыми.
- Классический пример: исправление ошибок в нескольких строках факта продаж за прошлый квартал, когда полный пересчёт стоит слишком дорого.
Что значит «с сущностью»
Под «сущностью» в контексте хранилища подразумевается:
- SCD Type 2-таблица (исторически изменяемая)
- Facts-таблица с датой действия
- Master-data (справочник)
Во всех случаях у нас уже есть:
- business key (уникальный идентификатор сущности),
- поле версии (valid_from / valid_to),
- партиционирование (обычно по дате).
Стратегии подкладывания подклада
Append-only patch
Самая простая стратегия: просто дописываем новые строки с тем же business key, но новым valid_from.
Плюсы: нет риска затереть старое.
Минусы: придётся потом чистить дубли.
Upsert (Merge) patch
Используем MERGE INTO (Delta Lake) или dbt snapshot.
Логика такая:
MERGE INTO staging.sales t USING patch.sales_delta s ON t.business_key = s.business_key AND t.valid_to = '9999-12-31' WHEN MATCHED THEN UPDATE SET valid_to = s.valid_from WHEN NOT MATCHED THEN INSERT (...)
Partition swap
Если ошибка затронула только одну партицию (например, 2023-11-15), можно:
- сформировать новую партицию с правильными данными,
- атомарно свапнуть партицию в метасторе.
Это самый быстрый способ при больших объёмах.
Пошаговый алгоритм для Apache Spark / dbt
Шаг 0. Подготовьте окружение
export DELTA_TABLE_PATH="s3://lakehouse/staging/sales" export PATCH_PATH="s3://tmp/sales_patch_$(date +%F)"
Шаг 1. Создайте дельта-патч
spark.sql("""
CREATE OR REPLACE TABLE delta.`$PATCH_PATH`
AS SELECT * FROM source_view
WHERE business_key IN (/список ключей с ошибками/)
""")
Шаг 2. Проверьте целостность
spark.sql("""
SELECT business_key, COUNT(*) cnt
FROM delta.`$PATCH_PATH`
GROUP BY business_key
HAVING cnt > 1
""").show
Шаг 3. Примените merge-патч
spark.sql("""
MERGE INTO delta.`$DELTA_TABLE_PATH` t
USING delta.`$PATCH_PATH` s
ON t.business_key = s.business_key
AND t.valid_to = '9999-12-31'
WHEN MATCHED THEN UPDATE SET
valid_to = current_timestamp
WHEN NOT MATCHED THEN INSERT *
""")
Шаг 4. Проверьте и зафиксируйте метаданные
spark.sql("OPTIMIZE delta.`$DELTA_TABLE_PATH` ZORDER BY (business_key)")
Распространённые ошибки и как их избежать
- Забыли отключить автоматическое кэширование → используйте
spark.databricks.delta.optimizeWrite.enabled=falseна время патча. - Нарушена последовательность версий → всегда проверяйте, что valid_from новой записи > max(valid_to) предыдущей.
- Конфликт партиций → применяйте
REPLACE WHEREвместо перезаписи всей партиции, если данные точечные. - Потеря метаданных → после
ALTER TABLE DROP PARTITIONсразу делайтеMSCK REPAIR TABLE.
- Определите тип сущности и наличие историчности.
- Выберите стратегию: append, merge или partition swap.
- Сформируйте минимальный дифф-патч, проверьте дубликаты.
- Примените merge/upsert с правильной логикой valid_from/valid_to.
- Оптимизируйте таблицу и обновите статистику.
- Зафиксируйте версию в lakeFS / Delta log / Git LFS для возможности отката.
Следуя этим шагам, вы сможете «подложить подклад» на рассорку с сущностью быстро, безопасно и воспроизводимо. Удачных вам патчей и пусть ваши данные всегда будут актуальны!