Clickhouse中的记录排名

Posted

技术标签:

【中文标题】Clickhouse中的记录排名【英文标题】:Record ranking in Clickhouse 【发布时间】:2020-05-14 09:34:19 【问题描述】:

例如,我有一张桌子:

CREATE DATABASE IF NOT EXISTS example;
CREATE TABLE IF NOT EXISTS example.etable (starttime datetime, name string,) ENGINE = MergeTree; 

为了应用 GROUP BY 操作,我需要计算每条记录的排名,以便“名称”字段值相同的连续有序记录具有相同的排名。如果当前记录的 name 字段的值不是上一个,则排名递增。

mysql 中,这可以通过这样的查询来完成:

SELECT name, starttime, 
    @prev := @curr,
    @curr := name,
    @rank := IF(@prev = @curr, @rank, @rank+1) AS rank
FROM example.etable,
    (SELECT @curr := null, @prev := null, @rank := 0) r
ORDER BY starttime ASC;

示例输出:

+------+---------------------+----------------+---------------+------+
| name | starttime           | @prev := @curr | @curr := name | rank |
+------+---------------------+----------------+---------------+------+
| s1   | 2020-05-14 15:56:46 | NULL           | s1            | 1    |
| s1   | 2020-05-14 15:56:49 | s1             | s1            | 1    |
| s1   | 2020-05-14 15:56:51 | s1             | s1            | 1    |
| s2   | 2020-05-14 15:56:53 | s1             | s2            | 2    |
| s1   | 2020-05-14 15:56:56 | s2             | s1            | 3    |
| s3   | 2020-05-14 15:56:59 | s1             | s3            | 4    |
+------+---------------------+----------------+---------------+------+

那么,问题来了,如何在 Clickhouse 中实现这一点?

【问题讨论】:

【参考方案1】:

计算排名包括三个步骤:

将关系转换为数组 (groupArray) 计算等级 (arrayCumSum) 将数组转换为关系 (arrayJoin)。
SELECT result.1 starttime, result.2 name, result.3 rank
FROM (
    SELECT 
        groupArray(starttime) starttime_arr,
        groupArray(name) name_arr,
        arrayCumSum((name, index) -> index = 1 ? 1 : (name_arr[index - 1] = name ? 0 : 1), name_arr, arrayEnumerate(name_arr)) ranks,
        arrayZip(starttime_arr, name_arr, ranks) result_array,
        arrayJoin(result_array) result
    FROM (
        SELECT * 
        FROM (
            /* emulate the 'example.etable'-table */
            SELECT toDateTime(test_data.1) AS starttime, test_data.2 AS name
            FROM (
                SELECT arrayJoin([
                    ('2020-05-14 15:56:46', 's1'),
                    ('2020-05-14 15:56:49', 's1'),
                    ('2020-05-14 15:56:51', 's1'),
                    ('2020-05-14 15:56:53', 's2'),
                    ('2020-05-14 15:56:56', 's1'),
                    ('2020-05-14 15:56:59', 's3')
                ]) test_data))
        ORDER BY starttime)
    )

/* result
┌───────────starttime─┬─name─┬─rank─┐
│ 2020-05-14 15:56:46 │ s1   │    1 │
│ 2020-05-14 15:56:49 │ s1   │    1 │
│ 2020-05-14 15:56:51 │ s1   │    1 │
│ 2020-05-14 15:56:53 │ s2   │    2 │
│ 2020-05-14 15:56:56 │ s1   │    3 │
│ 2020-05-14 15:56:59 │ s3   │    4 │
└─────────────────────┴──────┴──────┘
*/

【讨论】:

谢谢!它有点复杂但有效!

以上是关于Clickhouse中的记录排名的主要内容,如果未能解决你的问题,请参考以下文章

[3]Clickhouse列式存储的明日之星:如何利用ClickHouse查询Github上点赞排名靠前的站点?

[3]Clickhouse列式存储的明日之星:如何利用ClickHouse查询Github上点赞排名靠前的站点?

clickhouse clickhouse配置查询记录query_log

为啥clickhouse写批记录慢?

Elasticsearch VS. ClickHouse

clickhouse使用问题记录