Представьте, что вам нужно проанализировать данные об элементах, которые клиенты видят в списке веб-приложения. Это могут быть результаты поиска, товары для продажи, наиболее релевантные сообщения в ленте новостей и список новых звонков в службу поддержки клиентов  —  для аналитиков они все одинаковы.

Такие данные могут быть использованы аналитиками для оценки CTR (показателя кликабельности) при разработке тех или иных рекомендательных алгоритмов, позволяющих определить наблюдаемость различных позиций в списке (например, 1-я по сравнению с 10-й).

В современном стеке данных такой тип данных легко собрать.

1. Фронтенд или мобильное приложение покажет пользователю список и одновременно отправит в аналитику событие, содержащее следующий JSON:

2. “Отправить в аналитику” означает отправить на конечную точку API. Это позволит доставить JSON в конвейер доставки данных (на основе Kafka и более современных инструментов, таких как Airbyte и Fivetran).

3. Конвейер доставки данных будет добавлять каждый входящий JSON в целевую таблицу в современной аналитической базе данных Snowflake. Назовем эту таблицу RAW_Events.

4. Вот и все!

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

Как аналитик может работать с такими данными? Современные аналитические базы данных, такие как Snowflake, работают напрямую с JSON и требуют от аналитиков знания только SQL.

Вернемся к примеру с событием:

Это означает, что пользователь с идентификатором 3299223 открыл приложение (время открытия  —  ‘2022–04–21 12:31:55 UTC’) и просмотрел список из шести элементов, где 1037287139  —  первый, 1727228887  —  второй и 1665899805—  последний. Элементы хранятся в виде массива. Позиция в массиве соответствует позиции на экране.

Такой подход к хранению данных нарушает первую нормальную форму. В прошлом аналитики не могли работать с такими данными (JSON, массивы в одном поле), используя только SQL. Но теперь можно легко “разворачивать” такой массив.

Представьте, что аналитики хотят посмотреть, сколько пользователей сегодня видели элемент 1037287139 на первой позиции. Как это сделать?

В мире современного стека данных запрос, подобный приведенному выше, будет работать, даже если таблица Events содержит сотни миллиардов событий, до 10 000 новых событий в секунду.

Но вернемся к изначальному вопросу: почему стоит заботиться о моделировании, если все так прекрасно?

Запрос 2 отвечает на этот вопрос. Его синтаксис сложен. Чтобы получить необходимые данные, требуется прочитать буквально все JSON из таблицы Raw_Events, распаковать их, развернуть и выполнить вычисление, даже если ответ равен 42, а таблица RAW_Events на самом деле содержит сотни миллиардов JSON. Такой запрос может быть долгим и затратным, особенно в современном стеке данных, инструменты которого по сути предусматривают решение проблем производительности посредством вливания большего количества денег.

Представьте, что аналитик намерен продолжить исследование. Допустим, он хочет оценить среднее положение элементов в списке, в отношении которых в данный момент были активированы дополнительные услуги.

Чтобы решить эту проблему, запрос 1 должен быть объединен с другими таблицами (если они есть в системе). Такой JOIN не только сложен в написании для аналитиков, но и ему потребуется обработка всех JSON из таблицы RAW_Events снова и снова, чтобы получить результат запроса.

Приведенный пример дает представление о ситуациях, когда может понадобиться моделирование данных даже в мире современного стека данных. Вот эти ситуации:

  • данные достаточно большие;
  • запросы к данным достаточно часты;
  • количество аналитиков ограничено;
  • необходимо, чтобы все аналитики выполняли одну и ту же операцию одинаково эффективно, не выдавая противоречивых результатов.

Рассмотрим следующий этап моделирования данных:

Таблица Events будет содержать все данные из RAW_Events, уже распакованные и отсортированные. Ее можно инкрементально заполнять новыми входящими событиями ежедневно и ежечасно, что делает такие операции чрезвычайно быстрыми и дешевыми.

Аналитикам, желающим узнать, сколько пользователей сегодня видели элемент 1037287139 на первом месте, нужно сделать следующий запрос:

И вот разница между запросом 2 и запросом 4, отвечающими на один и тот же вопрос:

Описанный выше эксперимент был проведен с таблицей RAW_Events, содержащей примерно 20 млн файлов JSON.

Оба запроса выполнялись на одном кластере Snowflake размером X-Small. Даже для такой маленькой выборочной задачи разница огромна.

Реальные аналитические задачи требуют анализа миллиардов JSON, что заставляет каждый запрос обрабатывать как минимум в 1000 раз больше данных и тратить соответственно больше времени и/или денег.

Как видно из примера выше, однократный запуск запроса 2 (медленный, 47 с) вполне приемлем. Однако если немногим аналитикам нужно выполнять такие запросы несколько раз в день, они, скорее всего, предпочтут запрос 4 как более простой и быстрый.

Подведем итоги. 10-20 лет назад вряд ли можно было представить, что аналитик может использовать запросы типа 1 или 2 для анализа сотен миллионов строк без предварительной подготовки данных инженером по данным или специалистом по моделированию данных. Современный стек данных предоставляет аналитику возможность самостоятельно исследовать данные. Подготовка данных и моделирование данных могут повысить производительность (запросы 3 и 4), но не принципиально.

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Nikolay Golov: Data modeling in the world of the Modern Data Stack 2.0

Предыдущая статьяКак обеспечить работу современного кода JavaScript во всех браузерах
Следующая статья#04TheNotSoToughML | “Давай, минимизируй ошибки” — Но достаточно ли этого?