将行转置/转换为Cascalog中的列?

时间:2014-04-28 13:51:16

标签: clojure cascading cascalog

假设我有一组要由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中最好的方法是什么?

1 个答案:

答案 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函数中,其中包含两个查询:

  1. 内部查询将给定日期的所有?name ?value对聚合到?sum地图中。

  2. 外部查询使用select-values?sum地图和最终结果行中获取列的值。

  3. 由于我们知道列是Pizza, Hamburger, Cheeseburger,我们可以简单地将它们硬编码到查询中。如果您想知道如何使列动态,请阅读Nathan Marz在creating a news feed in Cascalog上的博客文章。

    请注意,我们必须将列表示为可空变量(使用!),因为并非每列都具有任何给定行的值。如果我们想避免null结果,我们可以将select-values更改为使用0作为默认值。

    (需要注意的是,这不会在最终输出中产生任何标题,因此必须将其作为后处理步骤完成。)

相关问题