Infinispanのクエリをもうちょっと勉強してみようと思い、その時に合わせてLuceneも覚えられたらいいなぁということで。
で、現時点でのLuceneの最新版は4.3.0なのですが、
Apache Lucene
http://lucene.apache.org/core/index.html
Infinispanでクエリを使う時に使用するHibernate Searchは、Lucene 3.6までの対応となっています。
Hibernate Search
http://www.hibernate.org/subprojects/search.html
Hibernate Searchでも、Lucene 4系への対応はJIRAに挙がっているのですが
Update to Lucene 4.0
https://hibernate.atlassian.net/browse/HSEARCH-1191
対応する目標がHibernate Search 5.0になっていますし、今のGitHubでのmasterブランチは4.3.0のSNAPSHOTなので、これは当分対応しないだろうなぁと…。
https://github.com/hibernate/hibernate-search
というわけで、Hibernate Searchを介さずに、普通にLuceneのDirectoryとしてInfinispanを触ってみることにしました。
Infinispan as a storage for Lucene indexes
https://docs.jboss.org/author/display/ISPN/Infinispan+as+a+storage+for+Lucene+indexes
まずは、動作させてみて、その後ページの英訳に進んでいこうと思います。
*ドキュメントの英訳は、こちらへ
http://d.hatena.ne.jp/Kazuhira/20130519/1368965554
動かしてみる
InfinispanでLuceneのDirectoryを作成するには、org.infinispan.lucene.directory.DirectoryBuilderクラスを使います。
Cache cache = // create an Infinispan cache, configured as you like
Directory indexDir = DirectoryBuilder.newDirectoryInstance(cache, cache, cache, indexName)
.create();
そして、Directoryの作成には、3つのCacheが必要になります。それぞれ意味があるのですが、InfinispanのWikiではサンプルとしては全て同じCacheを使用しています。厳密には、用途毎に分けた方がよいみたいです。この辺りは、後で…。
最後の引数は、インデックスの名前になります。インデックス毎に、ユニークな名前を指定する必要があります。
では、これを使ってLuceneのサンプルを書いてみます。
Introduction to Lucene's APIs
http://lucene.apache.org/core/4_3_0/core/overview-summary.html#overview_description
build.sbt
name := "infinispan-lucene" version := "0.0.1-SNAPSHOT" scalaVersion := "2.10.1" organization := "littlewings" libraryDependencies ++= Seq( "org.infinispan" % "infinispan-core" % "5.3.0.Beta2", "org.infinispan" % "infinispan-lucene-directory" % "5.3.0.Beta2", "org.apache.lucene" % "lucene-core" % "4.3.0", "org.apache.lucene" % "lucene-analyzers-common" % "4.3.0", "org.apache.lucene" % "lucene-queryparser" % "4.3.0" )
Infinispanは、5.3からLucene 4に対応しています。が、5.3はまだ開発中なのでBeta2ですね…。今回、これで初めてBeta版を触っています…。
また、Infinispan 5.3はLucene 3系にも4系にも対応していますが、デフォルトは3系を見ているので、Lucene 4への依存関係を定義すると、Lucene 3の依存関係がevictされてLucene 4用のDirectoryを使うようになります。
サンプルコード。
src/main/scala/InfinispanLucene.scala
import org.infinispan.Cache import org.infinispan.lucene.directory.DirectoryBuilder import org.infinispan.manager.DefaultCacheManager import org.apache.lucene.analysis.standard.StandardAnalyzer import org.apache.lucene.document.{Document, Field, TextField} import org.apache.lucene.index.{DirectoryReader, IndexWriter, IndexWriterConfig} import org.apache.lucene.queryparser.classic.QueryParser import org.apache.lucene.search.IndexSearcher import org.apache.lucene.store.Directory import org.apache.lucene.util.Version object InfinispanLucene { def main(args: Array[String]): Unit = { val manager = new DefaultCacheManager // 各種キャッシュの作成 val metaDataCache: Cache[_, _] = manager.getCache("metaDataCache") val chunksCache: Cache[_, _] = manager.getCache("chunksCache") val distLocksCache: Cache[_, _] = manager.getCache("distLocksCache") val luceneVersion = Version.LUCENE_43 // LuceneのDirectoryを作成 val indexDir = DirectoryBuilder .newDirectoryInstance(metaDataCache, chunksCache, distLocksCache, "indexName") .create() // 今回使用するAnalyzer val analyzer = new StandardAnalyzer(luceneVersion) // インデックスへの登録 val indexWriterConfig = new IndexWriterConfig(luceneVersion, analyzer) val indexWriter = new IndexWriter(indexDir, indexWriterConfig) val document = new Document val text = "This is the text to be indexed." document.add(new Field("fieldName", text, TextField.TYPE_STORED)) indexWriter.addDocument(document) indexWriter.close() // インデックスからの読み出し val directoryReader = DirectoryReader.open(indexDir) val indexSearcher = new IndexSearcher(directoryReader) // Queryの作成 val queryParser = new QueryParser(luceneVersion, "fieldName", analyzer) val query = queryParser.parse("text") val hits = indexSearcher.search(query, null, 1000).scoreDocs // 検索結果表示 println(s"hits length => ${hits.length}") for (h <- hits) { val hitDoc = indexSearcher.doc(h.doc) println(s"Hit Text => ${hitDoc.get("fieldName")}") } directoryReader.close() indexDir.close() metaDataCache.stop() chunksCache.stop() distLocksCache.stop() manager.stop() } }
Infinispanを使っていること以外は、ほぼLuceneのサンプルのままです。
一応、Cacheは別々に用意しました。
// 各種キャッシュの作成 val metaDataCache: Cache[_, _] = manager.getCache("metaDataCache") val chunksCache: Cache[_, _] = manager.getCache("chunksCache") val distLocksCache: Cache[_, _] = manager.getCache("distLocksCache") // ... // LuceneのDirectoryを作成 val indexDir = DirectoryBuilder .newDirectoryInstance(metaDataCache, chunksCache, distLocksCache, "indexName") .create()
これとCache、DefaultCacheManagerのstop以外は、ほぼサンプルと同じです。ちょっと変数名が変わっていたり、Scalaでの書き方になっていたりしますが。
動かしてみます。
> run [info] Running InfinispanLucene 5 19, 2013 2:08:48 午後 org.infinispan.factories.GlobalComponentRegistry start INFO: ISPN000128: Infinispan version: Infinispan 'Tactical Nuclear Penguin' 5.3.0.Beta2 5 19, 2013 2:08:49 午後 org.infinispan.jmx.CacheJmxRegistration start INFO: ISPN000031: MBeans were successfully registered to the platform MBean server. 5 19, 2013 2:08:49 午後 org.infinispan.jmx.CacheJmxRegistration start INFO: ISPN000031: MBeans were successfully registered to the platform MBean server. 5 19, 2013 2:08:49 午後 org.infinispan.jmx.CacheJmxRegistration start INFO: ISPN000031: MBeans were successfully registered to the platform MBean server. hits length => 1 Hit Text => This is the text to be indexed. [success] Total time: 4 s, completed 2013/05/19 14:08:51
動きましたねー。
このサンプルだけだと、LuceneのRAMDirectoryを使った場合と、違いがある気がしませんね…。
ここからページの英訳をしようと思ったのですが、エントリが長くなりそうなので別にします。