Bigquery - оптимизировать запрос с помощью фильтра на основе количества - PullRequest
0 голосов
/ 12 апреля 2020

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

baseTable

code,id,event
55d718,ABAjH0j7yZmVBMhdDf4ab5,eventA
55d718,ABAjH0j7yZmVBMhdDf4ab5,eventB
55d718,ABAjH0j7yZmVBMhdDf4ab5,eventA
55d718,ABAjH0ggMvi-k5z8pbyR8_,eventA
98b1de,ABAjH0gkRy7s1enuFYGgzf,eventC
...

То, что я - концептуально - это "черный список" id, используемый для фильтрации baseTable: любая строка, содержащая id, содержащаяся в черный список должен быть отфильтрован. Правило для внесения в черный список: число идентификаторов больше 1 для данного кода и заданное c событие eventA.

Expected result

code, eventA (count), eventB (count), eventC (count)
55d718, 352, 18, 12
98b1de, 846, 78, 65

Ожидаемым результатом является подсчет каждого события для всех различных кодов, но любой id, который появляется более 1 раза для данного code и event = eventA (в частности, eventA, а не остальные) должны быть полностью удалены из конечного результата. В примере данные ABAjH0j7yZmVBMhdDf4ab5 имеют более 1 строки для кода 55d718 и eventA, поэтому filterTable не должно содержать одну строку с id = ABAjH0j7yZmVBMhdDf4ab5 (даже для других событий).

Рабочий (но неоптимизированный) запрос:

WITH 

  baseTable as (select
    REGEXP_EXTRACT(cs_uri,r'code=([^&]*)') AS code,
    REGEXP_EXTRACT(cs_uri,r'id=([^&]*)') AS id,
    REGEXP_EXTRACT(cs_uri,r'event=([^&]*)') AS event
    from  `my-project.raw_data` 
    ),


  filteredTable as (SELECT *
  FROM baseTable
  where id = 'abcd' AND id NOT IN (
  SELECT
    id
  from baseTable where (event = 'eventA')  and code = 'abcd'
  group by id
  having count(id ) > 1  
 )
 )

  SELECT eventA , eventB from 
  (Select count(id) from filteredTable where event = 'eventA') as eventA,
  (Select count(id) from filteredTable where event = 'eventB') as eventB
  ... other queries on filteredTable

Каждый добавляемый мной запрос filteredTable добавляет к обработанным данным размер baseTable, есть ли лучший способ?

Лучшим (я думаю) запросом было бы установить having code='XXXX' непосредственно в baseTable, поскольку мне не нужно запрашивать несколько кодов одновременно, но проблема в том, что я не могу сделайте это без group by id, code, event, что делает невозможным правильную настройку черного списка (поскольку тогда невозможно получить счет для eventA).

Ответы [ 2 ]

2 голосов
/ 12 апреля 2020

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

Вам не нужно писать подзапросы в последней части. Таким образом, вы можете изменить их на count(case when condition then id end). Кроме того, поскольку вы хотите вывод для каждого кода, вы должны использовать group by code

Другое дело, я думаю, что вы перефильтруете случаи в отфильтрованной таблице. Вы не должны фильтровать столбец id для значения abcd, насколько я понимаю из вашего объяснения.

Итак, вы можете использовать этот код для ожидаемого вывода. Например, код, я изменил ваш базовый код. Поэтому не забудьте изменить его на свой оригинальный код с помощью regex:)

WITH 
baseTable as (
  SELECT '55d718' AS code, 'ABAjH0j7yZmVBMhdDf4ab5' as id,'eventA' as event UNION ALL
  SELECT '55d718' AS code, 'ABAjH0j7yZmVBMhdDf4ab5' as id,'eventB' as event UNION ALL
  SELECT '55d718' AS code, 'ABAjH0j7yZmVBMhdDf4ab5' as id,'eventA' as event UNION ALL
  SELECT '55d718' AS code, 'ABAjH0ggMvi-k5z8pbyR8_' as id,'eventA' as event UNION ALL
  SELECT '98b1de' AS code, 'ABAjH0gkRy7s1enuFYGgzf' as id,'eventC' as event
),
blackList as (
  SELECT id
  from baseTable where (event = 'eventA')  and code = 'abcd'
  group by id
  having count(id ) > 1  
),
filteredTable as (
  SELECT baseTable.*
  FROM baseTable
  LEFT JOIN blackList USING (id)
  where blackList.id IS NULL
)
SELECT 
  code, 
  count(case when event='eventA' then id end) as eventA,
  count(case when event='eventB' then id end) as eventB
from filteredTable
group by code
1 голос
/ 12 апреля 2020

Я думаю, что вы хотите:

with baseTable as ( 
      select REGEXP_EXTRACT(cs_uri,r'code=([^&]*)') AS code,
             REGEXP_EXTRACT(cs_uri,r'id=([^&]*)') AS id,
             REGEXP_EXTRACT(cs_uri,r'event=([^&]*)') AS event
      from  `my-project.raw_data` 
     )
select code, countif(event = 'eventA') as num_a,
       countif(event = 'eventB') as num_b
       countif(event = 'eventC') as num_c
from baseTable
group by code
having countif(event = 'eventA' and code = 'abcd') = 0;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...