в данной ситуации.
Дано: есть S3, куда в виде паркетных файлов выкладываются данные, E-com сайта или группы сайтов.
Дальнейший процессинг данных осуществляется с помощью Spark.
Нужно сохранять лог событий в один или несколько паркетных файлов.
Вопрос, как правильно организовать структуру хранения.
Проблема в том, что есть разные типы событий. У разных типов событий может быть разный набор дополнительных атрибутов.
Причем продаваться могут очень разные типы айтемов, с совершенно разными атрибутами.
Для каких-то событий, например, хватит
- userId
- itemId
- eventType
- timestamp
Для каких-то нужно добавить дополнительные атрибуты. Например (но не суть важно)
- Price
- Discount
- Quantity
- ...
Теоретически, мы ожидаем, что время от времени у нас могут добавляться новые типы событий, которые могут приносить с собой новые атрибуты.
Предполагаемые варианты:
1. Хранить все события в одной табличной структуре с полным списком полей. Недостатки:
------>дополнительные поля, которые актуальны только для некоторых типов событий, будут висеть с null'ами и при занимать место в памяти при чтении
------->добавление нового типа события с доп. атрибутами приводит к добавлению столбцов-атрибутов сразу для всех событий в источнике (и видимо для всей истории). Кажется, что это больновато или нужно думать, как это делать
2. Группировка типов событий с более-менее однородным атрибутным составом и раскладывание в разные таблицы. Проблема: нулевая гибкость и масштабируемость на новые источники и типы событий.
3. Есть основная таблица с событиями, где хранится минимум атрибутов, которые общие для всех. У каждого события есть ключ. Дополнительные атрибуты хранятся в отдельных "выносных" таблицах с join'ом по ключу. Недостаток: обилие тех самых join'ов при обработке данных
4. Есть основная таблица с событиями, где хранится минимум атрибутов, общих для всех. Доп. атрибуты хранятся во вложенной json-подобной структуре. И там уже кому сколько чего надо
5. Каждый тип события складывается в свой отдельный паркетный файл (файлы) со своим атрибутным составом. ИД типа события - часть названия файла. Если нужно выбрать определенный набор типов событий, формируется условие по маске файлов. (Меня лично от этого варианта сильно коробит, но его мне активно предлагают. Тут варианта 2, либо я пойму, что я неправильно смотрю на мир, и это на самом деле окей :), либо накоплю побольше аргументов, почему это нехорошо :) )
6. ... может быть, есть другие классные идеи? Наверняка, проблема известная и 10 раз решенная, просто нужно знать стандартные рецепты, а мне эрудиции не хватает...
В общем, прошу прощения за лонгрид и заранее спасибо за идеи и мнения
Гипотетически, можно ещё во что-то вроде hbase положить, тогда не придется перебивать из-за того, что схема разная и скачет. Но это от паттерна использования данных зависит.
(5) с разделением по s3 prefix будет ок, скорее всего s3://bucket-name/data/structured/source_type=... /event_type=... /day=2021-02-22/..
Я бы максимально пытался выделить общие колонки таблицы, далее сделать колонку data, которая map(string, string). Эту таблицу положил бы в raw(bronze) слой, а на ружу, для пользования сделал бы отдельную таблицу, где схема подведена к читаему виду
А какие варианты по схеме таблицы для пользования?
Ну тогда это превращается в вариант 1, кажется?
Таблица на запись похоже на ваш 4й вариант, таблица на чтение это больше похоже на промежуточные витрины
А насколько ок запросу на несколько событий? Фильтрация типов событий с помощью файловой маски как-то не очень красиво выглядит. Или я драматизирую?
Вот я пытаюсь представить себе на что похожа таблица на чтение. И получается, что она похожа на вариант 1. Чем она отличается?
Вообще можно было б не заморачиваться, отдать на чтение таблицу в которой есть колонка data (с мапой), но тогда спарку будет тяжелее
Тут расчёт на то, что для 70%+ запросов атрибуты в мапе не нужны. Но все равно, не уверен, насколько это хорошее решение
не совсем. для диапазона дат у вас будет чтение с WHERE event_type IN (..) но если типов событий > 30, то будет очень много партиций, а это тоже неприятно но вообще, для разных типов запросов совершенно нормально материализовывать одну и ту же дату по-разному сколько даты в 1 день в сжатом виде приходит сейчас?
Может, я не совсем понял, но если разные события в разных источниках с разным s3 prefix, какой where in? Или мы всегда читаем весь каталог?
весь каталог не читаем никогда, если прокидываем partition filter по event_type
Обсуждают сегодня