R-Tree原理及朴素实现代码

R树是用于空间访问方法的树数据结构,即用于索引多维信息,例如地理坐标、矩形或多边形。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割 

1、空间数据

如果一个对象至少具有一个捕获其在 2D 或 3D 空间中的位置的属性,则该对象被表征为空间对象。 此外,空间物体可能在空间中具有几何范围。 例如,我们可以说建筑物是一个空间对象,因为它在 2D 或 3D 地图中具有位置和几何范围。

在多维空间中不存在保持空间邻近性的全序。 因此,空间中的对象无法以理论上为空间查询提供最佳性能范围的方式物理集群到磁盘页面。

假设我们尝试使用某些一维排序键对一组二维点进行排序。 无论我们使用哪个键,按皮亚诺曲线或希尔伯特排序的列排序,我们都不能保证任何在空间上接近的对象对在总顺序上也将接近。

R 树正在绘制我们的世界,这是一个现实世界的应用程序。 它们存储空间数据对象,例如商店位置和创建地图的所有其他形状。 例如,从城市街区或您最喜欢的餐厅创建多边形的地理坐标。

为什么这个有用?

嘿,Siri! 找到离我最近的麦当劳

是的,我们需要根据对象的实际位置进行查询。

2、R树中的“R”代表矩形

数据结构的关键思想是将附近的对象分组并用矩形表示它们。 最小外接矩形或简称 MBR。 这是递归发生的:

由于所有对象都位于此边界矩形内,因此不与边界矩形相交的查询也无法与任何包含的对象相交。 在叶级别,每个矩形描述一个空间对象。 所有其他级别都只是节点指针。

该树的一个约束是每个节点(根节点除外)应至少为 40%,以便正确利用磁盘空间。 下面我们可以看到 R 树的示例。

为了保持 R 树的利用率,我们必须做四件事:

  • 目录节点条目的 MBR 所覆盖的区域应最小化。
  • 同一级别目录项的 MBR 之间的重叠应最小化。
  • 目录节点条目的 MBR 的边距应最小化。
  • R 树节点中的平均条目数应最大化。

3、批量加载

批量加载(bulk loading)是一种通常以“大块”的方式将数据加载到数据库中的方法。 我们将使用一种称为排序平铺递归 (STR:Sort Tile Recursive) 的方法。

每个 MBR 包含以下由制表符 (‘\t’) 分隔的内容: object-id、 x-low、 x-high、 y-low、 y-high。 下面我们可以看到一个计算矩形列表的 MBR 的函数。 每个矩形都存储在一个字符串中:

def find_mbr(slc):# convert the string that contains the rectangles info into a list of listsa = [item.split() for item in slc]# itemgetter(0) has the idx_low = min(a, key=operator.itemgetter(1))[1]x_max = max(a, key=operator.itemgetter(2))[2]y_low = min(a, key=operator.itemgetter(3))[3]y_max = max(a, key=operator.itemgetter(4))[4]return [x_low, x_max, y_low, y_max]

STR 技术首先根据矩形的 x-low 对 n 个矩形进行排序。 经过排序,我们知道树中会有 L = ⌈n/C⌉ 的叶子节点。 属性C指的是每个节点的容量。 具体来说它可以存储多少个矩形:

def construct(rectangle_file, node_array, counter_left_of):global tree_levelglobal node_counter# sort according to the second column (x-low).data = sorted(rectangle_file, key=lambda line: line.split()[1])number_of_data_rectangles = len(data)# assume each rectangle needs 36 bytes and each node can hold up to 1200 bytes.node_can_hold = math.floor(1200 / 36)number_of_nodes = math.ceil(number_of_data_rectangles / node_can_hold)number_of_slices = math.ceil(math.sqrt(number_of_nodes))

然后,(已排序的)矩形被分为 ⌈SquareRoot( L)⌉ 组(垂直条纹),并且使用矩形的 y-low 作为键对每个组进行排序。 这种排序的输出被打包到叶节点中,并且树是通过递归调用以自下而上的方式构建的。

