「Clickhouse Array 的力量」2-2

1,100 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金。


这很容易,但我们还远远没有解决整个问题。获胜的行程实际上是什么样子的?在这一点上,我们需要引入数组。让我们只从问题的一部分开始,加入每一跳的出发时间。

SELECT Carrier, TailNum,
  groupArray(DepTime) as Departures,
  length(groupArray(DepTime)) as Hops
FROM ontime
WHERE (FlightDate = toDate('2017-01-15')) AND (DepTime < ArrTime)
GROUP BY Carrier, TailNum
ORDER BY Hops DESC, Carrier, TailNum
LIMIT 5

/* sql answer*/
┌─Carrier─┬─TailNum─┬─Departures───────────────────────────┬─Hops─┐
 HA       N488HA   [1157,1813,1921,1042,658,544,170...]    14 
 HA       N492HA   [718,824,938,1512,1622,1056,1743...]    14 
 HA       N493HA   [627,728,1012,1647,1801,904,1523...]    14 
 HA       N483HA   [845,725,1800,1904,1259,1407,113...]    12 
 HA       N489HA   [2047,1936,1031,1602,1438,1256,9...]    12 
└─────────┴─────────┴──────────────────────────────────────┴──────┘

这个查询引入了groupArray(),它是一个聚合函数。

它收集每个GROUP BY子集的值,并按照处理行的顺序将它们添加到数组中。如果你在不同的列上调用groupArray(),它将为每个列创建一个数组。最重要的是,生成的数组将始终是相同的大小,并且有相同的顺序。换句话说,groupArray()是我们在上一篇博客文章中学习的ARRAY JOIN操作符的逆向操作(这句话很重要:说白了 → 一个是列转行,一个是行转列)

构建飞行路径的工作比较多。首先,我们只有出发时间,没有机场。第二,出发时间没有被排序。 让我们在下一个例子中解决这个问题,它增加了更多的数组,并按出发时间顺序进行排序:

SELECT Carrier, TailNum,
  arraySort(groupArray(DepTime)) as Departures,
  arraySort((x,y) -> y, groupArray(Origin), groupArray(DepTime)) as Origins,
  length(groupArray(DepTime)) as Hops
FROM ontime WHERE (FlightDate = toDate('2017-01-15')) AND (DepTime < ArrTime)
GROUP BY Carrier, TailNum
ORDER BY Hops DESC, Carrier, TailNum
LIMIT 5 \G

/* sql answer*/
Row 1:
──────
Carrier:    HA
TailNum:    N488HA
Departures: [544,658,818,930,1042,1157,1322,1443,1556,1708,1813,1921,2025,2126]
Origins:    ['HNL','KOA','HNL','LIH','OGG','LIH','HNL','OGG','LIH','OGG','HNL','OGG','HNL','OGG']
Hops:       14
...

如上面所示,我们依靠的是一个新的、非常通用的函数:arraySort()。

前面的查询说明了它的不同使用方法。在最简单的形式下,arraySort()接收一个数组参数并返回排序后的值。下面是一个例子。

SELECT arraySort([1224, 1923, 1003, 745]) AS s

/* sql answer*/
┌─s────────────────────┐
 [745,1003,1224,1923] 
└──────────────────────┘

我们可以通过添加一个lambda表达式来使事情变得更加有趣,该表达式指示arraySort如何处理它遇到的每个数组值。

如果存在的话,lambda表达式总是第一个参数。下面的例子使用一个lambda表达式来扭转排序顺序。这个lambda表达式被应用于每个连续的数组值,ClickHouse使用所得到的值作为数组中的值的排序键。

SELECT arraySort(x -> (-x), [1224, 1923, 1003, 745]) AS s

/* sql answer*/
┌─s────────────────────┐
 [1923,1224,1003,745] 
└──────────────────────┘

lambda并不总是必要的。你可以使用另外一种方法:arrayReverseSort()。下面的查询返回完全相同的答案:

SELECT arrayReverseSort([1224, 1923, 1003, 745]) AS s

最后,我们可以完全添加一个不同的键(另外一个是指定顺序的键。可以理解另类的排序键)。下面的例子有两个数组,用一个lambda表达式来挑选第二个数组作为排序键。ClickHouse将使用第二个数组的值作为键对第一个数组进行排序。

SELECT
  arraySort((x, y) -> y, [1224, 1923, 1003, 745], [2, 1, 3, 4]) AS s

/* sql answer*/
┌─s────────────────────┐
│ [1923,1224,1003,745] │
└──────────────────────┘