`
TonyLian
  • 浏览: 397297 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

重新更新索引的方法

阅读更多

由于分词工具用的用户字典有了更新,比如加入了一些出现频度较高的专有名词。
这时候希望通过重建索引,使查询结果更加准确。
但是,由于一些信息是当初建索引时加入的,而且这些信息是不能从原始文件中提取的,如当初的上传者是谁、上传日期 等。所以,不能够直接删除索引文件,重新来过。

为此,必须遍历原有索引,将其中进行了分析的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时间不长,不知道以上自己“杜撰”的代码是否可行,请大家多多指点。

 

 

 

  • 大小: 3.2 KB
  • 大小: 622 Bytes
分享到:
评论
2 楼 wodettaworld 2012-10-24  
1 楼 TonyLian 2010-02-02  
今天发现一个小Bug。就是每次重建索引时,Documents的数量会翻番,索引所占用的磁盘空间也会翻番。

但是,在搜索时,确实只有一个版本,不存在重复的结果。

研究一番,发现,在关闭IndexWriter时,要对其进行“优化”。
它才会“压缩”空间,即被update的Document的被覆盖版本,才会被剔除,磁盘空间也会被释放。

// 在 iwriter.close(); 前加上这一句
iwriter.optimize();

相关推荐

Global site tag (gtag.js) - Google Analytics