目前,我正在使用Java平台上的Lucene 4.9.0开发高性能NRT系统,该系统检测近乎重复的文本文档。
为此,我查询Lucene返回一些匹配候选项并在本地进行近似重复计算(通过检索和缓存术语向量)。但我主要担心的是将Lucene的docId(可以改变)绑定到我自己的索引中存储的唯一且不可变的文档id的性能问题。
我的流程如下:
我的主要瓶颈是“获取我独特的文档ID”步骤,这会导致巨大的性能下降(特别是有时我必须在单循环中进行计算,比如40000个术语向量)。 / p>
try {
Document document = indexReader.document(id);
return document.getField(ID_FIELD_NAME).numericValue().intValue();
} catch (IOException e) {
throw new IndexException(e);
}
我正在考虑的可能解决方案是:
还有其他建议吗?
答案 0 :(得分:0)
我已经找到了如何使用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();
它运作得非常快。我主要担心的是使用大索引时内存使用率可能非常高。