「Clickhouse Array 的力量」2-3

1,772 阅读1分钟

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

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


总结一下,groupArray()从分组的值中建立数组,sortArray()对这些值进行排序,用一个数组作为其他数组的排序键。下面剩下的就是构建完整的查询。我们将使用ARRAY JOIN将我们的结果以一种更可读的格式展开。

SELECT Carrier, TailNum, Depart, Arr, Origin, Dest
FROM
(
  SELECT Carrier, TailNum,
    arraySort(groupArray(DepTime)) AS Departures,
    arraySort(groupArray(ArrTime)) AS Arrivals,
    arraySort((x, y) -> y, groupArray(Origin), groupArray(ArrTime)) AS Origins,
    arraySort((x, y) -> y, groupArray(Dest), groupArray(ArrTime)) AS Destinations,
    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
)
ARRAY JOIN Departures AS Depart, Arrivals AS Arr,
    Origins AS Origin, Destinations AS Dest
LIMIT 15

/* sql answer*/
┌─Carrier─┬─TailNum─┬─Depart─┬──Arr─┬─Origin─┬─Dest─┐
│ HA      │ N488HA  │    544 │  632 │ HNL    │ KOA  │
│ HA      │ N488HA  │    658 │  749 │ KOA    │ HNL  │
│ HA      │ N488HA  │    818 │  853 │ HNL    │ LIH  │
│ HA      │ N488HA  │    9301020 │ LIH    │ OGG  │
│ HA      │ N488HA  │   10421126 │ OGG    │ LIH  │
│ HA      │ N488HA  │   11571229 │ LIH    │ HNL  │
│ HA      │ N488HA  │   13221406 │ HNL    │ OGG  │
│ HA      │ N488HA  │   14431535 │ OGG    │ LIH  │
│ HA      │ N488HA  │   15561646 │ LIH    │ OGG  │
│ HA      │ N488HA  │   17081742 │ OGG    │ HNL  │
│ HA      │ N488HA  │   18131857 │ HNL    │ OGG  │
│ HA      │ N488HA  │   19211958 │ OGG    │ HNL  │
│ HA      │ N488HA  │   20252107 │ HNL    │ OGG  │
│ HA      │ N488HA  │   21262207 │ OGG    │ HNL  │
│ HA      │ N492HA  │    501 │  542 │ HNL    │ LIH  │
└─────────┴─────────┴────────┴──────┴────────┴──────┘

很高兴看到我们的N488HA飞机的始发机场和出发机场正确排列。

漏斗分析

正如介绍中提到的,漏斗分析是一种重要的技术,可以在时间序列数据中跟踪目标的进展。我们可以使用漏斗来回答以下问题:

  1. 有多少网站客户把东西放进购物车,然后在同一时段购买?
  2. 营销线索是如何从联系人发展到注册客户的?
  3. 有多少飞机在同一天内飞往芝加哥,然后飞往亚特兰大?

既然我们有航班数据,我们将用它来建立一个漏斗,以回答最后一个问题。为了增加趣味性,我们将在整个数据集中按年份汇总结果。读取更多的数据使我们更容易评估性能。

就像之前的跟踪序列的例子一样,我们将从一个更简单的查询开始,然后增加功能,直到我们有一个解决方案。我们最初的查询生成了一个按时间排序的每架飞机的每日目的地列表。为了保持快速,我们将只看单日的数据。

SELECT FlightDate, Carrier, TailNum,
    arraySort(groupArray(ArrTime)) AS Arrivals,
    arraySort((x, y) -> y, groupArray(Dest), groupArray(ArrTime)) AS Dests
  FROM ontime
  WHERE DepTime < ArrTime AND TailNum != ''
    AND toYYYYMM(FlightDate) = toYYYYMM(toDate('2017-01-01'))
  GROUP BY FlightDate, Carrier, TailNum
  ORDER BY FlightDate, Carrier, TailNum
LIMIT 5\G

/* sql answer*/
Row 1:
──────
FlightDate: 2017-01-01
Carrier:    AA
TailNum:    N001AA
Arrivals:   [1021,2213]
Dests:      ['MIA','ATL']
. . .

我们最初的查询给了我们正确排序的列表,但我们现在需要寻找经过芝加哥的航班。我们将搜索限制在奥黑尔('ORD')和中途岛('MDW')上,这两个机场是服务于芝加哥市的主要机场。为了更快地检查结果,我们将添加一个HAVING子句,以便我们只看包括在芝加哥停留的航线。

SELECT FlightDate, Carrier, TailNum,
    arraySort(groupArray(ArrTime)) AS Arrivals,
    arraySort((x, y) -> y, groupArray(Dest), groupArray(ArrTime)) AS Dests,
    arrayFilter((arr, dest) -> (dest in ('MDW', 'ORD')), Arrivals, Dests)[1] as CHI_Arr,
    length(Arrivals) as Hops
  FROM ontime
  WHERE DepTime < ArrTime AND TailNum != ''
    AND toYYYYMM(FlightDate) = toYYYYMM(toDate('2017-01-01'))
  GROUP BY FlightDate, Carrier, TailNum
  HAVING CHI_Arr > 0
  ORDER BY FlightDate, Carrier, TailNum
LIMIT 5 \G

/* sql answer*/
Row 1:
──────
FlightDate: 2017-01-01
Carrier:    AA
TailNum:    N005AA
Arrivals:   [1238,1757,2158]
Dests:      ['JAC','ORD','ATL']
CHI_Arr:    1757
Hops:       3
. . .

我们的示例查询依赖于一个新的函数:arrayFilter() ,它接受两个或多个参数。第一个是一个lambda表达式,其余的参数是数组。 arrayFilter() 返回第一个数组参数中的元素数组,其中λ表达式的结果为非零。下面是如何返回长于一个字符的字符串数组元素:

WITH ['a', 'bc', 'def', 'g'] AS array
SELECT arrayFilter(v -> (length(v) > 1), array) AS filtered

/* sql answer*/
┌─filtered─────┐
│ ['bc','def'] │
└──────────────┘