2012-03-12 22 views
6

Nei cubi OLAP è possibile eseguire ricerche molto veloci su grandi quantità di dati aggregati. La ragione principale di ciò è che si pre-aggregano i dati in operazioni che sono facili da combinare verso l'alto (principalmente +, -, media, std, max, min e alcuni altri).Datastructure pre-aggregato in clojure

Come ottenere questo comportamento "anti-pigro" in clojure?

sto pensando su qualcosa come

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

Come aggiornare un datastructure come questo e assicurarsi che i genitori di un'entità viene aggiornato troppo? Bisogna eseguire il proprio ref-implementazione?

risposta

3

Si potrebbe scrivere una funzione rollup ricorsiva come una funzione di ordine superiore, qualcosa di simile:

(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))))) 

che può quindi essere utilizzato con qualsiasi particolare operazione rollup o una gerarchia ti piace:

(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} 

Ovviamente diventa più complicato se si dispone di set di dati molto grandi o di gerarchie multiple, ecc., ma questo dovrebbe essere sufficiente per molti casi semplici.

+0

Questo è fantastico! Modo intelligente di utilizzare le funzioni di ordine superiore! La geografia sarà probabilmente una buona partita per derivare, proverà più con quella. – claj

4

Memorizzando i dati in un atomo, è possibile aggiungere gli orologi - callback essenzialmente quando l'atomo viene aggiornato

Qualcosa di simile a questo:

(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"))) 

Si potrebbe costruire una logica propagazione degli eventi in cima a quello .

+0

add-watch è un modo intelligente per mantenere la struttura in sincronia! Grazie per quello! – claj