SQLite R *树模块

2021-03-11 06:11:58

R树是一个专业的专用,用于执行范围查询。 R树最常见于地理空间系统中,其中每个条目是具有最小和最大X和Y坐标的矩形。鉴于查询矩形,R树是Ableto快速查找包含在查询矩形中包含的所有条目,该条目与查询矩形重叠。此思想很容易扩展Tothree尺寸以用于CAD系统。 R-Trous还可以在时间 - domainrange查找中找到使用。例如,假设数据库记录大量事件的启动安宁时间。 R树能够在Giventime间隔期间的任何时间都能快速查询,或者在特定时间间隔期间启动的所有事件,或者在给定的时间间隔内启动和结束的所有事件。等等。

R树概念起源于Toni Guttman:R树:用于空间搜索的动态索引结构,proc。 1984年ACM SIGMOD关于数据管理国际会议,PP。 47-57。SQLITE中发现的实施是Guttman' S ImericiDea的改进,通常称为" r *树和#34;那个描述了Bynorbert Beckmann,Hans-Peter Kriegel,Ralf Schneider,Bernhard Seeger: R * -tree:一个有效且强大的矩形的访问方法。 Sigmod大会1990:322-331。

将SQLite R *树模块的源代码包含在默认情况下作为禁用但禁用。要启用*树模块,只需使用SQLite_Enable_Rtree C-Preprocessor宏定义的编译。通过许多编译器,可以添加选项" -dsqlite_enable_rtree = 1"到了编译器中线。

SQLite R * Tree模块以虚拟表实现。每个R *树索引是具有奇数列之间的虚拟表,3到11之间。第一列始终为64位符号整数主键。其他列是对,每维一对,包含最大值和最大值该维度分别为1维r *树有3列。二维r *树有5列。3维r *树有7列。4维r *树有9列。5维r *树有11列。 SQLite R *树实施不支持宽于5维度的R *树。

SQLite R *树的第一列类似于正常SQLite表的整数主键列。它可能只存储64位签名的值。将空值插入此列导致SQLITETO自动生成一个新的唯一主键值。如果尝试将任何其他非整数值插入此列,则R树模块在编写ITINTO数据库之前静默将其转换为整数。

min / max-value对列作为&#34的32位浮点值存储为" rtree"虚拟表或&#34中的32位符号整数; rtree_i32"虚拟Tables。与可以在各种odataTypes和格式存储数据的常规SQLite表不同,R *树刚刚强制执行这些存储类型。如果将任何其他类型的值插入这样的列中,则R-Traemodule在将那录制到数据库中的记录写入然后写入数据库之前静默将其转换为所需类型。

<名称>您的应用程序是否选择了*树索引和<列名称>是3到11列之间的逗号分隔列表。虚拟< name>表创建了三个阴影表以实际才能实现其内容。这些影子表的名称是:

影子表是普通的SQLite数据表。如果您愿意,您可以直接查询它们,虽然这不太可能揭示任何更有的东西。并且您可以更新,删除,插入甚至丢弃影子表,但这样做会损坏您的r *树index.so,最好只忽略影子表。认识到他们的r *树索引信息,并让它如此。

使用Rtree(ID, - 整数主键MINX,MAXX,MAXX,最大x坐标MINY,MAXY - 最小和最大坐标)创建虚拟表DEMO_INDEX;

在" rtree"在“创建虚拟表”语句中,列的Amess从每个参数的第一个令牌中获取。静默地忽略每个参数中的后续令牌。例如,如果您尝试提供列的类型关联或添加诸如唯一或非null或默认toa列的约束,那些额外的令牌被接受为有效,但它们不会改变rtree的行为。在rtree虚拟表中,第一列始终具有整数的类型和所有其他类型数据列具有数字的类型亲和力。

推荐的做法是省略rtree规范中的任何额外令牌。将每个参数到" rtree"是一个单个普通标签,即相应列的名称,并省略参数列表中的所有其他令牌。

通常的插入,更新和删除命令在r * treeindex上工作,就像在常规表上一样。因此要将一些数据插入我们的采样器*树索引,我们可以做到这样的事情:

