clojuredatomic

Why the fulltext search failed on Datomic?


Tested on datomic-free 0.9.5697, clojure 1.10.3 and 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: #{}

Why did the above fulltext search return empty?


Solution

  • As @Steffan Westcott has pointed out, we need add :db/fulltext true to the desired attribute in the schema thus enable the feature of fulltext search on it. Now it works after wasting hours to find out myself. Thanks a ton, Steffan.

    According to the doc,

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

    So the said schema is corrected below,

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

    We can demonstrate that fulltext search on Datomic works by another example below - find who are "Smith" and "music" is one of their hobbies.

    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
    

    run it to get the expected result below,

    $ 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]}