Как я должен изменить свой запрос, чтобы применить функцию к каждой записи массива в BigQuery? - PullRequest
0 голосов
/ 17 мая 2019

Я немного новичок в использовании 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)

Приведенный выше запрос в основном состоит из следующих запросов:

  1. filtered_data0: отфильтровывает таблицу по разделам и пределам строк
  2. transformed_data0: выбирает столбцы из отфильтрованных данных, анализирует строки JSON в схеме BigQuery
  3. hashed_details: личная информация хэша, которая все еще существует в transformed_data0 которые существуют в форме ARRAY
  4. transformed_data1: объединения hashed_details с transformed_data0
  5. 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 ниже.Но это снизит производительность, так как время обработки запроса будет значительно больше.

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

Решение

  1. Создание детерминированного запроса (спасибо Raymond Nijland) Добавьте ORDER BY при использовании LIMIT, чтобы сделать запрос детерминированным

  2. Применение функции к массивам Используйте UNNEST в подзапросе ARRAY.Это преобразует весь мой запрос и устраняет необходимость объединения таблиц.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...