使用 mySQL 的 OpenStreetMap 邻近搜索

Posted

技术标签:

【中文标题】使用 mySQL 的 OpenStreetMap 邻近搜索【英文标题】:OpenStreetMap Proximity search using mySQL 【发布时间】:2011-02-28 08:04:38 【问题描述】:

我只是在玩由 JOSM 生成的我所在地区的数据集。我使用 Osmosis 将它移到了带有 0.6 API 方案的 mysql DB 中,现在我正在拼命尝试以下方法:

我想获得一个城市的所有街道。 AFAIK OSM 数据中没有标签/关系来确定这一点,所以我尝试使用邻近搜索来获取代表市中心的节点周围半径内的所有节点。

大部分时间我都在看方法here

我得到的是以下 SQL 代码,它应该让我在 id 为 36187002 的节点周围和半径 10 公里内获得最近的 100 个节点。

set @nodeid = 36187002;
set @dist = 10;
select longitude, latitude into @mylon, @mylat from nodes where id=@nodeid limit 1;


SELECT id, ( 6371 * acos( cos( radians(@mylon) ) * cos( radians( latitude ) ) * 
cos( radians(  longitude ) - radians(@mylat) ) + sin( radians(@mylon) ) * sin( radians( latitude ) ) ) ) 
AS distance
FROM nodes HAVING distance < @dist ORDER BY distance LIMIT 0 , 100;

嗯..它不起作用。 :( 我想主要问题是 OSM 经纬度乘以 10.000.000,我不知道如何纠正此功能以使其正常工作。

对此有什么想法吗?非常欢迎所有解决方案/替代方案!

【问题讨论】:

【参考方案1】:

为以double 数据类型表示的纬度和经度添加额外的列可能会更快(因此三角函数有机会) - 您可能想要更进一步并预先计算 xaxis、yaxis 和zaxis 作为列(同样,存储为double

因此,您的新列是松散的(您可能需要根据需要添加数据类型转换):

XAxis   = cos(radians(Latitude / 10000000)) * cos(radians(Longitude / 10000000))
YAxis   = cos(radians(Latitude / 10000000)) * sin(radians(Longitude / 10000000))
ZAxis   = sin(radians(Latitude / 10000000))

然后,您的邻近搜索变为:

set @nodeid = 36187002;
set @dist = 10;
SELECT XAxis, YAxis, ZAxis
INTO @CntXAxis, @CntYAxis, @CntZAxis
FROM nodes
WHERE id=@nodeid limit 1;

SELECT id, ( 6371 * acos(
             CASE
                WHEN nodes.XAxis * @CntXAxis
              + nodes.YAxis * @CntYAxis
              + nodes.ZAxis * @CntZAxis > 1.0 THEN 1.0
              ELSE  nodes.XAxis * @CntXAxis
              + nodes.YAxis * @CntYAxis
              + nodes.ZAxis * @CntZAxis 
             END
           ) AS Distance
FROM nodes 
HAVING Distance < @dist 
ORDER BY distance LIMIT 0 , 100;

【讨论】:

【参考方案2】:

我稍微修改了查询,它可以工作。 这是我的代码:

    set @nodeid = 122317;
    set @dist = 10;
    select lon, lat into @mylon, @mylat from nodes where id=@nodeid limit 1;

    SELECT id, ( 6371 * acos(
    sin(radians(@mylat)) * sin(radians(lat)) +
    cos(radians(@mylat)) * cos( radians(lat)) * 
    cos(radians(lon) - radians(@mylon)) 
    )) 
    AS distance
    FROM nodes having distance <@dist

我从德国***得到了这个公式,它工作正常。我有一些 ruby​​ 代码拳头,但它也可以用作 sql 查询。

为了选择一些特殊的节点,我添加了这个

(select nodes.id,lat,lon,k,v from nodes join node_tags on nodes.id=node_tags.id where k='public_transport') as stations

作为 FROM 条件来指定节点的标签。 (当然它改变了上面代码中对stations.lat/stations.log的lat/log访问。

【讨论】:

以上是关于使用 mySQL 的 OpenStreetMap 邻近搜索的主要内容,如果未能解决你的问题,请参考以下文章

使用 Mapkit 框架加载 openstreetmap

如何在颤动中使用传单“openstreetmap”?

使用 OpenStreetMap 获取给定 GPS 坐标集的国家名称

OpenStreetMap地图数据介绍(转)

如何在我的 mapview iOS 7 中使用 OpenLayer (OpenStreetMap) 瓦片

从 Openstreetmap 缓存切片