if number_of_slices > 1:# create the slicesslices = list(divide_chunks(data, node_can_hold*number_of_slices))# sort every slice according to the fourth column (y-low)sorted_slices = [sorted(item, key=lambda line: line.split()[3]) for item in slices]# merges the slices into a single listconcat_list = [j for i in sorted_slices for j in i]# divide them again in chunks that a node can holdslices = list(divide_chunks(concat_list, node_can_hold))# find the MBR of each slicembr = [find_mbr(item) for item in slices]# this counter is passed to the upper recursion level so the# next level nodes will know where to point.counter_left_of = node_counter# append the nodes in the node arrayfor slc in slices:node_array.append(Node(node_counter, len(slc), slc, tree_level))node_counter += 1node_ids = [i for i in range(counter_left_of, node_counter)]# create the chunks that are needed for the upper level, mbrs of every slice and where# they will pointdata_for_the_upper = [str(a) + '\t' + str(b[0]) + '\t' + str(b[1]) + '\t' + str(b[2]) + '\t' + str(b[3]) fora, b in zip(node_ids, mbr)]tree_level += 1number_of_nodes_per_level.append(number_of_nodes)average_MBR_area_per_level.append(get_area(data)/len(data))# recursively construct from bottom to topconstruct(data_for_the_upper, node_array, counter_left_of)

当切片数为 1 时,递归结束。这意味着我们到达了根级别:

# recursion is over, we reached top node
else:# sort  according to the fourth column (y-low)data = sorted(data, key=lambda line: line.split()[4])node_array.append(Node(node_counter, len(data), data, tree_level))node_counter += 1

4、让我们查询树

遵循与查询范围相交的条目指针,以深度优先的方式遍历树。 查询算法采用三个参数; 查询范围q,检索对象应满足q的谓词θ,以及R树节点n。

如果我们位于叶节点上,我们会搜索该节点的每个 MBR 以检查它们是否满足我们的查询。 如果是的话,我们将矩形添加到答案集中。

如果我们不在叶节点上,我们将搜索该节点的每个 MBR 以检查它们是否满足我们的查询。 如果确实如此,我们将递归调用该函数。 我们使用相同的参数。 唯一改变的参数是节点。 我们现在正在传递当前节点所指向的节点。

简单来说,我们要检查是否与查询的 MBR 存在交集。

我们希望能够执行 3 种查询类型。 交集,对于至少有一个公共点的 MBR,内部,对于位于查询内部的 MBR,以及包含,对于包含查询的 MBR 的 MBR。

def query(rectangles_answer_set, rectangle_of_the_query, node_array, node_from_recursion, first_call, nodes_accessed,q_type):# hacky way to count the accesses with a mutable type passing with reference, globals would not work herenodes_accessed.append('1')if first_call:# the first call gets the root nodenode_to_check = node_array[-1]else:node_to_check = node_from_recursionif node_to_check.tree_level == 1:for mbr in node_to_check.list_of_attrs:mbr_splitted = mbr.split()if query_type(rectangle_of_the_query, mbr_splitted, q_type):rectangles_answer_set.append(mbr)else:for mbr in node_to_check.list_of_attrs:mbr_splitted = mbr.split()points_to = mbr_splitted[0]if query_type(rectangle_of_the_query, mbr_splitted, 'intersection'):query(rectangles_answer_set, rectangle_of_the_query, node_array, node_array[int(points_to)], False,nodes_accessed, q_type)

每个非叶节点必须仅检查交集。 我们可以通过下面的例子看到,如果我们严格过滤非叶节点上的所有 MBR,我们会错过很多结果。

考虑内部查询和非叶节点处的步骤。 黑色矩形是查询的 MBR。 红色是被过滤的中间节点,绿色是实际对象。 如果在递归中我们有严格的规则要求 MBR 完全位于内部进行检查,则红色将不会通过过滤器,因此我们将失去绿色的 MBR,因为它是符合标准的实际对象:

接受对象的标准取决于其几何形状,如下所示:

# At least one  point intersecting.
if q_type == 'intersection':x_axis = (query_x_high >= mbr_x_low) or (query_x_high <= mbr_x_high)y_axis = (query_y_low <= mbr_y_high) or (query_y_high <= mbr_y_low)return x_axis and y_axis# The MBR of the rectangle we examine must be inside of the MBR of the query.
elif q_type == 'inside':x_axis = (query_x_high >= mbr_x_high) and (query_x_low <= mbr_x_low)y_axis = (query_y_low <= mbr_y_low) and (query_y_high >= mbr_y_high)return x_axis and y_axis# Exactly the opposite from the previous. We can change the positions in the comparisons.
elif q_type == 'containment':x_axis = (mbr_x_high >= query_x_high) and (mbr_x_low <= query_x_low)y_axis = (mbr_y_low <= query_y_low) and (mbr_y_high >= query_y_high)return x_axis and y_axis

5、结束语

空间数据库系统中处理空间选择的方式取决于所查询的关系 R 是否已索引。 如果 R 没有索引,我们线性扫描它并将每个对象与查询范围进行比较。 正如所讨论的,DBMS 应用了两步处理技术,该技术在对象的精确几何形状之前针对查询测试对象的 MBR。 如果关系被索引(例如,通过 R 树),那么我们可以使用它来快速查找符合过滤步骤的对象。


