У меня есть фрейм данных X
, содержащий некоторые события (моменты времени, с временными метками) и другой фрейм данных Y
, содержащий диапазоны времени (также заданные временными метками.)
Путем экспериментов и некоторого чтения Я обнаружил, что базовый подход к соединению по меткам времени напрямую:
return X.join(Y, (X.ts >= Y.start_ts) & (X.ts < Y.end_ts), "inner")
Оказывается намного медленнее, чем первое объединение по датам, а затем фильтрация по определенным временным меткам:
X = X.withColumn("event_date", ts.cast('date'))
Y = Y.withColumn("date", explode(array([start_ts.cast('date')), end_ts.cast('date'))])))
return X \
.join(Y, (X.event_date == Y.date), "inner") \
.filter((X.ts >= Y.start_ts) & (X.ts < Y.end_ts))
Насколько я понимаю, базовый подход к выполнению объединения в первом примере:
- Порядок X на
ts
и Y на start_ts
, а затем end_ts
(возможно в nlogn в Spark?)
- Соединение может быть выполнено линейно, с максимум 2
long
сравнениями на кандидата
Во втором примере:
- Линейно выполнить приведение на сегодняшний день, удваивая размер данных со взрывом
- Упорядочить оба кадра данных по датам (nlogn, меньшая константа не более 2x)
- Выполнить объединение линейно, самое большее 1
long
сравнение на кандидата
- Линейная фильтрация результатов с максимум 2
long
сравнениями на строку
Достаточно ли меньшей константы из пункта 2 во втором примере, чтобы так сильно ее ускорить? Или есть какая-то оптимизация Spark, которая заставляет Perf вести себя таким образом?