【问题标题】:High performance unique document id retrieval高性能唯一文档 ID 检索
【发布时间】:2014-09-11 18:38:40
【问题描述】:

目前我正在使用 Java 平台上的 Lucene 4.9.0 开发高性能 NRT 系统,该系统可检测近乎重复的文本文档。

为此,我查询 Lucene 以返回一组匹配的候选者,并在本地进行近乎重复的计算(通过检索和缓存术语向量)。但我主要关心的是将 Lucene 的 docId(可以更改)绑定到我自己存储在索引中的唯一且不可变的文档 ID 的性能问题。

我的流程如下:

  • 在 Lucene 中查询文档
  • 对于每个文档:
    • 根据 Lucene docId 获取我的唯一文档 ID
    • 从缓存中为我的文档 ID 获取术语向量(如果它不存在 - 从 Lucene 中获取它并填充缓存)
    • 做数学...

我的主要瓶颈是“获取我的唯一文档 ID” 步骤,这会导致性能大幅下降(尤其是有时我必须在单个循环中计算 40000 个词向量)。

    try {
        Document document = indexReader.document(id);
        return document.getField(ID_FIELD_NAME).numericValue().intValue();
    } catch (IOException e) {
        throw new IndexException(e);
    }

我考虑的可能解决方案是:

还有其他建议吗?

【问题讨论】:

    标签: lucene


    【解决方案1】:

    我已经想出如何利用 Lucene 的 AtomicReader 的优势部分解决这个问题。为此,我使用全局缓存来保留已经实例化的段的 FieldCache。

    Map<Object, FieldCache.Ints> fieldCacheMap = new HashMap<Object, FieldCache.Ints>();
    

    在我的方法中,我使用以下代码:

    Query query = new TermQuery(new Term(FIELD_NAME, fieldValue));
    IndexReader indexReader = DirectoryReader.open(indexWriter, true);
    
    List<AtomicReaderContext> leaves = indexReader.getContext().leaves();
    
    // process each segment separately
    for (AtomicReaderContext leave : leaves) {
        AtomicReader reader = leave.reader();
    
        FieldCache.Ints fieldCache;
        Object fieldCacheKey = reader.getCoreCacheKey();
    
        synchronized (fieldCacheMap) {
            fieldCache = fieldCacheMap.get(fieldCacheKey);
            if (fieldCache == null) {
                fieldCache = FieldCache.DEFAULT.getInts(reader, ID_FIELD_NAME, true);
                fieldCacheMap.put(fieldCacheKey, fieldCache);
            }
            usedReaderSet.add(fieldCacheKey);
        }
    
        IndexSearcher searcher = new IndexSearcher(reader);
        TopDocs topDocs = searcher.search(query, Integer.MAX_VALUE);
    
        ScoreDoc[] scoreDocs = topDocs.scoreDocs;
    
        for (int i = 0; i < scoreDocs.length; i++) {
             int docID = scoreDocs[i].doc;
             int offerId = fieldCache.get(docID);
             // do your processing here
        }
    }
    
    // remove unused entries in cache set
    synchronized(fieldCacheMap) {
        Set<Object> inCacheSet = fieldCacheMap.keySet();
        Set<Object> toRemove = new HashSet();
        for(Object inCache : inCacheSet) {
            if(!usedReaderSet.contains(inCache)) {
                toRemove.add(inCache);
            }
        }
    
        for(Object subject : toRemove) {
             fieldCacheMap.remove(subject);
        }
    
    }
    
    indexReader.close();
    

    它运行得非常快。我主要担心的是内存使用量在使用大索引时会非常高。

    【讨论】:

      猜你喜欢
      • 2018-07-21
      • 1970-01-01
      • 2018-05-06
      • 2011-01-15
      • 1970-01-01
      • 1970-01-01
      • 2015-08-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多