【问题标题】:Top N rows by group in ClickHouseClickHouse 中按组排列的前 N ​​行
【发布时间】:2019-07-20 03:15:40
【问题描述】:

在 ClickHouse 中按组查询前 N 行的正确方法是什么?
让我们以具有 id2、id4、v3 列且 N=2 的 tbl 为例。 我尝试了以下

SELECT                                                                          
    id2,                                                                        
    id4,                 
    v3 AS v3        
FROM tbl
GROUP BY                 
    id2,                 
    id4                  
ORDER BY v3 DESC                                                                
LIMIT 2 BY                       
    id2,                 
    id4      

但出现错误

Received exception from server (version 19.3.4):
Code: 215. DB::Exception: Received from localhost:9000, 127.0.0.1. DB::Exception
: Column v3 is not under aggregate function and not in GROUP BY..

我可以将v3 放入 GROUP BY 中,它似乎确实有效,但按指标分组效率不高。

any 聚合函数,但我们实际上想要 all 值(由 LIMIT BY 子句限制为 2)而不是 any 值,所以这里听起来不是正确的解决方案。

SELECT                                                                          
    id2,                                                                        
    id4,                 
    any(v3) AS v3        
FROM tbl
GROUP BY                 
    id2,                 
    id4                  
ORDER BY v3 DESC                                                                
LIMIT 2 BY                       
    id2,                 
    id4      

【问题讨论】:

    标签: greatest-n-per-group clickhouse


    【解决方案1】:

    可以这样使用aggregate functions

    SELECT
        id2,
        id4,
        arrayJoin(arraySlice(arrayReverseSort(groupArray(v3)), 1, 2)) v3
    FROM tbl
    GROUP BY
        id2,
        id4
    

    【讨论】:

    • 感谢您的解决方案,但它没有以预期的格式返回结果,多行折叠成数组,这不是预期的格式。我不想在输出中有嵌套的数据结构。
    • 查询已修复;)
    • 这样就完成了。有人知道这个解决方案的性能吗?
    【解决方案2】:

    您也可以按照thread 中所述的“普通”SQL 中的方式进行操作

    虽然 vladimir 的解决方案适用于许多情况,但不适用于我的情况。我有一张桌子,看起来像这样:

    column    | group by    
    ++++++++++++++++++++++
    A         | Yes
    B         | Yes
    C         | No
    

    现在,假设 A 列标识用户,B 列代表用户可以执行的任何操作 e。 G。在您的网站或在线游戏上。 C 列是用户执行此特定操作的频率的总和。 Vladimir 的解决方案将允许我获得 A 列和 C 列,但不是用户已执行的操作(B 列),这意味着我会知道用户多久执行一次某事,但不知道 what .

    这样做的原因是按 A 和 B 进行分组是没有意义的。每一行都是一个唯一的组,并且您无法找到前 K 行,因为每个组只有 1 个成员。结果是您查询的同一张表。相反,如果您仅按 A 分组,则可以应用 vladimir 的解决方案,但只会得到 A 列和 C 列。您不能输出 B 列,因为它不是所解释的 Group By 语句的一部分。

    如果您想获得用户执行的前 2 个(或前 5 个或前 100 个)操作,您可能会寻找这样的解决方案:

    SELECT rs.id2, rs.id4, rs.v3
        FROM (
            SELECT id2, id4, v3, row_number()
            OVER (PARTITION BY id2, id4 ORDER BY v3 DESC) AS Rank
            FROM tbl
        ) rs WHERE Rank <= 2
    

    注意:要使用这个,你必须设置allow_experimental_window_functions = 1

    【讨论】:

    • 关于性能的任何想法?与其他人相比如何?
    • 有趣的问题。尚未对其进行基准测试。我将在接下来的几个月中与 ClickHouse 合作并对其进行测试以满足我们的需求,也许我会将这些方法相互比较并让您知道,如果在此期间没有其他人这样做。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-14
    • 1970-01-01
    • 2021-07-09
    • 1970-01-01
    • 1970-01-01
    • 2012-06-11
    • 1970-01-01
    相关资源
    最近更新 更多