我有一个大约 500 万行的表,每行有 10 列代表 10 个维度。我希望能够在新输入时在表中执行搜索,以使用曼哈顿距离返回最近的行。距离是 abs(Ai-Aj)+abs(Bi-Bj)的总和...问题是,目前如果我进行查询,它会对整个表进行全面扫描,以计算每行的距离,然后对它们进行排序以找到顶部 X。
有没有办法加快流程并使查询更有效率?
我在网上查看了SDO_GEOMETRY的距离函数,但我找不到超过 4 个维度的距离函数。
谢谢
如果要插入点 A,并且想要查找半径为 r 的邻域内的点(即,在任何度量上,距离小于 r),您可以执行非常简单的查询:
select x1, x2, ..., xn
from points
where x1 between a1 - r and a1 + r
and x2 between a2 - r and a2 + r
...
and xn between an - r and an + r
。其中 A = (a1, a2, ..., an)
,以求一个界。如果您有一个索引,涵盖所有x1
、...xn
points
字段,则此查询不需要完全扫描。现在,此结果可能包括邻域之外的点(即角落中的位),但很容易找到合适的子集:您现在可以检查此子查询中的记录,而不是检查表中的每个点。
您可以进一步细化此查询,因为使用曼哈顿度量时,邻域将是正方形的(尽管与上述呈 45 度),并且正方形相对容易使用!(即使是 10 个维度。然而,最终,所需的更复杂的逻辑可能更多的是开销,而不是优化。
我建议使用基于函数的索引。您需要计算此距离,因此使用基于函数的索引预先计算它。
您可能想阅读以下问题及其链接。基于函数的索引为您创建隐藏列。这个隐藏的列将保持曼汉坦的距离,因此排序会更容易。
感谢您@Xophmeister的评论。基于函数的索引不会帮助您获得任意点。我不知道任何sql函数在这里可以帮助您。但是如果你愿意使用机器学习数据挖掘算法。
我建议使用 k 均值聚类对 500 万行进行聚类。假设您找到了 1000 个集群中心。将此聚类中心放在另一个表上。根据定义聚类,您的点将被分配到聚类中心。因此,您知道哪些点最接近此聚类中心,例如集群 (1) 包含 20.000 个点, ...集群 ( 987) 包含 10.000 点 ...
您的任意点将靠近一个聚类。您发现您的点最接近聚类 987。运行你的sql,只使用属于这个集群中心的点,即10.000个点。
您需要向架构添加多个表/列才能使其有效。如果 5.000.000 行连续更改,则需要在它们更改时再次运行 k 均值聚类分析。但如果它们是相当恒定的值,则每周或每月进行一次聚类就足够了。