2011-03-28 5 views
2

안녕하세요
새 레코드로 자주 업데이트되는 lucene 인덱스가 있습니다. 색인에 5,000,000 개의 레코드가 있고 FieldCache를 사용하여 숫자 필드 중 하나를 캐싱하고 있습니다. 하지만 인덱스를 업데이트 한 후 다시 FieldCache를 다시로드하는 데 시간이 걸립니다. (캐쉬 원인 문서를 다시로드하면 DocID가 안정적이지 않습니다.) 그래서 새로 추가 된 DocID 만 FieldCache에 추가하여이 오버 헤드를 최소화 할 수 있습니다.이 기능으로 인해 병목 현상이 발생합니다. 신청.자주 업데이트하는 인덱스가있는 FieldCache


IndexReader reader = IndexReader.Open(diskDir); 
int[] dateArr = FieldCache_Fields.DEFAULT.GetInts(reader, "newsdate"); // This line takes 4 seconds to load the array 
dateArr = FieldCache_Fields.DEFAULT.GetInts(reader, "newsdate"); // this line takes 0 second as we expected 
// HERE we add some document to index and we need to reload the index to reflect changes 

reader = reader.Reopen(); 
dateArr = FieldCache_Fields.DEFAULT.GetInts(reader, "newsdate"); // This takes 4 second again to load the array 

나는 거기에 성능을 향상 시키려면이 http://invertedindex.blogspot.com/2009/04/lucene-dociduid-mapping-and-payload.html 같은 기술이지만 여전히 우리가 이미 가지고있는 모든 문서를로드하고 우리의 배열의 인덱스 만 새로 추가 된 문서를 추가하여이 시간을 최소화하는 메커니즘을 원한다 우리가 새로 추가 한 문서를 배열에 추가하는 방법을 찾으면 모두 다시로드 할 필요가 없다고 생각합니다.

+0

코드의 문제점은 내/외부 판독기로 설명하는 것입니다.외부 판독기 인 DirectoryReader를 FieldCache에 전달합니다. 두 명의 독자가 다르고 개별적으로 캐시한다고 생각합니다. 세그먼트별로 세그먼트를 채우기 위해 가장 안쪽의 리더 인 세그먼트 리더를 사용해야합니다. 즉, Reopen을 호출 한 후에 만 ​​변경 내용을로드합니다. 몇 분 안에이 코드를 게시 할 것입니다. – sisve

답변

4

FieldCache는 인덱스 판독기에 대한 약한 참조를 캐시의 키로 사용합니다. (쓸모 없게 된 IndexReader.GetCacheKey) IndexReader.Open에 대한 표준 호출은 FSDirectory이며 모든 세그먼트에 하나씩 독자 풀을 사용합니다.

항상 가장 안쪽의 리더기를 FieldCache에 전달해야합니다. 문서가 포함 된 개별 독자를 검색하려면 일부 도우미 항목에 대해 ReaderUtil을 확인하십시오. 문서 ID는 세그먼트 내에서 변경되지 않습니다. 예측할 수 없거나 변동이 있다고 생각할 때 의미하는 바는 두 개의 인덱스 커밋 사이에서 변경된다는 것입니다. 삭제 된 문서는 발음 될 수 있었고, 세그먼트가 병합되었으며, 그러한 작업을 할 수있었습니다.

커밋은 디스크에서 세그먼트를 제거 (병합/최적화 멀리)해야합니다. 즉, 새로운 독자에게는 풀링 된 세그먼트 판독기가 없으므로 가비지 수집은 이전의 모든 독자가 닫히 자마자이를 제거합니다.

절대 FieldCache.PurgeAllCaches()으로 전화하지 마십시오. 그것은 프로덕션 사용이 아닌 테스트 용입니다.

추가됨 2011-04-03; subreaders를 사용한 예제 코드.

var directory = FSDirectory.Open(new DirectoryInfo("index")); 
var reader = IndexReader.Open(directory, readOnly: true); 
var documentId = 1337; 

// Grab all subreaders. 
var subReaders = new List<IndexReader>(); 
ReaderUtil.GatherSubReaders(subReaders, reader); 

// Loop through all subreaders. While subReaderId is higher than the 
// maximum document id in the subreader, go to next. 
var subReaderId = documentId; 
var subReader = subReaders.First(sub => { 
    if (sub.MaxDoc() < subReaderId) { 
     subReaderId -= sub.MaxDoc(); 
     return false; 
    } 

    return true; 
}); 

