В BigQuery, как случайным образом разделить результаты запроса? - PullRequest
0 голосов
/ 21 мая 2018

В BigQuery (стандартный SQL) я хотел бы случайным образом разделить строки результата из запроса.

  • Разделение должно быть последовательным и не должно изменяться со временем: это означает, что каждыйпри выполнении запроса разбивка должна оставаться неизменной.

  • В частности, если данные добавляются в исходную таблицу, данные, ранее находившиеся на одной стороне разбиения, должны оставаться на том же уровне.split.

  • Стратегия должна быть в состоянии обрабатывать различные коэффициенты разделения

У меня есть, например, таблица mytable,с колонками (order_id, created_at, country):

для разделения 10% / 90%, с одной стороны

SELECT 
   *
FROM
   `mytable`
WHERE RAND() <= 10/90

с другой стороны

SELECT 
   *
FROM
   `mytable`
WHERE RAND() > 10/90

Но это приводит к противоречивому расколу.Есть ли способ добиться этого правильно?

1 Ответ

0 голосов
/ 21 мая 2018

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

BigQuery имеет хеш-функцию, котораяТип цели: INT64 (и источник STRING или BYTES): FARM_FINGERPRINT (из здесь ).

Решение заключается в кодировании каждой строки в соответствии с ееFARM_FINGERPRINT(orderId), который является выборкой из равномерного распределения всех INT64 чисел.

Для данного k, MOD(ABS(FARM_FINGERPRINT(orderId)),k) представляет собой равномерное распределение целых чисел в [0,k-1] (Осторожно, что MOD(a,b) с a отрицательным и b положительным может вернуть отрицательное число).

Таким образом, предположим, что вы хотите разделить на 10% / 90%.

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

SELECT 
   *
FROM
   `mytable`
WHERE MOD(ABS(FARM_FINGERPRINT(orderId)),10) = 0

и

SELECT 
   *
FROM
   `mytable`
WHERE MOD(ABS(FARM_FINGERPRINT(orderId)),10) != 0

Его можно обобщить на любое разбиение 1 / k:

SELECT 
   *
FROM
   `mytable`
WHERE MOD(ABS(FARM_FINGERPRINT(orderId)),@k) = 0

и

SELECT 
   *
FROM
   `mytable`
WHERE MOD(ABS(FARM_FINGERPRINT(orderId)),@k) != 0

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

Последнее, но не менее важное:

  • сгибыдобавление данных в таблицу
  • сгибы остаются неизменными при каждом выполнении запросов
...