2013-05-05 119 views
2

我希望能夠做這樣的事情:datomic查詢 - 功能過濾和結合

(defn match? [m] (re-find (re-pattern "so (\\d+)") m)) 

(datomic.api/q 
    '[:find ?m 
    :where [[?e :user/regex-match ?r] 
      [(user/match? ?e) ?m]] 
    dbconn) 

這給了我什麼,我期待,但它稱之爲「是否匹配?」每個實體兩次:

(datomic.api/q 
    '[:find ?m 
    :where [[?e :user/regex-match ?r] 
      [(user/match? ?e) ?m] 
      [(user/match? ?e)] 
    dbconn) 
+0

添加(身份?米)代替主叫用戶/匹配?再次似乎是迄今爲止我發現的最佳解決方案。不過,不知道它在datomic查詢中的習慣嗎? – 2013-05-05 17:45:00

+0

你是什麼意思「調用'匹配?'每個實體兩次?」你怎麼知道?您能否提供一些示例數據(即Clojure集合)? – noahlz 2013-05-06 15:51:56

+0

另外,Clojure正則表達式不需要你轉義反斜槓。我不得不將它改成'#「(\ d +)」' – noahlz 2013-05-08 05:04:59

回答

0

這個問題似乎是?m給你的匹配,而不是實體。你想要類似下面的東西:

user=> (->> (d/q '[:find ?e ?m :in $ :where [?e :user/regex-match ?r] 
              [(user/match? ?r) ?m]] 
      [[1 :user/regex-match "so 111"] 
      [2 :user/regex-match "so 222"] 
      [3 :user/regex-match "blah 333"]]) 
      (filter #(seq (second %)))) 

([2 ["so 222" "222"]] [1 ["so 111" "111"]]) 

請注意,我使用clojure集合嘲笑數據庫。

基於這個輸出,你的正則表達式有一個子表達式 - 這就是爲什麼你可能看到它「每個實體兩次」。

不知您是否可以從the Datomic filter functionality中受益?

3

如果你擔心性能,使用方法:

(->> (d/datoms (d/db conn) :aevt :user/regex-match) 
(filter #(user/match? (:v %))) 
(map :v)) 

它使用datomic.api/datoms API來進行流匹配的謂詞即user/match?:user/regex-match屬性值。這個保證你的謂詞函數只執行一次(每個實體)。請注意,您可以用(map :e)替換(map :v)來替換其實體ID。

如果你是真的擔心性能,並願意使用更多的內存來實現它,使用:

(def fast-match? (memoize match?)) 

(->> (d/datoms (d/db conn) :aevt :user/regex-match) 
(filter #(fast-match? (:v %))) 
(map :v)) 

它創建了一個memoized版本的功能。此版本具有更強的性能保證,因爲您的謂詞函數最多會運行一次最多(即每個不同值有一次),並且如果屬性值是有限集的一部分,它可以爲您提供卓越的性能。

對於一個完整的代碼示例,請參見https://gist.github.com/a2ndrade/5651065