kakiro-webカキローウェブ

システム開発情報とコンピューター書籍の紹介サイト

【Lucene】基本処理 インデックスの登録

全文検索を行うシステムを構築するには、まず検索を行いたい文書データの登録を行います。

Luceneでは文書データの登録を行うことはインデックスの登録と呼ばれています。

インデックスとはいわゆる書籍の最後のほうのページにある索引のようなもので、書籍では索引から目的のキーワードが含まれているページが探せるように、Luceneではインデックスに文書とキーワードの関連を登録して、検索を行えるようにします。

まずはインデックスの登録を行う処理の基本的な流れを理解するために、簡単なサンプルプログラムを以下に示します。

import java.io.File;
import java.util.Iterator;
import java.util.List;

import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.AtomicReader;
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.Fields;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.Version;

public class WriteIndex {

    public static void main(String[] args) {
        try {
            WriteIndex wi = new WriteIndex();
            wi.main();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void main() throws Exception {
        //インデックスの登録先となるディレクトリのパス
        String indexPath = "index";

        Directory dir = null;
        Analyzer analyzer = null;
        IndexWriter writer = null;

        try {
            dir = FSDirectory.open(new File(indexPath));//---(1)

            analyzer = new StandardAnalyzer(Version.LUCENE_46);//---(2)

            IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_46, analyzer);//---(3)
            config.setOpenMode(OpenMode.CREATE);

            writer = new IndexWriter(dir, config);//---(4)

            Document doc = null;

            doc = new Document();//---(5)
            doc.add(new TextField("txt1", "ab cd ef", Field.Store.YES));
            doc.add(new StringField("str1", "gh ij kl", Field.Store.YES));

            writer.addDocument(doc);//---(6)

            doc = new Document();
            doc.add(new TextField("txt1", "abc def ghi", Field.Store.YES));
            doc.add(new StringField("str1", "jkl mno pqr", Field.Store.YES));

            writer.addDocument(doc);

            doc = new Document();
            doc.add(new TextField("txt1", "abcd efgh ijkl", Field.Store.YES));
            doc.add(new StringField("str1", "mnop qrst uvwx", Field.Store.YES));

            writer.addDocument(doc);

            writer.commit();//---(7)

            //登録したインデックスの確認
            checkIndex(writer);//---(8)
        } finally {
            if (writer != null) {
                writer.close();
            }

            if (analyzer != null) {
                analyzer.close();
            }

            if (dir != null) {
                dir.close();
            }
        }
    }

    private void checkIndex(IndexWriter writer) throws Exception {
        //(略)※別途記載
    }

}

上記プログラムの解説を行います。

(1)

インデックスの登録先はDirectoryで指定を行います。

ここではファイルシステム上にインデックスを登録しますので、FSDirectoryを使用してインデックスの登録先のディレクトリのパスを指定し、Directoryの生成を行っています。

Directoryにはいくつかの種類があり、メモリ上にインデックスを登録するRAMDirectoryというものもあります。

(2)

テキストデータからキーワードの抽出を行うにはAnalyzerを使用します。

Analyzerにはいくつかの種類があり、使用するものによってテキストデータからキーワードを抽出する方法が変わります。

ここでは標準的なAnalyzerとなるStandardAnalyzerを使用しています。

コンストラクタでは使用するLuceneのバージョンを指定しています。

Analyzerは重要な役割を持つものになりますので、別途解説を行います。

(3)

IndexWriterConfigはインデックスの登録を行うときに使用するIndexWriterの設定情報になります。

コンストラクタでは使用するLuceneのバージョンと(2)で生成したAnalyzerを指定しています。

setOpenModeメソッドではインデックスの登録を開始するときのモードを、列挙型IndexWriterConfig.OpenModeで指定します。モードの種類には以下のようなものがあります。

CREATE 新規にインデックスの登録を行います。既に登録済みのインデックスがある場合は、全て削除され新たに登録が行われます。
APPEND 既に登録済みのインデックスに追加を行います。既存のインデックスが存在しない場合は、IndexWriterの生成時にエラーがスローされます。
CREATE_OR_APPEND 既存のインデックスが存在しない場合は、新規にインデックスの登録を行います。既存のインデックスが存在する場合は、そこに追加を行います。

ここではサンプルプログラムを繰り返し実行しても、新規にインデックスが作成された状態になるようにCREATEを指定していますが、実運用ではCREATE_OR_APPENDを指定することになるかと思います。

(4)

インデックスの登録を行うにはIndexWriterを使用します。

コンストラクタでは(1)で生成したDirectoryと(3)で生成したIndexWriterConfigを指定しています。

(5)

インデックスに登録する文書データはDocumentで指定を行います。

1つの文書データに対し、1つのDocumentを使用します。

DocumentのデータはFieldで指定を行います。

Fieldは名前、値、タイプから成り立っています。

1つのDocumentに対し、複数のFieldを指定することができます。

DocumentのaddメソッドでFieldの追加を行います。

Fieldにはいくつかの種類があり、使用するものによってインデックスへの登録のされ方が変わります。

ここではTextFieldを使用して、txt1というフィールドの名前と、任意のフィールドの値、Field.Store.YESというフィールドのタイプを指定し、StringFieldを使用して、str1というフィールドの名前と、任意のフィールドの値、Field.Store.YESというフィールドのタイプを指定しています。

Fieldは重要な役割を持つものになりますので、別途解説を行います。

ひとまずここでは文書データはDocumentとFieldを使用して表現されることを押さえておいてください。

それぞれのフィールドがどのようにインデックスに登録されるかは、後述のインデックスの確認処理もご覧ください。

(6)

Documentを使用して指定した文書データは、IndexWriterのaddDocumentメソッドでインデックスに追加を行います。

以降同じ形式のFieldを持つDocumentを生成し、合わせて3つの文書データを追加しています。

(7)

文書データのインデックスへの追加が確定されるのは、IndexWriterのcommitメソッド、またはcloseメソッドが実行されたときになります。

commitメソッド、またはcloseメソッドが実行されるまでは、addDocumentメソッドでDocumentの追加を行っていても、他の検索処理から検索されることはありません。

(8)

実際どのように文書データがインデックスに登録されるのか確認できたほうがイメージが付き易いと思いますので、別途インデックスの確認処理を記載しています。

インデックスの確認のページをご覧ください。

この確認処理は実運用上では必要となるものではありません。