BigQuery argmax: поддерживается ли порядок массивов при выполнении CROSS JOIN UNNEST - PullRequest
0 голосов
/ 05 декабря 2018

Вопрос:

В BigQuery стандартный SQL, если я запускаю

SELECT *
FROM mytable
CROSS JOIN UNNEST(mytable.array)

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

Пример:

Допустим, у меня есть следующая таблица mytable:

Row | id   | prediction
1   | abcd | [0.2, 0.5, 0.3]

Если я запускаю SELECT * FROM mytable CROSS JOIN UNNEST(mytable.prediction), могуЯ уверен, что порядок строк такой же, как порядок массива?Т.е. результирующая таблица всегда будет:

Row | id   | unnested_prediction
1   | abcd | 0.2
2   | abcd | 0.5
3   | abcd | 0.3

Дополнительные сведения о сценарии использования (argmax):

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

Row | id   | argmax
1   | abcd | 2

Используя CROSS JOIN, оконную функцию DENSE_RANK, упорядоченную по значению prediction и оконную функцию ROW_NUMBER, чтобы найти argmax, яв состоянии сделать эту работу с некоторыми данными испытаний.Вы можете проверить с помощью этого запроса:

WITH predictions AS (
  SELECT 'abcd' AS id, [0.2, 0.5, 0.3] AS prediction
  UNION ALL
  SELECT 'efgh' AS id, [0.7, 0.2, 0.1] AS prediction
),
ranked_predictions AS (
  SELECT 
    id,
    ROW_NUMBER() OVER (PARTITION BY id) AS rownum, -- This is the ordering I'm curious about
    DENSE_RANK() OVER (PARTITION BY id ORDER BY flattened_prediction DESC) AS array_rank
  FROM
     predictions P
  CROSS JOIN
    UNNEST(P.prediction) AS flattened_prediction
)
SELECT
  id,
  rownum AS argmax
FROM
  ranked_predictions
WHERE array_rank = 1

Это может быть просто совпадением, что ROW_NUMBER ведет себя хорошо в моих тестах (то есть, что он упорядочен в соответствии с невыпущенным массивом), поэтому было бы неплохобудь уверен.

Ответы [ 3 ]

0 голосов
/ 05 декабря 2018

Краткий ответ: нет, заказ не гарантированно поддерживается.

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

SELECT *
FROM (
  SELECT 3 AS x UNION ALL
  SELECT 2 UNION ALL
  SELECT 1
  ORDER BY x
)

Каков ожидаемый порядок вывода?ORDER BY находится в подзапросе, и внешний запрос не налагает никакого упорядочения, поэтому BigQuery (или любой другой движок, на котором вы его запускаете) может свободно переупорядочивать строки в выводе по своему усмотрению.Вы можете получить обратно 1, 2, 3, или вы можете получить 3, 2, 1 или любой другой заказ.Более общий принцип заключается в том, что проекции не сохраняют порядок.

Хотя массивы имеют четко определенный порядок своих элементов, когда вы используете функцию UNNEST, вы конвертируете массив в отношение,который не имеет четко определенного порядка, если вы не используете ORDER BY.Например, рассмотрим этот запрос:

SELECT ARRAY(SELECT x + 1 FROM UNNEST(arr) AS x) AS new_arr
FROM (SELECT [1, 2, 3] AS arr)

Массив new_arr фактически не гарантирует наличие элементов [2, 3, 4] в этом порядке, так как запрос внутри функции ARRAY не используетORDER BY.Вы можете справиться с этим недетерминизмом, упорядочив на основе смещения элементов, однако:

SELECT ARRAY(SELECT x + 1 FROM UNNEST(arr) AS x WITH OFFSET ORDER BY OFFSET) AS new_arr
FROM (SELECT [1, 2, 3] AS arr)

Теперь гарантированно получится [2, 3, 4].

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

ranked_predictions AS (
  SELECT 
    id,
    ROW_NUMBER() OVER (PARTITION BY id ORDER BY OFFSET) AS rownum,
    DENSE_RANK() OVER (PARTITION BY id ORDER BY flattened_prediction DESC) AS array_rank
  FROM
     predictions P
  CROSS JOIN
    UNNEST(P.prediction) AS flattened_prediction WITH OFFSET
)

Я добавил WITH OFFSET после UNNEST и ORDER BY OFFSET внутри ROW_NUMBER окно, чтобы гарантировать, что номера строк вычисляются на основе исходного порядка элементов массива.

0 голосов
/ 05 декабря 2018

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

вы должны использовать WITH OFFSET, чтобы получить положение элементов в массиве, чтобы затем вы могли использовать их для упорядочения в вашей дальнейшей логике

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 'abcd' id, [0.2, 0.5, 0.3] prediction
)
SELECT id, unnested_prediction
FROM `project.dataset.table`, 
UNNEST(prediction) unnested_prediction WITH OFFSET pos
ORDER BY id, pos  
0 голосов
/ 05 декабря 2018

По умолчанию похоже, что порядок массивов остается неизменным.

Однако один из возможных способов быть на 100% уверенным - навязать какую-то незначительную сортировку, которая скажет обработчику запросов в черном ящике BQ не использовать какой-либо порядок упорядочения по умолчанию, если он попытается.

Что-то вроде:

WITH predictions AS (
  SELECT 'abcd' AS id, [2.1, 0.1, 0.1, 0.2] AS prediction
)
select id, p from predictions
cross join unnest(prediction) p
order by 1=1
...