2014-07-21 2 views
1

현재 거의 중복되는 텍스트 문서를 감지하는 Java 플랫폼에서 Lucene 4.9.0을 사용하는 고성능 NRT 시스템에서 작업 중입니다.고성능 고유 ID 검색

이 목적을 위해 Lucene은 일치하는 후보 집합을 반환하고 부분적으로 (용어 벡터를 검색하고 캐싱하여) 거의 중복 계산을 수행합니다. 하지만 내 주요 관심사는 Lucene의 docId (변경할 수 있음)를 색인 내에 저장된 고유하고 불변의 고유 한 문서 ID에 바인딩하는 성능 문제입니다.

  • 쿼리를 문서 루씬 각 문서에 대한
  • 에 :
    • 내 고유의 문서 ID를 가져 루씬 DOCID
    • 캐시에서 용어 벡터를 얻을 수에 따라 다음과 같이

      내 흐름은 내 문서 ID (존재하지 않는 경우 - Lucene에서 가져 와서 캐시를 채 웁니다)

    • 수식을 수행 ...

내 주요 병목 입니다 엄청난 성능 저하를 (때로는 단일 루프에서 40000 개 용어 벡터,의 말을하자에 대한 계산을해야 할 특히 있음) 소개 단계 "내 고유의 문서 ID를 가져." 내가 고려하고

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

가능한 해결책이었다 :

독특하고 지속적인 문서 식별자를 처리 Zoie, FieldCache (여전히 매우 비효율적)의
  • 사용을 사용

    다른 제안 사항이 있습니까?

  • 답변

    0

    Lucene의 AtomicReader의 이점을 부분적으로 사용하여 문제를 해결하는 방법을 알아 냈습니다. 이 목적을 위해 이미 인스턴스화 된 세그먼트의 FieldCache를 유지하기 위해 전역 캐시를 사용합니다.

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

    그것은 꽤 빨리 작동 : 내 방법에서

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

    나는 다음 코드 조각을 사용합니다. 내 주요 관심사는 큰 인덱스를 사용할 때 실제로 높을 수있는 메모리 사용량입니다.