【问题标题】:Way to achieve overlapping GROUP BY groups with correct subtotals in Clickhouse在 Clickhouse 中使用正确的小计实现重叠 GROUP BY 组的方法
【发布时间】: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


【解决方案1】:

虽然它为分组计算了正确的结果,但 sum(events) 的结果对于小计不正确(因为重复的行计数多次)

您可以在不使用汇总的情况下手动创建my_grouping_id = 0。例如,

select arrayJoin(
  arrayConcat(
    [0],
    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

这似乎效率不高,因为它会产生大量数据重复(而我只是希望将同一行聚合到多个组中)

目前不可能。但我看到了可能性。我将尝试制作GROUP BY ARRAY 的 POC。这似乎是一个有效的用例。

【讨论】:

  • “你可以手动创建 my_grouping_id = 0 而不使用汇总”你是对的,我没有考虑过。这解决了我当前的一些问题,但长期来看仍然不能很好地组合(因为我想按日期等更多列进行分组,并且仍然可以访问汇总)。 GROUP BY ARRAY 听起来也很棒;我想这会使混合“普通”和“数组”列有点尴尬(GROUP BY ARRAY [a], b, [c], d?),但这可能没什么大不了的(或者可以通过不同的语法来解决)。
猜你喜欢
  • 2021-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-29
  • 1970-01-01
  • 2022-01-24
  • 1970-01-01
  • 2012-08-06
相关资源
最近更新 更多