Могут ли оконные функции перемещаться и условно выбирать определенные строки в упорядоченном наборе строк BigQuery? - PullRequest
1 голос
/ 07 мая 2019

У меня есть набор результатов BigQuery, содержащий события веб-сайта, которые можно сгруппировать и отсортировать по нескольким столбцам, включая отметку времени, тип события и идентификатор пользователя.

Для каждого userId я хотел бы вернуть первую строку с отметкой времени event_type_1 (вход в систему), а затем для того же пользователя вернуть первую строку event_type_2 (pageView), но только если event_type_2.timestamp> = event_type_1.timestamp. Повторите эти действия для полдюжины типов событий и верните результаты для всех пользователей.

Я знаю, что могу сделать это, используя именованные подзапросы, например, предложение WITH, как показано в следующем примере. Но это неэффективно, поскольку он запускает подзапрос для каждой ссылки на него. Подзапрос внутри оператора WITH выполняется примерно за 5 секунд, тогда как весь запрос занимает кратное 5 секунд, в зависимости от того, сколько раз ссылается на подзапрос.

WITH filtered_events AS 
    (
    SELECT * FROM per_user_events ORDER BY userId, timestamp -- note: this is vastly simplified
  ),
event_type_1 as (
  SELECT *
  FROM filtered_events
  WHERE filtered_events.type = 1),
event_type_2 as (
  SELECT filtered_events.*
  FROM filtered_events
    INNER JOIN event_type_1 ON event_type_1.userId = filtered_events.userId
  WHERE filtered_events.type = 2
  AND filtered_events.timestamp >= event_type_1.timestamp),
event_type_3 as (
  SELECT filtered_events.*
  FROM filtered_events
    INNER JOIN event_type_2 ON event_type_2.userId = filtered_events.userId
  WHERE filtered_events.type = 3
  AND filtered_events.timestamp >= event_type_2.timestamp),
event_type_4 as (
  SELECT filtered_events.*
  FROM filtered_events
    INNER JOIN event_type_3 ON event_type_3.userId = filtered_events.userId
  WHERE filtered_events.type = 4
  AND filtered_events.timestamp >= event_type_3.timestamp)
SELECT * FROM event_type_1
UNION DISTINCT
SELECT * FROM event_type_2
UNION DISTINCT
SELECT * FROM event_type_3
UNION DISTINCT
SELECT * FROM event_type_4
ORDER BY userId, timestamp

Я знаю, что могу материализовать подзапрос как временную или постоянную таблицу BQ, если моя единственная цель - более быстрые запросы / меньше ресурсов. Но мне интересно, могут ли оконные функции (для каждого пользователя) найти первую event_type_1 по метке времени, а затем найти первую event_type_2, которая приходит после timestamp1, затем первую event_type_3 после метки времени2 и т. д.

Я знаком с использованием оконной функции ROW_NUMBER() OVER (PARTITION BY) для выбора подмножества строк для каждого события, но это не помогает мне пропустить прошлые экземпляры события2, которые приходят до события1, и, следовательно, заканчиваются с желаемой последовательностью событий event1 -> event2 -> event3 для каждого пользователя.

...