对lucene的docValue的读取是在Lucene410DocValuesProducer中,我们看下他的构造方法,其中类的代码我也复制了一些有用的
class Lucene410DocValuesProducer extends DocValuesProducer implements Closeable { /** 适用于numericDocValue的docValue,key是域号,value是对应的域的meta文件的属性,在打开时候就会读取meta文件*/ private final Map<Integer, NumericEntry> numerics; private final AtomicLong ramBytesUsed; private final IndexInput data; private final int maxDoc; private final int version; // memory-resident structures private final Map<Integer, MonotonicBlockPackedReader> addressInstances = new HashMap<>(); private final Map<Integer, MonotonicBlockPackedReader> ordIndexInstances = new HashMap<>(); /** expert: instantiates a new reader */ Lucene49DocValuesProducer(SegmentReadState state, String dataCodec, String dataExtension, String metaCodec, String metaExtension) throws IOException { String metaName = IndexFileNames.segmentFileName(state.segmentInfo.name, state.segmentSuffix, metaExtension); // read in the entries from the metadata file. ChecksumIndexInput in = state.directory.openChecksumInput(metaName, state.context); this.maxDoc = state.segmentInfo.getDocCount(); boolean success = false; try { version = CodecUtil.checkHeader(in, metaCodec, Lucene49DocValuesFormat.VERSION_START, Lucene49DocValuesFormat.VERSION_CURRENT); numerics = new HashMap<>(); 。。。//省略了一些不相关的 readFields(in, state.fieldInfos);//读取所有的docValue,包括各种类型的,这个是在meta(也就是在索引文件,dvm)中读取的 CodecUtil.checkFooter(in); success = true; } finally { if (success) { IOUtils.close(in); } else { IOUtils.closeWhileHandlingException(in); } } String dataName = IndexFileNames.segmentFileName(state.segmentInfo.name, state.segmentSuffix, dataExtension); this.data = state.directory.openInput(dataName, state.context);//打开实际的存储文件。 success = false; 。。。//省略 ramBytesUsed = new AtomicLong(RamUsageEstimator.shallowSizeOfInstance(getClass())); }
在构造这个读取docValue的对象的时候,就会读取索引文件,里面会读取meta文件,然后封装为XxxEntry对象,放到内存中,这个类中的private final Map<Integer, NumericEntry> numerics;属性就是根据域存放的meta文件的描述。读取meta文件在readFields方法中,里面会读取各种不同的类型的docValue,这里只看了数字类型的:
static NumericEntry readNumericEntry(IndexInput meta) throws IOException { //读取的当前的docvalue的信息,来自于meta, NumericEntry entry = new NumericEntry(); entry.format = meta.readVInt();//存储的 格式,比如最大公约数差值、差值、压缩表 entry.missingOffset = meta.readLong();//存储的missing的docs在data中的fp(偏移量) entry.offset = meta.readLong();//正真的存储位置的偏移量(也就是再超过上面的missingDocBitset) entry.count = meta.readVLong();//一共多少个doc switch (entry.format) { case GCD_COMPRESSED://基于最大公约数的 entry.minValue = meta.readLong();//最小值 entry.gcd = meta.readLong();//最大公约数 entry.bitsPerValue = meta.readVInt();//每个数字占据的bit的数量,用于解码 break; case TABLE_COMPRESSED://压缩表的,适用于docValue的数字比较少的时候 final int uniqueValues = meta.readVInt();//具体的数字的个数 if (uniqueValues > 256) { throw new CorruptIndexException( "TABLE_COMPRESSED cannot have more than 256 distinct values, input=" + meta); } entry.table = new long[uniqueValues]; for (int i = 0; i < uniqueValues; ++i) {//读取所有的值,之前都放在meta中了。 entry.table[i] = meta.readLong(); } entry.bitsPerValue = meta.readVInt();//这个值是用于解码用的。 break; case DELTA_COMPRESSED: entry.minValue = meta.readLong();//最小值, entry.bitsPerValue = meta.readVInt();//在data中用于记录某个值的位数,用于解码。 break; case MONOTONIC_COMPRESSED://这个是没有的。在Lucene49DocValuesConsumer只有上面的三种格式 entry.packedIntsVersion = meta.readVInt(); entry.blockSize = meta.readVInt(); break; default: throw new CorruptIndexException("Unknown format: " + entry.format + ", input=" + meta); } entry.endOffset = meta.readLong();//结束位置, return entry; }
这里可以发现,是把meta文件中有用到的属性 都读取出来,然后放到内存中了,但是还没有真正的读取数字类型的docValue。真正的读取操作是在这个方法里面
@Override public NumericDocValues getNumeric(FieldInfo field) throws IOException { NumericEntry entry = numerics.get(field.number); return getNumeric(entry); }
其中的numerics就是之前读取的所有的域的meta文件,里面根据域的序号进行查找的,所以更关键的方法是getNumeric方法:
//尽管我们可以使用多种类型的数字类型的,但是在存储的时候都是存储的long类型的,这里读取的也是 LongValues getNumeric(NumericEntry entry) throws IOException { RandomAccessInput slice = this.data.randomAccessSlice(entry.offset, entry.endOffset - entry.offset);//这个方法是最关键的,他会读取data文件中的指定的一块。但是是否读取到内存中,我也不知道,求帮助! switch (entry.format) { case DELTA_COMPRESSED://差值的 final long delta = entry.minValue; final LongValues values = DirectReader.getInstance(slice, entry.bitsPerValue); return new LongValues() { @Override public long get(long id) { return delta + values.get(id);//直接读取差值+最小值即可 } }; case GCD_COMPRESSED://最大公约数的,和差值的差不多 final long min = entry.minValue; final long mult = entry.gcd; final LongValues quotientReader = DirectReader.getInstance(slice, entry.bitsPerValue); return new LongValues() { @Override public long get(long id) { return min + mult * quotientReader.get(id); } }; case TABLE_COMPRESSED://压缩表的,根据排序值进行读取 final long table[] = entry.table; final LongValues ords = DirectReader.getInstance(slice, entry.bitsPerValue); return new LongValues() { @Override public long get(long id) { return table[(int) ords.get(id)]; } }; default: throw new AssertionError(); } }
在看懂了写入的前提下,读取的代码要简单的多,但是有一个重要的地方就是上面标红的randomAcessSlice方法。如果有大神看到了,希望能给我们解疑答惑一下,他到底是读取到内存中呢,还是靠操作系统加载到内存中呢还是压根就不会再内存中操作。
还有一个需要注意的地方是,在读取的时候没有考虑了那个bitset,就是记录含有值得doc的id的bitset,所以如果读到了0,还需要判断一下是不是存在,即是不是在那个bitset中。
相关推荐
lucene3源码分析
Lucene项目的文档和源码,很好的java学习资料哦
lucene索引查看工具及源码lucene索引查看工具及源码lucene索引查看工具及源码
Lucene.Net-2.9.2 c# 源码,已经用它做了查询网站
lucene全文检索案例源码 lucene全文检索案例源码
Lucene是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎。该资源是Lucene的完整源码,利用源码,可以定制适合自身需要的搜索引擎。
lucene.net2.9.4.2源码版 dll版本是2.9.4.2 对2.9.4版的局部改进版
Lucene3.5全部源码,打包jar文件,可以直接打开查看源码,Lucene开发必备
Lucene源码解读、功能分析,Lucene入门
Lucene学习源码.rar
lucene.net 2.9.1 源码,lucene.net 2.9.1最新dll
这是基于lucene搜索引擎的java源码,里面数据库,包括建立索引,增量索引一应俱全,希望对大家有作用。
描述了Lucene中如何使用FST算法构建term的内存索引,使用了很多图,直观的展现了FST图的构建流程,能够对想了解lucene内部实现机制原理的同学有帮助。
lucene-core-4.3.1的源码 可以用的 放心用吧 官网上很多链接都打不开
Lucene,作为一种全文搜索的辅助工具,为我们进行条件搜索,无论是像Google,Baidu之类的搜索引 擎,还是论坛中的搜索功能,还是其它C/S架构的搜索,都带来了极大的便利和比较高的效率。本文主要是利用Lucene对MS Sql...
Lucene.net 搜索引擎 Lucene.net源码 Lucene.net中文文档; 好的东西需要分享
lucene 华电项目 源码
lucene3.0.3源码和教程
lucene5.0源码包,里面有源码、帮助文档、API、架包
Lucene 4.1 最新版本 源码 修复诸多BUG 含英文API 新增AnalyzingSuggester和FuzzySuggester等,性能优化 欢迎下载