Lucene 是 Apache 旗下的 Java 全文檢索工具包,非獨立應用,而是嵌入式程式庫。本文系統介紹其核心架構、索引機制、中文分詞策略與效能調優實戰。
資料庫索引基於 B+ 樹,不支援 LIKE '%keyword%',全表掃描效能極差。Lucene 採用**倒排索引**:
| 維度 | Lucene 全文索引 | 資料庫 LIKE |
|---|---|---|
| 索引結構 | 詞元→文件映射,含位置、頻率 | B+ 樹,無法支援模糊前綴 |
| 匹配單位 | 詞元,可經語言分析器處理 | 字串,%net% 會匹配 netherlands |
| 多關鍵字 | 邏輯組合精確查詢 | %com%net% 無法匹配倒序 |
| 相關度 | TF/IDF 演算法排序 | 無相關度概念 |
| 結果輸出 | Top-N 緩衝流式讀取 | 全量結果集佔記憶體 |
| 可定制性 | 分析器、查詢解析器可擴展 | 無擴展介面 |
核心差異:檢索系統只需滿足 98% 用戶的前 100 條結果。
傳統單一索引檔案更新導致大量 I/O。Lucene 採用**段式架構**:新增索引建立新段檔案,定期背景合併小段為大段,不阻塞查詢,平衡寫入與查詢效能。
中文無天然分隔符,單字索引會導致「上海」匹配「海上」。兩大流派:
| 策略 | 原理 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|---|
| 詞庫分詞 | 機器學習/詞典最大匹配 | 語義準確,索引體積小(原文 30%) | 維護成本高,需詞頻統計 | 專業搜尋引擎 |
| N-gram 自動切分 | Bigram:「北京天安門」→「北京 京天 天安 安門」 | 無詞庫維護,實現簡單,多語言通用 | 索引冗大(近原文大小),查詢分析複雜 | 嵌入式、資源受限、多語言環境 |
工業級引擎常結合兩者:詞庫為主,N-gram 兜底。
org.apache.lucene.search/ 查詢入口 org.apache.lucene.index/ 索引入口 org.apache.lucene.analysis/ 語言分析器 org.apache.lucene.queryParser/ 查詢解析器 org.apache.lucene.document/ 文件/欄位結構 org.apache.lucene.store/ 底層 IO 儲存 org.apache.lucene.util/ 通用資料結構
索引:
IndexWriter writer = new IndexWriter(indexPath, new SimpleAnalyzer(), false);
Document doc = new Document();
doc.add(Field.UnIndexed("path", filePath)); // 僅儲存
doc.add(Field.Text("body", new InputStreamReader(is))); // 分詞索引+儲存
writer.addDocument(doc);
writer.close();
欄位型別決定分詞/索引/儲存行為:Text、Keyword、UnIndexed、UnStored。
查詢:
Searcher searcher = new IndexSearcher(indexPath);
Query query = QueryParser.parse(queryString, "body", new SimpleAnalyzer());
Hits hits = searcher.search(query);
for (int i = 0; i < hits.length(); i++) {
System.out.println(hits.doc(i).get("path") + "; Score: " + hits.score(i));
}
Term,IndexReader.delete(term) 後重新索引docID 替代 score 排序(修改 HitCollector)IndexWriter.mergeFactor 增大可減少 I/O、提升批量索引速度RAMDirectory 實現數量級查詢加速Lucene 體現經典 OO 設計:高內聚低耦合、介面導向、原子化模組(QueryParser、IndexReader、Similarity 等可獨立替換)。其 20/80 原則、批量優化參數、小結果集策略,對資料庫優化亦有借鑑價值。