插入demo_index值(1, - 主键 - Sqlite.org总部-80.7749,-80.7747, - 经度范围35.3776,35.3778 - 纬度范围);插入Demo_Index值(2, - NC第12届国会区2010 -81.0,-79.6,35.0,36.2);

上面的条目可能代表(例如)围绕SQLite.org的主办公室的边界框和北卡罗来纳州北卡罗来纳州第12届北卡罗来纳州(2011年之前)的边界框中,其中Sqlite.org位于其中。

任何有效的查询都将针对R *树索引工作。但是R * TreeMoMentation旨在使两种询问尤其良好。首先,针对主键的查询是有效的:

当然,普通的SQLite表也将有效地针对ITSInteger主键进行查询,因此前面没有大不了的问题。使用R *树的真正原因是因为您可以有效地对协调角度有效查询。要查找北卡罗来纳州夏洛特附近所包含的索引的所有元素可能会做:

即使*树包含数百万条目,上面的查询也非常快速地定位1的ID。以前是A&#34的一个例子;包含在内的"询问。 R *树也支持"重叠"查询。例如,要查找重叠的所有边界框,其中

该第二查询将找到输入1(SQLite.org Office)的内容,其中包含在查询框和Alsothe第12个国会区内延伸,但仍然与查询框重叠。

请注意,R *树Indexto中的所有坐标都不需要约束,以便为索引搜索是高效的。

但是,一般来说,R *树模块以及边界框越小的约束,越突出的结果将越快。

默认情况下,坐标使用32位浮点值存储在R *树中。当坐标由A32位浮点数完全表示时,较大的坐标是圆形的,上限坐标圆形。因此,边界框可能略大于指定,但永远不会更小。这恰恰是做出更常见的&#34所需的内容;重叠"查询应用程序希望在RableA查询边界框中找到R *树中的每个条目。如果前门边界框的边缘对应于查询边界框的边缘,则舍入向外若要导致Avew额外条目出现在重叠查询中。但重叠查询永远不会错过有效的表格条目。

但是,对于A"包含 - 内部"样式查询,向外舍入边界框可能会导致从结果模板中排除的一些条目,条目边界框的边缘对应于查询框的边缘。为了防范此,应用应该在每个维度中舍入到距离坐标并舍入顶部坐标,稍微略微扩展到查询框中(0.000012%)。

它是Guttman R-Tree算法的性质,任何写入Mightrady地重构树,并且在过程中更改节点的扫描顺序。因此,通常不可能在R树的查询中间修改R树。尝试使用sqlite_locked&#34进行播出失败;数据库表被锁定"错误。

然后为每个" id"返回的值,假设应用程序创建如下的更新语句,并绑定" id"返回"?1"范围:

然后,更新可能会失败,使用SQLite_Locked错误。原因是初始查询尚未完成完成。它正在记住它的扫描扫描的中间。因此,R-Tree的更新无法容忍,因为这会破坏扫描。

还可以在单​​个查询中表达此类同时读取和写入R树,例如,如果更新语句基于从另一行的复杂Query改变R-TRE的一行值的值r树,也许是这样的:

