Lucene8:Facetの使い方サンプル
Lucene 4 Cookbookの例をアレンジしてみた。
import org.apache.lucene.analysis.standard.*;
import org.apache.lucene.document.*;
import org.apache.lucene.facet.*;
import org.apache.lucene.facet.taxonomy.*;
import org.apache.lucene.facet.taxonomy.directory.*;
import org.apache.lucene.index.*;
import org.apache.lucene.search.*;
import org.apache.lucene.store.*;
import org.junit.*;
public class FacetTest {
@Test
public void test() throws Exception {
StandardAnalyzer analyzer = new StandardAnalyzer();
Directory indexDirectory = new RAMDirectory();
Directory facetDirectory = new RAMDirectory();
IndexWriterConfig config = new IndexWriterConfig(analyzer);
FacetsConfig facetsConfig = new FacetsConfig();
// インデックスライタ
try (IndexWriter indexWriter = new IndexWriter(indexDirectory, config)) {
// タクソノミーライター
try (DirectoryTaxonomyWriter taxonomyWriter =
new DirectoryTaxonomyWriter(facetDirectory)) {
Document doc = new Document();
doc.add(new StringField("BookId", "B1", Field.Store.YES));
doc.add(new FacetField("著者", "夏目漱石"));
doc.add(new FacetField("カテゴリ", "猫"));
indexWriter.addDocument(
// ドキュメントに何らかの添付を行って書き込む?
facetsConfig.build(taxonomyWriter, doc)
);
doc = new Document();
doc.add(new StringField("BookId", "B2", Field.Store.YES));
doc.add(new FacetField("著者", "森鴎外"));
doc.add(new FacetField("カテゴリ", "猫"));
indexWriter.addDocument(
facetsConfig.build(taxonomyWriter, doc)
);
doc = new Document();
doc.add(new StringField("BookId", "B3", Field.Store.YES));
doc.add(new FacetField("著者", "芥川龍之介"));
doc.add(new FacetField("カテゴリ", "藪"));
indexWriter.addDocument(
facetsConfig.build(taxonomyWriter, doc)
);
}
}
try (IndexReader indexReader = DirectoryReader.open(indexDirectory)) {
// サーチャー
IndexSearcher indexSearcher = new IndexSearcher(indexReader);
// FacetsCollectorを指定してサーチ。全データが対象
FacetsCollector fc = new FacetsCollector();
FacetsCollector.search(indexSearcher, new MatchAllDocsQuery(), 10, fc);
// タクソノミーリーダ
try (DirectoryTaxonomyReader taxonomyReader = new DirectoryTaxonomyReader(facetDirectory)) {
Facets facets = new FastTaxonomyFacetCounts(taxonomyReader, facetsConfig, fc);
// カテゴリのトップ10を取得
{
FacetResult facetResult = facets.getTopChildren(10, "カテゴリ");
System.out.println("\nカテゴリ----");
for (LabelAndValue labelAndValue : facetResult.labelValues) {
System.out.println(labelAndValue.label + ":" + labelAndValue.value);
}
}
// 著者のトップ10を取得
{
FacetResult facetResult = facets.getTopChildren(10, "著者");
System.out.println("\n著者----");
for (LabelAndValue labelAndValue : facetResult.labelValues) {
System.out.println(labelAndValue.label + ":" + labelAndValue.value);
}
}
System.out.println("\nカテゴリを猫に?");
DrillDownQuery drillDownQuery = new DrillDownQuery(facetsConfig);
drillDownQuery.add("カテゴリ", "猫");
DrillSideways drillSideways = new DrillSideways(indexSearcher, facetsConfig, taxonomyReader);
DrillSideways.DrillSidewaysResult drillSidewaysResult = drillSideways.search(drillDownQuery, 10);
System.out.println("\nカテゴリ----");
{
FacetResult facetResult = drillSidewaysResult.facets.getTopChildren(10, "カテゴリ");
for (LabelAndValue labelAndValue : facetResult.labelValues) {
System.out.println(labelAndValue.label + ":" + labelAndValue.value);
}
}
System.out.println("\n著者----");
{
FacetResult facetResult = drillSidewaysResult.facets.getTopChildren(10, "著者");
for (LabelAndValue labelAndValue : facetResult.labelValues) {
System.out.println(labelAndValue.label + ":" + labelAndValue.value);
}
}
}
}
}
}
実行結果は以下。
カテゴリ----
猫:2
藪:1
著者----
夏目漱石:1
森鴎外:1
芥川龍之介:1
カテゴリを猫に?
カテゴリ----
猫:2
藪:1
著者----
夏目漱石:1
森鴎外:1
後の方でカテゴリを「猫」に絞ったにも関わらず、「藪」も出ているが、これはカテゴリの一つを選択しても、別のカテゴリも選ぶかもしれないという仮定が行われているからだそうだ。
intやlongフィールドではfacet専用のディレクトリは不要なのだが、サンプルは別途示すことにする。