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:如何从内存中删除对象?

Clojure HoneySQL - 如何在连接后将字符串值聚合到单行中?

Clojure基础课程2-Clojure中的数据长啥样?

Clojure基础课程2-Clojure中的数据长啥样?

clojure 中关系数据库中的一个_model_ 数据如何?

Clojure 测试中的数据库模拟