应用程序如何执行邻近搜索?例如,用户输入邮政编码,然后应用程序会按附近顺序列出20英里内的所有企业。
我想在PHP和MySQL中构建类似的东西。这种方法正确吗?
- 获取我感兴趣的地点的地址并存储在我的数据库中
- 使用谷歌的地理编码服务对所有地址进行地理编码
- 编写一个包含Haversine公式的数据库查询,以进行邻近搜索和排序
这样可以吗?在步骤3中,我将计算每个查询的接近度。有一个列出每个企业和几个参考地点之间距离的PROXIMITY表更好吗?
如果有足够的记录来影响速度,这里有一种提前对它们进行索引的方法。
定义一个侧面约20英里的垃圾箱网格。将垃圾箱编号与每个商店的记录一起存储。在搜索时,计算与搜索点20英里半径相交的所有垃圾箱的数量。然后检索这些存储箱中的所有存储,并像以前一样继续操作。
我们用它来做成千上万的点。如果您在SQL中执行此操作,那么在Latitude和Longitude列上创建索引是非常重要的。我们在SQL 2008中尝试过使用空间索引来实现这一点,但我们确实没有看到预期的性能提升。但是,如果您想在距离ZIP一定距离内进行计算,则需要考虑是使用ZIP质心还是使用ZIP代码的多边形表示。
哈弗辛福鲁姆拉是一个很好的起点。
我们在计算飞行距离时没有遇到性能问题,我们确实提前计算了一些应用程序的距离,在这些应用程序中,我们提前知道了点,并且将有数百万条记录。
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
我们为大约1200个位置执行此操作。我只是即时使用Haversine公式,尽管根据您的应用程序,将其存储在PHP中而不是SQL中可能会更好。(我们的实现在.net中,所以您的相似性可能会有所不同)。
实际上,我们实现方式的最大缺点是,每一次计算(直到最近)都必须在数据层上计算,这非常慢(我说慢,我的意思是非瞬时的,它需要一秒钟左右),但这是因为它必须根据提供的邮政编码计算所有1200个位置的距离。
根据您选择的路线,有一些方法可以加快数字距离的计算,方法是查看经度和纬度,并删除预定义范围之外的地址(例如,如果您查看20英里内的所有地址,则有一个经度范围,您可以计算出20英里外的所有地址必须属于哪个地址。)如果需要的话,这可以加快你的查询速度。
实际上,我们考虑将所有可能的组合存储在数据库中。事实上,它听起来可能是一个大型数据存储,但实际上并不在大范围内。有了索引,它可以非常快,而且你不必担心算法优化等。我们决定不这样做,因为我们在C#中有等式,它允许我们缓存在业务层中进行所有计算所需的信息。两者都可以,这只是你的偏好的问题。