まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:elasticsearch

(注 今回のエントリは以下の内容が古くなってしまったため、新たに書き直したものです)



全文検索エンジン ElasticSearch に日本語形態素解析ソフトウェア Kuromoji のプラグインを導入して日本語全文検索エンジンを作ります。なおプラットフォームは CentOS 6 を前提とします。


まず ElasticSearch の動作に必要な Java 環境を用意します。Oracle Java を導入しても構いませんが、Open Java であれば以下のコマンドで導入可能です(Java 7 の場合):
# yum install java-1.7.0-openjdk

次に検索エンジンである ElasticSearch 本体を導入します。公式サイトから最新版(2016/07/11時点では 2.3.4)のインストールモジュールをダウンロードします。インストールモジュールにはいくつかの種類はありますが、今回は rpm パッケージ版(elasticsearch-2.3.4.rpm)をダウンロードします:
https://www.elastic.co/downloads/elasticsearch

2016071101


ダウンロードできたら rpm コマンドでインストールして起動、および自動起動設定までを行います。ちなみにこの rpm 版をインストールした場合、ElasticSearch 本体は /usr/share/elasticsearch/ 以下に導入されます :
# rpm -ivh elasticsearch-2.3.4.rpm
# /etc/init.d/elasticsearch start
# chkconfig elasticsearch on

これで ElasticSearch 本体の導入は完了しました。続けて Kuromoji (とウェブ GUI である head)を導入します。いったん ElasticSearch を止めた上で本体のディレクトリに移動し、それぞれのプラグインを導入します:
# /etc/init.d/elasticsearch stop
# cd /usr/share/elasticsearch
# bin/plugin install analysis-kuromoji
# bin/plugin install mobz/elasticsearch-head

設定ファイル(/etc/elasticsearch/elasticsearch.yml)を編集します。まずデフォルトの状態だとウェブ GUI にはローカルホストからでないとアクセスできません。何かと不便なので外部からもアクセスできるように変更します(以下の例では全てのホストからのアクセスを許可しています)。また解析エンジンのデフォルトとして Kuromoji を利用するよう変更します:
(/etc/elasticsearch/elasticsearch.yml)

# allow http connection from every hosts
network.host: 0.0.0.0

# set kuromoji as default Tokenizer
index.analysis.analyzer.default.type: custom
index.analysis.analyzer.default.tokenizer: kuromoji_tokenizer

この状態で ElasticSearch を起動すれば日本語全文検索エンジンとしての ElasticSearch が、ウェブ GUI 付きで稼働します:
# /etc/init.d/elasticsearch start

ウェブ GUI にアクセスするにはウェブブラウザから http://(ElasticSearch のホスト):9200/_plugin/head/ にアクセスします:

2016071102


では実際に日本語データを挿入して検索してみましょう。以下の内容のテキストを manho.json という名前で保存します:
(manho.json)

{"create":{"_id":"4442072443477838363"}}
{"id": 4442072443477838363,"username": "michelle_yama","created": "2016/07/11 12:49:25","updated": "2016/07/11 12:49:25","tag": "","filename": "","type": "image/jpeg","address": "","text": "","lat": 35.6565093994141,"lng": 139.752868652344,"nice": 0,"niceby": "","width": 480,"height": 360,"imgkey": "","misc": "東京都港区芝大門2丁目1"}

{"create":{"_id":"5545583388040541151"}}
{"id": 5545583388040541151,"username": "42ER03","created": "2016/07/11 05:59:20","updated": "2016/07/11 05:59:20","tag": "市章と市の花「ツツジ」","filename": "20051119兵庫県加古川市山手2丁目29-12地先_ .jpg","type": "image/jpeg","address": "","text": "平成17年11月撮影","lat": 34.78293426048821,"lng": 134.88915952863033,"nice": 0,"niceby": "","width": 480,"height": 480,"imgkey": "","misc": "兵庫県加古川市山手2丁目27"}

