`
suichangkele
  • 浏览: 200344 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

lucene中的docValue实现源码解读(四)——BinaryDocValue的写入

阅读更多

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源码分析

    ### Lucene3源码分析知识点概述 #### 一、全文检索的基本原理 ##### 1. 总论 全文检索系统是一种高效的信息检索技术,能够帮助用户在海量文档中快速找到包含特定关键词的信息。Lucene是Java领域内最受欢迎的全文...

    Lucene项目的文档和源码

    源码阅读是理解任何软件内部工作原理的最好方式,通过研究Lucene的源码,我们可以深入了解其内部的数据结构、算法实现以及优化技巧。例如,可以学习到如何实现Trie数据结构进行高效查询,或者如何使用BitSet进行布尔...

    lucene.net2.9.4.2源码版

    《深入剖析Lucene.NET 2.9.4.2源码》 Lucene.NET是一个开源全文搜索引擎库,它是Apache Lucene项目的.NET版本。这个源码版是2.9.4.2版本,相较于2.9.4版进行了一些局部改进,以适应.NET平台的需求和优化。在本文中...

    Lucene源码解读1

    【Lucene源码解读1】 Lucene是一款开源的全文搜索引擎库,由Apache软件基金会开发,广泛应用于各种信息检索系统。其强大的搜索功能和高效的性能深受开发者喜爱。在深入理解Lucene之前,我们需要先了解它的核心概念...

    Lucene3.5源码jar包

    总的来说,深入学习Lucene 3.5.0的源码,可以帮助开发者掌握全文检索的核心技术,了解其内部工作原理,并能灵活应用到自己的项目中。这份源码不仅适用于初学者,也是经验丰富的开发者的宝贵参考资料。通过阅读和理解...

    Lucene.Net-2.9.2 c#源码

    通过深入理解Lucene.Net 2.9.2的源码,开发者可以定制自己的分析器、优化查询性能、调整索引策略,从而在实际项目中充分发挥Lucene.Net的潜力。在构建查询网站时,结合C#的特性,可以构建出高效、灵活且用户体验良好...

    Lucene学习源码.rar

    本文将主要围绕Java Lucene进行深入探讨,并基于提供的“Lucene学习源码.rar”文件中的“Lucene视频教程_讲解部分源码”展开讨论。 一、Lucene核心概念 1. 文档(Document):Lucene中的基本单位,用于存储待检索...

    lucene全文检索案例源码

    通过对“lucene全文检索案例源码”的学习,我们可以理解Lucene如何在实际项目中实现全文检索。从索引构建到搜索执行,每个步骤都至关重要。通过源码的深入研究,有助于我们在实际开发中更好地运用Lucene,提升搜索...

    lucene.net 2.9.1 源码

    《深入剖析Lucene.NET 2.9.1:源码解析与应用开发》 Lucene.NET 2.9.1是开源搜索引擎库Lucene的.NET版本,它为.NET开发者提供了强大的全文检索和索引功能。这个版本的源码提供了一个宝贵的资源,帮助我们理解其内部...

    使用Lucene对doc、docx、pdf、txt文档进行全文检索功能的实现 - 干勾鱼的CSDN博客 - CSDN博客1

    在Java开发中,Lucene被广泛用于实现文件的全文检索功能,包括对doc、docx、pdf、txt等常见格式文档的文本内容检索。在本文中,我们将探讨如何使用Lucene对这些文件类型进行全文检索的实现。 首先,为了实现全文...

    基于lucene搜索引擎的java源码

    学习这个源码包可以帮助你理解如何在Java环境中使用Lucene进行全文检索,以及如何实现数据库与索引之间的交互。这不仅涉及到了Lucene的核心功能,也涵盖了实际项目中常见的增量索引和数据库集成问题。通过阅读和理解...

    lucene in action源码2

    总之,《Lucene in Action》的源码是一份宝贵的教育资源,它能帮助开发者深入理解搜索引擎的运作原理,从而在实际项目中更好地利用Lucene。通过细致研究源码,我们不仅可以解决具体的技术问题,还能培养出更强的解决...

    lucene 华电项目 源码

    本文将结合“lucene 华电项目 源码”,深度解析Lucene的核心原理以及在华电项目中的实际应用。 首先,我们要理解Lucene的基本架构。Lucene的核心组件包括Analyzer(分析器)、Document(文档)、IndexWriter(索引...

    Lucene中的FST算法描述

    4. FSTHashMap:这是一个基于探测法实现的HashMap,其key是基于FSTNode生成的hash值,而value是FSTnode在FSTbytes数组中的位置索引。FSTHashMap可以加速判断某个节点是否已经被存储到FSTbytes中。 5. Frontier:这...

    Lucene In Action 2源码

    源码文件通常包含了书中各个章节的示例程序,这些示例涵盖了Lucene的基本用法到高级特性的实现,如文档索引、搜索查询、结果排序、过滤器、分词器、高亮显示等。通过研究这些源码,开发者可以了解如何有效地利用...

    运用在lucene中的中文分词算法源码

    《深入剖析Lucene中的中文分词算法源码》 在信息检索领域,Lucene作为一款强大的全文搜索引擎库,被广泛应用于各种数据检索系统。而中文分词是Lucene处理中文文本时的关键步骤,它决定了搜索的准确性和效率。本文将...

    lucene源码和程序

    在`lucene-1.4-final`这个压缩包中,包含了Lucene 1.4版本的源代码,你可以深入研究其内部实现,理解各个类和方法的工作原理。同时,这也可以帮助你定制分析器、优化搜索性能,或者扩展Lucene的功能,例如集成到你的...

    Lucene.Net源码与说明文档

    **Lucene.Net** 是一个基于 .NET Framework 的全文搜索引擎库,它是 Apache Lucene 项目的 .NET 实现。这个开源项目提供了高效、可扩展的搜索功能,使得开发者能够在其应用程序中轻松地实现高级的文本检索功能。 **...

    lucene-2.9.2.jar包+源码

    在Lucene-2.9.2的源码中,你可以看到关于TF-IDF的具体实现,如`TFIDFSimilarity`类,它是Lucene对TF-IDF算法的封装。它不仅包含了TF和IDF的计算逻辑,还考虑了诸如短语匹配、长度惩罚等因素,以提升搜索精度。 除了...

    Lucene源码

    作为一款Java实现的全文搜索引擎架构,Lucene 提供了完整的索引和查询引擎,使得开发者能够快速、有效地在大量数据中进行文本搜索。 ### Lucene 的核心组件 1. **索引(Indexing)**: Lucene 的索引过程将文档内容...

Global site tag (gtag.js) - Google Analytics