Выберите имена столбцов с максимальными значениями X - PullRequest
0 голосов
/ 27 сентября 2018

Я создал матрицу пользователей и взаимодействий с категориями продуктов, мои данные выглядят так: каждая строка - это пользователь, а каждый столбец - категория, а число указывает, сколько взаимодействий они сделали с этой категорией:

    User     Cat1     Cat2     Cat3     Cat4     Cat5     ...
    1        0        1        0        2        30
    2        0        0        10       5        0
    3        0        5        0        0        0
    4        2        0        20       2        0
    5        0        40       0        0        0
    ...

Я хотел бы добавить столбец (либо в этом запросе, либо в новом запросе к этой таблице), который возвращает для каждого пользователя 3 имени столбца, которые содержат самые высокие значения.

Мои полные данные содержат более 200 столбцов.

Есть ли какие-либо предложения о том, как мне этого добиться в StandardSQL?

Вот код, который я использовал для построения своей сетки:

SELECT
  customDimension.value AS UserID,
  SUM(IF(LOWER(hits_product.productbrand) LIKE "Brand 1",1,0)) AS brand_1,
  SUM(IF(LOWER(hits_product.productbrand) LIKE "Brand 2",1,0)) AS brand_2,
  SUM(IF(LOWER(hits_product.productbrand) LIKE "Brand 3",1,0)) AS brand_3,

FROM
  `table*` AS t
CROSS JOIN
  UNNEST (hits) AS hits
CROSS JOIN
  UNNEST(t.customdimensions) AS customDimension
CROSS JOIN
  UNNEST(hits.product) AS hits_product
WHERE
  parse_DATE('%y%m%d',
    _table_suffix) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 1 day)
  AND DATE_SUB(CURRENT_DATE(), INTERVAL 1 day)
  AND customDimension.index = 2
  AND hits.eventInfo.eventCategory = 'Ecommerce'
  AND hits.eventInfo.eventAction = 'Purchase'
GROUP BY
  UserID
  LIMIT 50

Ответы [ 3 ]

0 голосов
/ 27 сентября 2018

Вы бы использовали массивы в больших запросах:

select t.*,
       (select array_agg(s.colname order by s.val desc limit 3)
        from unnest(array[struct('col1' as colname), col1 as val),
                          struct('col2' as colname), col2 as val),
                          . . .
                         ]
                   ) s
       ) as top3
from t
0 голосов
/ 27 сентября 2018

Ниже для стандартного SQL BigQuery (и не зависит от количества столбцов категории - хотя в примере только 5)

#standardSQL
SELECT *, 
  ARRAY_TO_STRING(ARRAY(
    SELECT SPLIT(kv, ':')[OFFSET(0)]
    FROM UNNEST(SPLIT(REGEXP_REPLACE(TO_JSON_STRING(t), r'[{"}]', ''))) kv
    WHERE LOWER(SPLIT(kv, ':')[OFFSET(0)]) <> 'user'
    ORDER BY CAST(SPLIT(kv, ':')[OFFSET(1)] AS INT64) DESC
    LIMIT 3
  ), ',') top3_cat
FROM `yourproject.yourdataset.yourtable` t

Вы можете протестировать, поиграть с вышеприведенными, используя фиктивные данные из вашего вопроса:

#standardSQL
WITH `project.dataset.table` AS (
  SELECT 1 user, 0 cat1, 1 cat2, 0 cat3, 2 cat4, 30 cat5 UNION ALL
  SELECT 2, 0, 0, 10, 5, 0 UNION ALL
  SELECT 3, 0, 5, 0, 0, 0 UNION ALL
  SELECT 4, 2, 0, 20, 2, 0 UNION ALL
  SELECT 5, 0, 40, 0, 0, 0 
)
SELECT *, 
  ARRAY_TO_STRING(ARRAY(
    SELECT SPLIT(kv, ':')[OFFSET(0)]
    FROM UNNEST(SPLIT(REGEXP_REPLACE(TO_JSON_STRING(t), r'[{"}]', ''))) kv
    WHERE LOWER(SPLIT(kv, ':')[OFFSET(0)]) <> 'user'
    ORDER BY CAST(SPLIT(kv, ':')[OFFSET(1)] AS INT64) DESC
    LIMIT 3
  ), ',') top3_cat
