BinaryDocValue是存储的byte[],也就是他可以存一些字符串、图片,等可以用byte[]表示的内容。他的使用场景我们不关心,主要看下他是如何在lucene中存储的吧。他的添加还是在DefaultIndexingChain.indexDocValue方法里面,这里还是先保存在内存中,我们介绍一下如何在内存中保存的。使用的类是:BinaryDocValuesWriter,构造方法如下:
public BinaryDocValuesWriter(FieldInfo fieldInfo, Counter iwBytesUsed) { this.fieldInfo = fieldInfo;//要添加的域 this.bytes = new PagedBytes(BLOCK_BITS);//这个是要保存所有的byte[]的容器,他的好处是他是压缩的,可以节省内存。可以直接将其看作是一个很大的byte[] this.bytesOut = bytes.getDataOutput();//获得上面说的byte[]的添加入口 this.lengths = PackedLongValues.deltaPackedBuilder(PackedInts.COMPACT);//用来记录每个doc的byte[]长度的东西,因为在最后是将每个doc的byte[]放到一个大大的byte[]里面,所以要记录每个doc的byte[]的长度 this.iwBytesUsed = iwBytesUsed;//用来记录使用的内存的,可以忽略 this.docsWithField = new FixedBitSet(64);//记录含有值得doc的id的对象 this.bytesUsed = docsWithFieldBytesUsed(); iwBytesUsed.addAndGet(bytesUsed); }
下面看下添加docValue的方法:
public void addValue(int docID, BytesRef value) { 。。。//校验的方法去掉 // Fill in any holes: while (addedValues < docID) {//这个是添加窟窿,因为有的doc没有byte[],这时候要在记录长度的对象里面用0填充。(其实我觉得没有必要,只需要稍微改动下下面的迭代器的代码就可以避免这里的操作了。见下面加粗倾斜的说明) addedValues++; lengths.add(0); } addedValues++; lengths.add(value.length);//记录要添加的byte[]的大小 try { bytesOut.writeBytes(value.bytes, value.offset, value.length);//将byte[]写入到内存中 } catch (IOException ioe) { // Should never happen! throw new RuntimeException(ioe); } docsWithField = FixedBitSet.ensureCapacity(docsWithField, docID); docsWithField.set(docID);//记录这个id,表示其在这个域中有值 updateBytesUsed(); }
通过上面的额方法已经将每一个doc的byte[]写入到内存里面了,我们看下当flush的时候的操作
public void flush(SegmentWriteState state, DocValuesConsumer dvConsumer) throws IOException { final int maxDoc = state.segmentInfo.getDocCount();//当前段的所有的doc的数量 bytes.freeze(false); final PackedLongValues lengths = this.lengths.build();// dvConsumer.addBinaryField(fieldInfo, new Iterable<BytesRef>() {//添加的一个参数是一个迭代器生成器,重写了iterator方法,返回的迭代器的参数第一个是所有的额doc的数量,第二个是记录每个doc的byte[]的对象 public Iterator<BytesRef> iterator() { return new BytesIterator(maxDoc, lengths); } }); }
看一下迭代器,BytesIterator的next方法,他返回所有的要保存在索引中的byte[]
public BytesRef next() { if (!hasNext()) { throw new NoSuchElementException(); } final BytesRef v; if (upto < size) { int length = (int) lengthsIterator.next();//得到这个byte[]de 长度 value.grow(length); value.setLength(length); try { bytesIterator.readBytes(value.bytes(), 0, value.length());//从里面读取指定长度的byte[],读取到value里面 } catch (IOException ioe) { // Should never happen! throw new RuntimeException(ioe); } if (docsWithField.get(upto)) {//如果存在这个id的,则返回value。(如果我们把这个检查放在lengthsIterator.next前面,如果不存在的话,就可以直接返回null,这样上面也就不用填窟窿了) v = value.get(); } else {//不存在返回null v = null; } } else { v = null; } upto++; return v; }
从这个方法里面可以得出,他会将所有的doc的值返回,如果这个doc没有值,则返回null,堆byte[]的读取是通过记录每个byte[]的对象 以及记录所有的byte[]的对象联合实现的。我们看下最终的flush方法,也就是DocValueConsumer使用迭代器的方法。4.10.4中使用的是Lucene410DocValuesConsumer,和数字类型的docValue是一样的,只不过调用的方法是addBinaryField方法,
@Override public void addBinaryField(FieldInfo field, Iterable<BytesRef> values) throws IOException { meta.writeVInt(field.number);//写入域号,这里的meta和numericDocValue的是一样的,都是data的索引文件, meta.writeByte(Lucene410DocValuesFormat.BINARY); int minLength = Integer.MAX_VALUE; int maxLength = Integer.MIN_VALUE; final long startFP = data.getFilePointer(); long count = 0; boolean missing = false; for (BytesRef v : values) {//循环所有的byte[],如果不是null,则写入到data中, final int length; if (v == null) { length = 0; missing = true; } else { length = v.length; } minLength = Math.min(minLength, length); maxLength = Math.max(maxLength, length); if (v != null) { data.writeBytes(v.bytes, v.offset, v.length);//写入所有的byte[]到data中,这样data就相当于是一个大大的byte[]了,将多个晓得byte[]记录在里面。 } count++; } //写入的格式,有两种,一个是没有压缩的,当所有的byte[]一样长的时候,否则使用压缩的。 meta.writeVInt(minLength == maxLength ? BINARY_FIXED_UNCOMPRESSED : BINARY_VARIABLE_UNCOMPRESSED); if (missing) {//如果有没有值得doc,则在data中记录所有的含有值的id,这一点和numericDocValue也是一样的。 meta.writeLong(data.getFilePointer());//在meta中记录docset写入的fp,也就是索引。 writeMissingBitset(values); } else {//否则写入-1 meta.writeLong(-1L); } meta.writeVInt(minLength); meta.writeVInt(maxLength); meta.writeVLong(count);//doc的数量,这个源码中的注释错了,他的注释是写入的值得个数,并不是的,其实是doc的数量,因为有的额doc是没有值的。 meta.writeLong(startFP);//记录没有写入任何的byte[]是的data的fp, // if minLength == maxLength, its a fixed-length byte[], we are done (the addresses are implicit) otherwise, we need to record the length fields... 这句英文的意思是如果所有的byte[]的长度都一样,则就没事了,但是这个在实际中几乎是不成立的, if (minLength != maxLength) {//如果长度不一致,则写入每个doc的值得长度,这样就很容易从那个大大byte[]里面里面找到每个doc的开始位置了。 meta.writeLong(data.getFilePointer());//记录此时的data的索引,下面要记录每个doc的开始位置了 meta.writeVInt(PackedInts.VERSION_CURRENT); meta.writeVInt(BLOCK_SIZE); final MonotonicBlockPackedWriter writer = new MonotonicBlockPackedWriter(data, BLOCK_SIZE); long addr = 0; writer.add(addr);//写入第一个doc的开始位置 for (BytesRef v : values) { if (v != null) {//写入每个doc的结束位置(也就是下一个doc的开始位置),这样,相邻的两个doc的差值就是前一个doc的值的长度,对于没有值的doc,他的长度是0,前后两个的值是一样的 addr += v.length; } writer.add(addr);//如果v==null则addr不变化,长度是0 } writer.finish(); } }
这样,就将每个byte[]写入到索引里面了。
总结一下,BinaryDocValue其实就是将所有的byte[]写入到硬盘上,然后再将记录每个doc的byte[]长度的数字也写到硬盘上,并且将每个部分的fp(也就是开始位置,理解为索引)写入到meta文件中。
其实binaryDocValue要比NumericDocValue简单,因为他不会有很多形式。
相关推荐
### Lucene3源码分析知识点概述 #### 一、全文检索的基本原理 ##### 1. 总论 全文检索系统是一种高效的信息检索技术,能够帮助用户在海量文档中快速找到包含特定关键词的信息。Lucene是Java领域内最受欢迎的全文...
源码阅读是理解任何软件内部工作原理的最好方式,通过研究Lucene的源码,我们可以深入了解其内部的数据结构、算法实现以及优化技巧。例如,可以学习到如何实现Trie数据结构进行高效查询,或者如何使用BitSet进行布尔...
《深入剖析Lucene.NET 2.9.4.2源码》 Lucene.NET是一个开源全文搜索引擎库,它是Apache Lucene项目的.NET版本。这个源码版是2.9.4.2版本,相较于2.9.4版进行了一些局部改进,以适应.NET平台的需求和优化。在本文中...
【Lucene源码解读1】 Lucene是一款开源的全文搜索引擎库,由Apache软件基金会开发,广泛应用于各种信息检索系统。其强大的搜索功能和高效的性能深受开发者喜爱。在深入理解Lucene之前,我们需要先了解它的核心概念...
总的来说,深入学习Lucene 3.5.0的源码,可以帮助开发者掌握全文检索的核心技术,了解其内部工作原理,并能灵活应用到自己的项目中。这份源码不仅适用于初学者,也是经验丰富的开发者的宝贵参考资料。通过阅读和理解...
通过深入理解Lucene.Net 2.9.2的源码,开发者可以定制自己的分析器、优化查询性能、调整索引策略,从而在实际项目中充分发挥Lucene.Net的潜力。在构建查询网站时,结合C#的特性,可以构建出高效、灵活且用户体验良好...
本文将主要围绕Java Lucene进行深入探讨,并基于提供的“Lucene学习源码.rar”文件中的“Lucene视频教程_讲解部分源码”展开讨论。 一、Lucene核心概念 1. 文档(Document):Lucene中的基本单位,用于存储待检索...
通过对“lucene全文检索案例源码”的学习,我们可以理解Lucene如何在实际项目中实现全文检索。从索引构建到搜索执行,每个步骤都至关重要。通过源码的深入研究,有助于我们在实际开发中更好地运用Lucene,提升搜索...
《深入剖析Lucene.NET 2.9.1:源码解析与应用开发》 Lucene.NET 2.9.1是开源搜索引擎库Lucene的.NET版本,它为.NET开发者提供了强大的全文检索和索引功能。这个版本的源码提供了一个宝贵的资源,帮助我们理解其内部...
在Java开发中,Lucene被广泛用于实现文件的全文检索功能,包括对doc、docx、pdf、txt等常见格式文档的文本内容检索。在本文中,我们将探讨如何使用Lucene对这些文件类型进行全文检索的实现。 首先,为了实现全文...
学习这个源码包可以帮助你理解如何在Java环境中使用Lucene进行全文检索,以及如何实现数据库与索引之间的交互。这不仅涉及到了Lucene的核心功能,也涵盖了实际项目中常见的增量索引和数据库集成问题。通过阅读和理解...
总之,《Lucene in Action》的源码是一份宝贵的教育资源,它能帮助开发者深入理解搜索引擎的运作原理,从而在实际项目中更好地利用Lucene。通过细致研究源码,我们不仅可以解决具体的技术问题,还能培养出更强的解决...
本文将结合“lucene 华电项目 源码”,深度解析Lucene的核心原理以及在华电项目中的实际应用。 首先,我们要理解Lucene的基本架构。Lucene的核心组件包括Analyzer(分析器)、Document(文档)、IndexWriter(索引...
4. FSTHashMap:这是一个基于探测法实现的HashMap,其key是基于FSTNode生成的hash值,而value是FSTnode在FSTbytes数组中的位置索引。FSTHashMap可以加速判断某个节点是否已经被存储到FSTbytes中。 5. Frontier:这...
源码文件通常包含了书中各个章节的示例程序,这些示例涵盖了Lucene的基本用法到高级特性的实现,如文档索引、搜索查询、结果排序、过滤器、分词器、高亮显示等。通过研究这些源码,开发者可以了解如何有效地利用...
《深入剖析Lucene中的中文分词算法源码》 在信息检索领域,Lucene作为一款强大的全文搜索引擎库,被广泛应用于各种数据检索系统。而中文分词是Lucene处理中文文本时的关键步骤,它决定了搜索的准确性和效率。本文将...
在`lucene-1.4-final`这个压缩包中,包含了Lucene 1.4版本的源代码,你可以深入研究其内部实现,理解各个类和方法的工作原理。同时,这也可以帮助你定制分析器、优化搜索性能,或者扩展Lucene的功能,例如集成到你的...
**Lucene.Net** 是一个基于 .NET Framework 的全文搜索引擎库,它是 Apache Lucene 项目的 .NET 实现。这个开源项目提供了高效、可扩展的搜索功能,使得开发者能够在其应用程序中轻松地实现高级的文本检索功能。 **...
在Lucene-2.9.2的源码中,你可以看到关于TF-IDF的具体实现,如`TFIDFSimilarity`类,它是Lucene对TF-IDF算法的封装。它不仅包含了TF和IDF的计算逻辑,还考虑了诸如短语匹配、长度惩罚等因素,以提升搜索精度。 除了...
作为一款Java实现的全文搜索引擎架构,Lucene 提供了完整的索引和查询引擎,使得开发者能够快速、有效地在大量数据中进行文本搜索。 ### Lucene 的核心组件 1. **索引(Indexing)**: Lucene 的索引过程将文档内容...