邻近搜索

时间:2008-11-03 23:33:14

标签: php mysql proximity

应用程序如何执行邻近搜索?例如,用户键入邮政编码,然后应用程序列出距离接近的20英里范围内的所有商家。

我想在PHP和MySQL中构建类似的东西。这种方法是否正确?

  1. 获取我感兴趣的地点的地址并存储在我的数据库中
  2. 使用Google的地理编码服务对所有地址进行地理编码
  3. 编写包含Haversine公式的数据库查询,以执行邻近搜索和排序
  4. 这样好吗?在第3步中,我将计算每个查询的接近度。最好是有一个PROXIMITY表,列出每个企业和几个参考位置之间的距离吗?

3 个答案:

答案 0 :(得分:11)

我们用它来做数千点。如果您在SQL中执行此操作以在“纬度”和“经度”列上创建索引,则这一点非常重要。我们尝试在SQL 2008中使用空间索引执行此操作,但我们确实没有看到我们预期的性能提升。虽然如果你想在一个ZIP的一定距离内计算,你需要考虑是否要使用ZIP质心或邮政编码的多边形表示。

Haversine forumla是一个很好的起点。

我们没有在运行中计算距离的性能问题,我们会提前计算一些应用程序,我们事先知道这些点,并且会有数百万条记录。

SELECT
        [DistanceRadius]=
        69.09 *
        DEGREES(
          ACOS(
            SIN( RADIANS(latitude) )*SIN( RADIANS(@ziplat) ) 
           +
            COS( RADIANS(latitude) )*COS( RADIANS(@ziplat) ) 
           *
            COS( RADIANS(longitude - (@ziplon)) )
          )
        )
        ,*
        FROM
            table

    ) sub
WHERE
    sub.DistanceRadius < @radius

答案 1 :(得分:9)

如果有足够的记录速度,那么这是一种提前索引它们的方法。

定义一侧约20英里的垃圾箱网格。将箱号存储在每个商店的记录中。在搜索时,计算与搜索点相距20英里半径的所有箱的数量。然后检索任何这些箱中的所有商店,并像以前一样继续。

答案 2 :(得分:2)

我们为大约1200个地点执行此操作。我会动态使用Haversine公式,虽然取决于你的应用程序,最好将它存储在PHP而不是SQL中。 (我们的实施是在.net,所以你的milage可能会有所不同)。

我们实施它的方式真的是我们最大的缺点是,每次计算(直到最近)都必须在数据层上计算得很慢(当我说慢时,我的意思是非瞬时它需要一个第二个左右),但这是因为它必须根据提供的邮政编码计算所有1200个地点的距离。

根据您选择的路线,有多种方法可以加快数字距离计算,方法是查看经度和纬度并移除预定义范围之外的数据(例如,如果您查看20英里范围内的所有地址)有一个经度范围,你可以计算出所有地址必须落在20英里以外。)如果需要,这可以加快你的查询速度。

我们实际上已经考虑过在数据库中存储所有可能的组合。实际上,它听起来像是一个大型数据存储,但实际上并不是在大范围内。使用索引它可以非常快,而且你不必担心算法优化等。我们决定反对它,因为我们在C#中有等式,它允许我们缓存所有计算所需的信息。业务层。要么工作得很好,这只是你的偏好的问题。