FROM `project.dataset.table` t

с результатом

Row user    cat1    cat2    cat3    cat4    cat5    top3_cat     
1   1       0       1       0       2       30      cat5,cat4,cat2   
2   2       0       0       10      5       0       cat3,cat4,cat2   
3   3       0       5       0       0       0       cat2,cat3,cat1   
4   4       2       0       20      2       0       cat3,cat4,cat1   
5   5       0       40      0       0       0       cat2,cat3,cat1   

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

#standardSQL
WITH `query_result` AS (
  SELECT
    customDimension.value AS UserID,
    SUM(IF(LOWER(hits_product.productbrand) LIKE "Brand 1",1,0)) AS brand_1,
    SUM(IF(LOWER(hits_product.productbrand) LIKE "Brand 2",1,0)) AS brand_2,
    SUM(IF(LOWER(hits_product.productbrand) LIKE "Brand 3",1,0)) AS brand_3,
    ...
    ...
  FROM
    `table*` AS t
  CROSS JOIN
    UNNEST (hits) AS hits
  CROSS JOIN
    UNNEST(t.customdimensions) AS customDimension
  CROSS JOIN
    UNNEST(hits.product) AS hits_product
  WHERE
    parse_DATE('%y%m%d',
      _table_suffix) BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 1 day)
    AND DATE_SUB(CURRENT_DATE(), INTERVAL 1 day)
    AND customDimension.index = 2
    AND hits.eventInfo.eventCategory = 'Ecommerce'
    AND hits.eventInfo.eventAction = 'Purchase'
  GROUP BY
    UserID
    LIMIT 50    
)
SELECT *, 
  ARRAY_TO_STRING(ARRAY(
    SELECT SPLIT(kv, ':')[OFFSET(0)]
    FROM UNNEST(SPLIT(REGEXP_REPLACE(TO_JSON_STRING(t), r'[{"}]', ''))) kv
    WHERE LOWER(SPLIT(kv, ':')[OFFSET(0)]) <> LOWER('UserID')
    ORDER BY CAST(SPLIT(kv, ':')[OFFSET(1)] AS INT64) DESC
    LIMIT 3
  ), ',') top3_cat
FROM `query_result` t
0 голосов
/ 27 сентября 2018

Расширение моего комментария: если бы ваши данные были в более разумном формате, таком как user | category | cat_count, вы могли бы выполнить что-то вроде:

SELECT user, group_concat(category) as top_3_cat
FROM
    (
        SELECT user, category, rank() OVER (PARTITION BY user ORDER BY cat_count) as cat_rank
        FROM yourtable
    ) cat_ranking
WHERE cat_rank <= 3;

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

Я бы сосредоточился на том, чтобы сначала отключить вашу таблицу, чтобы ее можно было запустить через sql выше.Это может быть возможно при использовании преобразования bigquery unpivot , хотя я не уверен, каков предел для удаления столбцов.

unpivot col:cat1, cat2, cat3, cat4, cat5, catN groupEvery:N

Я не использую bigquery, поэтому яне уверен, как это будет применяться к вашему набору данных, но выглядит многообещающе.

Другой вариант - UNION много операторов вместе, чтобы составить yourtable в этом sql выше:

SELECT user, 'cat1' as category, cat1 FROM yourtable
UNION ALL SELECT user, 'cat2', cat2 FROM yourtable
UNION ALL SELECT user, 'cat3', cat3 FROM yourtable
UNION ALL SELECT user, 'cat4', cat4 FROM yourtable
UNION ALL SELECT user, 'cat5', cat5 FROM yourtable
UNION ALL SELECT user, 'catN', catN FROM yourtable;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...