Apache Solr を組み込み実行
オープンソースの全文検索エンジン Apache Solr は、 Servlet として実装されており、通常は jetty 等のサーブレットエンジン(コンテナ)で実行しますが、今回は組み込み実行を試してみました。
ソースは http://github.com/fits/try_samples/tree/master/blog/20140710/
はじめに
Solr を組み込み実行 (サーバーを起動せずに直接処理を実行) するには下記のような方法が考えられます。
- (1) EmbeddedSolrServer を使用
- (2) SolrCore を使用
(1) は SolrJ の API を使うので高レベル API、(2) は Core API をそのまま使うので低レベル API といったところでしょうか。
(1) EmbeddedSolrServer を使用
EmbeddedSolrServer
を使って検索処理を実装するのは簡単です。
今回は、実行時引数 (第1引数で Solr のホームディレクトリ、第2引数でコア名) で指定したコアのドキュメントを全件取得するようにしてみました。
search1.groovy
@Grab('org.apache.solr:solr-core:4.9.0') @Grab('org.slf4j:slf4j-nop:1.7.7') import org.apache.solr.core.CoreContainer import org.apache.solr.client.solrj.SolrQuery import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer def cores = new CoreContainer(args[0]) cores.load() def server = new EmbeddedSolrServer(cores, args[1]) // 全件取得のクエリ def q = new SolrQuery(query: '*:*') // 検索 def result = server.query(q) // 結果の出力 result.results.each { println it } server.shutdown()
なお、EmbeddedSolrServer をインスタンス化している箇所を new HttpSolrServer('http://localhost:8983/solr/collection1')
のように書き換えれば、サーブレットエンジン上で実行している Solr サーバーに対して検索を行うようになります。
実行結果は下記の通りです。
実行結果
> groovy search1.groovy /solr-4.9.0/example/solr collection1 [id:GB18030TEST, name:Test with some GB18030 encoded characters, features:[No accents here, ?是一个功能, This is a feature (translated), ??文件是很有光?, This document is very shiny (translated)], price:0.0, price_c:0,USD, inStock:true, _version_:1473119790218346496] ・・・
(2) SolrCore を使用
次に、同様の処理を SolrCore
を使って実装してみました。
SolrCore では XXXResponseWriter (BinaryResponseWriter
や JSONResponseWriter
等) を使って処理結果をストリームへ出力します。
search2.groovy
@Grab('org.apache.solr:solr-core:4.9.0') @Grab('org.slf4j:slf4j-nop:1.7.7') import org.apache.solr.core.CoreContainer import org.apache.solr.request.LocalSolrQueryRequest import org.apache.solr.response.SolrQueryResponse import org.apache.solr.response.BinaryResponseWriter import org.apache.solr.common.util.JavaBinCodec def cores = new CoreContainer(args[0]) cores.load() def core = cores.getCore(args[1]) // 検索ハンドラ取得 def handler = core.getRequestHandler('/query') def req = new LocalSolrQueryRequest(core, [ q: ['*:*'] as String[] // 全件取得 ]) def res = new SolrQueryResponse() // 検索 core.execute(handler, req, res) def writer = new ByteArrayOutputStream() def rw = new BinaryResponseWriter() // 検索結果をストリームへ出力 rw.write(writer, req, res) def resolver = new BinaryResponseWriter.Resolver(req, res.getReturnFields()) def bais = new ByteArrayInputStream(writer.toByteArray()) // バイト配列を Java オブジェクト化 (ここでは SimpleOrderedMap オブジェクトが返ります) def result = new JavaBinCodec(resolver).unmarshal(bais) // 結果の出力 result.response.each { println it } core.close() cores.shutdown()
Solr に含まれている example/solr
の collection1
コアを使う場合は、/query
の他に /select
ハンドラも利用でき、違いはデフォルト設定値だけのようです。 (/query は indent が true に設定されている等)
実行結果は下記の通りです。
実行結果
> groovy search2.groovy /solr-4.9.0/example/solr collection1 [id:GB18030TEST, name:Test with some GB18030 encoded characters, features:[No accents here, ?是一个功能, This is a feature (translated), ??文件是很有光?, This document is very shiny (translated)], price:0.0, price_c:0,USD, inStock:true, _version_:1473119790218346496] ・・・
JSON で結果出力
JSON で検索結果を出力したい場合、BinaryResponseWriter の代わりに JSONResponseWriter を使用します。
search2_json.groovy
・・・ // 検索 core.execute(handler, req, res) def writer = new StringWriter() def rw = new JSONResponseWriter() rw.write(writer, req, res) // 結果の出力 (JSON) println writer.toString() ・・・
実行結果
> groovy search2_json.groovy /solr-4.9.0/example/solr collection1 { "responseHeader":{ "status":0, "QTime":94, "params":{ "q":"*:*"}}, "response":{"numFound":32,"start":0,"docs":[ { "id":"GB18030TEST", "name":"Test with some GB18030 encoded characters", "features":["No accents here", "?是一个功能", "This is a feature (translated)", "??文件是很有光?", "This document is very shiny (translated)"], "price":0.0, "price_c":"0,USD", "inStock":true, "_version_":1473119790218346496}, ・・・