lucene 從0到1

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();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章