{"create":{"_id":"1831807387175567807"}}
{"id": 1831807387175567807,"username": "ippei0605","created": "2016/07/10 23:07:24","updated": "2016/07/11 16:01:52","tag": "居合の稽古","filename": "image.jpeg","type": "image/jpeg","address": "","text": "","lat": 35.76108611111111,"lng": 139.5356611111111,"nice": 1,"niceby": "dotnsf","width": 480,"height": 360,"imgkey": "","misc": "東京都東久留米市新川町1丁目10 都道125号線"}

{"create":{"_id":"3546975096233083798"}}
{"id": 3546975096233083798,"username": "dotnsf","created": "2016/07/10 22:28:51","updated": "2016/07/10 22:28:51","tag": "hiroshima shobara","filename": "hilside.jpg","type": "image/jpeg","address": "","text": "国営備北丘陵公園内のヒルサイドパークマンホール","lat": 34.83977596170017,"lng": 132.99681892575074,"nice": 0,"niceby": "","width": 269,"height": 480,"imgkey": "","misc": "広島県庄原市上原町1300"}

{"create":{"_id":"4946513086810703103"}}
{"id": 4946513086810703103,"username": "minamu4545","created": "2016/07/10 21:06:11","updated": "2016/07/10 21:08:31","tag": "","filename": "image.jpeg","type": "image/jpeg","address": "","text": "某水泳アニメの聖地となった岩美町の色蓋(おすい)。<br/>浦富海岸が描かれて美しい蓋。此の蓋もかなり美しいですが、實際の海岸はもっと美しかったです。<br/>色蓋は浦富海岸沿いの縣道155號線にたくさん設置されてますが、路上なので状態は惡いものが多いです。<br/>此の蓋もガムが付いて無ければ完璧だったのですが殘念です。蓋にガム捨てるのほんとやめて欲しい。<br/>","lat": 35.59056896685199,"lng": 134.32106172622503,"nice": 0,"niceby": "","width": 480,"height": 480,"imgkey": "","misc": "鳥取県岩美郡岩美町大字浦富 県道155号線"}

{"create":{"_id":"7542390449304551253"}}
{"id": 7542390449304551253,"username": "42ER03","created": "2016/07/10 07:50:19","updated": "2016/07/10 07:50:19","tag": "ビルバオ市の市章","filename": "20140731③ビルバオ03_.jpg","type": "image/jpeg","address": "","text": "2014年07月撮影/グッゲンハイム美術館付近","lat": 43.26813637672919,"lng": -2.9336467575902736,"nice": 0,"niceby": "","width": 480,"height": 480,"imgkey": "","misc": "スペイン"}

{"create":{"_id":"8484297972018100687"}}
{"id": 8484297972018100687,"username": "42ER03","created": "2016/07/09 08:17:30","updated": "2016/07/09 08:17:30","tag": "高崎まつり","filename": "20160610,1156,03群馬県高崎市高崎駅東口_.jpg","type": "image/jpeg","address": "","text": "平成28年06月撮影","lat": 36.32132769063828,"lng": 139.01428243101884,"nice": 0,"niceby": "","width": 480,"height": 480,"imgkey": "","misc": "群馬県高崎市栄町16"}

{"create":{"_id":"4255462064362665608"}}
{"id": 4255462064362665608,"username": "minamu4545","created": "2016/07/08 19:42:02","updated": "2016/07/08 19:43:49","tag": "","filename": "image.jpeg","type": "image/jpeg","address": "","text": "にかほ市(旧象潟町)小滝地區の農業集落排水の色蓋。<br/>描かれているのは奈曽の白滝。<br/>奈曽の白滝の駐車場前の歩道に設置されていますが劣化が激しいです。<br/>ちなみに、駐車場の横には農業集落排水の処理場があります。","lat": 39.18138258105665,"lng": 139.94690930427362,"nice": 0,"niceby": "","width": 480,"height": 480,"imgkey": "","misc": "秋田県にかほ市象潟町小滝"}

