如何有效搜索某个地标范围内的所有地标?


14

我正在尝试从一个地理搜索项目开始,该项目将查找特定地标的10公里/英里(对于这个故事而言并不重要)中的所有地标。

例如,假设我有一个包含1,000,000个地标的数据库。为了找到具有特定坐标的地标10英里范围内的所有地标,我必须计算搜索到的地标与1,000,000个地标之间的距离。

有更好的方法吗?

我当时想过的替代方法是对地标进行分类,例如国家,地区,城市,邻里,商业,历史等,以便企业可以成为邻里或城市的一部分。城市是一个地区,一个国家等的一部分。这可以缩小计算范围,但是为了快速,准确地进行搜索,它仍然看起来像需要做很多工作。

Google Maps API可以提供帮助吗?


5
您可以通过执行快速的曼哈顿距离计算,然后再执行第二个过滤器,以排除10公里见方但半径10公里以外的地标,从而消除很多人。
尼尔

3
您正在使用什么数据库技术?答案不是与数据库无关。
18

1
@Neil作为第二遍,您可以包括x和y都落在原点7公里之内的任何地标,而无需计算实际距离。
JimmyJames

Answers:


10

从SQL Server 2008开始,有一种地理数据类型可以存储位置(经纬度对),并使您可以轻松编写与位置相关的查询。

现有的StackOverflow答案对此进行了深入讨论。

查找最接近的7个项目的基本查询

USE AdventureWorks2012  
GO  
DECLARE @g geography = 'POINT(-121.626 47.8315)';  
SELECT TOP(7) SpatialLocation.ToString(), City FROM Person.Address  
WHERE SpatialLocation.STDistance(@g) IS NOT NULL  
ORDER BY SpatialLocation.STDistance(@g);  

基本查询,查找100m以内的所有内容(问题的第二个答案)

-- Get the center point
DECLARE @g geography
SELECT @g = geo FROM yourTable WHERE PointId = something

-- Get the results, radius 100m
SELECT * FROM yourTable WHERE @g.STDistance(geo) <= 100

11
@KonradRudolph:与用于查询具有大行数的表的任何SQL列一样。您是正确的,但该注释几乎适用于作为答案发布的所有SQL查询。
扁平的

2
您在哪里读了“ MS SQL Server”这个问题?
布朗

3
@Flater我同意这通常是显而易见的和多余的,但是OP的措辞似乎表明他们没有意识到这种机制。
康拉德·鲁道夫

2
@ jpmc26:您为我列出了有效的选项而感到震惊,并且没有包含其他选项?什么?如果您觉得添加PostGIS很重要,请自己添加答案(您这样做了),不要因为没有与您相同的想法而批评他人。
扁平的

3
在我看来,您的答案基本上只是MS SQL销售人员。您的评论建议他们将数据库切换到将花费数万美元的东西,而无需实际询问他们的情况只会使数据库看起来更加混乱。它甚至都没有描述OP如何实际实现查询,也没有讨论在MS SQL中这样做并确保使用空间索引这一事实并不像在其他DB中那样简单。它也没有讨论任何底层概念。不管它是否“有效”,这都是一个错误的答案。这就是为什么它困扰我。
jpmc26

29

使用支持GIS(地理信息系统)查询的数据库。大多数数据库完全支持此功能或具有扩展名,但是详细信息将特定于数据库(在其答案中,Flater显示SQL Server的语法)。

如果需要在应用程序中实现此类查询,则可以实现允许空间查询的数据结构,例如kd Tree。这类似于二叉搜索树,只是树的每个级别在不同的坐标维度上分区。这使您可以将搜索限制为一小部分可行的候选对象。有效地,您将搜索“半径10 km”转换为每个坐标维度的边界,并在递归到树中时拉紧边界。



8
PostGIS是首要的免费选项。它支持的功能远远超过SQL Server的非常基本的GIS类型和功能。但这是基本功能。
18

@amon我认为jpmc26的注释是不错的补充,并没有批评您的示例那么多。“如果您想从头开始,则无需为获得许可的数据库付费-这个免费的开放源代码数据库也可以很好地解决问题”。
mgarciaisaia

11

