Lucene 源码分析——BKD-Tree

news2024/11/16 13:39:03

Lucene 源码分析——BKD-Tree - AIQ

Bkd-Tree

Bkd-Tree作为一种基于K-D-B-tree的索引结构,用来对多维度的点数据(multi-dimensional point data)集进行索引。Bkd-Tree跟K-D-B-tree的理论部分在本篇文章中不详细介绍,对应的两篇论文在附件中,感兴趣的朋友可以自行下载阅读。本篇文章中主要介绍Bkd-Tree在Lucene中的实现,即生成树的过程。

预备知识

如果只是想了解Bkd-Tree生成过程,那么这节内容可以跳过,这块内容是为介绍索引文件.dim、.dii作准备的。

点数据

点数据(Point Data),源码中又称为点值(Point Value),它是由多个数值类型组成。
图1:

1.png

上图中由4个int类型数值组成一个点数据/点值,并且根据点数据中的数值个数定义了维度个数。上图中即有四个维度。同一个域名的点数据必须有相同的维度个数,并且在当前7.5.0版本中,维度个数最多为8个。

int numPoints

numPoints是一个从0开始递增的值,可以理解为是每一个点数据的一个唯一编号,并且通过这个编号能映射出该点数据属于哪一个文档(document)。映射关系则是通过docIDs[ ]数组实现。

int docIDs[ ]数组

docIDs[ ]数组在PointValuesWriter.java中定义,数组下标是点数据的编号numPoint,数组元素是点数据所属的文档号。由于一篇文档中可以有多个点数据,所以相同的数组元素对应的多个数组下标值,即numPoints,即点数据,都是属于同一个文档。
图2:

2.png

上图中只添加了2篇文档,处理顺序按照文档号的顺序,所以文档0的点数据的numPoints的值为0,另外一篇文档可以有多个点数,所以numPoints的值分别为1、2。生成的docIDs[]数组如下:
图3:

3.png

int ord[ ]数组

ord数组的数组元素为numPoints,下面的一句话很重要:ord数组中的元素是有序的,排序规则不是按照numPoints的值,而是按照numPoints对应的点数据的值。这里ord数组的用法跟SortedDocValues中的sortedValues[]数组是一样的用法。例如根据图2中的点数据,如果我们按照第三个维度的值,即"99"、"23"、"12"来描述点数据的大小关系,那么ord数组如下图所示:
图4:

4.png

这里先提一句,在生成BKD-Tree之后,叶子节点中的点数据会根据某个维度进行排序的,并且所有叶子节点中的点数据的大小关系就存放在ord[]数组中,后面的内容会详细介绍这过程。

流程图

一句话概括整个流程的话就是:根据某一个维度将点数据集划分为两部分,递归式将两部分的点数据子集进行划分,最终生成一个满二叉树
图5:

5.png

点数据集

图6:

6.png

点数据集即为待处理的点数据集合。

是否要切分?

图7:

7.png

如果数据集的个数大于1024个,那么需要进行拆分。在源码中并不是通过判断数据集的个数,而是在建立Bkd-Tree之前就预先计算出当前数据会对应生成节点(node)的个数(可以认为每个节点中的数据都是空的),然后采用深度遍历方式处理每一个节点,通过节点编号来判断是否为叶子节点。如果不是叶子节点,说明要切分(节点赋值)。

选出切分维度

图8:

8.png

一个点数据中有多个维度,例如图1中就有四个维度。

  • 本文地址:Lucene 源码分析——BKD-Tree
  • 本文版权归作者和AIQ共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出

  1. 先计算出切分次数最多的那个维度,切分次数记为maxNumSplits,如果有一个维度的切分次数小于 (maxNumSplits / 2) ,并且该维度中的最大跟最小值不相同,那么令该维度为切分维度。
  2. 计算出每一个维度中最大值跟最小值的差值,差值最大的作为切分维度(篇幅原因,下面的例子中仅使用了这种判定方式)。