{"create":{"_id":"5394969523646972723"}}
{"id": 5394969523646972723,"username": "ujiteaa","created": "2016/07/08 06:08:46","updated": "2016/07/08 06:08:46","tag": "埼玉県川越市旭町","filename": "_20160708_053352.JPG","type": "image/jpeg","address": "","text": "","lat": 35.690625,"lng": 139.699788,"nice": 0,"niceby": "","width": 473,"height": 480,"imgkey": "","misc": "東京都新宿区西新宿1丁目1"}

{"create":{"_id":"3662100910616235567"}}
{"id": 3662100910616235567,"username": "ujiteaa","created": "2016/07/08 06:07:30","updated": "2016/07/08 06:07:30","tag": "埼玉県川越市","filename": "_20160708_053352.JPG","type": "image/jpeg","address": "","text": "","lat": 35.690625,"lng": 139.699788,"nice": 0,"niceby": "","width": 473,"height": 480,"imgkey": "","misc": "東京都新宿区西新宿1丁目1"}

この内容をバルク API でまとめて挿入します。以下の例ではインデックスに manholes、タイプに geo を指定しています:
# curl -XPOST http://localhost:9200/manholes/geo/_bulk --data-binary @manho.json

ではこの状態で「美しさ」というキーワードで検索してみましょう:
# curl -X GET http://localhost:9200/manholes/geo/_search -d '{"query":{"match":{"text":"美しさ"}}}'