原文链接:R-Tree原理及朴素实现 - BimAnt

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实打实好用!微信客户高效管理神器大揭秘!

如果你的微信里的客户很多&#xff0c;每次回复消息都不及时&#xff0c;或是有遗漏&#xff0c;那么&#xff0c;你一定要试试这个微信客户高效管理神器——微信管理系统&#xff0c;能够让你事半功倍&#xff0c;提高工作效率。 首先&#xff0c;让我们来看看这款微信管理系…

掼蛋残局技巧

一、根据对手张数出牌 口诀&#xff1a;十打二来九打一&#xff0c;打成八张不着急&#xff1b; 对手七张或八张&#xff0c;可以反手打一夯&#xff1b; 五打二来六打三&#xff0c;打得对手把眼翻&#xff1b; 枪不打四&#xff1b; 两张&#xff1a;出两张以上的牌&#xff…

【嵌入式】SD NAND:小身躯蕴含大能量的新型嵌入式存储解决方案

&#x1f9d1; 作者简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向的学习指导…

Day16_学点儿JavaEE_实践_基于IDEA2023的简易JavaWeb项目、Tomcat输出乱码解决

0 JavaWeb项目目录 └──JavaWeb├──resources│ └──db.properties├──src│ └──com.sdust.web│ ├──servlet│ │ └──StudentServlet│ ├──pojo│ │ └──Student│ └──util│ └──JDBCUtil├──web│ ├──st…

使用icpc tool进行滚榜操作

前言 参加ACM的同学都知道&#xff0c;比赛非常有趣的环节就是赛后的滚榜环节&#xff0c;所以为了一个比赛的完整性&#xff0c;自己办比赛时也想要加入滚榜的操作&#xff0c;经过一段时间的研究学习&#xff0c;已经可以将滚榜程序与domjudege程序成功完成融合&#xff0c;…

2024.4.15

代码&#xff1a;uart4.c #include "uart4.h"void uart4_config() {//使能GPIO\GPIOG\UART4的外设时钟RCC->MP_AHB4ENSETR | (0x1<<1);RCC->MP_AHB4ENSETR | (0x1<<6);RCC->MP_APB1ENSETR | (0x1<<16);//设置PB2和PG11为管脚复用功能//P…

【C/C++】什么是内存泄漏?如何检测内存泄漏?

一、内存泄漏概述 1.1 什么是内存泄漏 内存泄漏是在没有自动 gc 的编程语言里面&#xff0c;经常发生的一个问题。 自动垃圾回收&#xff08;Automatic Garbage Collection&#xff0c;简称 GC&#xff09;是一种内存管理技术&#xff0c;在程序运行时自动检测和回收不再使用…

淘宝商品详情API数据采集接口|如何快速采集淘宝商品数据?

如何快速采集淘宝商品数据 无论是谁&#xff0c;如果单凭人工的方式去收集淘宝、天猫等平台的商品数据信息&#xff0c;工作量是巨大的&#xff0c;如果借助有采集软件的第三方公司操作&#xff0c;则可实现对大数据的轻松掌握&#xff0c;但是外包给第三方公司需要支付一定的…

一文读懂自动化运维工具ansible及其使用

1. ansible简介 ansible是干什么的 ansible是目前最受运维欢迎的自动化运维工具&#xff0c;基于Python开发&#xff0c;集合了众多运维工具&#xff08;SaltStack puppet、chef、func、fabric&#xff09;的优点&#xff0c;实现了批量系统配置、批量程序部署、批量运行命令…

韩顺平Java | C25 JDBC和连接池(上)

概述 JDBC概述&#xff1a;JDBC为访问不同数据库提供统一接口&#xff0c;为使用者屏蔽细节问题。Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统&#xff0c;从而完成对数据库的各种操作。 // 模拟代码 //JdbcInterface.java --Java规定的JDBC接口(方法) p…

《自动机理论、语言和计算导论》阅读笔记:p172-p224

《自动机理论、语言和计算导论》学习第 8 天&#xff0c;p172-p224总结&#xff0c;总计 53 页。 一、技术总结 1.Context-Free Grammar(CFG) 2.parse tree (1)定义 p183&#xff0c;But perhaps more importantly, the tree, known as a “parse tree”, when used in a …

智能物联网远传冷水表管理系统

智能物联网远传冷水表管理系统是一种基于物联网技术的先进系统&#xff0c;旨在实现对冷水表的远程监测、数据传输和智能化管理。本文将从系统特点、构成以及带来的效益三个方面展开介绍。 系统特点 1.远程监测&#xff1a;系统可以实现对冷水表数据的远程监测&#xff0c;无…