由于分词工具用的用户字典有了更新,比如加入了一些出现频度较高的专有名词。
这时候希望通过重建索引,使查询结果更加准确。
但是,由于一些信息是当初建索引时加入的,而且这些信息是不能从原始文件中提取的,如当初的上传者是谁、上传日期 等。所以,不能够直接删除索引文件,重新来过。
为此,必须遍历原有索引,将其中进行了分析的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时间不长,不知道以上自己“杜撰”的代码是否可行,请大家多多指点。