Data Analysis / Big Data
2.73K subscribers
662 photos
4 videos
2 files
3.05K links
Лучшие посты по анализу данных и работе с Big Data на русском и английском языке

Разместить рекламу: @tproger_sales_bot

Правила общения: https://tprg.ru/rules

Другие каналы: @tproger_channels
Download Telegram
Как DuckDB ускоряет чтение Parquet из S3

В тесте TPC-H Q6 запрос к Parquet-файлу размером около 22 ГБ выполнился за 2,844 секунды на DuckDB v2.0.0-dev вместо 8,230 секунды на стабильной v1.5.5. Данные читались напрямую из S3 без файлового кеша.

Ускорение даёт отдельный пул потоков ASYNC: он заранее запрашивает диапазоны байтов, пока обычные рабочие потоки декодируют текущую группу строк. Если данные ещё не пришли, задача чтения освобождает рабочий поток для других операций.

Глубину предзагрузки задаёт read_ahead_depth: значение N ограничивает очередь N заданиями, 0 отключает предзагрузку, а режим по умолчанию подстраивает её под доступную память. Для своего озера данных стоит проверить предварительную сборку на типичных файлах и сравнить время запроса, загрузку сети и расход памяти. Схема очереди и условия бенчмарка помогут воспроизвести эксперимент.
Как Meta удвоила эффективность обучения рекомендательной модели GEM

За 12 месяцев Meta в четыре раза увеличила вычисления при обучении GEM и подняла эффективность до 20–25% MFU: доли пиковой производительности GPU, занятой моделью.

История действий пользователя достигает десятков тысяч элементов. Выравнивание последовательностей тратило до 50% вычислений. JFA обрабатывает переменную длину без дополнения, а BlockAttention снижает стоимость внимания с O(L²) до O(L).

Схема оптимизации GEM предлагает порядок профилирования: сначала ядра, точность и память, затем обмен данными, балансировка нагрузки и топология сети.
Как 20–100 запросов в секунду перегрузили Elasticsearch в Zalando

Внутреннее приложение отправляло фасетные запросы: Elasticsearch строил агрегации по SKU, уникальному идентификатору товара. Из-за множества уникальных значений даже небольшой поток параллельных запросов создавал тяжёлую нагрузку. Синтаксис был корректным, а 20–100 запросов в секунду терялись на фоне тысяч обычных.

После разделения рынков команда сузила поиск до одного кластера, а анализ трассировок обнаружил внутреннее приложение с потоком в 50 раз выше обычного.

Практический вывод для дата-инженеров: общего RPS недостаточно. Нагрузку нужно сопоставлять с клиентом и типом запроса, ограничивать размеры агрегаций по полям высокой кардинальности и изолировать тяжёлые служебные задачи.
Как подготовить медицинские изображения и честно проверить модель

Два рентгеновских снимка 512 × 512 могут показывать разные физические области: масштаб пикселя хранится в DICOM. Перед обучением нужно удалить идентификаторы, учесть положение пациента и пересчитать масштаб после изменения размера. Разбор пути снимка до предсказания содержит ноутбук с pydicom, NumPy и OpenCV.

Нормализация приводит пиксели к общей шкале, гармонизация уменьшает различия между сканерами. Данные делят по пациентам: иначе снимки одного человека попадут и в обучение, и в тест.

Для классификации нужна метка снимка, для детекции — область, для сегментации — маска. Модель проверяют на данных другой больницы и оценивают не только перекрытие, но и форму находок.
Почему 1000 файлов на процесс в PostgreSQL не жёсткий лимит

max_files_per_process по умолчанию равен 1000. Это размер кэша открытых дескрипторов, а не порог ошибки. Когда пул заполнен, бэкенд закрывает давно не использованный файл и открывает нужный. Запрос работает, но тратит время на системные вызовы.

В PostgreSQL 18.6 таблица из 3000 разделов создала 6000 файлов. При значении 8192 повторное сканирование обошлось без open() и ускорилось примерно на 8%: со 180 до 165 мс. Данные уже были в shared_buffers.

