在clojure中预先聚合的数据结构

时间:2012-03-12 15:43:31

标签: clojure olap aggregation

在OLAP-cubes中,可以快速查看大量聚合数据。这样做的主要原因是一个预先聚合操作中的数据,这些数据易于向上组合(主要是+, - ,mean,std,max,min和更多)。

如何在clojure中获得这种“反懒惰”行为?

我正在考虑像

这样的事情
(def world-population {:africa 4e8            ;;this is an aggregation!
                       :africa/liberia 3.4e6
                       :africa/ethiopia 7.4e7
                       ...})

如何更新这样的数据结构并确保实体的父级也更新?有人必须推出自己的ref实现吗?

2 个答案:

答案 0 :(得分:4)

通过将数据存储在原子中,您可以添加监视 - 实际上是在更新原子时的回调

这样的事情:

(def world-population (atom {:africa 4e8
                             :africa/liberia 3.4e6
                             ...}))

(add-watch word-population :population-change-key
      (fn [key ref old new]
         (prn "population change")))

您可以在此基础上构建一些事件传播逻辑。

答案 1 :(得分:3)

您可以将递归汇总函数编写为高阶函数,例如:

(defn rollup 
  ([data heirarchy func]
    (loop [top (second (first heirarchy))]
      (if (nil? (heirarchy top))
        (rollup data heirarchy func top)
        (recur (heirarchy top)))))
  ([data heirarchy func root]
    (let [children (reduce (fn [l [k v]] (if (= v root) (cons k l) l)) '() heirarchy)
          data (reduce (fn [d c] (if (d c) d (rollup d heirarchy func c))) data children)
          child-values (map data children)]
      (assoc data root (apply func child-values)))))

然后可以将其用于您喜欢的任何特定汇总操作或层次结构:

(def populations { :africa/liberia 3.4e6
                   :africa/ethiopia 7.4e7})

(def geography {:africa/liberia :africa 
                :africa/ethiopia :africa
                :africa :world})

(rollup populations geography +)
=> {:africa           7.74E7, 
    :world            7.74E7, 
    :africa/ethiopia  7.4E7, 
    :africa/liberia   3400000.0}

如果您拥有非常大的数据集或多个层次结构等,显然会变得更复杂,但对于许多简单的情况,这应该足够了。