如何按不同的值将 clickhouse 中的 (value,count) 数组分组?
Posted
技术标签:
【中文标题】如何按不同的值将 clickhouse 中的 (value,count) 数组分组?【英文标题】:How can I group by distinct value into a (value,count) array in clickhouse? 【发布时间】:2020-03-27 09:19:43 【问题描述】:例如,我有一张桌子 A
create table A (
id Int64,
discrete1 String
discrete2 String
) engine=Log;
还有一些数据
insert into A values
(1,'A','a')
(1,'B','b')
(1,'A','c')
(2,'C','a')
(1,'A','a');
如何选择这个结果,元组是(value,count)
1,[(A,3),(B,1)],[(a,2),(b,1),(c,1)]
2,[(C,1)],[(a,1)]
我的表可能有许多离散值列,有什么方法可以在一次选择中做到这一点,而无需逐个按离散值列分组。
【问题讨论】:
【参考方案1】:SELECT
id,
arrayMap((x, y) -> (x, y),
(arrayReduce('sumMap', [(groupArrayArray([discrete1]) as arrdiscrete1)],
[arrayResize(CAST([], 'Array(UInt64)'), length(arrdiscrete1), toUInt64(1))]) as sdiscrete1).1,
sdiscrete1.2) rdiscrete1,
arrayMap((x, y) -> (x, y),
(arrayReduce('sumMap', [(groupArrayArray([discrete2]) as arrdiscrete2)],
[arrayResize(CAST([], 'Array(UInt64)'), length(arrdiscrete2), toUInt64(1))]) as sdiscrete2).1,
sdiscrete2.2) rdiscrete2
FROM A
GROUP BY id
┌─id─┬─rdiscrete1────────┬─rdiscrete2────────────────┐
│ 2 │ [('C',1)] │ [('a',1)] │
│ 1 │ [('A',3),('B',1)] │ [('a',2),('b',1),('c',1)] │
└────┴───────────────────┴───────────────────────────┘
【讨论】:
运行查询时出错: Received exception from server (version 19.17.2): Code: 43. DB::Exception: Received from clickhouse-server:9000. DB::Exception: 聚合函数 sumMap 的参数类型非法。 因为strings , v20.3.2.1, 2020-03-12 为sumMap添加String和FixedString键的支持【参考方案2】:试试这个查询(您只需定义所需的“离散”列及其计数):
SELECT id, groupArray(result_per_id_column) result_per_id
FROM (
SELECT id, groupArray(count_result) result_per_id_column
FROM
(
SELECT id, index_discrete.1 as index, (index_discrete.2, count()) AS count_result
FROM
(
SELECT id, arrayJoin(arrayMap((x, index) -> (index, x),
[discrete1, discrete2, discrete3 /* so on for other 'discrete'-columns */],
range(3 /* count of 'discrete'-columns */))) index_discrete
FROM (
/* test data */
SELECT
data.1 AS id,
data.2 AS discrete1,
data.3 AS discrete2,
data.4 AS discrete3
FROM
(
SELECT arrayJoin([(1, 'A', 'a', 'aa'), (1, 'B', 'b', 'aa'), (1, 'A', 'c', 'bb'), (2, 'C', 'a', 'bb'), (1, 'A', 'a', 'cc')]) AS data
)))
GROUP BY id, index_discrete.1, index_discrete.2
)
GROUP BY id, index
ORDER BY id, index)
GROUP BY id
/* result
┌─id─┬─result_per_id──────────────────────────────────────────────────────────────┐
│ 1 │ [[('A',3),('B',1)],[('a',2),('b',1),('c',1)],[('cc',1),('bb',1),('aa',2)]] │
│ 2 │ [[('C',1)],[('a',1)],[('bb',1)]] │
└────┴────────────────────────────────────────────────────────────────────────────┘
*/
【讨论】:
对不起,我改变了我的问题。 我修正了答案,考虑到对于一组“离散”列而不是许多列,它只返回一个具有数组类型的列。 谢谢。似乎对这个要求没有更多的“直接”支持。也许 clickhouse 可以有一些聚合函数,如 groupCountArray 等。【参考方案3】:SELECT
id,
sumMap(arr, arrayResize(CAST([], 'Array(UInt64)'), length(arr), toUInt64(1))) AS s
FROM
(
SELECT
id,
groupArrayArray([discrete1, discrete2]) AS arr
FROM A
GROUP BY id
)
GROUP BY id
┌─id─┬─s───────────────────────────────────┐
│ 2 │ (['C','a'],[1,1]) │
│ 1 │ (['A','B','a','b','c'],[3,1,2,1,1]) │
└────┴─────────────────────────────────────┘
SELECT
id,
arrayMap((x, y) -> (x, y), (sumMap(arr, arrayResize(CAST([], 'Array(UInt64)'), length(arr), toUInt64(1))) AS s).1, s.2) AS r
FROM
(
SELECT
id,
groupArrayArray([discrete1, discrete2]) AS arr
FROM A
GROUP BY id
)
GROUP BY id
┌─id─┬─r─────────────────────────────────────────┐
│ 2 │ [('C',1),('a',1)] │
│ 1 │ [('A',3),('B',1),('a',2),('b',1),('c',1)] │
└────┴───────────────────────────────────────────┘
SELECT
id,
arrayMap((x, y) -> (x, y),
(arrayReduce('sumMap', [(groupArrayArray([discrete1, discrete2]) as arr)],
[arrayResize(CAST([], 'Array(UInt64)'), length(arr), toUInt64(1))]) as s).1,
s.2) r
FROM A
GROUP BY id
┌─id─┬─r─────────────────────────────────────────┐
│ 2 │ [('C',1),('a',1)] │
│ 1 │ [('A',3),('B',1),('a',2),('b',1),('c',1)] │
└────┴───────────────────────────────────────────┘
【讨论】:
我不想将所有离散的列合并在一起,我想分别计算它们的百分比 @xiemeilong 我又添加了一个答案以上是关于如何按不同的值将 clickhouse 中的 (value,count) 数组分组?的主要内容,如果未能解决你的问题,请参考以下文章
ClickHouse 单机安装及基础知识与 Spark 应用
熊猫,我怎样才能避免使用 iterrow (如何根据来自另一个数据帧的值将值分配给数据帧中的新列)