重新更新索引的方法
阿新 • • 發佈:2019-01-04
由於分詞工具用的使用者字典有了更新,比如加入了一些出現頻度較高的專有名詞。
這時候希望通過重建索引,使查詢結果更加準確。
但是,由於一些資訊是當初建索引時加入的,而且這些資訊是不能從原始檔案中提取的,如當初的上傳者是誰、上傳日期 等。所以,不能夠直接刪除索引檔案,重新來過。
為此,必須遍歷原有索引,將其中進行了分析的Field重新分析並更新,不需要分析的Field則保持不變。
/** * 為現有檔案重新建立索引 * 例如當更新了使用者字典時使用 */ public void rebuildIndex(){ IndexReader ireader = null; IndexWriter iwriter = null; Directory directory = null; try { long start = new Date().getTime(); //前期準備工作 File indexPath = new File(SystemProperties.getIndexPath()); directory = FSDirectory.open(indexPath); //例項化IKAnalyzer分詞器 Analyzer analyzer = new IKAnalyzer(); //Analyzer analyzer = new CJKAnalyzer(Version.LUCENE_CURRENT); //建立記憶體索引物件 ireader = IndexReader.open(directory); if (indexPath.list().length > 0) { // 已有以往索引 iwriter = new IndexWriter(directory, analyzer, false, IndexWriter.MaxFieldLength.LIMITED); } else { // 首次建立索引 iwriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED); } //遍歷每一已有Document for (int i = 0; i < ireader.maxDoc(); i++) { try { // 提取原Document Document oldDoc = ireader.document(i); // 建立新Document Document newDoc = new Document(); // 不變的Field直接從原Document中取 // KEY newDoc.add(oldDoc.getField(Constants.FEILD_NAME_KEY)); // 檔名 newDoc.add(oldDoc.getField(Constants.FEILD_NAME_CLIENTNAME)); newDoc.add(oldDoc.getField(Constants.FEILD_NAME_SERVERNAME)); // 檔案型別 newDoc.add(oldDoc.getField(Constants.FEILD_NAME_FILETYPE)); // 加入時間 newDoc.add(oldDoc.getField(Constants.FEILD_NAME_ADDTIME)); // 所屬部門,使用者查詢時的許可權控制 newDoc.add(oldDoc.getField(Constants.FEILD_NAME_OWNER)); // 不變的Field從原Document中取得後,重新Analyse // 標題 String title = oldDoc.getField(Constants.FEILD_NAME_TITLE).stringValue(); newDoc.add(new Field(Constants.FEILD_NAME_TITLE, title, Field.Store.YES, Field.Index.ANALYZED)); // 內容 String text = oldDoc.getField(Constants.FEILD_NAME_CONTENTS).stringValue(); newDoc.add(new Field(Constants.FEILD_NAME_CONTENTS, text, Field.Store.YES, Field.Index.ANALYZED)); String key = oldDoc.getField(Constants.FEILD_NAME_KEY).stringValue(); // 用KEY做查詢條件 Term term = new Term(Constants.FEILD_NAME_KEY, key); // 替換原有的Document iwriter.updateDocument(term, newDoc); } catch (Throwable t) { if (log.isErrorEnabled()) { log.error(t.getMessage()); } } } long end = new Date().getTime(); if (log.isDebugEnabled()) { log.debug("Rebuild Index: " + ireader.maxDoc() + " documents, in " + (end - start) + " milliseconds."); } } catch (Throwable t) { if (log.isErrorEnabled()) { log.error(t.getMessage()); } } finally { if (ireader != null) { try { ireader.close(); } catch (AlreadyClosedException e) { log.error(e.getMessage()); } catch (IOException e) { log.error(e.getMessage()); } } if (iwriter != null) { try { // 注意這一句非常重要,否則雖然效果已經達到,但Documents數和儲存空間都會翻倍! // 但使用此方法的前提是,磁碟剩餘空間必須有已用索引空間的2倍 // 此時由於重建,索引空間已經是翻倍的了,所以剩餘空間應該有之前索引空間的4被! iwriter.optimize(); iwriter.close(); } catch (AlreadyClosedException e) { log.error(e.getMessage()); } catch (IOException e) { log.error(e.getMessage()); } } if (directory != null) { try { directory.close(); } catch (IOException e) { log.error(e.getMessage()); } } } }
剛剛接觸Lucene時間不長,不知道以上自己“杜撰”的程式碼是否可行,請大家多多指點。