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

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

タグ:plugin

ElasticSearch で英語以外のテキストを使った検索エンジンを実装しようとすると、多くの場合 ICU(International Components for Unicode) というプラグインを使うことになります。特に日本語を扱う場合は kumoroji プラグインとセットで使うことが多いようですが、日本語文字列を正規化してフィルタリングをかける場合のデファクトスタンダードになっている組み合わせだと思います。

この ICU プラグインを ElasticSearch に導入する方法は ICU プラグインのホームページに記載されています:
https://github.com/elastic/elasticsearch-analysis-icu


具体的な導入方法は上記ページ内に記述されているように、コマンドラインから
# bin/plugin -install elasticsearch/elasticsearch-analysis-icu/(ICU のバージョン番号)

と入力・・・ だと思っていました。ところがこの方法は ElasticSearch のバージョンが 1.x までの頃の話でした:
2016111801


現在、多くの人が使っている ElasticSearch のバージョンは 2.x 以上だと思っています(2016/Nov/18 時点の最新バージョンは 5.0)。では ElasticSearch 2.x で ICU を導入するにはどのようにすればいいのでしょうか?

答はこれでした。かなりシンプルになりました:
# bin/plugin -install analysis-icu

これ、公式のどこかに書いてないのかな・・・

世のノーツ開発者の興味が XPages に寄っている中で、1世代前の技術情報になることをご容赦ください(苦笑)。

久しぶりに触ったノーツに、久しぶりにプラグインをインストールしようとしてハマりました。何言っても言い訳になることはわかった上で、でもこの業界で1年半のブランクは大きいようです(苦笑)。


ノーツ(IBM Notes) はバージョン8から Eclipse RCP(Rich Client Platform) をベースとしたクライアントに生まれ変わり、Eclipse 向けに提供されているプラグインをノーツにもインストールできるようになりました。そもそも Eclipse は開発環境なので、世に出ているプラグインは開発環境向けのものが多いです。それもあって、プラグインの互換性は100%ではないのですが、Eclipse のプラグイン開発技術やスキルを使ってノーツの機能拡張もできるようになった、というものでした。

Eclipse の場合、プラグインをインストールしようとするとメニューの Help から Install New Software を選んで・・という手順になります:
2015030101


ノーツの場合はその方法からして異なるのですが、実はそれ以前に「そもそもプラグインインストールをメニューに表示するための準備」が必要でした。

それが
 (ノーツをインストールしたディレクトリ)/framework/rcp/plugin_customization.ini ファイルに
 com.ibm.notes.branding/enable.update.ui=true の一行を追加する
というもの。これをしてノーツを再起動すると、メニューの File - Application からインストールができるようになる・・・ はずだったのです。

でも試してみたらこんな感じ。File - Application までは表示されるのですが、その先にインストールの選択肢がありません:
2015030102


あれ?これは何?? と驚きましたが、どうやらノーツのバージョン9からこの部分の仕様が変更されていた模様です。詳しくはこちらの Technote にかかれていましたが、この設定に加えてランタイム設定の com.ibm.notes.branding.prefs ファイルから一行削除する必要がありそうでした:
[ファイル] - [アプリケーション] - [インストール] メニューが plugin_customization.ini ファイルで設定しても表示されない


ここまでの設定をしてノーツを再起動すると、無事にインストールメニューまでが表示されるようになりました:
2015030103


うーん、しばらく離れていて気づきませんでした。いつの間に・・・

この方法で UpdateSite の URL を指定して Eclipse プラグインをインストールすることができます。

またノーツ用の拡張機能を使って Eclipse プラグインを開発することもできますが、その手順の解説がどこかにないかなあ、と探していたら、こんなページを見つけてしまいました。今となっては懐かしくもあり、恥ずかしくもある技術解説ページです:
Lotus Notes 8 プラグインでグラフィックコンテキストを利用する



で、個人的にこんなの(画面右)を作ってたりします:
2015030104

