lib.lucene

component-managed Lucene indexing and search

Create memory or disk-backed search engines, define field templates, and query indexed documents through a shared protocol.

1    Overview

LuceneSearch implements the search-engine and component protocols. Configuration selects a store and describes document fields and analyzers.

2    Walkthrough

2.1    Create an engine

(require '[lib.lucene :as lucene])

(def engine
  (lucene/lucene
   {:store :memory
    :template
    {:article
     {:analyzer {:type :standard}
      :type {:id {:stored true}
             :title {:stored true}
             :body {:stored true}}}}}))

2.2    Use the engine protocol

The engine protocol provides document addition, replacement, removal, and search. Stop the component when the engine is no longer required so readers, writers, analyzers, and storage are released.

(require '[lib.lucene.protocol :as search])
(require '[std.lib.component :as component])

(search/index-add engine :article
                  {:id "1" :title "Foundation"}
                  {})
(search/search engine :article {:title "Foundation"} {})
(component/stop engine)

3    API



lucene ^

[m]
Added 3.0

constructs a lucene engine

v 3.0
(defn lucene
  ([m]
   (-> (protocol.search/-create (assoc m :type :lucene))
       (component/start))))
link
(lucene {:store :memory :template {:album {:analyzer {:type :standard} :type {:id {:stored false}}}}}) => lib.lucene.LuceneSearch


-create ^

Added 4.0

creates a lucene object

v 4.0
(defmulti -create
  :type)
link
(defmethod -create :test [_] :created) (-create {:type :test}) => :created


create-analyzers ^

[{:keys [template], :as engine}]
Added 3.0

creates multiple analyzers

v 3.0
(defn create-analyzers
  ([{:keys [template] :as engine}]
   (let [ks (keys template)]
     (reduce (fn [out k]
               (let [analyser (analyzer/analyzer (get-in template [k :analyzer]))]
                 (assoc out k analyser)))
             {}
             ks))))
link
(with-redefs [analyzer/analyzer (constantly :analyzer)] (create-analyzers {:template {:a {}} :root "test"})) => {:a :analyzer}

create-directories ^

[{:keys [store root template refresh], :as engine}]
Added 3.0

create multiple lucene directories

v 3.0
(defn create-directories
  ([{:keys [store root template refresh] :as engine}]
   (let [ks (keys template)]
     (reduce (fn [out k]
               (let [path (str root "/" (name k))
                     _    (if refresh (fs/delete path))
                     directory (index/directory {:store store
                                                 :path path})]
                 (assoc out k directory)))
             {}
             ks))))
link
(with-redefs [index/directory (constantly :dir)] (create-directories {:template {:a {}} :root "test"})) => {:a :dir}

get-index ^

[{:keys [instance]} index]
Added 3.0

gets a particular index

v 3.0
(defn get-index
  ([{:keys [instance]} index]
   (let [directory (get-in @instance [:directories index])
         analyzer  (get-in @instance [:analyzers index])]
     (if (and directory analyzer)
       [directory analyzer]
       (throw (ex-info "Index not found" {:status :error
                                          :tag :index/not-found
                                          :data {:index index}}))))))
link
(get-index {:instance (atom {:directories {:a :dir} :analyzers {:a :analyzer}})} :a) => [:dir :analyzer]

index-add-lucene ^

[{:keys [template], :as engine} index entry opts]
Added 3.0

adds an entry to the index

v 3.0
(defn index-add-lucene
  ([{:keys [template] :as engine} index entry opts]
   (let [[directory analyzer] (get-index engine index)]
     (index/add-entry directory analyzer (get-in template [index :type]) entry opts))))
link
(with-redefs [index/add-entry (constantly :added)] (index-add-lucene {:instance (atom {:directories {:a :dir} :analyzers {:a :analyzer}})} :a {} {})) => :added

index-remove-lucene ^

[engine index terms opts]
Added 3.0

removes an entry from the index

v 3.0
(defn index-remove-lucene
  ([engine index terms opts]
   (let [[directory analyzer] (get-index engine index)]
     (index/remove-entry directory analyzer terms opts))))
link
(with-redefs [index/remove-entry (constantly :removed)] (index-remove-lucene {:instance (atom {:directories {:a :dir} :analyzers {:a :analyzer}})} :a {} {})) => :removed

index-update-lucene ^

[{:keys [template], :as engine} index terms entry opts]
Added 3.0

updates an entry in the index

v 3.0
(defn index-update-lucene
  ([{:keys [template] :as engine} index terms entry opts]
   (let [[directory analyzer] (get-index engine index)]
     (index/update-entry directory analyzer (get-in template [index :type]) terms entry opts))))
link
(with-redefs [index/update-entry (constantly :updated)] (index-update-lucene {:instance (atom {:directories {:a :dir} :analyzers {:a :analyzer}})} :a {} {} {})) => :updated

search-lucene ^

[engine index terms opts]
Added 3.0

searches lucene

v 3.0
(defn search-lucene
  ([engine index terms opts]
   (let [[directory analyzer] (get-index engine index)]
     (index/search directory analyzer terms opts))))
link
(with-redefs [index/search (constantly :found)] (search-lucene {:instance (atom {:directories {:a :dir} :analyzers {:a :analyzer}})} :a {} {})) => :found

start-lucene ^

[{:keys [instance], :as engine}]
Added 3.0

starts the lucene engine

v 3.0
(defn start-lucene
  ([{:keys [instance] :as engine}]
   (swap! instance assoc
          :directories (create-directories engine)
          :analyzers   (create-analyzers engine)) engine))
link
(with-redefs [create-directories (constantly {:a :dir}) create-analyzers (constantly {:a :analyzer})] (let [res (start-lucene {:instance (atom {})})] @(:instance res))) => {:directories {:a :dir} :analyzers {:a :analyzer}}

stop-lucene ^

[{:keys [instance], :as engine}]
Added 3.0

stops the lucene engine

v 3.0
(defn stop-lucene
  ([{:keys [instance] :as engine}]
   (let [{:keys [directories]} @instance]
     (doseq [[k directory] directories]
       (index/close directory))
     (reset! instance nil)
     engine)))
link
(with-redefs [index/close (constantly nil)] (let [res (stop-lucene {:instance (atom {:directories {:a :dir}})})] @(:instance res))) => nil