Одной настройки мало: systemd даёт процессу мягкий лимит 1024. Сначала посчитайте файлы в каталоге базы и увеличьте LimitNOFILE, затем задайте пул с запасом и перезапустите PostgreSQL. В PostgreSQL 18 ориентируйтесь на весь сервер: воркеры асинхронного ввода-вывода обслуживают все бэкенды.
Как в Zalando сократили состояние Flink на 75%

В пайплайне обогащения товарных данных цепочка SQL JOIN раздула состояние Flink до 235–245 ГБ. Каждый независимый оператор хранил собственную копию входных и промежуточных записей. Часовые снимки загружали процессор на 100% почти на 12 минут, увеличивали задержку и провоцировали перезапуски.

Команда объединила входящие потоки в DataStream[BaseEvent], сгруппировала события по SKU и заменила цепочку JOIN одной KeyedProcessFunction. Данные каждого товара теперь лежат в одном ValueState: событие обновляет нужные поля, а записи со старой временной меткой отбрасываются до записи состояния.

Переход на собственный MultiStreamJoinProcessor уменьшил состояние до 56 ГБ, а восстановление после перезапуска сократил с 12–20 до 4–5 минут. Полезный повод проверить, не дублируют ли последовательные stateful JOIN промежуточные данные в ваших Flink-задачах.
Как Apache Celeborn сохраняет shuffle-данные Spark при потере исполнителей

Spot-инстансы могут отключить за две минуты. Если Spark хранит shuffle-данные на локальном диске исполнителя, потеря узла запускает повторное вычисление стадий.

Apache Celeborn выносит shuffle в отдельный кластер: исполнители отправляют блоки общим worker-узлам, поэтому их можно заменять без потери промежуточных данных. Каждый раздел shuffle реплицируется ещё на два worker-узла.

Схема развёртывания для EMR on EC2 и EMR on EKS включает настройки Spark и мониторинг через Prometheus и Grafana.
❤2
Как ограничить память GROUP BY в ClickHouse при высокой кардинальности

22,82 GiB против 9,57 GiB пиковой памяти: такой результат даёт max_bytes_before_external_group_by в эксперименте с высококардинальной группировкой. Когда объём промежуточных данных достигает заданного порога, ClickHouse продолжает агрегацию с использованием диска. Цена экономии памяти: время запроса выросло с 9,433 до 13,930 секунды.

Для динамических атрибутов авторы предлагают Map. Поля, по которым часто фильтруют или считают агрегаты, стоит материализовать в отдельные типизированные колонки: так запросам не приходится каждый раз читать карту и преобразовывать строки в числа.

Разбор высокой кардинальности в ClickHouse поможет выбрать компромисс между памятью и скоростью, а также спроектировать хранение атрибутов под реальные запросы.
PySpark завис на 99%: как найти и устранить перекос данных

199 из 200 задач завершаются за секунды, а последняя работает 30 минут. Строки с одинаковым ключом попадают в одну партицию, и горячий ключ задерживает весь этап.

В Spark UI сравните максимальные Duration, Shuffle Read Size и Spill с медианой. Разница в десятки раз укажет на перекос. Затем посчитайте строки по ключам.

В разборе для Spark 3.5 советуют включить AQE: он дробит перекошенные партиции при соединении. Для малой таблицы используйте broadcast join, а для горячих ключей — salting, добавляющий суффиксы и распределяющий строки по партициям.
Как подготовить Parquet для быстрых запросов Power BI Direct Lake

На столбце из 142 млн строк запись encoding_stats в футере Parquet сократила первое обращение с 10 857,5 до 689,3 мс. VertiPaq выбрал быстрый путь после подтверждения словарного кодирования в метаданных.

Direct Lake загружает только затронутые запросом столбцы. Без словарного кодирования значения приходится декодировать и хешировать заново.

Эксперименты с DuckDB и delta-rs рекомендуют 2–6 млн строк на группу, словарное кодирование столбцов и сортировку по полям фильтров. Результат измеряйте на холодном и прогретом кеше.
Как выявить перекос долей выборки в A/B-тесте с NumPy и SciPy

В тесте на миллионе пользователей группы 502 470 и 497 530 кажутся равными, но для плана 50/50 это почти пять стандартных отклонений.