このプラグインはいずれ公開したいとずっと思っていて、でもそれには公開 Domino サーバーが必要で、さてどうしたものか・・・と悩んでいたのですが、最近になって IBM Bluemix を使う方法を思いつきました。いずれ公開しますのでお楽しみに。なお、その際はこのページに書かれた設定も必要になると思うので、その時にまた参照してください。




WordPress は世界中の多くのサイトで使われているオープンソースコンテンツ管理システムです。

ブログシステムとして使っている人も多いと思いますが、ウェブサイトのコンテンツ管理システムとしてもよく使われています。そしてユーザーが多いこととオープンソースであることからコミュニティも形成され、WordPress 自体をさらに便利にするプラグインも多く開発され、公開されています。

先日(2015/Feb/25)、WordPress の Twitter プラグインが公開されました。しかもこれ、ツイッター社が作った「純正プラグイン」です。 面白そうなので試してみました。


以下にその手順を紹介しますが、実際に試してみるには管理者権限でアクセスできる WordPress 環境が必要です。もし新たに作成する必要があれば、IBM Bluemix を使うことで無料の WordPress サーバー環境を構築することができます。詳しくはこちらの紹介記事も参照ください:
IBM Bluemix で無料の WordPress 環境を構築する


管理者として使える WordPress 環境が用意できたら実際に Twitter プラグインを導入して使ってみます。まずは管理者ページ(http://(WordPress サーバー)/wp-admin/)にログインし、「プラグイン」 - 「新規追加」 で "twitter" と入力して検索します。すると多くの twitter 関連プラグインが見つかりますが、その中に作成者が "Twitter" となっている純正プラグインがるので、それを選んで「いますぐインストール」ボタンをクリックします:
2015022601


Twitter プラグインがインストールされます。完了したら「プラグインを有効化」をクリックしてサイト内で有効にします:
2015022602


次に有効にしたプラグインの動作環境設定を行います。「プラグイン」パネルを選ぶと、インストール済みプラグインの一覧が表示されます。その中に「Twitter」が追加できているはずなので、その「設定」をクリックします:
2015022603


Twitter プラグインの設定が表示されます。ツイートボタンをクリックした時の動作として特定の Twitter ユーザーへのメンションを行う設定や、ツイートボタンの表示位置などを指定できます。最後に保存します:
2015022604


これで Twitter プラグインが有効になって、設定した内容で動くはずです。試しにこの WordPress サイト内のツイートを1つ表示すると、Twitter の「ツイート」ボタンが追加されているはずです:
2015022605


このボタンをクリックすると、このページへのリンクが付与されたツイートが、エントリタイトルと併せて表示されます。またこの例では @dotnsf (僕です)ユーザーへのメンションが付与されるようになっています:
2015022606


最後にこのツイートテキストの内容をカスタマイズする方法も紹介します。管理者権限でこのツイートの編集画面(あるいは新規投稿時の作成画面)の下の方に、Twitter カスタムテキストの設定が追加されているはずです。この中のテキストを変更したり、あるいはハッシュタグを付けて保存します:
2015022607


この状態で先ほどのツイートボタンをクリックすると、今度はツイート内容が指定したテキストになっているはずです。またハッシュタグを指定していた場合はその内容も含まれているはずです:
2015022608


シンプルな内容ですが、WordPress のコンテンツが簡単に Twitter ボタンと連携できるようになっていると思います。ブログコンテンツをカスタマイズしてツイートしたい(させたい)時に便利です。


なお、管理者画面のプラグイン一覧の "Twitter" で「編集」をクリックすると、このプラグインの PHP ソースコードが確認できます。ツイッター社の純正 PHP コードが目にできるのは珍しい機会なので、書き方とか興味ある人はこちらも見ておくといいかも:
2015022609












 

最近のマイブームの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 なので、プログラマ的にも便利で楽しそうな検索エンジンです。



 

このページのトップヘ