Apache Lucene 使用指南备忘录

Apache Lucene 是什么?

一个由Java编写的开源搜索引擎库。

读音是”Luxin”。

还有一种叫做Apache Solr的服务可以集成Lucene并提供搜索服务。

环境 –

操作系统

    Windows 7 64bit SP1

Java – Java语言

    1.8.0_20

驱动演示

安装

从这里下载zip或tar文件。

假设我们将文件解压到 F:\tmp\lucene 目录下,接下来继续说明。

F:\tmp\lucene
  `-lucene-4.9.0
    |-CHANGES.txt
    |-JRE_VERSION_MIGRATION.txt
    |-LICENSE.txt
    |-MIGRATE.txt
    |-NOTICE.txt
    |-README.txt
    |-SYSTEM_REQUIREMENTS.txt
    |-analysis/
    |-benchmark/
    |-classification/
    |-codecs/
    :
    (以下略)

从命令行切换到 F:\tmp\lucene 目录。

>cd /d F:\tmp\lucene

设置类路径

>set classpath=lucene-4.9.0/core/lucene-core-4.9.0.jar;lucene-4.9.0/queryparser/lucene-queryparser-4.9.0.jar;lucene-4.9.0/analysis/common/lucene-analyzers-common-4.9.0.jar;lucene-4.9.0/demo/lucene-demo-4.9.0.jar

我已将以下四个jar文件添加到CLASSPATH中。

    • lucene-core-4.9.0.jar

 

    • lucene-queryparser-4.9.0.jar(検索のときに使用する)

 

    • lucene-analyzers-common-4.9.0.jar(インデックス作成のときに使用する)

 

    lucene-demo-4.9.0.jar(デモの実装)

创建索引

>java org.apache.lucene.demo.IndexFiles -docs lucene-4.9.0/docs

在\index下生成索引文件(如果需要明确指定,则使用-index选项)。

搜索

>java org.apache.lucene.demo.SearchFiles
Enter query:

输入要搜索的关键词并按 Enter 键,将会输出搜索结果。

apache
Searching for: apache
5757 total matching documents
1. lucene-4.9.0\docs\core\allclasses-noframe.html
2. lucene-4.9.0\docs\facet\allclasses-noframe.html
3. lucene-4.9.0\docs\test-framework\allclasses-frame.html
4. lucene-4.9.0\docs\test-framework\allclasses-noframe.html
5. lucene-4.9.0\docs\analyzers-common\overview-frame.html
6. lucene-4.9.0\docs\highlighter\allclasses-frame.html
7. lucene-4.9.0\docs\highlighter\allclasses-noframe.html
8. lucene-4.9.0\docs\core\overview-frame.html
9. lucene-4.9.0\docs\test-framework\overview-frame.html
10. lucene-4.9.0\docs\suggest\allclasses-frame.html
Press (n)ext page, (q)uit or enter number to jump to a page.

在搜索结果中按n键显示下一条记录,按q键结束显示,并等待输入下一个搜索关键词。

使用 Ctrl + C 结束。

实施

预备

依赖关系

dependencies {
    compile 'org.apache.lucene:lucene-queryparser:4.9.0'
    compile 'org.apache.lucene:lucene-analyzers-common:4.9.0'
}

生成索引

package sample.lucene;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

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.Store;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.index.IndexWriterConfig.OpenMode;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

public class Main {

    public static void main(String[] args) throws IOException {
        // インデックスの出力先を定義
        Directory indexDir = FSDirectory.open(new File("index"));
        // テキストの解析方法(アナライザー)を定義
        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_4_9);
        // 解析方法の設定
        IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);

        // インデックスが既に存在する場合の動作を定義する(OpenMode.CREATE の場合、新規に作成して上書きする)
        config.setOpenMode(OpenMode.CREATE);

        // インデックスを作成するファイル
        File file = new File("MIGRATE.html");

        try (IndexWriter writer = new IndexWriter(indexDir, config);
             BufferedReader br = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {

            // Document に、インデックスに保存する各ファイルの情報を設定する
            Document doc = new Document();
            doc.add(new StringField("path", file.getPath(), Store.YES));
            doc.add(new TextField("contents", br));

            // インデックスを書き出す
            writer.addDocument(doc);
        }
    }
}

我正在尝试为名为MIGRATE.html的文件(位于docs文件夹下)创建索引。

将多个文件添加到索引中

从查看IndexFiles的实现中可以看出,需要自己实现文件夹的递归搜索并创建索引。

搜索

package sample.lucene;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

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.Store;
import org.apache.lucene.document.LongField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.DirectoryReader;
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.queryparser.classic.ParseException;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;

public class Main {

    public static void main(String[] args) throws IOException, ParseException {
        // 検索文字列を解析するためのパーサーを生成する
        Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_4_9);
        // 検索対象のフィールドを第二引数で指定している
        QueryParser parser = new QueryParser(Version.LUCENE_4_9, "contents", analyzer);

        // 検索文字列を解析する
        String searchText = "lucene";
        Query query = parser.parse(searchText);

        // 検索で使用する IndexSearcher を生成する
        Directory indexDir = FSDirectory.open(new File("index"));
        IndexReader indexReader = DirectoryReader.open(indexDir);
        IndexSearcher indexSearcher = new IndexSearcher(indexReader);

        // 検索を実行する(第二引数は、検索結果の最大数)
        TopDocs results = indexSearcher.search(query, 10);

        // 検索の結果、該当した Document を1つずつ取得する
        for (ScoreDoc scoreDoc : results.scoreDocs) {
            Document doc = indexSearcher.doc(scoreDoc.doc);

            // Document の path を取得して出力する
            String path = doc.get("path");
            System.out.println(path);
        }
    }
}

使用创建的索引进行搜索,查找包含“lucene”关键字的内容。

当然的是,搜索结果只有一个MIGRATE.html。

输出行号

如果想要显示行号,似乎需要改进文档的制作方法。

在实施示例中,每个文件创建一个文档。
将其改为每行文件创建一个文档,并添加一个保存行号的字段到文档中。

try (IndexWriter writer = new IndexWriter(indexDir, config)) {

    int lineNumber = 1;
    for (String line : Files.readAllLines(file.toPath(), StandardCharsets.UTF_8)) { // 1行ずつ Document を生成する
        Document doc = new Document();
        doc.add(new StringField("path", file.getPath(), Store.YES));
        doc.add(new TextField("contents", new StringReader(line)));
        doc.add(new LongField("lineNumber", lineNumber++, Store.YES)); // ここで行番号を記録

        writer.addDocument(doc);
    }
}

对日语进行分析

标准分词器的问题。

在前面的例子中使用了StandardAnalyzer。
然而,使用这个分析器无法得到预期的日语解析结果。

假设有一个像下面这样的文本文件。

日本語で書かれた文書

使用StandardAnalyzer对其进行分析时,索引将按以下方式创建。

lucene.JPG

每个字符都被细分开来,日语的单词完全被忽略。

在这种情况下,假设我们以“文字”这个字符串进行搜索。
“文字”这个字符串将被分割成“文”和“字”进行搜索。
然后,由于japanese.txt拥有“文”这个字符的索引,Lucene会错误地从japanese.txt中抽取出来(尽管实际上并不包含“文字”这个词!)。

我认为「在Apache Solr中学习搜索引擎常识 – @IT」这篇文章能够详细解释相关内容。

关于索引的确认

使用Luke工具可以查看由Lucene生成的索引内容。

然而,根据官方的更新情况,最新版本似乎停留在4.0.0,并且无法使用Lucene 4.9.0生成的索引。

可以使用在 GitHub 上发布的 Luke,该版本也能与最新的 Lucene 兼容,这是由自愿者提供的。

将项目下载下来后,使用ant进行构建,会在dist文件夹下输出lukeall-<版本号>.jar文件。然后,只需使用java -jar lukeall-<版本号>.jar进行启动。

使用lucene-gosen对日语进行分析

香草郁郁,指的是 Lucene-Gosen。

为了应对上述问题,需要进行形态素解析。

Lucene-gosen是一個能夠進行日語詞素解析的開源程式庫。

使用lucene-gosen

可以从这里下载 jar 文件。
※ 最新版本可以从 “External links” 而不是 “Downloads” 下载。

下载lucene-gosen-4.9.0.1-naist-chasen.jar并将其添加到项目的类路径中。

-niast-chasen 和 -ipadic 两者都在jar文件内部嵌入了字典。

只需要在实现上做一个变更,将使用 StandardAnalyzer 的部分替换为 org.apache.lucene.analysis.gosen.GosenAnalyzer。

Analyzer analyzer = new GosenAnalyzer(Version.LUCENE_4_9);
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_9, analyzer);
Analyzer analyzer = new GosenAnalyzer(Version.LUCENE_4_9);
QueryParser parser = new QueryParser(Version.LUCENE_4_9, "contents", analyzer);

当在Google上搜索”lucene-gosen”的用法时,会发现许多使用JapaneseAnalyzer的例子。但是,中途对于包结构等进行了重大更改,目前似乎是使用GosenAnalyzer。

产生的索引

lucene.JPG

正确地将其分割成有意义的日语单元。

如果使用”文字”这个字符串进行搜索,不会抽取目标为japanese.txt的内容。

请查阅

    • Lucene Search Result with Line Numbers? | Lucene | Java-User

 

    • 全文検索システムApache Luceneを使ってみる – Java入門

 

    • Overview (Lucene 4.9.0 API)

 

    • Luke – Luceneインデックスブラウザ | 関口宏司のLuceneブログ

 

    • Luke (Lucene インデックスブラウザ) の lucene-4.x 対応版 – ソフトウェアエンジニア現役続行

 

    • 【重要】lucene-gosen 2.0.0リリース | johtani の日記

 

    形態素解析とは 【 morphological analysis 】 – 意味/解説/説明/定義 : IT用語辞典
广告
将在 10 秒后关闭
bannerAds