没有索引的最近邻居查询的pl / sql代码,用于在oracle中包含点数据的表

时间:2011-04-04 12:18:28

标签: algorithm oracle plsql nearest-neighbor

我正在尝试构建一个过程,以获得具有所选ID的点的k个最近邻点。 我需要在不使用任何空间定位器功能(如sdo_geometry或nn)的情况下执行此操作。

基本上我在oracle中有一个带有ID,Data_X,Data_Y的表。假设我的表中有10个条目,我需要3个最近点到虚构点target_x,target_y。

我们需要用给定的虚构点计算表中每个点的欧氏距离。我只是不知道pl / sql中的算法会返回最近的邻居ID。

2 个答案:

答案 0 :(得分:3)

计算每个点与所选点之间的距离(毕达哥拉斯),并按距离排序。 伪sql:

select id from points
order by sqrt(sqr(Data_x - target_x) + sqr(Data_y - target_y)) 

前3行是最接近的3点。

答案 1 :(得分:2)

nang的答案是一个很好的起点,如果它完成了这项工作,我就会使用它。不幸的是,它很可能需要全表扫描(或者如果你有覆盖索引,可能需要完整的索引扫描)。

如果性能成为一个问题,你可能会考虑在数据上制作一个穷人的空间索引。它不会像“创建索引”那么简单,但它可能会起作用。

正确的方法是创建一个自定义索引,但这只会重新发明sdo_geometry轮,这是你想要避免的路径。

一种简单但粗略的方法(免责声明:这只是我头脑中的一个想法,未经测试)可能是创建一个基于函数的索引,将2D空间中的所有点分组为方块。您基本上创建一个索引,将每个(x,y)对映射到块列表中。每个块都有一个定义的宽度和高度,要进行搜索,首先要确定需要搜索哪个块网格,然后只查询该网格中的点列表。

示例索引类似于:

CREATE INDEX grid_block_i ON points (TRUNC(Data_X/100), TRUNC(Data_Y/100), id);

您替换100的值取决于您的积分所采用的值范围。您需要将平面划分为大量网格块,以便索引具有合理的选择性;但不是那么大,以至于典型的查询必须搜索太多的块才能找到候选者。

您可以使用以下查询来使用上面的索引:

select id
from (select id, Data_X, Data_Y
      from points
      where TRUNC(Data_X/100) BETWEEN TRUNC(:target_x/100)) - :threshold
                                  AND TRUNC(:target_x/100)) + :threshold
      and   TRUNC(Data_Y/100) BETWEEN TRUNC(:target_y/100)) - :threshold
                                  AND TRUNC(:target_y/100)) + :threshold
     )
order by sqrt(sqr(Data_x - :target_x) + sqr(Data_y - :target_y))

然后,您可以设置:阈值,基本上从查询中消除大量的点块。我估计如果功能索引(即100)和阈值的值设置正确,您将看到查询使用基于函数的索引来获取一小组候选,而不是计算每个点的距离。桌子。

缺点是如果:阈值太低,查询可能不返回任何行。另一方面,根据您的需要,这可能是一个有用的功能。