条件1优先条件2。

点数据集排序

图9:

9.png

当确定了切分维度后,我们对当前节点中的点数据集进行排序,排序规则根据该每个点数据中的该维度的值,排序算法使用最大有效位的基数排序(MSB radix sort)。

切分出左子树点数据集、切分出右子树点数据集

图10:

10.png

执行完排序操作后,当前节点中的点数据集数量为N,那么将前 (N / 2)个的点数据集划分为左子树,剩余的划分为右子树。
这么划分的目的使得无论初始的点数据集是哪种数据分布,总是能生成一颗满二叉树

是否退出

图11:

11.png

当前节点不需要切分,需要判断下算法是否需要退出。

结束

  • 当前节点是满二叉树的最右子树,那么算法结束,可以退出。
  • 当前树中只有一个节点,且该节点不需要切分,那么算法结束,可以退出。

返回上一层

  • 当前处理的节点是左子树节点或者是非最右子树节点,说明该节点是由 划分左右子树生成的,即算法还处在递归中,当不需要划分后,返回到递归的上一层。

例子

Lucene 7.5.0版本源码中当一个节点中的点数据个数大于1024才会进行切分,为了能简单示例,例子中假设一个节点中的点数据个数大于2个才会进行切分,并且点数据的维度为2。

点数据集

图12:

12.png

上图中一共有8个点数据,每个点数据有两个维度。为了描述方便,下面统称为x维度,跟y维度。

处理节点1

  • 是否要切分:初始的数据集作为第一个节点,即节点1开始进行切分,该节点中有8个数据,大于节点切分的条件值2,所以需要切分。
  • 选出切分维度:x维度的最大值跟最小值的差值为7 ,而y维度的最大值跟最小值的差值为9,所以当前节点的切分维度为y维度。
  • 点数据排序:对8个点数据按照y维度的值进行排序,排序后的结果如下:
{1,2} -> {4,3} -> {3,4} -> {4,6} -> {6,7} -> {2,8} -> {8,9} -> {7,11}
  • 切分出左子树数据集、切分出右子树数据集:当前节点个数为8,从排序后的点数据中取前一半的点数据划为左子树(节点2),剩余的划为右子树(节点3)。
左子树:{1,2}、{4,3}、{3,4}、{4,6}
右子树:{6,7}、{2,8}、{8,9}、{7,11}

图13:

13.png

处理节点2

  • 是否要切分:节点2中有4个数据,大于节点切分的条件值2,所以需要切分。
  • 选出切分维度:x维度的最大值跟最小值的差值为3 ,而y维度的最大值跟最小值的差值为4,所以当前节点的切分维度为y维度。
  • 点数据排序:对4个点数据按照y维度的值进行排序,排序后的结果如下:
{1,2}、{4,3}、{3,4}、{4,6}
  • 切分出左子树数据集、切分出右子树数据集:当前节点个数为4,从排序后的点数据中取前一半的点数据划为左子树(节点4),剩余的划为右子树(节点5)。
左子树:{1,2}、{4,3}
右子树:{3,4}、{4,6}

图14:

14.png

处理节点4、5

源码中对叶子结点还有一些处理,目的是为了生成索引文件作准备,在随后的介绍索引文件.dii、.dim时候会介绍跟叶子节点相关的知识,这篇文章主要介绍生成Bkd-Tree的过程。

处理节点3

  • 是否要切分:节点3中有4个数据,大于节点切分的条件值2,所以需要切分。
  • 选出切分维度:x维度的最大值跟最小值的差值为6 ,而y维度的最大值跟最小值的差值为4,所以当前节点的切分维度为x维度。
  • 点数据排序:对4个点数据按照x维度的值进行排序,排序后的结果如下:
{2,8}、{6,7}、{7,11}、{8,9}
  • 切分出左子树数据集、切分出右子树数据集:当前节点个数为4,从排序后的点数据中取前一半的点数据划为左子树(节点6),剩余的划为右子树(节点7)。
