为什么在 Datomic 上全文搜索失败?

Why the fulltext search failed on Datomic?

datomic-free 0.9.5697、clojure 1.10.3 和 openjdk 17.01 上测试。

(require '[datomic.api :as d])

(def uri "datomic:mem://test")
(d/create-database uri)
(def conn (d/connect uri))
(def db (-> conn d/db delay))

(def schema [{:db/ident :person/name
              :db/valueType :db.type/string
              :db/cardinality :db.cardinality/one}])
(d/transact conn schema)

(def datoms [{:person/name "Oliver Smith"}])
(d/transact conn datoms)

(def query '[:find ?name
             :where
             [_ :person/name ?name]])
(-> (d/q query @db) println) ; ok => #{[Oliver Smith]}

(def query '[:find ?name
             :where
             [(fulltext $ :person/name "Smith") [[_ ?name]]]])

(-> (d/q query @db) println) ; nok => expected: #{[Oliver Smith]}, actual: #{}

为什么上面fulltext搜索return为空?

正如@Steffan Westcott 指出的那样,我们需要将 :db/fulltext true 添加到模式中所需的属性,从而启用对其进行全文搜索的功能。现在,在浪费数小时来了解自己之后,它开始起作用了。非常感谢,Steffan。

根据doc,

:db/fulltext specifies a boolean value indicating that an eventually consistent fulltext search index should be generated for the attribute. Defaults to false.

所以在下面更正了所述架构,

(def schema [{:db/ident :person/name
              :db/valueType :db.type/string
              :db/cardinality :db.cardinality/one
              :db/fulltext true}
            ])

我们可以通过下面的另一个例子来证明 Datomic 上的全文搜索是有效的——找到谁是“Smith”,“music”是他们的爱好之一。

test.clj

(require '[datomic.api :as d])

(def uri "datomic:mem://test")
(d/create-database uri)
(def conn (d/connect uri))
(def db (-> conn d/db delay))

(def schema [{:db/ident :person/name
              :db/valueType :db.type/string
              :db/cardinality :db.cardinality/one
              :db/fulltext true}
             {:db/ident :person/hobby
              :db/valueType :db.type/string
              :db/cardinality :db.cardinality/one
              :db/fulltext true}
             ])
(d/transact conn schema)

(def datoms [{:person/name "Oliver Smith" :person/hobby "reading, sports and music"}
             {:person/name "Amelia Smith" :person/hobby "reading, music and dance"}
             {:person/name "George Smith" :person/hobby "reading and sports"}
             {:person/name "Amelia Jones" :person/hobby "reading, music and dance"}
             ])
(d/transact conn datoms)

(def query '[:find ?name ?hobby
             :where
             [(fulltext $ :person/name "Smith") [[?p ?name]]]
             [(fulltext $ :person/hobby "music") [[?p ?hobby]]]
             ])
(-> (d/q query @db) println) ; ok

运行 得到下面的预期结果,

$ clj -Sdeps '{:deps {com.datomic/datomic-free {:mvn/version "0.9.5697"}}}' -M test.clj

stdout: #{[Oliver Smith reading, sports and music]
          [Amelia Smith reading, music and dance]}