Я немного новичок в использовании BigQuery.В настоящее время я реализую функцию для массивов, используя операторы WITH, в которой я сначала создаю запрос, который выбирает столбец массива, раскручивает его и применяет функцию к таблице необязательных массивов.Наконец, я объединю эту обработанную таблицу с исходной таблицей.
Однако я столкнулся с проблемой при использовании запросов WITH и LIMIT.Я ожидаю, что объединенный результат всегда будет существовать, поскольку обработанная таблица совпадает с исходной.Однако после того, как я присоединился к таблицам, я обнаружил, что результат нестабилен, иногда результаты существуют, но чаще это не так.
Фоновый контекст:
Таблица, которую я хочу запросить, разделена по времени на день и изначально содержит данные JSON, поэтому я хочу разобрать ее в правильную схему BigQuery и типы данных, а также хэшировать личную информацию.Данные в окончательной форме будут состоять из различных типов данных BigQuery от примитивов до комплексов, таких как ARRAY или RECORD.
Вот фрагмент моего запроса, иллюстрирующий мой случай:
CREATE TEMP FUNCTION ConvertToArrayOfString(input STRING)
RETURNS ARRAY<STRING>
LANGUAGE js AS """
return JSON.parse(input);
""";
WITH
timestamp_ranges AS (
SELECT
TIMESTAMP_TRUNC(TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY), DAY) AS start_timestamp,
TIMESTAMP_TRUNC(CURRENT_TIMESTAMP(), DAY) AS end_timestamp,
),
filtered_data0 AS(
SELECT
*,
_PARTITIONTIME AS partition_time
FROM `project-id.dataset.booking_table`, timestamp_ranges
WHERE
_PARTITIONTIME BETWEEN start_timestamp
AND end_timestamp
LIMIT 100
),
transformed_data0 AS (
SELECT
COALESCE(SAFE_CAST(JSON_EXTRACT_SCALAR(data, '$.id') AS INT64), id) AS id,
STRUCT(
TO_HEX(SHA256(JSON_EXTRACT_SCALAR(data, '$.contact.name'))) AS name,
ConvertToArrayOfString(JSON_EXTRACT(data, '$.contact.phone')) AS phone,
TO_HEX(SHA256(JSON_EXTRACT_SCALAR(data, '$.contact.email'))) AS email
) AS contact,
FROM filtered_data0
),
hashed_details AS (
SELECT
id,
ARRAY_AGG(TO_HEX(SHA256(p))) AS phone
FROM transformed_data0, UNNEST(contact.phone) p
GROUP BY id
),
transformed_data1 AS (
SELECT
LSQ.* EXCEPT (contact),
STRUCT(
LSQ.contact.name,
COALESCE(RSQ.phone, LSQ.contact.phone) AS phone,
LSQ.contact.email
) AS contact
FROM transformed_data0 LSQ
JOIN hashed_details RSQ
ON LSQ.id = RSQ.id
)
SELECT
LSQ.id as l_id,
RSQ.id as r_id
FROM transformed_data0 LSQ
FULL JOIN hashed_details RSQ
USING(id)
Приведенный выше запрос в основном состоит из следующих запросов:
filtered_data0
: отфильтровывает таблицу по разделам и пределам строк transformed_data0
: выбирает столбцы из отфильтрованных данных, анализирует строки JSON в схеме BigQuery hashed_details
: личная информация хэша, которая все еще существует в transformed_data0
которые существуют в форме ARRAY transformed_data1
: объединения hashed_details
с transformed_data0
main query
: проверка полного соединения между hashed_details
и transformed_data0
Итак, я ожидаю, что transformed_data1
результаты будут существовать.Тем не менее, в большинстве случаев я получаю пустой результат.Я попытался отладить эту проблему с помощью основного запроса и обнаружил, что данные (идентифицированные по id), которые существуют в transformed_data0
и hashed_details
, отличаются .
Почему и как возникает эта проблема?Это связано с обработкой порядка запросов?
Если вы видите запрос, hashed_details
фактически использует transformed_data0
в качестве источника, поэтому я ожидаю, что данные в hashed_details
будут такими же, как transformed_data0
.Обратите внимание, что эта проблема разницы в данных не возникнет, если я переместил запрос LIMIT
с filtered_data0
на main query
ниже.Но это снизит производительность, так как время обработки запроса будет значительно больше.
Пожалуйста, дайте мне знать, если у вас есть какие-либо ответы или лучшее решение для решения моей проблемы (которая первоначально применяет функцию к каждой записимассив).Спасибо.
Решение
Создание детерминированного запроса (спасибо Raymond Nijland) Добавьте ORDER BY
при использовании LIMIT
, чтобы сделать запрос детерминированным
Применение функции к массивам Используйте UNNEST в подзапросе ARRAY.Это преобразует весь мой запрос и устраняет необходимость объединения таблиц.