Как объединить потоковые данные с большими данными истории, установленными в Dataflow/Beam

Я изучаю журналы обработки из сеансов веб-пользователей через Google Dataflow/Apache Beam и должен объединять журналы пользователей по мере их поступления (потоковой передачи) с историей сеанса пользователя за последний месяц.

Я рассмотрел следующие подходы:

  • Используйте 30-дневное фиксированное окно: скорее всего, большой размер окна будет помещен в память, и мне не нужно обновлять историю пользователей, просто обратитесь к нему.
  • Используйте CoGroupByKey для объединения двух наборов данных, но два набора данных должны иметь одинаковый размер окна (https://cloud.google.com/dataflow/model/group-by-key#join), что в моем случае неверно (24 ч против 30 дней).
  • Использовать боковой вход для получения истории сеансов пользователя для заданного element в processElement(ProcessContext processContext)

Я понимаю, что данные, загруженные через .withSideInputs(pCollectionView), должны вписываться в память. Я знаю, что могу поместить всю историю сеансов одного пользователя в память, но не все истории сеансов.

Мой вопрос в том, есть ли способ загрузки/потоковой передачи данных с бокового ввода, относящегося только к текущему сеансу пользователя?

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

Некоторый псевдокод для иллюстрации:

public static class MetricFn extends DoFn<LogLine, String> {

    final PCollectionView<Map<String, Iterable<LogLine>>> pHistoryView;

    public MetricFn(PCollectionView<Map<String, Iterable<LogLine>>> historyView) {
        this.pHistoryView = historyView;
    }

    @Override
    public void processElement(ProcessContext processContext) throws Exception {
        Map<String, Iterable<LogLine>> historyLogData = processContext.sideInput(pHistoryView);

        final LogLine currentLogLine = processContext.element();
        final Iterable<LogLine> userHistory = historyLogData.get(currentLogLine.getUserId());
        final String outputMetric = calculateMetricWithUserHistory(currentLogLine, userHistory);
        processContext.output(outputMetric);
    }
}

Ответ 1

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

Одним из возможных способов решения проблемы является использование побочных входов для распределения указателей на фактическую историю сеансов. Код, генерирующий 24-х сессионные истории, может загрузить их в GCS/BigQuery/etc, а затем отправить местоположения в виде бокового ввода в код соединения.