Такой перекос называют Sample Ratio Mismatch, или SRM. Его ищут χ²-тестом: сравнивают фактические размеры групп с плановыми долями. Достаточно счётчиков, NumPy и scipy.stats; метрика теста не участвует.

Если SRM сработал, сначала проверьте логирование и фильтрацию участников, затем оценивайте эффект. Код проверки и симуляция потери пользователей показывают, почему малый перекос опасен на большой выборке.
Как согласовывать JSON-события в DuckDB без Python

В CDC-потоке событие часто меняет одно-два поля. В DuckDB v2.0 json_merge_patch_diff вычисляет патч между старым и новым состоянием, а json_merge_patch восстанавливает документ.

json_deep_merge объединяет JSON из разных источников, сохраняя исходное значение при JSON null. Для дедупликации json_normalize сортирует ключи перед хешированием.

Примеры SQL и тест на 500 000 синтетических CDC-событий
Как Zalando проверяет качество поиска до запуска нового рынка

В 2025 году Zalando выходила в Люксембург, Португалию и Грецию. Данных о запросах и кликах ещё не было, поэтому качество поиска заранее оценивали с помощью LLM-судьи.

Пайплайн проверки релевантности берёт запросы действующих рынков: NER-модель выделяет атрибуты, а похожие запросы переводят на язык нового рынка.

Airflow запускает получение выдачи в Kubernetes, затем GPT-4o оценивает товары по шкале от 0 до 4 с учётом описания и изображения. Низкие оценки помогают найти ошибки в товарных данных, атрибутах и ранжировании.

Кеш хранит товары и оценки пар «запрос — товар», поэтому после исправлений прогон можно повторить без лишних обращений к API.
Как инкрементальный ETL в Apache Hudi сокращает повторную обработку данных

Если таблица на 10 ТБ получает 50 ГБ изменений в час, полный пересчёт читает все 10 ТБ. Инкрементальный пайплайн берёт только дельту: объём чтения сокращается в 200 раз.

Apache Hudi читает изменения после сохранённой контрольной точки. Запрос возвращает последнее состояние изменённых записей, а CDC-журнал — каждую операцию до и после изменения.

Для цепочки таблиц нужны первичные ключи и порядок коммитов. Частые записи создают мелкие файлы, поэтому Hudi асинхронно уплотняет и очищает данные, не останавливая запись.
Почему RLS в PostgreSQL может замедлить запрос с индексом

В тесте PostgreSQL 17.10 поиск по lower(customer_email) занимал 0,21 мс без RLS и 34–45 мс с политикой доступа. Это результат для крупнейшего клиента: около 267 тысяч строк в таблице почти на 2 млн записей.

Составной индекс использовался только для tenant_id, а условие по email стало фильтром. Причина в правилах RLS: функция lower() не помечена как leakproof, поэтому её нельзя свободно применять к строкам до проверки доступа.

В этом сценарии помогла сохранённая вычисляемая колонка с email в нижнем регистре и индексом по паре «клиент, email»: время вернулось к 0,25 мс. Замеры сделаны с прогретым кэшем. Проверяйте план под ролью приложения: владелец таблицы обычно обходит RLS.

Замеры, планы и варианты политик
Polars: как отличить медленный JOIN от ожидания данных

В примере профилирования Polars запрос выполнялся около 5 секунд, а CPU-время JOIN составило примерно 103 мс. Основным ограничением было чтение из S3.

Профилировщик показывает логический и физический планы, потоки строк и прогресс узлов. Для локального запроса нужно установить polars_cloud и включить pl.Config.enable_monitoring(). Возможность описана для streaming- и distributed-движков.

Запрос исполняется на вашей инфраструктуре; планы и телеметрия передаются в платформу Polars Cloud. Там можно смотреть текущие и завершённые запросы, находить дорогие операции и проверять, насколько рано применяются фильтры.

Такой профиль помогает выбрать, что оптимизировать первым: загрузку данных, JOIN или агрегацию.

Подключение и разбор профиля Polars
Когда DuckDB хватает для ETL вместо Spark

В примере AWS задание на DuckDB выполнилось примерно за 56 секунд, а эквивалентное на Spark — за 117. Оба запускались в Glue 6.0 с конфигурацией 2 DPU и вернули 1176 строк.

