Clojure
AdventCalendar
Elasticsearch
ClojureDay 19

Elastischを使ってClojureで全文検索

More than 1 year has passed since last update.

Elastischとは

elastischとはApache Lucene上で稼働する全文検索システムElasticsearchのclojureクライアントです.
データをPOSTするだけでインデックスを自動で作成してくれ,
日本語の形態素解析プラグインを入れれば日本語での全文検索も可能になります.
Elasticsearchを使うと,ニュースサイト等の「この記事を読んだ人におすすめ」機能,検索サイトの曖昧検索や「もしかして ・・・」機能を実装することができます.

インストール

Elasticsearchのインストール

最新バージョンを公式サイトからインストール(2014/12/19時点で1.4.2)

$ wget https://download.elasticsearch.org/elasticsearch/elasticsearch/elasticsearch-1.4.2.tar.gz
$ tar -xf elasticsearch.tar.gz
$ rm elasticsearch.tar.gz
$ mv elasticsearch-* elasticsearch

また,mac環境ではbrewを使ってインストールすることも可能です.
起動は./elasticsearch/bin/elasticsearch -f
起動確認はhttp://localhost:9200 にアクセスし,以下のように返ってくれば問題なく稼働しています.

{
  "ok" : true,
  "status" : 200,
  "name" : "Hellstrom, Damion",
  "version" : {
    "number" : "1.4.2",
    "build_hash" : "909b037218cf880e8772b066a764f179f2d5e719",
    "build_timestamp" : "2014-12-18T16:08:16Z",
    "build_snapshot" : false,
    "lucene_version" : "4.6"
  },
  "tagline" : "You Know, for Search"
}

elasticsearchのGUIの使い方や,日本語全文検索の方法は

elasticsearch-headを入れてelasticsearchのGUIを使う

elasticsearchで日本語全文検索

Elasticsearch 日本語で全文検索 その1

等を参考にしてください.

Elastischのインストール

Leiningenを使っているなら、project.cljのdependenciesに以下を加えてください.

[clojurewerkz/elastisch "2.1.0"]

使い方

以下は全てElasticsearchを起動した状態で実行します.

接続,データセット作成

(ns elastisch-sample
  (:require [clojurewerkz.elastisch.rest  :as esr]
            [clojurewerkz.elastisch.rest.index :as esi]
            [clojurewerkz.elastisch.rest.document :as esd]))

(defn -main
  [& args]
  (let [conn          (esr/connect "http://127.0.0.1:9200")
        mapping-types {"book" {:properties {:title      {:type "string" :analyzer "snowball"}
                                              :author     {:type "string"}
                                              :year  {:type "integer"}}}}]

(esi/create conn "testindex" :mappings mapping-types))

まず,(clojurewerkz.elastisch.rest/connect "http://127.0.0.1:9200")でElasticsearchに接続します.
Elasticsearchでは事前にデータセットの型を指定しなくても動作しますが,事前にセットの型を決めるためには,Mappingのための連想配列を作成し,(clojurewerkz.elastisch.rest.index/create conn "testindex" :mappings mapping-types)のように,IndexやType(RDBでのデータベースやテーブル)を生成するのと同時に登録します.この際インデックス作成時やクエリ解析時のデータ処理方法をanalyzerによって指定することも出来ます.

analyzerの詳しい指定法は,

elasticsearch入門

Hello! Elasticsearch

実践!Elasticsearch

を参考にしてください.

データ登録は,

(let [data {:title "primer of elastisch" :author "taro" :year "2014"}]
(clojurewerkz.elastisch.rest.document/create "testindex" "book" data))

のように登録場所のIndex, Typeを指定し,データの連想配列を順次作成・登録していきます.

検索

登録したデータの検索にはclojurewerkz.elastisch.rest.document,clojurewerkz.elastisch.query,clojurewerkz.elastisch.rest.response を用います.

(ns clojurewerkz.elastisch.docs.examples
  (:require [clojurewerkz.elastisch.rest          :as esr]
            [clojurewerkz.elastisch.rest.document :as esd]
            [clojurewerkz.elastisch.query         :as q]
            [clojurewerkz.elastisch.rest.response :as esrsp]
            [clojure.pprint :as pp]))

(defn -main
  [& args]
    (let [conn (esr/connect "http://127.0.0.1:9200")
        res  (esd/search conn "testindex" "book" :query {:term {:title "elistisch"}})
        n    (esrsp/total-hits res)
        hits (esrsp/hits-from res)]
    (println (format "Total hits: %d" n))
    (pp/pprint hits)))

esd/searchにより検索クエリを投げます.上の例ではtitleにelistischが含まれるデータが検索されます.検索ヒット件数は(esrsp/total-hits res)により取得でき,(esrsp/hits-from res)によって以下のように検索結果が取得できます.

[{:_index "testindex",
  :_type "book",
  :_id "AUpi5KYEf1scKu3S3YhW",
  :_score 0.15342641,
  :_source
  {:author "taro", :year "2014", :title "primer of elastisch"}}
 {:_index "testindex",
  :_type "book",
  :_id "AUpi6B8qf1scKu3S3YhZ",
  :_score 0.19178301,
  :_source
  {:author "jiro", :year "2013", :title "effective elastisch"}}
]

上記の例は最も単純な単語検索なので,例えば検索語句をタイポし,elistischで検索をかけた場合は何もヒットしません.このような曖昧検索に対応するために,Elasticsearchにはfuzzy検索機能が実装されており,elasitischからは

res (esd/search conn "testindex" "book" :query {:fuzzy {:title 
                                                    {:value "elistisch"
                                                     :boost 1.2
                                                     :min_similarity 0.5
                                                     :prefix_length 0}}})   

のように呼び出す事で,曖昧検索をおこなうことができます.