是的,有更好的方法。您需要使用空间索引。这些索引组织有关几何的元数据,以非常快速地过滤掉较远的几何,从而避免了您描述的计算,从而节省了大量CPU周期。您不必费心实现自己,因为所有主要的关系数据库都提供了空间几何类型和索引。

您要查找的是“在距离内”查询(对于某些其他几何的一定距离内的几何的查询)。这些是非常标准且非常解决的问题,可以在上述所有数据库中(并内置到多个数据库中):

  • PostGIS: ST_DWithin
  • SQL Server :(STDistance不清楚在此功能的3D地理版本上支持索引使用)
  • Oracle :(SDO_WITHIN_DISTANCE这没有明确表示将触发索引使用。我会仔细检查查询计划。您可能需要应用an SDO_FILTER才能使用它来使用索引。)
  • MySQL:仍在解决这个问题。

触发索引使用的解决方法

在使系统无法在这些查询中使用空间索引的最坏情况下,可以添加其他过滤器。你会创建一个长度为2 *(搜索距离)的正方形边框在你的搜索点为中心,并表几何对边界框比较检查的实际距离之前。这就是ST_DWithin上面的PostGIS 在内部所做的。


GIS中的距离

尽管空间索引非常棒,并且绝对是解决问题的正确方法,但距离计算在逻辑上可能会变得复杂。特别是,您需要担心数据存储在什么投影(基本上是坐标系统的所有参数)中。大多数2D投影(除了角度坐标系以外的其他东西,例如各种经/纬投影)都会使长度明显失真。例如,Web Mercator投影(由Google,Bing和其他主要基础地图提供商使用的投影)随着位置距赤道的距离越来越大,从而扩大了面积和距离。由于我尚未接受GIS的正规教育,所以我可能是错的,但是对于2D投影,我看到的最好的是一些特定的投影,这些投影可以保证距A的正确距离。整个世界中唯一的恒定点。(不,对每个查询使用不同的投影是不切实际的;这会使您的索引无用。)

最重要的是,您需要确保数学正确。从开发的角度来看,最简单的方法是使用角度投影(通常称为“地理”)和支持使用椭球体模型进行数学运算的函数,但这些计算比2D对应模型要贵一些并且某些数据库可能不支持为其编制索引。但是,如果使用它们可以获得令人满意的性能,那可能就是方法。另一个常见的选择是区域投影(如UTM区域),如果您的数据仅限于世界的某个特定区域,则距离和区域都非常接近可以校正。哪种应用最适合您,取决于您的特定要求,

即使您不使用内置空间索引,这也适用。无论您当前正在使用或将来使用什么技术,您的数据都有一定的预测能力,并且当前已经在影响您进行的任何查询和计算。


3

我同意,如果可能的话,在数据库中使用特定的支持将是最明智的方法。

但是,如果我必须在没有特定支持的情况下在数据库上执行此操作,那么我将首先查询一个包围圆的正方形,例如(y>(y1-rad))AND(y <(y1 + rad))AND(x>( x1-rad))AND(x <(x1 + rad))。假设您的点具有大致均匀的分布查询正方形,则将获得您的真实匹配项以及大约30%的错误匹配项。然后,您可以排除错误的匹配项。


但是如果没有适当的空间索引,这样的查询将在最坏的情况下扫描整个数据库,至多扫描在给定纬度或经度范围内的所有项,具体取决于您的索引,即“带”而不是正方形。如果不想降低性能,请使用支持空间索引的数据库!
jcaron

@jcaron我相信这个查询可以用普通的B树索引上进行优化xy。(也许结合起来,也许是分开的。我要介绍一下,以找出哪种方法在实践中会更好。)
jpmc26

@ jpmc26不,它不能。仔细考虑,您会看到的。
jcaron

@jcaron如果您对明显不简单的内容不了解,可能会更好。B树可用于BETWEEN查询。我不明白为什么在最坏的情况下您不能拥有2个索引,然后将每个索引的过滤结果合并在一起。(当RDBMS认为值得使用多个索引时,这是内部做的事情。)如果组合索引有效,则应在第一层完全过滤掉一个维度,然后在第二层相对迅速地缩小范围。
jpmc26

2
@jcaron实际上,您可以使用index之类的东西, y between -68 and -69 and x between 10 and 11但是空间索引当然可以更好地完成该任务
Juan Carlos Oropeza
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.