FiledCache介绍
Lucene作为列缓存, 可以获取设置了Filed.Store.Yes上的正排数据信息.通常IndexSearcher.doc(docId)获得Document的所有域值,访问速度比较慢.但是通过FieldCache读取doc的分片信息,速度可以提升很多.
注意:FieldCache并非在存储域中读取,而是在索引域中读取,从而不必构造Document对象,要求此索引域是不分词的,有且只有一个Token.
在lucene中,一些用于排序的字段,lucene 在首次使用的时候将这个field下所有term转换成float(如下图所示),并存放入FieldCache中,这样在第二次使用的时候就能直接从该缓存中获取。从term->docId倒排信息转化为常驻内存的正排信息.(数组中index为docid的次序)
代码示例:
DirectoryReader dirReader = (DirectoryReader) DirectoryReader.open(IDX_DIR);;
FieldCache.Ints ints = FieldCache.DEFAULT.getInts(dirReader.leaves().get(0).reader(), "id", false);
BinaryDocValues terms = FieldCache.DEFAULT.getTerms(dirReader.leaves().get(0).reader(), "string", false);
BytesRef bytesRef = terms.get(0);
Assert.assertEquals("abc", bytesRef.utf8ToString());
从示例代码中可以看出,FieldCache通过FieldCacheImpl来实现缓存的功能,而FiledCacheImpl底层实现是利用 WeakHashMap, 详见代码:
/** Expert: Internal cache. */
abstract static class Cache {
Cache(FieldCacheImpl wrapper) {
this.wrapper = wrapper;
}
final FieldCacheImpl wrapper;
final Map<Object,Map<CacheKey,Accountable>> readerCache = new WeakHashMap<>();
protected abstract Accountable createValue(AtomicReader reader, CacheKey key, boolean setDocsWithField)
throws IOException;
/** Remove this reader from the cache, if present. */
public void purgeByCacheKey(Object coreCacheKey) {
synchronized(readerCache) {
readerCache.remove(coreCacheKey);
}
}
WeakHashMap包含了一个自动调用的方法expungeStaleEntries,这样就会在值被引用后直接执行这个隐含的方法,将不用的键清除掉.
FieldCacheImpl中get函数获取流程
FiledCache在数据获取过程中, 首先到DocValues中获取,如果数据不存在,然后通过FiledCacheImpl读取cache信息.DocValues优点见:Lucene系列-docValues
public BinaryDocValues getTerms(AtomicReader reader, String field, boolean setDocsWithField, float acceptableOverheadRatio) throws IOException {
BinaryDocValues valuesIn = reader.getBinaryDocValues(field);
if (valuesIn == null) {
valuesIn = reader.getSortedDocValues(field);
}
if (valuesIn != null) {
// Not cached here by FieldCacheImpl (cached instead
// per-thread by SegmentReader):
return valuesIn;
}
final FieldInfo info = reader.getFieldInfos().fieldInfo(field);
if (info == null) {
return DocValues.emptyBinary();
} else if (info.hasDocValues()) {
throw new IllegalStateException("Type mismatch: " + field + " was indexed as " + info.getDocValuesType());
} else if (!info.isIndexed()) {
return DocValues.emptyBinary();
}
BinaryDocValuesImpl impl = (BinaryDocValuesImpl) caches.get(BinaryDocValues.class).get(reader, new CacheKey(field, acceptableOverheadRatio), setDocsWithField);
return impl.iterator();
}