{
  :
 "hits":{
  "total":2,
  "max_score":0.045926645,
  "hits":[
   {
    "_index":"manholes",
    "_type":"geo",
    "_id":"4946513086810703103",
    "_score":0.045926645,
    "_source":{
     "id": 4946513086810703103,
       :
     "text": "某水泳アニメの聖地となった岩美町の色蓋(おすい)。&lt;br/&gt;浦 富海岸が描かれて美しい蓋。此の蓋もかなり美しいですが、實際の海岸はもっと美しかったです。&lt;br/&gt;色蓋は浦富海岸沿いの縣道155號線にたくさん設置されてますが、路上なので状態は惡いものが多いです。&lt;br/&gt;此の蓋もガムが付いて無ければ完璧だ ったのですが殘念です。蓋にガム捨てるのほんとやめて欲しい。&lt;br/&gt;",
       :
   },
   {
    "_index":"manholes",
    "_type":"geo",
    "_id":"4255462064362665608",
    "_score":0.0049227546,
    "_source":{
     "id": 4255462064362665608,
       :
     "text": "にかほ市(旧象潟町)小滝地區の農業集落排水の色蓋。&lt;br/&gt;描かれているのは奈曽の白滝。&lt;br/&gt;奈曽の白滝の駐車場前の歩道に設置されていますが劣化が激しいです。&lt;br/&gt;ちなみに、駐 車場の横には農業集落排水の処理場があります。",
       :
   }
  ]
 }
}

「美しさ」で完全一致するデータは存在しませんが、「美しい」でヒットしたようです。正しく日本語が形態素解析されて判断されていることがわかります。

というわけで、日本語全文検索エンジンの出来上がり!


最近のマイブームの1つになっている、全文検索エンジン ElasticSearch に MySQL のデータを取り込んで、MySQL データベースの全文検索エンジンとして ElasticSearch を使う手順の紹介です。
2014070401


まず検索エンジンである ElasticSearch を導入します。日本語形態素解析エンジンである Kuromoji まで含めてのインストール手順を別エントリで紹介しているので、こちらを参照ください:
ElasticSearch に Kuromoji プラグインを導入する


また取り込み先である MySQL サーバーについても環境は構築済みであると仮定します。こちらの構築手順についても、こちらのエントリを参照ください:
CentOS に MySQL をインストール/セットアップする

なお、自分個人的には MySQL ではなく MariaDB を使って同じことをできているので、以下の内容に関しては MariaDB でも同様に可能だと思っています。


さて、ElasticSearch に MySQL データを取り込むための準備として ElasticSearch 自体のインストール後に以下のステップを行う必要があります:
1. (MySQL クライアントと)JDBC ドライバの導入
2. JDBC River プラグインのインストール


最終的には ElasticSearch の River プラグインと呼ばれる拡張機能を使って MySQL からのデータ取り込みを行います。このプラグインの動作に必要な MySQL JDBC ドライバを先にインストールしておく、というステップになります。


まず、これは必須ではありませんが、あると確認に便利なので MySQL のクライアント環境を ElasticSearch サーバー内に構築しておきます。MySQL サーバーに接続する機能があればいいので、MySQL サーバー機能は不要で、クライアント機能だけが必要、ということになります。もし MySQL サーバーと ElasticSearch サーバーが同じサーバーだとすると、既に MySQL クライアント環境は導入済みだと思うので、インストールは不要です。 MySQL クライアントが導入されていない場合は以下のコマンドで MySQL クライアントをインストールします:
# yum install mysql
# vi /etc/my.cnf
  :
(以下の2行を追加)
[mysql]
default-character-set=utf8

MySQL クライアントが導入できた所で、取り込み元の MySQL サーバーへ接続してみます。仮に今回取り込むデータの内容が以下であると仮定します:
 MySQL サーバー: mysql.mylocal.com
 ユーザー名: username
 パスワード: password
 データベース名: mydb
 取り込む内容: samples テーブル


実際に MySQL クライアントで目的のデータベースにアクセスしてみます。ここまでが出来るようであればファイアウォールなども含めて接続準備ができているといえます:
# mysql -h mysql.mylocal.com -u username -ppassword mydb
> select * from samples;
:
:
(samples テーブルの内容)
:
: > quit


次に MySQL サーバーへ Java 環境から接続するための JDBC ドライバー(MySQL Connector/J)を導入します。ドライバー自体はこちらのサイトからダウンロードできます:
MySQL :: Download Connector/J 


ダウンロードしたファイルを展開して JAR ファイルを取り出し、/usr/share/java にコピーします:
# unzip mysql-connector-java-5.1.30.zip
# cd mysql-connector-java-5.1.30
# cp mysql-connector-java-5.1.30-bin.jar /usr/share/java

環境変数 CLASSPATH に、この JAR ファイルを追加します:
# vi /etc/bashrc
  :
(以下の1行を追加)
export CLASSPATH=$CLASSPATH:/usr/share/java/mysql-connector-java-5.1.30-bin.jar
 

# source /etc/bashrc

JDBC ドライバの準備が出来た所で River プラグインをインストールします。リポジトリを確認したところ、2014/07/01 時点での最新バージョンは 1.2.1.1 だったので、このバージョンを指定して導入します:
# /usr/share/elasticsearch/bin/plugin --install jdbc --url http://xbib.org/repository/org/xbib/elasticsearch/plugin/elasticsearch-river-jdbc/1.2.1.1/elasticsearch-river-jdbc-1.2.1.1-plugin.zip
# cp /usr/share/java/mysql-connector-java-5.1.30-bin.jar /usr/share/elasticsearch/plugins/jdbc/

これで必要なソフトウェアは揃いました。では実際に MySQL からデータを取り込んでみましょう

まず ElasticSearch 側に kuromoji を使った検索インデックス(kuromoji_sample)を作成します。インデックスの作成については別エントリでも紹介しましたが、まだこの内容を実行していない場合は以下のコマンドを実行します(コマンドは黒字部分で、青字はレスポンスを表しています):
# curl -XPUT http://localhost:9200/kuromoji_sample -d '{ "index": { "analysis": { "tokenizer": { "kuromoji_user_dict" : { "type":"kuromoji_tokenizer" } }, "analyzer": { "analyzer": { "type":"custom", "tokenizer": "kuromoji_user_dict" } } } } }'
{"acknowledged":true}

次に River を使って、作成した kuromoji_sample インデックスに MySQL データベースサーバーからデータを取り込みます:
# curl -XPUT http://localhost:9200/_river/my_jdbc_river/_meta -d '{ "type": "jdbc", "jdbc": { "url": "jdbc:mysql://mysql.mylocal.com:3306/mydb", "user": "username", "password": "password", "sql": "select * from samples", "index": "kuromoji_sample", "type": "samples" } }'
{"_index": "_river", "_type": "my_jdbc_river", "_id": "_meta", "_version": 1, "created": true}

上記入力パラメータ(JSON)の中で選択(select)の SQL を発行しています。この SQL の実行結果が ElasticSearch に取り込まれることになります。

取り込みができたら、最後に検索してみます。この例では取り込んだデータの name フィールドに「ほげほげ」が含まれているデータを検索しています:
# curl -XPOST http://localhost:9200/kuromoji_sample/_search?pretty -d '{ "query": { "query_string": { "query": "name:ほげほげ" } } }'
{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "failed" : 0
  },
  "hits" : {
    "total" : 29,
    "max_score" : 3.687642,
    "hits" : [ {
      "_index" : "kuromoji_sample",
      "_id" : "XXXXXXXXXXXXXX",
      "_score" : 3.687642,
      "_source":{"id":"1234","name":"ほげほげ"}
    }, {
      "_index" : "kuromoji_sample",
        :
    } ]
  }
}

こんな感じで実現できました。

MySQL の like 節を使った単純検索をしていた頃と比べると、以前は localhost 内の MySQL に対して検索していたのでネットワークによる遅延はほとんどなかったはずで、今回作ってみた環境はリモートの ElasticSearch 環境にアクセスしているので、ネットワークの遅延影響がでるはずです。

にも関わらず、検索パフォーマンスは 10 倍程度になりました。これはでかい!

ElasticSearch の検索パターンやその API 実行方法についてはいずれまたプログに書く予定です。


 

(注 この記事は古くなったので、新しい記事をこちらに記載しています)
http://dotnsf.blog.jp/archives/1059206837.html


全文検索エンジン ElasticSearch に日本語形態素解析ソフトウェアである Kuromoji のプラグインを導入して、日本語全文検索環境を構築します。


まずは ElasticSearch をインストールします。ElasticSearch のインストールそのものの手順については以前のエントリを参照してください:
ElasticSearch を導入して CouchBase サーバーの全文検索を行う


ElasticSearch の導入ができたら、この段階で動作確認をしておきます。まずはデータを登録します(青字は実行結果です):
# curl -XPUT http://localhost:9200/mytest/test/1 -d '{ "title":"memo", "text":"ほげほげ" }'

{"_index":"mytest","_type":"test","_id":"1","_version":1,"created":true}


id = 1 のデータとして、title = "memo", text = "ほげほげ" の JSON データを Index = mytest, Type = test で登録しました。次にこのデータを GET メソッドで検索します:
# curl -XGET http://localhost:9200/mytest/test/_search -d '{ "query": { "match": { "title":"memo" } } }'
{"took":54,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":1,"max_score":0.30685282,"hits":[{"_index":"mytest","_type":"test","_id":"1","_score":0.30685282,"_source":{"title":"memo","text":"ほげほげ"}}]}}


title = "memo" のデータを mytest/test で検索した所、"text" = "ほげほげ" の期待通りの結果が得られました!(ただし、この時点ではまだ Kuromoji を使っていません) 動作確認ができたので、このデータを削除しておきます:
# curl -XDELETE http://localhost:9200/mytest/test/1
{"found":true,"_index":"mytest","_type":"test","_id":"1","_version":1}

ElasticSearch が正しく導入できて、動作も確認できた所で Kuromoji プラグインを導入して ElasticSearch を再起動します:
# /usr/share/elasticsearch/bin/plugin --install elasticsearch/elasticsearch-analysis-kuromoji/2.2.0
# /etc/init.d/elasticsearch restart

そして Kuromoji を有効にして、再度簡単な動作確認をしてみます。まずは新しいインデックスを作成して、Kuromoji をアナライザとして指定します:
# curl -XPUT http://localhost:9200/kuromoji_sample -d '{ "index": { "analysis": { "tokenizer": { "kuromoji_user_dict" : { "type":"kuromoji_tokenizer" } }, "analyzer": { "analyzer": { "type":"custom", "tokenizer": "kuromoji_user_dict" } } } } }'
{"acknowledged":true}

この新しく作成したインデックスに対して日本語文字列を POST して、形態素解析が有効になっているかどうかを確認します:
# curl -XPOST 'http://localhost:9200/kuromoji_sample/_analyze?analyzer=analyzer&pretty' -d '東京スカイツリー'
{
"tokens":[{
"token":"東京",
"start_offset":0,
"end_offset":2,
"type":"word",
"position":1
},{
"token":"スカイ",
"start_offset":2,
"end_offset":5,
"type":"word",
"position":2
},{
"token":"ツリー",
"start_offset":5,
"end_offset":8,
"type":"word",
"position":3
}]
}

「東京スカイツリー」が3つの単語に分割できていることがわかります。これが kuromoji による拡張機能です。


この kuromoji を使ったインデックスを ElasticSearch のデフォルトアナライザとして指定し、ElasticSearch を再起動します:
# vi /etc/elasticsearch/elasticsearch.yml
  :
index.analysis.analyzer.default.type: custom
index.analysis.analyzer.default.tokenizer: kuromoji_user_dict
  :
# /etc/init.d/elasticsearch restart

では改めて2つの日本語データを登録しておきます:
# curl -XPUT http://localhost:9200/kuromoji_sample/test/1 -d '{ "title":"メモ1", "text":"カレーは飲み物" }'
{"_index":"kuromoji_sample","_type":"test","_id":"1","_version":1,"created":true}

# curl -XPUT http://localhost:9200/kuromoji_sample/test/2 -d '{ "title":"メモ2", "text":"カレーライスは和食" }' {"_index":"kuromoji_sample","_type":"test","_id":"2","_version":1,"created":true}

そして、まずは「カレー」で検索してみます:
# curl -XGET http://localhost:9200/kuromoji_sample/test/_search -d '{"query":{"match":{"text":"カレー"}}}'
{
"took":67,"timed_out":false,"_shards":{
"total":5,"successful":5,"failed":0
},"hits":{
"total":1,"max_score":0.15342641,"hits":[{
"_index":"kuromoji_sample","_type":"test","_id":"1","_score":0.15342641,"_source":{
"title":"メモ1","text":"カレーは飲み物"
}
}]
}
}

正しく「カレーは飲み物」のデータがヒットすることが確認できます。気づいていただきたいのは、この時に2番目の「カレーライスは和食」のデータがヒットしていないということです。Kuromoji は「カレー」と「ライス」ではなく、「カレーライス」という単語を認識しているのだと想像できます。

次に「カレーは」で検索します:
# curl -XGET http://localhost:9200/kuromoji_sample/test/_search -d '{"query":{"match":{"text":"カレーは"}}}'
{
"took":8,"timed_out":false,"_shards":{
"total":5,"successful":5,"failed":0
},"hits":{
"total":2,"max_score":0.2169777,"hits":[{
"_index":"kuromoji_sample","_type":"test","_id":"1",
"_score":0.2169777,"_source":{
"title":"メモ1","text":"カレーは飲み物"
}},{
"_index":"kuromoji_sample","_type":"test","_id":"2",
"_score":0.02250402,"_source":{
"title":"メモ2","text":"カレーライスは和食"
}}]
}
}

2つのデータがヒットしています。ここでは "_score" の値に注目します。

_id = 1 のデータでは「カレーは飲み物」という7文字のうち4文字が一致しているため、そのスコアが高くなっています。一方、_id = 2 のデータでは「カレーライスは和食」という9文字のうち「カレー」という3文字と「は」という1文字しか一致していないこともあり、そのスコアが低くなっています。その結果、前者の方がより高い精度で一致していると判断されていることになります。これによってスコア付きの日本語検索も有効に行われていることが分かります。


結構簡単に日本語検索エンジンが作れてしまいました。ElasticSearch は REST でデータの読み書きができるし、Input/Output のフォーマットが JSON なので、プログラマ的にも便利で楽しそうな検索エンジンです。



 

CouchBase サーバーは高速なドキュメント指向(JSON)データベースです。高速・大容量のデータを得意とする一方、SQL 型と異なり、SQL select による(like 節による)全文検索は苦手です。

ただ CouchBase は Apache Lucene をベースとするオープンソースでスケーラブルな全文検索&解析エンジン ElasticSearch と連携することで、この苦手部分を補っています。単なる SQL select よりも強力な検索エンジンと組み合わせることで CouchBase サーバーは更に強力なデータベースとなります。


この CouchBase サーバー環境に ElasticSearch を導入して連携させるところまでの手順を紹介します。なお CouchBase サーバー自体の導入はこちらを参照してください。CouchBase サーバーの導入まではできているという前提で、また今回は CouchBase サーバーと同じサーバー内に ElasticSearch サーバーを導入して環境構築するという前提で以下を記述します。また以下の内容についてはこの記事を記載している 2014/06/11 時点の最新環境である CouchBase 2.5.1 / ElasticSearch 1.2.1 / Couchbase Plug-in for Elasticsearch 1.3.0 の各バージョンにて確認しています。


まず ElasticSearch の動作に必要な Java 環境(Java 6以上)を用意します。Oracle Java を導入しても構いませんが、Open Java であれば以下のコマンドで導入可能です(Java 7 の場合):
# yum install java-1.7.0-openjdk

次に検索エンジンである ElasticSearch 本体を導入します。公式サイトから最新版(2014/06/11時点では 1.2.1)のインストールモジュールをダウンロードします。インストールモジュールにはいくつかの種類はありますが、今回は rpm パッケージ版(elasticsearch-1.2.1.noarch.rpm)をダウンロードします。

ダウンロードできたら rpm コマンドでインストールして起動、および自動起動設定までを行います。ちなみにこの rpm 版をインストールした場合、ElasticSearch 本体は /usr/share/elasticsearch/ 以下に導入されます :
# rpm -ivh elasticsearch-1.2.1.noarch.rpm
# /etc/init.d/elasticsearch start
# chkconfig elasticsearch on 

これで検索エンジンの ElasticSearch 本体がインストールされました。が、実際の利用時には CouchBase サーバーのデータを ElasticSearch に複製した上で検索インデックスを作成して、CouchBase サーバーの中に入っているデータに対する検索エンジンとして使いたいのです。 というわけで、これら2つを接続するためのプラグイン(と、ElasticSearch の設定をウェブから行うためのインターフェースアプリケーション)を最後に導入します。
# cd /usr/share/elasticsearch
# bin/plugin -install transport-couchbase -url http://packages.couchbase.com.s3.amazonaws.com/releases/elastic-search-adapter/1.3.0/elasticsearch-transport-couchbase-1.3.0.zip
# echo "couchbase.password: password" >> /etc/elasticsearch/elasticsearch.yml
# echo "couchbase.username: Administrator" >> /etc/elasticsearch/elasticsearch.yml

(以下引き続き ElasticSearch Head(ウェブインターフェース)の導入) # /etc/init.d/elasticsearch stop # bin/plugin -install mobz/elasticsearch-head # /etc/init.d/elasticsearch start

Elastic Head の導入と、ElasticSearch の再起動までができたらウェブブラウザで
 http://(サーバーのIPアドレス):9200/_plugin/head/
にアクセスして、ウェブインターフェースが表示されることを確認してください:
2014061101


接続用プラグインが導入できたので、次はインデックステンプレートを導入します。今回はデフォルトのインデックステンプレートを使って、インストール時に追加した beer-sample サンプルバケットを対象に設定してみます。また ElasticSearch の導入されたホストから実行する前提で記載しているので localhost を使っていますが、ElasticSearch がリモート環境にある場合は localhost 部分を該当ホストの IP アドレスに変えて実行してください:
# cd /usr/share/elasticsearch
# curl -XPUT http://localhost:9200/_template/couchbase -d @plugins/transport-couchbase/couchbase_template.json
 →{ "acknowledged":true } が返ってくることを確認
# curl -XPUT http://localhost:9200/beer-sample
 →{ "ok":true, "acknowledged":true } が返ってくることを確認
# echo "couchbase.maxConcurrentRequests: 1024" >> /etc/elasticsearch/elasticsearch.yml
# /etc/init.d/elasticsearch restart
# curl -X POST -u Administrator:password http://localhost:8091/internalSettings -d xdcrMaxConcurrentReps=8

最後に XDCR の設定をしてデータの複製処理を定義します。
Couchbase ウェブコンソール(http://***:8091) にログインしてします:
2014061102


XDCR タブを開いて、 "Create Cluster Reference" をクリックします:
2014061103


以下を入力して "Save" します:
 Cluster Name: "ElasticSearch"
 IP: (IPアドレス):9091
 Username: Administrator
 Password: (パスワード)
2014061301



Cluster Reference が作成されたことを確認します:
2014061105


続いて "Create Replication" をクリックし、以下を入力して "Replicate" をクリックします:
 From -> Bucket: beer-sample
 To -> Cluster: ElasticSearch
 To -> Bucket: beer-sample
 Advanced -> XCDR Protocol: Version 1
2014061106

 
これで Replication が定義できました:
2014061107
 
 
この状態で改めて Elastic Search のウェブインターフェースにアクセスするとデータの複製が確認できます:
2014061108



では最後にこの環境で CouchBase サーバーに格納したデータが全文検索できることを確認してみましょう。

まずは CouchBase にいくつかのデータを格納してみます。CouchBase ウェブコンソールにログインし、Data Buckets タブを開き、上記で複製の設定を行った beer-sample バケットの右にある Documents ボタンをクリックします:
2014061302


beer-sample バケット内のデータ一覧が表示されます。が、最初の段階ではデータが入ってないので何も表示されません。ここに Document(レコード)を追加してみましょう。Create Document ボタンをクリックします:
2014061303


作成する Document の ID (ハッシュキー)を適当に指定します。ここでは doc001 と入力しています。Create ボタンで作成します:
2014061304


デフォルトの内容で Document が1つ作成されました。Document が JSON フォーマットになっていることが分かります。この画面はエディタなので、ここから Document の中身を変更することも可能です:
2014061305


こんな感じの日本語のデータに書き換えてみました:
{
 "title": "ワールドカップ",
 "body": "がんばれ、日本代表!"
}


Save で保存できます:
2014061306


Documents の一覧に戻ると作成したデータが登録されていることが確認できます。以降この手順を繰り返して Document をいくつか作成しておきます:
2014061307


検索用にいくつかのデータを適当に登録してみます。JSONフォーマットなので "title" や "body" といったフィールド名も自由に追加・変更して格納できます:
2014061308


先程複製の設定を済ませているので、ここで CouchBase サーバーに登録したデータは ElasticSearch に複製されており、全文検索ができるようになっているはずです。ではその様子を確認してみます。

今度は Elastic Head にアクセスしてみて、Browser タブを選択します。この時点では何の絞り込みもしていないので、管理用データも含めて全てのレコードが右側のペインに表示されています:
2014061309


試しに、上記の2番目に登録した、id = doc002 のデータを検索してみます。左側のペインで title と書かれた箇所をクリックして展開し、そのテキストフィールドに "タイトル" と入力すると、右側のペインに id 列が doc002 のデータが見つかるはずです。CouchBase サーバー内のデータが日本語で全文検索できるようになったことが確認できました
2014061310


検索されたレコードをダブルクリックするとこんな画面が表示されます。直接 CouchBase の中身が表示されるわけではなく、ElasticSearch 側に格納されたレコードの情報が表示されるので、実際に検索した文字列が表示されるわけではありません。その代わり「title フィールドに "タイトル" という文字が含まれているレコードの id は doc002」ということが分かりました。実際のアプリケーションではこの結果を元に再度 CouchBase サーバーに id 指定で問い合わせをして、このデータレコードの情報を取得・更新・削除する、という処理フローになります:
2014061311



高速・大規模利用を想定した CouchBase で、ネックだった全文検索(それも日本語の)もこの方法でカバーできるようになりそうです。自分もまだ詳しく理解できているわけではなくて、これから調べることも多そうだけど、これはなかなかヒットの予感。。



 

このページのトップヘ