Lucene 高性能的唯一文档id检索

Lucene 高性能的唯一文档id检索,lucene,Lucene,目前,我正在Java平台上使用Lucene 4.9.0开发高性能NRT系统,该系统可以检测几乎重复的文本文档 为此,我查询Lucene以返回一些匹配的候选项集,并在本地执行近似重复的计算(通过检索和缓存术语向量)。但我主要关心的是将Lucene的docId(可以更改)绑定到我自己存储在索引中的唯一且不可变的文档id的性能问题 我的流程如下: Lucene中的文档查询 对于每个文件: 基于Lucene docId获取我的唯一文档id 从缓存中获取我的文档id的术语向量(如果它不存在-从Luce

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

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

我的流程如下:

  • Lucene中的文档查询
  • 对于每个文件:
    • 基于Lucene docId获取我的唯一文档id
    • 从缓存中获取我的文档id的术语向量(如果它不存在-从Lucene获取它并填充缓存)
    • 做数学
我的主要瓶颈是“获取我唯一的文档id”步骤,这会导致性能严重下降(特别是有时我不得不在单个循环中计算40000个术语向量)

我正在考虑的可能解决办法是:

  • 尝试使用Zoie处理唯一和持久的文档标识符
  • 使用FieldCache(仍然非常低效)
  • 有效载荷的使用(根据)-但我不知道如何应用它

还有其他建议吗?

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

Map<Object, FieldCache.Ints> fieldCacheMap = new HashMap<Object, FieldCache.Ints>();
Map fieldCacheMap=newhashmap();
在我的方法中,我使用以下代码:

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();
Query Query=新术语查询(新术语(字段名称,字段值));
IndexReader IndexReader=DirectoryReader.open(indexWriter,true);
List leaves=indexReader.getContext().leaves();
//分别处理每个段
for(AtomicReaderContext离开:离开){
AtomicReader=leave.reader();
Ints FieldCache;
Object fieldCacheKey=reader.getCoreCacheKey();
已同步(fieldCacheMap){
fieldCache=fieldCacheMap.get(fieldCacheKey);
if(fieldCache==null){
fieldCache=fieldCache.DEFAULT.getInts(读卡器,ID\u FIELD\u NAME,true);
fieldCacheMap.put(fieldCacheKey,fieldCache);
}
UseDrawerSet.add(fieldCacheKey);
}
IndexSearcher search=新的IndexSearcher(阅读器);
TopDocs TopDocs=searcher.search(查询,整数.MAX_值);
ScoreDoc[]scoreDocs=topDocs.scoreDocs;
for(int i=0;i
它工作得相当快。我主要关心的是内存使用率,当使用大索引时,内存使用率可能非常高

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();