【问题标题】:Lucene performance: Transferring fields data from one index to anotherLucene 性能:将字段数据从一个索引传输到另一个索引
【发布时间】:2012-07-31 06:17:05
【问题描述】:

简而言之,我需要将多个字段和值的映射从一个索引交换到结果索引。

以下是场景。

索引 1 结构 [字段 => 值] [已存储]

Doc 1    
keys => keyword1;    
Ids => id1, id1, id2, id3, id7, id11, etc.. 

Doc 2    
keys => keyword2;    
Ids => id3, id11, etc..

索引 2 结构 [字段 => 值] [已存储]

Doc 1    
ids => id1    
keys => keyword1, keyword1

Doc 3    
ids => id3    
keys => keyword1, keyword2, etc..

请注意,结果索引中的键ids 映射是相反的

就时间复杂度而言,您认为最有效的方法是什么? ..

我能想到的唯一方法就是……

1) index1Reader.terms();    
2) Process only terms belonging to "Ids" field    
3) For each term, get TermDocs    
4) For each doc, load it, get "keys" field info    
5) Create a new Lucene Doc, add 'Id', multi Keys, write it to index2.     
6) Go to step 2.

由于存储了字段,我相信有多种方法可以做到这一点。

请用任何表演技巧指导我。 考虑到 Index1 的大小约为 6GB,即使是最轻微的改进也会对我的方案产生巨大影响。

总数独特关键词:1800万; 总数唯一 ID 数:90 万

有趣的更新

优化 1

  • 在添加新文档时,不是创建多个重复的“字段”对象,而是使用“”分隔符创建单个 StringBuffer,然后将整个字段添加为单个字段,这似乎有高达 25% 的改进。

更新 2:代码

    public void go() throws IOException, ParseException {
    String id = null;
    int counter = 0;
    while ((id = getNextId()) != null) { // this method is not taking time..
        System.out.println("Node id: " + id);
        updateIndex2DataForId(id);
        if(++counter > 10){
            break;
        }
    }
    index2Writer.close();
}

private void updateIndex2DataForId(String id) throws ParseException, IOException {
    // Get all terms containing the node id
    TermDocs termDocs = index1Reader.termDocs(new Term("id", id));
    // Iterate
    Document doc = new Document();
    doc.add(new Field("id", id, Store.YES, Index.NOT_ANALYZED));
    int docId = -1;        
    while (termDocs.next()) {
        docId = termDocs.doc();
        doc.add(getKeyDataAsField(docId, Store.YES, Index.NOT_ANALYZED));            
    }
    index2Writer.addDocument(doc);
}

private Field getKeyDataAsField(int docId, Store storeOption, Index indexOption) throws CorruptIndexException,
        IOException {
    Document doc = index1Reader.document(docId, fieldSelector); // fieldSel has "key"
    Field f = new Field("key", doc.get("key"), storeOption, indexOption);
    return f;
}

【问题讨论】:

  • 这只是一次性的吗?我的猜测是,考虑它所花费的时间会比优化节省的时间多……6gb 是一个很大的索引,但 lucene 可以很快处理这些东西……你有没有做过蛮力测试看看需要多长时间?
  • 感谢您的回复。尽管这是一次性的事情,但我可能必须在截止日期前做几次。因此,考虑 perf impr。是的,我已经尝试过上述方法,时间消耗有点令人失望。每个文档需要几秒钟(2-5+)。总数预期文档的数量高达一百万。
  • 什么是你花了这么长时间才分析出来的?
  • 还不确定,加载文档可能是罪魁祸首。我应该只加载“关键字”,在这种情况下我可以避免加载非常冗长的“ids”字段。
  • @phani 哇!每个文档多秒是非常离谱的......不应该这么慢。您可以发布一些您正在使用的代码以便我们看一下吗?

标签: java search lucene


【解决方案1】:

FieldCache 的使用就像一个魅力......但是,我们需要分配越来越多的 RAM 来容纳堆上的所有字段。

我已经用下面的 sn-p 更新了上面的 updateIndex2DataForId() ..

private void updateIndex2DataForId(String id) throws ParseException, IOException {
    // Get all terms containing the node id
    TermDocs termDocs = index1Reader.termDocs(new Term("id", id));
    // Iterate
    Document doc = new Document();
    doc.add(new Field("id", id, Store.YES, Index.NOT_ANALYZED));
    int docId = -1;
    StringBuffer buffer = new StringBuffer();
    while (termDocs.next()) {
        docId = termDocs.doc();
        buffer .append(keys[docId] + " "); // keys[] is pre-populated using FieldCache                 
    }
    doc.add(new Field("id", buffer.trim().toString(), Store.YES, Index.ANALYZED));   
    index2Writer.addDocument(doc);
}

String[] keys = FieldCache.DEFAULT.getStrings(index1Reader, "keywords");

它让一切变得更快,我无法告诉你确切的指标,但我必须说非常重要。

现在该程序在合理的时间内完成。无论如何,我们非常感谢您提供进一步的指导。

【讨论】:

  • 多哈。甚至没有考虑过使用字段缓存......是的,我想只有 3gb 你需要更多的东西才能让这个尖叫声继续。
猜你喜欢
  • 2016-03-13
  • 2017-09-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-29
相关资源
最近更新 更多