我希望能够做到这样的事情:
(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 :(得分: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中受益?