重新更新索引的方法

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

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

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值