高效存储和查询GPS坐标

13

我希望创建一个GPS坐标的大型数据库,可以通过说“返回所有距离[这个坐标]在n米以内的坐标”进行查询。

我需要尽可能高效,因此循环遍历数据库中的所有坐标并计算坐标是否在n米范围内不是理想的解决方案。

有更简单的解决方案吗?

谢谢

8个回答

6
我通常使用经纬度进行这种查询。使用球面几何,您可以在特定点周围放置一个边界框。例如,假设您有一个点(X,Y),您希望所有坐标在1英里内(将转换为米留给读者作为练习)。您可以确定一个边界框为(X-1,Y-1),(X+1,Y+1)。然后,您可以使用BETWEEN运算符查询您的点数据库(SELECT foo FROM bar WHERE LAT BETWEEN X-1 AND X+1 AND LON BETWEEN Y-1 AND Y+1) 。然后,您可以执行详细的距离计算以“圆角”您的边界框。
注意,经线在球体顶部更加接近,因此您离赤道越远,结果会偏斜。但它仍然可以快速过滤掉您的结果集。
Google“Great Circle Distance”进行计算。
编辑:每英里经度线约为0.167469度(实际范围从0.167469到0.014564不等),每英里纬度线约为0.014483度。因此,您的边界框为(lat -(miles * 0.014483),lon -(miles * 0.167469)),(lat +(miles * 0.014483),lon +(miles * 0.167469))。

2

SQL Server 2008支持存储空间数据。虽然我自己没有使用过,但我知道你可以创建所需类型的查询。


2

1
跟进Erich的话题 - 如果你有选择,使用PostGIS(postgresql),它是免费和开源的,可以非常快速地执行你所描述的查询,可以运行在几乎所有平台上,而且我提到了它是免费的吗?

1

GIS数据库(例如带有PostGIS的PostgreSQL)实际上为二维或三维区域搜索提供了数据结构(空间索引)。最简单的是网格索引,然后是不同的搜索树(kd-tree、quad-tree),其中R-tree是最常用的(用于更多维度的广义B-tree)。这些方法似乎是足够的。

基本的网格索引(将空间划分为网格单元,并仅在附近单元中进行搜索)可以轻松实现,并且可以显著减少搜索时间。搜索树稍微难以实现,但是有许多开源实现适用于许多编程语言和DB(如PostGIS或Geopandas等)。通常使用它们解决此类问题会得到回报。


0

如果您想避免使用GIS扩展,我将this post中的函数适配到了PostgreSQL SQL中:

create or replace function change_in_lat(miles numeric)
returns double precision as $$
with v as (select
    3960.0 as earth_radius,
    180 / pi() as radians_to_degrees
) select ( miles / earth_radius ) * radians_to_degrees from v;
$$ language sql
returns null on null input;

create or replace function change_in_long(lat numeric, miles numeric)
returns double precision as $$
with v as (select
    3960.0 as earth_radius,
    pi() / 180 as degrees_to_radians,
    180 / pi() as radians_to_degrees
) select (
    miles / (earth_radius * cos(lat * degrees_to_radians))
    ) * radians_to_degrees from v;
$$ language sql
returns null on null input;

使用它们,您可以进行一些周围方块的查询:

--find all "a"s within 25 miles of any "b"
select * from a join b on (
a.gpslat between
    b.gpslat - change_in_lat(25) and b.gpslat + change_in_lat(25)
and a.gpslong between
    b.gpslong - change_in_long(b.gpslat::numeric, 25)
    and b.gpslong + change_in_long(b.gpslat::numeric, 25)
);

如果你经常使用它,我相信将语句之间转换为单个函数会很容易。不过我从未使用过任何实际的“半径内”查询。

对于更复杂的操作,你可能需要像其他答案所说的那样使用GIS扩展。PostGIS很好用,但我发现许多gis特定的函数很难正确使用,除非你利用边界框索引,否则如果数据集足够大,你的空间查询可能需要一天时间。但是,为了获得所有花哨的功能(如以geojson格式输出数据等),复杂性上的权衡绝对是值得的。


0

我们可以使用Geohash算法。

Geohash的美妙之处在于它的构造方式。简而言之,Geohash是一种网格空间索引类型,其中世界被递归地划分为越来越小的网格,并带有每个附加位。(https://www.mapzen.com/blog/geohashes-and-you/

enter image description here

你可以在维基百科上找到它的描述(https://en.wikipedia.org/wiki/Geohash)。

我附上了下面的视频以便快速理解。

https://www.youtube.com/watch?v=UaMzra18TD8

https://youtu.be/mx1mMdHBi5Q?t=1955

在下一篇文章中,您可以找到AWS数据库DynamoDB的此类算法的实现。 https://read.acloud.guru/location-based-search-results-with-dynamodb-and-geohash-267727e5d54f 请为James Beswick的文章鼓掌。

0

如果你可以选择数据库,我会像rwwilden一样推荐使用带有空间数据功能的SQL 2008。如果你不能使用该解决方案或包括空间查询的解决方案,你可以查看微软自己关于分层三角网格的论文并实现这些内容。MSSQL '05的SDK也提供了一个完整的HTM解决方案,因此你可以将其转换为你正在使用的任何平台。

编辑:

这里有一个更详细的文档,解释了HTM和实现方法。当然,你可以将其转换为你选择的数据库。在2005年的SDK中可以找到完整的HTM实现源代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接