Lucene 全文檢索實戰:索引庫寫入與讀取流程完整解析
Lucene 核心架構圖

索引寫入流程

- 建立原始文檔(如 Student 物件)
- 創建
Directory(索引庫存儲位置,如 FSDirectory)
- 選擇
Analyzer(分詞器,如 StandardAnalyzer)
- 創建
IndexWriter(核心寫入元件)
- 將物件轉為
Document,添加 Field(指定存儲/索引/分詞策略)
indexWriter.addDocument(document) 寫入
indexWriter.close() 關閉,釋放鎖與 IO 資源
索引讀取/搜尋流程

- 開啟
Directory,創建 IndexSearcher
- 使用相同
Analyzer 創建 QueryParser 解析查詢語句
indexSearcher.search(query, n) 取得 TopDocs
- 遍歷
ScoreDoc,取得 Document 並映射回業務物件
完整代碼範例
寫入索引
public void testCreateIndex() throws Exception {
Student student = new Student();
student.setId(1L);
student.setName("張三");
Directory directory = FSDirectory.open(new File("./indexDir"));
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
IndexWriter indexWriter = new IndexWriter(directory, analyzer, MaxFieldLength.LIMITED);
Document document = new Document();
document.add(new Field("id", student.getId().toString(), Store.YES, Index.NOT_ANALYZED));
document.add(new Field("name", student.getName(), Store.YES, Index.ANALYZED));
indexWriter.addDocument(document);
indexWriter.close(); // 關鍵:釋放 write.lock
}
搜尋索引
public void testSearchIndex() throws Exception {
Directory directory = FSDirectory.open(new File("./indexDir"));
IndexSearcher indexSearcher = new IndexSearcher(directory);
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
QueryParser queryParser = new QueryParser(Version.LUCENE_30, "name", analyzer);
Query query = queryParser.parse("張");
TopDocs topDocs = indexSearcher.search(query, 2);
int totalHits = topDocs.totalHits;
ScoreDoc[] scoreDocs = topDocs.scoreDocs;
List list = new ArrayList<>();
for (ScoreDoc sd : scoreDocs) {
Document doc = indexSearcher.doc(sd.doc);
Student s = new Student();
s.setId(Long.parseLong(doc.get("id")));
s.setName(doc.get("name"));
list.add(s);
}
for (Student s : list) {
System.out.println(s.getId() + " " + s.getName());
}
}
關鍵機制:IndexWriter 鎖機制
- 同一時刻,同一索引庫只允許一個
IndexWriter 操作。
IndexWriter 創建即佔用鎖(write.lock 文件存在即表示上鎖)。
close() 雙重含義:關閉 IO 資源 + 釋放鎖。
- 新
IndexWriter 嘗試獲取鎖時會阻塞,直到舊實例釋放。
索引庫合併與內存索引
- 可建立多個索引庫,透過
RamDirectory 將磁碟索引載入內存。
- 使用
IndexWriter.addIndexesNoOptimize() 合併多個索引庫。
- 應用程式可直接與內存索引庫交互,提升查詢速度。