Regex datomic查询-筛选和绑定的函数

Regex datomic查询-筛选和绑定的函数,regex,clojure,datomic,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 [

我希望能够做到这样:

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

问题似乎是
?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集合模拟了数据库

基于此输出,regex有一个子表达式——这就是为什么您可能会看到“每个实体两次”


我想知道你是否能从中受益

如果您担心性能,请使用:

(->> (d/datoms (d/db conn) :aevt :user/regex-match)
 (filter #(user/match? (:v %)))
 (map :v))
它使用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))
这将创建函数的一个版本。此版本具有更强的性能保证,因为您的谓词函数最多运行一次(即,每个不同的值运行一次),如果您的属性值是有限集的一部分,它可以为您提供优异的性能


有关完整的代码示例,请参见添加(identity?m)而不是调用user/match?这似乎是迄今为止我找到的最好的解决办法。我想知道它在datomic查询中是否惯用?你说“调用<代码>匹配?每个实体两次”是什么意思?你怎么知道?您能否提供一些示例数据(例如Clojure集合)?此外,Clojure正则表达式不要求您转义反斜杠。我不得不把它改成
#“so(\d+)”