更新demo_index set maxy =(从demo_index中选择max(maxx)作为x2,其中maxy> = 35.0和miny< = 35.0;

这是仅限R树扩展的限制。普通表Insqlite能够同时读取和写入。其他虚拟表格(或可能不会)也是那种能力。在某些情况下,R-Tree可以在某些情况下同时写入,如果它可以在开始更新之前可靠地运行查询以便完成。 Butyou'对于每个查询都指望。一般而言,它是最避免在Sametime上运行查询和更新到相同的R树。

如果您真的需要基于对同一R树的复杂查询更新R-Tree,最好先运行复杂的查询并在临时表中存储结果,然后基于临时虚拟价值进行r-tree更新r树桌子。

对于3.24.0之前的SQLite版本(2018-06-04),R *树索引存储对象的唯一信息是整数ID及其边界框。其他信息需要存储在单独的表中并使用主键与R *树索引相关。对于上面的示例,可以创建一个辅助表,如下所示:

创建表Demo_data(ID Integer主键, - 主键objname文本, - 对象objtype文本的名称, - 对象类型边界Blob - 对象的详细边界);

在此示例中,demo_data.boundary字段旨在抓住对象的精确边界的二进制表示。R *树索引仅保存对对象的轴对齐的矩形边界。 R *树边界只是真正的ObjectBoundary的近似值。因此,通常发生的是,R *树索引用于将TONARROW A搜索到候选对象列表中,然后在每个候选人上完成更具详细的计算,以查找Chandidate是否真正符合搜索条件。

关键点:R *树索引通常不提供确切的答案,而是仅从数百万到数十个的潜在答案集。

假设demo_data.boundary字段为对象保存一些专有的数据说明,用于对象的复杂二维边界,并假设TheApplication使用了SQLite3_Create_Function()接口被创建的应用程序定义的函数" conted_in"和#34;重叠"接受两个demo_data.boundary对象并返回true或false.one可能会假设它" contedated_in"和#34;重叠"我们不想过于频繁地调用的相对速度。然后,一个有效的方法来查找位于Carolina 12th District的所有对象的名称,可能是这样的查询:

从demo_data,demo_index中选择objname,其中demo_data.id = demo_index.id和conted_in(demo_data.boundary,:边界)和minx> = - 81.0和maxx< - 79.6和miny> = 35.0和maxy< = 36.2;

在上面的查询中,一个人可能会绑定第12区的精确边界的二进制Blob描述到":边界"范围。

请注意,上面的查询如何工作:R *树索引在SuperLoop中运行,以查找包含在界限框中包含的条目-81 ..- 79.6和Latitude 35.0..36.2。对于找到的每个对象标识符,SQLite在demo_data表中查找相应的条目。然后,它将边界场从demo_data表中作为参数到CONTAINT_IN()函数,如果该函数返回true,则emo_data表中的objname字段将作为下一行查询结果返回。

在不使用R *树索引以下更简单的查询的情况下,可以获得相同的答案:

此后一查询的问题是它必须将Thecontained_in()函数应用于Memo_Data表中数百万条目。倒倒数查询中的R *树将函数的数量减少到Conted_in()函数中的一个小子集整个表.R *树索引没有找到确切的答案本身,它仅限于搜索空间。

从SQLite版本3.24.0(2018-06-04)开始,R-Tree TableScan具有存储任意数据的辅助列.Auxiliary列可以用于诸如" demo_data&#34等中的桌子。

辅助列标有A" +"符号在列名称之前。突出所有坐标边界列之前必须出现。以下示例显示了一个不超过100个辅助列的限制。与辅助列的R树表相当于两个表&# 34; demo_index"和#34; demo_data"以上:

使用Rtree(ID, - 整数主键MINX,MAXX,MAXX,MAXX)创建虚拟表DEMO_INDEX2 CON CONERY,MAXY, - 最小和最大y坐标+ objname文本, - 对象+ objtype文本的名称, - 对象类型+边界BLOB - 对象的详细边界);

通过将位置数据和相关信息组合到可打个信息中,辅助列可以提供更清晰的模型,减少需要加入的需要。例如,demo_index和demo_data之间的早期连接可以写成一个简单的查询,如下所示:

从demo_index2中选择objname,其中conted_in(边界,:边界)和minx> = - 81.0和maxx< - 79.6和miny> = 35.0和maxy> = 36.2;

对于辅助列,仅禁止列的名称。忽略类型的关联。忽略无效,唯一,参考或核心等。但是,SQLite的未来版本可能会开始关注类型的关联和控制,因此建议辅助列的用户离开空白,以避免将来的兼容性问题。

默认虚拟表(" rtree")通常存储坐标查询 - 精度(4字节)浮点数。如果所需的整数协调,请使用&#34声明表格; rtree_i32"反而:

rtree_i32存储坐标作为32位符号整数。但它是静止的浮点计算作为R树算法的一部分。

