2

我希望能够做这样的事情:

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

2 回答 2

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

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

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

于 2013-05-25T23:04:50.170 回答
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 集合模拟了数据库。

根据这个输出,你的正则表达式有一个子表达式——这就是为什么你可能会看到它“每个实体两次”。

我想知道您是否可以从Datomicfilter功能中受益?

于 2013-05-08T04:47:06.447 回答