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对其进行分析时,索引将按以下方式创建。
每个字符都被细分开来,日语的单词完全被忽略。
在这种情况下,假设我们以“文字”这个字符串进行搜索。
“文字”这个字符串将被分割成“文”和“字”进行搜索。
然后,由于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。
产生的索引
正确地将其分割成有意义的日语单元。
如果使用”文字”这个字符串进行搜索,不会抽取目标为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用語辞典