我正在尝试构建一个过程,以获得具有所选ID的点的k个最近邻点。 我需要在不使用任何空间定位器功能(如sdo_geometry或nn)的情况下执行此操作。
基本上我在oracle中有一个带有ID,Data_X,Data_Y的表。假设我的表中有10个条目,我需要3个最近点到虚构点target_x,target_y。
我们需要用给定的虚构点计算表中每个点的欧氏距离。我只是不知道pl / sql中的算法会返回最近的邻居ID。
答案 0 :(得分:3)
计算每个点与所选点之间的距离(毕达哥拉斯),并按距离排序。 伪sql:
select id from points
order by sqrt(sqr(Data_x - target_x) + sqr(Data_y - target_y))
前3行是最接近的3点。
答案 1 :(得分:2)
如果性能成为一个问题,你可能会考虑在数据上制作一个穷人的空间索引。它不会像“创建索引”那么简单,但它可能会起作用。
正确的方法是创建一个自定义索引,但这只会重新发明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)和阈值的值设置正确,您将看到查询使用基于函数的索引来获取一小组候选,而不是计算每个点的距离。桌子。
缺点是如果:阈值太低,查询可能不返回任何行。另一方面,根据您的需要,这可能是一个有用的功能。