左子树:{2,8}、{6,7}
右子树:{7,11}、{8,9}

图15:

15.png

处理节点6、7

同节点4、5

结语

本篇文件介绍了Bkd-Tree在Lucene中的实现,即生成满二叉树的过程,再以后介绍索引文件.dii、.dim中会继续讲一些细节的东西。另外在随后的文章中会介绍Bkd-Tree插入和更新的内容。

原文地址:https://www.amazingkoala.com.cn/Lucene/gongjulei/2019/0422/52.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1408365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

配置ntp时间服务器和ssh免密登录实验

1:配置ntp时间服务器,确保客户端主机能和服务主机同步时间 第一步,将服务器的时间同步对象改为阿里的时间服务器(这样比较精准) 先启动服务:[rootserver ~]# systemctl start chronyd 进入配置文件&#xf…

源 “MySQL 5.7 Community Server“ 的 GPG 密钥已安装,但是不适用于此软件包。请检查源的公钥 URL 是否配置正确

Is this ok [y/d/N]: y Downloading packages: 警告:/var/cache/yum/x86_64/7/mysql57-community/packages/mysql-community-server-5.7.44-1.el7.x86_64.rpm: 头V4 RSA/SHA256 Signature, 密钥 ID 3a79bd29: NOKEY 从 file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql 检…

知识图谱符号表示比较:特性图、RDF和OWL

目录 前言1 特性图:灵活的图结构表示1.1 优势与灵活性1.2 存储优化与查询优势1.3 挑战:缺乏工业标准支持 2 RDF(Resource Description Framework):面向Web的数据标准2.1 三元组结构的优势2.2 语义标准与词汇丰富性2.3 …

蓝桥杯备战——1.点亮LED灯

1.解析原理图 由上图可以看到8个共阳LED灯接到了573输出口,而573输入接到单片机P0口上。当573 LE脚输入高电平时,输出随输入变化,当LE为低电平时,输出锁存。 由上图可以看到Y4C接到了或非门74HC02的输出端,而输入端为…

顺序表的增、删、改、查

小伙伴们好,学完C语言,就要开始学数据结构了,数据结构也是非常重要的,今天我们主要来学习在数据结构中最常用的增删改查操作。话不多说,一起来学习吧 1.数据结构相关概念 1.什么是数据结构? 数据结构是由…

【Web前端开发基础】CSS3之Web字体、字体图标、平面转换、渐变

CSS3之Web字体、字体图标、平面转换、渐变 目录 CSS3之Web字体、字体图标、平面转换、渐变一、Web字体1.1 Web字体概述1.2 字体文件1.3 font-face 规则 二、字体图标2.1 字体图标2.2 字体图标的优点2.3 图标库2.4 下载字体包2.5 字体图标的使用步骤2.6 字体图标使用注意点2.7 上…

12.常用统计分析方法——聚类分析

目录 基础知识 实操 层次聚类 划分聚类 方法一:K均值聚类(最常见) 方法二:基于中心点的划分(PAM) 避免不存在的类 基础知识 概念: 聚类分析是一种数据归约技术,旨在揭露一个…

prometheus监控RabbitMQ策略

一般用官方的rabbitmq_exporter采取数据即可,然后在普米配置。但如果rabbitmq节点的队列数超过了5000,往往rabbitmq_exporter就会瘫痪,因为rabbitmq_exporter采集的信息太多,尤其是那些队列的细节,所以队列多了&#x…

vue3-深入组件-组件注册和props更多细节

组件注册 定义好的组件需要注册才能被使用。 注册方式有两种 全局注册 局部注册 全局注册 .component() 方法,让组件在当前 Vue 应用中全局可用。 在 main.ts 中 import ./assets/main.cssimport { createApp } from vue import { createPinia } from pinia i…

无人机航迹规划(五):七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划(提供MATLAB代码)

