先日のohkawaさんの記事に比べると大分カジュアルな内容になります。m(_ _)m
あれと比べると全然時間かけてません。
jruby sinatraでつくるスタンドアローンサーチエンジン
jruby sintraにelasticsearchを内蔵した簡易サーチエンジンを作ってみました。
注意) 実用的ではありません、やりたかっただけです。
sinatraで作ったオレオレサーバーにelasticsearchを組み込み
簡易REST APIから検索できるようにしてみました。
config/elasticsearch.ymlを適切に設定すれば既存のelasticsearch clusterに接続することももちろん可能です。
(そこまでするなら普通にruby api使えよって説もある)
webサーバーにはpumaを使用していて、それなりにパフォーマンスは出るはずです。
とりあえず動かす
gradleインストール
for mac
$ brew install gradle
起動
$ git clone git@github.com:shinjiikeda/jruby_embedded_elasticsearch.git
$ ./gradlew run
elasticsearch起動を確認
$ curl -XGET http://localhost:9200/
elasticsearchのendpointもそのまま使えます。
データフィード
データフィードはelasticsearchのAPIをそのまま使います。
別のターミナルから
$ cd example
$ ./import.sh
テスト
$ curl -XGET http://localhost:4567/test/type1?query=test1
{
"took" : 12,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 1,
"max_score" : 0.4375,
"hits" : [ {
"_index" : "test",
"_type" : "type1",
"_id" : "1",
"_score" : 0.4375,
"_source":{ "title" : "test1", "description": "a b c d" }
} ]
}
}
解説
Directoryレイアウト
config/ <- elasticsearch.ymlなどelasticsearchのコンフィグはここ
scripts/ <- ruby scriptはここ
data/ <- elasticsearchのindexはここ
plugins/ <- elasticsearchのpluginはここにいれる
ruby rest apiソース
scripts/app.rb
# encoding; utf-8
require 'java'
java_import org.elasticsearch.node.NodeBuilder
java_import org.elasticsearch.action.search.SearchResponse
java_import org.elasticsearch.action.search.SearchType
java_import org.elasticsearch.index.query.QueryBuilders
java_import org.elasticsearch.index.query.QueryStringQueryBuilder
require 'sinatra/base'
require 'json'
$node = NodeBuilder.nodeBuilder().node();
$client = $node.client();
class App < Sinatra::Base
configure do
end
get '/:index/:type' do
index = @params['index']
type = @params['type']
query = @params['query']
fields = ! @params['fields'] ? ["_all"] : @params['fields'].split(/,/)
from = @params['from'] ? @params['from'].to_i : 0
size = @params['size'] ? @params['size'].to_i : 10
qsq = QueryBuilders.queryStringQuery(query)
fields.each do | f |
qsq.field(f)
end
qsq.defaultOperator(QueryStringQueryBuilder::Operator::AND)
response = $client.prepareSearch(index)
.setTypes(type)
.setSearchType(SearchType::DFS_QUERY_THEN_FETCH)
.setQuery(qsq)
.setFrom(from).setSize(size)
.execute()
.actionGet()
response.to_s
end
run!
end
今回は時間もなかったのでjava apiを直で呼んでおります。
この辺は好きに加工してもらっていいと思います。
出力形式もhaml等使ってカスタマイズも簡単です。
小規模の検索サービスで既存のものを置き換えたいとか専用api作る必要あるけど、それだけのためにelasticsearchとapiをそれぞれ立てるのが面倒くさいときなどに役に立つかもしれません。