var values = FieldCache_Fields.DEFAULT.GetInts(subReader, "newsdate"); 
var value = values[subReaderId]; 
+0

감사합니다. Simon 씨, 감사합니다.하지만 새 문서를 인덱스에 추가하면 해당 문서의 문서 ID가 병합시 변경되지 않거나 위의 경우 변경됩니다. 솔루션은 내 필요를 충족시키지 않는다. 새로 추가 된 문서를 FieldCache에 다시 추가하여 FieldCache를 사용하여 모든 문서를 다시로드하지 못하도록하려는 경우, 세그먼트 판독기가 병합/최적화 중에 손상되지 않은 상태로 유지 될 수 있는지 확인한 후 당신의 솔루션과 다른 세그먼트 리더 값을 다시로드하고 점차적으로 성능을 향상 시키지만 여전히 이상적이지는 않습니다. – Ehsan

+0

기술적으로 독자는 병합/최적화 후에 그대로 유지되지만 쓸모없고 새로 만든 세그먼트로 대체됩니다. 현재 설정에서 문제가되는 코드 예제를 제공 할 수 있습니까? – sisve

+0

감사합니다 Simon 코드 스 니펫 코드가 완벽했습니다 – Ehsan

1

이 문제를 해결하는 방법 중 하나는 다음과 같습니다. 몇 분 간격으로 한 번에 하나씩 IndexSearcher 인스턴스를 생성하려면 백그라운드 스레드를 만들어야합니다. 백그라운드 스레드에서 새 인스턴스가 준비 될 때까지 현재 IndexSearcher 인스턴스를 계속 사용하십시오. 그런 다음 새로운 것을 현재의 것으로 교체하십시오. 각 인스턴스는 처음 열 때부터 인덱스의 스냅 샷으로 작동합니다. 한 번에 두 개의 인스턴스가 필요하기 때문에 FieldCache의 메모리 오버 헤드가 두 배가된다는 점에 유의하십시오. 이 상황이 발생하는 동안 IndexWriter에 안전하게 쓸 수 있습니다.

필요한 경우 색인 변경 사항을 즉시 검색 할 수 있도록 설정하면 더 많은 조치를 취할 수 있지만 까다로워 질 수 있습니다. 변경 사항을 메모리에 유지하려면 위의 각 스냅 샷 인스턴스에 RAMDirectory을 연결해야합니다. 그런 다음 RAMDirectory을 가리키는 두 번째 IndexWriter을 만듭니다. 각 색인 쓰기에 대해 IndexWriter 인스턴스에 모두 써야합니다. 검색의 경우 RAMDirectory에 걸쳐 MultiSearcher을 사용하고 디스크의 일반 색인을 사용합니다. RAMDirectory은 더 이상 사용하지 않을 때 IndexSearcher과 결합되면 폐기 될 수 있습니다. 나는 여기에 몇 가지 세부 사항에 대해 설명하고 있지만, 일반적인 생각이다.

희망이 도움이됩니다.

+0

디스크의 FSDirectory에 1000 개의 레코드가 있고 FieldCache를 사용하여로드하면 위의 설명처럼 RAMDirectory에 새로운 10 개의 레코드가 있다고 가정하여 각 디렉토리에 자체 docID가있는 두 개의 문서 ID 0, ..., 10이 있으므로 고유 한 docID가있는 통합 된 FieldCache를 만들 수 없으며 10 회 레코드를 추가 한 후에도 인덱스를 최적화합니다. 이 경우 docID가 변경 될 수 있습니다. – Ehsan

+0

두 번째 부분의 트릭은'FSDirectory'와'RAMDirectory'에서'MultiSearcher '를 사용하여'RAMDirectory'가 변경되기 전에'FSDirectory'가 열리도록하는 것입니다. 따라서 주어진 ID에 대한 두 개의 문서 중 하나가 존재하는 것으로 나타납니다. 그리고'MultiSearcher'는 검색을 수행 할 때이 둘을 병합합니다. 검색을하지 않고'FieldCache'를 사용하지 않는다면? 첫 번째 부분부터 시작 하겠지만, 백그라운드에서 두 번째'IndexSearcher' (또는'IndexReader') 인스턴스를 열어서'FieldCache'를 만들고 나서 그것을 바꿀 수 있습니다. – WhiteFang34

+0

예 FieldCache를 CustomScoreQuery의 검색 범위 외부에서 사용하려고합니다. – Ehsan

관련 문제