datomic query - 过滤和绑定的函数

时间:2013-05-05 16:46:14

标签: regex clojure 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)

2 个答案:

答案 0 :(得分:3)

如果您担心表现,请使用:

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

使用datomic.api/datoms API流出与谓词匹配的:user/regex-match属性值,即user/match?。这个保证你的谓词函数只执行一次(每个实体)。请注意,您可以将(map :v)替换为(map :e)来检索其实体ID。

如果您 真的 担心性能并愿意使用额外的内存来实现它,请使用:

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

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

这会创建您的函数的memoized版本。此版本具有更强大的性能保证,因为您的谓词函数最多运行 (即每个不同的值一次),如果您的属性值是有限集的一部分,它可以为您提供卓越的性能。 / p>

有关完整的代码示例,请参阅https://gist.github.com/a2ndrade/5651065

答案 1 :(得分: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中受益?