DuckDB работает внутри одного воркера: читает Parquet из S3, выполняет SQL-преобразования и записывает результат в S3 Tables через Iceberg REST catalog. Выходную таблицу можно запрашивать из Athena.

Для небольших регулярных заданий время запуска и накладные расходы движка могут заметно влиять на итог. Здесь DuckDB уложился в минимальную минуту тарификации, а Spark потребовал две.

Это замер одного сценария. Для своего ETL сравните объём входных данных, сложность JOIN, доступную память и полное время задания.

Код пайплайна и условия сравнения
Как LinkedIn ищет метрики среди миллиардов записей

Индекс метаданных метрик LinkedIn обслуживает более 150 тысяч запросов в минуту со средней задержкой 68 мс. Он работает с более чем 13 млрд метрик, около 30% которых меняются за день.

Раньше запросы распределялись между собственным поисковым индексом, Elasticsearch и KV-хранилищем. Теперь общий шлюз переводит их в SQL для ClickHouse, поэтому потребителям не пришлось менять интеграции.

Данные лежат в ReplacingMergeTree. Поток изменений поддерживает актуальность индекса, а свежая ежедневная таблица догоняет изменения перед переключением. Отдельные колонки заменяют поиск регулярками по составным именам; projections ускоряют тяжёлые агрегации.

По оценке команды, расход памяти сократился примерно в пять раз. 68 мс — среднее по разным типам запросов, включая аналитические.

Архитектура индекса и результаты миграции
Как ускорить запросы Spark без переписывания SQL

Тяжёлый запрос приходит из BI-дашборда, а изменить его SQL сложно. В AWS Spark runtime можно ускорить такой запрос через материализованное представление Iceberg.

Оптимизатор сравнивает логический план с доступными представлениями. Если одно из них покрывает запрос целиком или частично, план читает заранее вычисленный результат. Если совпадения нет, выполняется исходный запрос.

Статья разбирает разные варианты покрытия: JOIN, агрегации и точное совпадение более сложных вычислений. Представление хранится как Iceberg-таблица; обновление можно настроить по расписанию.

Автоматическая подстановка доступна в Amazon EMR начиная с 7.12.0 и AWS Glue с 5.1. При выборе представления учитывайте частоту запросов, стоимость обновления и допустимую задержку данных.

Примеры планов и настройка подстановки
Как передавать данные датчиков из MQTT в Kafka

Датчик публикует JSON в локальный MQTT-брокер. Чтобы отправить эти события в Kafka, нужно выбрать маршрут, схему сообщений и способ сохранить сведения об источнике.

Автор проверил несколько вариантов, включая MQTT Source Connector, Pro Mosquitto и HiveMQ. Коннектор забирает сообщения из доступного ему брокера и использует полное имя MQTT-топика как ключ Kafka-сообщения.

У MQTT нет встроенной схемы данных. Для дальнейшей обработки автор предлагает задать и проверять её, например, во Flink. В отдельных интеграциях имя исходного топика не переносится: идентификатор площадки придётся добавить в payload.

Есть и нюанс эксплуатации: изменение числа задач или списка топиков MQTT Source Connector может привести к потере данных из-за перераспределения подписок.

Схемы подключения, конфигурации и ограничения
Как обслуживать большой dbt-проект и находить медленные модели

В IFCO миллиарды событий отслеживания превращаются в показатели движения тары. Некоторые данные опаздывают на недели и месяцы, поэтому пайплайн должен корректировать уже рассчитанную историю.

Команда настраивала инкрементальные dbt-модели по реальному плану выполнения: проверяла объём чтения и записи, стратегию MERGE, liquid clustering и dynamic file pruning. Время основного задания сократилось более чем на 60%; ночной полный пересчёт убрали.

Для эксплуатации каждую модель вынесли в отдельную задачу Databricks Jobs через открытый databricks-dbt-factory. Так видно, какой шаг задерживает запуск, а повторно выполнять можно конкретные модели.

Скомпилированный SQL показывает намерение модели. План выполненного запроса помогает проверить, сколько данных она действительно обработала.

Разбор моделей, диагностики и запуска dbt