【发布时间】:2020-09-06 18:05:57
【问题描述】:
假设以下架构:
CREATE TABLE test
(
date Date,
user_id UInt32,
user_answer UInt8,
user_multi_choice_answer Array(UInt8),
events UInt32
)
ENGINE = MergeTree() ORDER BY date;
及内容:
INSERT INTO test VALUES
('2020-01-01', 1, 5, [2, 3], 15),
('2020-01-01', 2, 6, [1, 2], 7);
假设我想查询“给我 # 个用户和 # 个按日期和 user_answer 分组的事件,并带有小计”。这很简单:
select date, user_answer, count(distinct user_id), sum(events) from test group by date, user_answer with rollup;
┌───────date─┬─user_answer─┬─uniqExact(user_id)─┬─sum(events)─┐
│ 2020-01-01 │ 5 │ 1 │ 15 │
│ 2020-01-01 │ 6 │ 1 │ 7 │
│ 2020-01-01 │ 0 │ 2 │ 22 │
│ 0000-00-00 │ 0 │ 2 │ 22 │
└────────────┴─────────────┴────────────────────┴─────────────┘
我不能轻易做的是对重叠的组进行查询,例如按多项选择题的个别选项进行分组时。例如:
- 用户数和事件数按日期和 user_multi_choice_answer 分组,并带有小计
- 按任意手写分组条件分组的用户数和事件数,例如“将 user_answer=5 和 has(user_multi_choice_answer, 1) 的用户与 has(user_multi_choice_answer, 2) 的用户进行比较”
例如,对于第一个查询,我希望看到以下内容:
┌───────date─┬─user_multi_choice_answer─┬─uniqExact(user_id)─┬─sum(events)─┐
│ 2020-01-01 │ 1 │ 1 │ 15 │
│ 2020-01-01 │ 2 │ 2 │ 22 │
│ 2020-01-01 │ 3 │ 1 │ 7 │
│ 2020-01-01 │ 0 │ 2 │ 22 │
│ 0000-00-00 │ 0 │ 2 │ 22 │
└────────────┴──────────────────────────┴────────────────────┴─────────────┘
第二个:
┌─my_grouping_id─┬─uniqExact(user_id)─┬─sum(events)─┐
│ 1 │ 1 │ 15 │ # users fulfilling arbitrary condition #1
│ 2 │ 2 │ 22 │ # users fulfilling arbitrary condition #2
│ 0 │ 2 │ 22 │ # subtotal
└────────────────┴────────────────────┴─────────────┘
我能做到的最接近的方法是使用arrayJoin():
select date, arrayJoin(user_multi_choice_answer) as multi_answer, count(distinct user_id), sum(events)
from test group by date, multi_answer with rollup;
select arrayJoin(
arrayConcat(
if(user_answer=5 and has(user_multi_choice_answer, 3), [1], []),
if(has(user_multi_choice_answer, 2), [2], [])
)
) as my_grouping_id, count(distinct user_id), sum(events)
from test group by my_grouping_id with rollup;
但这不是一个好的解决方案,原因有两个:
- 虽然它计算了正确的分组结果,但
sum(events)的结果对于小计不正确(因为重复行计数多次) - 它似乎效率不高,因为它会产生大量数据重复(而我只是希望将同一行聚合到多个组中)
因此,我再次寻找一种方法,可以让我轻松地对多项选择题的答案进行分组,并通过某些列上的任意条件进行探索。我可以更改架构以使其成为可能,但我主要希望 Clickhouse 有一个内置的方法来实现这一点。
【问题讨论】:
-
只是备注:“sum(events) 的结果对于小计不正确” - 汇总按要求正常工作。作为一种解决方法,您可以使用直接查询来计算每个子组:选择日期,arrayJoin(user_multi_choice_answer) 作为 multi_answer,count(distinct user_id) 作为 uniq_users,sum(events) 来自测试组的总和按日期,multi_answer union all select date, 0 as multi_answer, count(distinct user_id) as uniq_users, sum(events) as sum from test group by date;
-
只是原始建议:1) 考虑展平原始表格 - 而不是 user_multi_choice_answer Array(UInt8) 使用 UInt8 choise_answer。它会导致行数显着增加,并可能获得一些性能优势。 2) 如果“任意”查询可以形式化,则考虑使用带有AggregatingMergeTree-engine 的额外表,其中存储预先计算的中间结果。
-
“Rollup 根据需要正常工作”我知道,只是我的措辞不好。结果是正确的,只是不是我最终需要的。 “您可以使用直接查询来计算每个子组”我可以,但如果我想
group by不仅仅是日期和单个答案列,它不会扩展。 -
至于原始建议:不幸的是,我的真实表有更多列,其中一些也是“多项选择”,因此展平实际上并不可行(除非我将该数据分成单独的较小的每个用户表并加入它,但这会带来不同的问题)。
标签: clickhouse