假设我有一组要由Cascalog处理的元组,格式为[Date, Name, Value]
,例如
2014-01-01 Pizza 3
2014-01-01 Hamburger 4
2014-01-01 Cheeseburger 2
2014-01-02 Pizza 1
2014-01-02 Hamburger 2
鉴于我有一个像[Pizza, Hamburger, Cheeseburger]
这样的列的列表,我想转置/转动数据,使它看起来像这样:
Date Pizza Hamburger Cheeseburger
2014-01-01 3 4 2
2014-01-02 1 2 0
Cascalog中最好的方法是什么?
答案 0 :(得分:2)
这是一种方法:
(:use cascalog.api)
(def input
[["2014-01-01" "Pizza" 3]
["2014-01-01" "Hamburger" 4]
["2014-01-01" "Cheeseburger" 2]
["2014-01-02" "Pizza" 1]
["2014-01-02" "Hamburger" 2]])
(defn init-aggregate [k v]
{k v})
(def combine-aggregate
(partial merge-with +))
(defparallelagg aggregate
:init-var #'init-aggregate
:combine-var #'combine-aggregate)
(defn select-values [hashmap keyseq]
(map #(get hashmap %) keyseq))
(def columns
["Pizza" "Hamburger" "Cheeseburger"])
(defn transpose [data]
(<- [?date !pizza !hamburger !cheeseburger]
((<- [?date ?sum]
(data ?date ?name ?value)
(aggregate ?name ?value :> ?sum))
?date ?sum)
(select-values ?sum columns :> !pizza !hamburger !cheeseburger)))
(?- (stdout) (transpose input))
让我们快速浏览一下代码:
大部分操作都发生在transpose
函数中,其中包含两个查询:
内部查询将给定日期的所有?name ?value
对聚合到?sum
地图中。
外部查询使用select-values
从?sum
地图和最终结果行中获取列的值。
由于我们知道列是Pizza, Hamburger, Cheeseburger
,我们可以简单地将它们硬编码到查询中。如果您想知道如何使列动态,请阅读Nathan Marz在creating a news feed in Cascalog上的博客文章。
请注意,我们必须将列表示为可空变量(使用!
),因为并非每列都具有任何给定行的值。如果我们想避免null
结果,我们可以将select-values
更改为使用0作为默认值。
(需要注意的是,这不会在最终输出中产生任何标题,因此必须将其作为后处理步骤完成。)