Искры, оптимизация генерации показателей из DF

Это вопрос оптимизации, это моя текущая (рабочая) ситуация:

  • Spark работает в автономном режиме с использованием spark-jobserver;
  • У меня есть файл паркета с ~ 3M строк, кэшированных в памяти в виде таблицы;
  • Таблица представляет собой совокупность всех данных с сайта электронной торговли, каждая строка представляет пользователя, но пользователь может иметь больше строк;

Клиентский запрос должен выполнять SQL-запрос и показывать результаты на веб-странице в некоторых таблицах, каждый из которых представляет метрику с помощью счетчика, например:

Возраст = > 18-20: 15 пользователей, 21-35: 42 пользователей,...

Страна = > США: 22 пользователя, GB: 0 пользователей,...

И так далее. Подсчитывая все таблицы (вместе с некоторыми сеансами пользователей, которые генерируются на основе активности, периода и года), мы имеем в настоящее время ~ 200 показателей.

Последняя выпущенная система в производстве использует (учитывая df как DataFrame в результате SQL-запроса):

df.rdd.aggregate(metricsMap) (

      (acc: MetricsMap, r:Row) => {
        acc.analyzeRow(r)
        acc
      },

      (acc1: MetricsMap, acc2: MetricsMap) => {
        acc1.merge(acc2)
        acc1
      }
    ) 

Где MetricsMap - это объект, используемый для извлечения и агрегирования данных из строки.

Эта операция очень интенсивна для процессора, а на сервере требуется ~ 20 секунд, чтобы извлекать данные из запроса без параметров (поэтому из всех данных в файле паркета).

Я решил использовать агрегацию, потому что для их статистического анализа им нужны несколько перспектив: некоторые показатели должны подсчитываться с помощью ключа пользователя, другого по имени пользователя (для сайта...), а другое - по ключу продукта. Используя этот метод, мне пришлось циклически перебирать результат только один раз, но я не знаю, подходит ли ему лучший подход...

Это лучший подход или существует какой-то другой (более быстрый) метод для получения того же результата?

Что касается вопроса о вычислении метрик заранее, запросы, которые они могут делать в наборе данных, не связаны, поэтому я не знаю, возможно ли это или нет... Не могли бы вы привести пример?

Отвечая на некоторые вопросы

Ответ 1

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

Может быть более эффективным, хотя и не взаимодействовать с искровым сердечником.

Например, если ваша схема DF выглядит следующим образом:

root
 -- age
 -- country

Затем вы можете попытаться выполнить следующий псевдо-базовый запрос:

Select 
CASE WHEN (age BETWEEN 18 AND 22) THEN '18-22' 
     WHEN (age BETWEEN 22 AND 30) THEN '22-30' 
     ELSE 'Other' as age_group,
country
from metrics_df

Вы также можете рассмотреть возможность использования UDF для возрастной группы. Как упомянуто в @assaf-mendelson, здесь больше информации.