Elastischを使ってClojureで全文検索

# Elastischとは

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

# インストール

## Elasticsearchのインストール

最新バージョンを[公式サイト](http://www.elasticsearch.org/)からインストール(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を使う](http://www.drunk-boarder.com/blog/elasticsearchhead/)

[elasticsearchで日本語全文検索](http://www.drunk-boarder.com/blog/kuromoji/)

[Elasticsearch 日本語で全文検索 その１](https://medium.com/hello-elasticsearch/91c9f22c663a)

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

## 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入門](http://sssslide.com/speakerdeck.com/johtani/elasticsearchru-men)

[Hello! Elasticsearch](https://medium.com/hello-elasticsearch)

[実践！Elasticsearch](http://engineer.wantedly.com/2014/02/25/elasticsearch-at-wantedly-1.html)

を参考にしてください．

データ登録は，

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

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