通过在SELECT查询的WHERE子句中使用标准SQL表达式,程序员可以查询与WHERE子句中的匹配机构中的与特定边界-COSTOM R *树查询中相交或包含在特定边界框中的所有R *树条目选择,允许程序员查询与任何任意区域或形状相交的R *树条目的集合,而不仅仅是一个框。例如,此功能是有用的,例如,在从位于3-D空间中的相机中可见的R *树中的对象子集。

自定义R *树查询的区域由应用程序的R *树几何呼叫定义,并通过呼叫对以下两个API的呼叫注册了SQLite:

int sqlite3_rtree_query_callback(sqlite3 * db,const char * zqueryfunc,int(* xqueryfunc)(sqlite3_rtree_query_info *),void * pcontext,void(* xdestructor)(void *)); int sqlite3_rtree_geometry_callback(sqlite3 * db,const char * zgeom,int (* XWEOM)(SQLite3_RTREE_GEOMETRY *,INT NCOORD,DOUBLE * ACOORD,INT * PRES),VOID * PContext);

SQLite3_Rtree_Query_CallBack()已使用SQLite版本3.8.5(2014-06-04)可用,并且是首选界面。SQLite3_Rtree_Geometry_callback()是向后兼容性支持的较旧的且较少的灵活性接口。

对上述一个API的调用创建一个由theSecond参数(zqueryfunc或zgeom)命名的新SQL函数。当SQL函数出现匹配操作员的右侧和Thematch运算符的左侧是R *树虚拟表中的任何列,那么由第三个参数(XQueryFunc或XGeOM)定义的回调确定特定对象或子树与所需区域重叠。

例如,如下所示的查询可用于查找与圆圈重叠的Allr *树条目以5.0的Aradius为中心为45.3,22.9:

无论哪个interface,sqlite3_rtree_geometry_callback()或sqlite3_rtree_query_callback()用于注册SQL函数,SQL语法是相同的。但是,较新的查询-DequeryEcallbacks为应用程序提供了更好地控制查询所需的操作。

使用四个参数调用传统XWEOM回调。 FirstRgument是指向SQLite3_Rtree_Geometry结构的指针,它提供了关于如何调用SQL函数的方式。第二个Aructionis每个R树条目中的坐标的数量,并且始终是任何给定的R *树的同伴。坐标的数量为1维r *树,4为2维r *树,为3维r *树的6,等等。第三个参数,Acoord [],是一个数组NCOORD坐标定义要测试的边界框。最后一个参数是应该写回调结果的指针。结果是ZEROIF由XWEOM回调定义的ACOORS []定义的边界框,如果边界框在内部或与XGEOM区域重叠的情况下,结果是非零的。 XGeomcallback通常应返回SQLite_ok。如果XWEOM返回其他以其他方式SQLITE_OK,则R树查询将中止错误。

sqlite3_rtree_geometry结构是thexGeom回调点的第一个参数具有下面显示的结构。确切的SameSQlite3_Rtree_GeometryStructure用于同一匹配操作员的每个回调。 SQLite3_Rtree_GeometryStructure的内容由SQLite初始化,但随后修改了arenot。如果需要,回调是可以自由地对结构的Xdeluser元素进行更改。

typedef struct sqlite3_rtree_geometry sqlite3_rtree_geometry; struct sqlite3_rtree_geometry {void * pcontext; / * pcontext的副本传递给s_r_g_c()* / int nparam; / *阵列的大小aparam * / double * aparam; / *传递给SQL GeoM功能的参数* / void * puser; / *回调实现用户数据* / void(* xdeluser)(void *); / *由SQLite调用以清理PUSER * /};

SQLite3_Rtree_Geometryrystructure的PContext成员始终设置为PContextAlgument的副本,当注册了Thecallback时传递给SQLite3_Rtree_geometry_callback()。 aparam [] array(size nparam)包含传递给匹配运算符的右侧的SQL函数的参数服务。在示例"圆圈"上面查询,NPARAM将设置为3,APARAM []数组将包含三个值45.3,22.9和5.0。

SQLite3_Rtree_Geometry结构的PUSER和XDELUSER成员全部设置为NULL。 PUSER变量可以由响铃算法设置为a

......