一、七种算法(DBO、LO、SWO、COA、LSO、KOA、GRO)简介 1、蜣螂优化算法DBO 蜣螂优化算法(Dung beetle optimizer,DBO)由Jiankai Xue和Bo Shen于2022年提出,该算法主要受蜣螂的滚球、跳舞、觅食、偷窃和繁…

10. UE5 RPG使用GameEffect创建血瓶修改角色属性

前面我们通过代码实现了UI显示角色的血量和蓝量,并实现了初始化和在数值变动时实时更新。为了测试方便,没有使用GameEffect去修改角色的属性,而是通过代码直接修改的数值。 对于GameEffect的基础,这里不再讲解,如果需要…

微机原理常考填空以及注意事项第(三)弹~

前面已经总结了200个常考题注意事项,可以翻阅查看。 以下仅个人总结的易错以及注意事项: 1,汇编语言源程序的基本格式: DATA SEGMENT;存放数据项的数据段 DATA ENDS EXTRA SEGMENT;存放数据项的附加段 EXTRA ENDS STACK1 SEGM…

Mybatis四大组件

一、Mybatis四大组件 SqlSessionFactoryBuild、SqlSessionFactory、SqlSession、Mapper。 二、SqlSession四大对象 Executor、StatementHandler、ParameterHandler、ResultSetHandler。 这里阐述一下上图的流程 Exeutor发起sql执行任务 1、先调用statementHandler中的pre…

输入某年某月某日,判断这一天是这一年的第几天?(Java)

思路: 1,分别定义三个变量来接收 年 月 日 2,累加已经过完的月份的天数 日期 3,二月份的天数要根据是否是闰年,随之改变 1 3 5 7 8 10 12 ---> 31天 4 6 9 11 ---> 30天 2 ---> 闰…

【bioinfo】收藏生信常用网址

文章目录 文件格式文档SAM/VCF工具手册bwa/samtools基因组统计学wikisam flag值查询序列反向互补TransVar 变异注释UCSC-blat在线比对常用数据库 NCBI/nsembl/HGNC论坛 biostars/SEQanswers查询文献影响因子假设检验查询生信软件查询在线可视化工具Proksee 文件格式文档SAM/VCF…

阿里云国外服务器价格购买与使用策略

阿里云国外服务器优惠活动「全球云服务器精选特惠」,国外服务器租用价格24元一个月起,免备案适合搭建网站,部署独立站等业务场景,阿里云服务器网aliyunfuwuqi.com分享阿里云国外服务器优惠活动: 全球云服务器精选特惠…

为什么JDK1.7的HashMap会出现扩容死链

为什么JDK1.7的HashMap会出现扩容死链? JDK1.7版本的HashMap在多线程的情况下扩容出现死循环(扩容死链),根本原因是:HashMap在进行扩容时需要进行数据转移,jdk1.7的版本数据转移使用的是头插法&#xff08…

【每日一题】最大交换

文章目录 Tag题目来源解题思路方法一:暴力法方法二:贪心 写在最后 Tag 【暴力法】【贪心法】【数组】【2024-01-22】 题目来源 670. 最大交换 解题思路 本题的数据规模比较小,暴力法也可以通过。以下将会介绍暴力法和本题最优法。 方法一…

【AIGC】Diffusers:扩散模型的开发手册说明1

主要组件 最先进的扩散管道 diffusion pipelines,只需几行代码即可进行推理。可交替使用的各种噪声调度器 noise schedulers,用于平衡生成速度和质量。预训练模型 models,可作为构建模块,并与调度程序结合使用,来创建…

阿赵UE学习笔记——12、植物系统

阿赵UE学习笔记目录 大家好,我是阿赵。   继续学习虚幻引擎的用法。这次需要使用植物系统在地形上添加一些草和石头的装饰。 一、素材准备 之前介绍过,可以在Quixel上面获取免费的资源,所以我这里就下载了一些资源,有草和石头的…