【问题标题】: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
    相关资源
    最近更新 更多