clojure 中的预聚合数据结构
Posted
技术标签:
【中文标题】clojure 中的预聚合数据结构【英文标题】:Pre-aggregated datastructure in clojure 【发布时间】:2012-03-12 15:43:31 【问题描述】:在 OLAP 多维数据集中,可以非常快速地查找大量聚合数据。造成这种情况的主要原因是在易于向上组合的操作中预先聚合数据(主要是 +、-、mean、std、max、min 等)。
如何在 clojure 中获得这种“反懒惰”的行为?
我正在考虑类似的事情
(def world-population :africa 4e8 ;;this is an aggregation!
:africa/liberia 3.4e6
:africa/ethiopia 7.4e7
...)
如何更新这样的数据结构并确保实体的父级也得到更新?是否必须推出自己的重新实现?
【问题讨论】:
【参考方案1】:通过将数据存储在 atom 中,您可以添加 watch - 本质上是 atom 更新时的回调
类似这样的:
(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")))
您可以在此基础上构建一些事件传播逻辑。
【讨论】:
add-watch 是一种保持结构同步的巧妙方法!谢谢你!【参考方案2】:您可以将递归汇总函数编写为高阶函数,例如:
(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
如果您有非常大的数据集或多个层次结构等,显然它会变得更加复杂,但这对于许多简单的情况来说应该足够了。
【讨论】:
这太棒了!使用高阶函数的巧妙方法!地理可能很适合派生,会尝试更多。以上是关于clojure 中的预聚合数据结构的主要内容,如果未能解决你的问题,请参考以下文章
Clojure HoneySQL - 如何在连接后将字符串值聚合到单行中?