Lucene[‘lusen] 是一個高性能的 java 全文檢索工具包(引擎),現階段 Apache 的頂級的開源項目,可基於它開發出各種全文搜索的應用。
一個全文檢索系統需要做的可以分爲兩部分,第一部分是建立索引,第二部分是進行檢索。下面就結合代碼對這兩部分進行講解。
先創建一個由 maven 管理的 java 項目,在 pom 中添加 lucene 依賴
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-core</artifactId>
<version>${lucene.version}</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-queryparser</artifactId>
<version>${lucene.version}</version>
</dependency>
</dependencies>
然後
mvn clean install
把各種依賴導入
建立索引
建立索引是從原始文檔到索引文件的過程,索引中包含索引和文檔對象。每個文檔對象有唯一的 id,文檔對象裏包含了很多 field,每個 field 有自己的名字(可重複)和相應的值。索引的最小單位是 Term,可以理解爲分詞之後的每個單詞或者不進行分詞的整體,也可以建立 n-gram 的 term。
常用的 Field 類如下:
Field 類 | 數據類型 | 是否分詞 | 是否索引 | 是否存儲 | 備註 |
---|---|---|---|---|---|
StringField(FieldName, FieldValue,Store.YES)) | String | No | Yes | Yes or No | 用於不進行分詞的字符串,如訂單號 |
LongField(FieldName, FieldValue,Store.YES) | long | Yes | Yes | Yes or No | |
StoredField(FieldName, FieldValue) | 重載方法,支持多種類型 | No | No | Yes | 需要儲存的文檔信息,但不進行索引和分詞 |
TextField(FieldName, FieldValue, Store.NO) | String | Yes | Yes | Yes or No | 需要儲存的正文內容 |
TextField(FieldName, reader) | streamming | Yes | Yes | No | 因爲是流,lucene猜測內容比較多,會採用Unstored |
建立索引,第一步當然就是創建索引對象
Directory index = FSDirectory.open(Paths.get(indexPath));
因爲有些內容需要分詞,所以也需要建立文本分析器對象,並把它加入到索引 Writer 的配置中配置 IndexWriter,也對增量更新(IndexWriterConfig.OpenMode.APPEND、IndexWriterConfig.OpenMode.CREATE_OR_APPEND)還是全量更新(IndexWriterConfig.OpenMode.CREATE)進行設置:
Analyzer analyzer = new StandardAnalyzer();
IndexWriterConfig config = new IndexWriterConfig(analyzer);
config.setOpenMode(IndexWriterConfig.OpenMode.CREATE);
IndexWriter writer = new IndexWriter(index, config);
下面就可以對索引進行寫操作了,對於每個文檔:
// 先創建一個文檔(Document 對象)
Document doc = new Document();
// 解析原始文本並往文檔中添加相應的 Field
Field pathField = new StringField("path", file.toString(), Field.Store.YES);
Field contentsField = new TextField("contents", buffer.toString(),Field.Store.YES);
doc.add(pathField);
doc.add(contentsField);
writer.addDocument(doc);
最後記得把該關的都關了
index.close();
writer.close();
建立後查看索引內內用
有一個開源項目可以查看索引文件,項目地址:https://github.com/DmitryKey/luke
克隆後進入文件夾“mvn install”,然後
java target/luke-swing-with-deps.jar
會彈出UI界面,選擇索引所在文件夾,就可飲查看索引和進行一些簡單的操作了。
進行查詢
進行查詢,首先要創建 IndexReader 對象來讀取索引,並且把它交給 IndexSearcher 對象來進行搜索
IndexReader reader = DirectoryReader.open(FSDirectory.open(Paths.get(indexPath)));
IndexSearcher searcher = new IndexSearcher(reader);
對於輸入的 String 類型的 query 我們需要對其解析成 IndexSearcher 可以查詢的 query 類型
Analyzer analyzer = new StandardAnalyzer();
QueryParser parser = new QueryParser(field, analyzer);
Query query = parser.parse(raw_input);
進行搜索
TopDocs results = searcher.search(query, 10);// 搜索結果,包含了一些搜索的信息
ScoreDoc[] hits = results.scoreDocs;// 搜索所得結果的列表
int numTotalHits = Math.toIntExact(results.totalHits);//一共所得的結果
for (ScoreDoc hit : hits) {
int docID = hit.doc;
Document document = searcher.doc(docID);
System.out.println("文檔:" + document.get("path"));
System.out.println(document.getField("contents").stringValue());
System.out.println("相關度:" + hit.score);
System.out.println("================================");
}
搜索常用的方法,評分應該是根據idf來算的
方法 | 說明 |
---|---|
IndexSearcher.search(query, n) | 根據 query 搜索評分最高的 n 條記錄 |
IndexSearcher.search(query, filter, n) | 添加過濾策略 |
IndexSearcher.search(query, n, sort) | 添加排序策略 |
IndexSearcher.search(query, filter, n, sort) | 添加過濾策略和排序策略 |
最後把該關的都關了
reader.close();