查找到所选点的特定距离内的所有地址的最佳方法是什么

我正在开发一个应用程序,该应用程序应该显示位于某个位置的特定距离内的地址。我知道如何找到两点之间的距离,但问题是我不确定在性能方面什么是最好的方法。

一种方法是检索所有地址并逐个检查它们到后端中的所选地址,但是有没有办法最大限度地减少我从数据库中检索的项目数,而不是使用内存?最好的方法是什么,如何做到这一点?

想象一下,我有300,000条记录,我必须全部检索它们并计算它们到所选点的距离吗?正如James建议的那样,我可以拥有不同地区的记录并计算距离,那么哪种方法适合遵循,通过查询或Java计算距离?

  public class Address{
    long Id;
    Double latitude;
    Double longitude;
    ..
  }

计算

public static double distFrom(double lat1, double lng1, double lat2, double lng2) {
  double earthRadius = 3958.75;
  double dLat = Math.toRadians(lat2-lat1);
  double dLng = Math.toRadians(lng2-lng1);
  double sindLat = Math.sin(dLat / 2);
  double sindLng = Math.sin(dLng / 2);
  double a = Math.pow(sindLat, 2) + Math.pow(sindLng, 2)
        * Math.cos(Math.toRadians(lat1)) *     Math.cos(Math.toRadians(lat2));
  double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  double dist = earthRadius * c;

  return dist;
}

这个问题这个问题提供了通过mysql计算距离的方法,但是哪种方法是Java还是mysql更好,我非常困惑。


答案 1

当我在MySQL中实现它时(用于在扁球体上存储位置,这基本上就是地球(我假设你说的是地球!)),我已经在数据库中存储了尽可能多的预先计算的信息。因此,对于存储 和 的行,我还在插入时计算以下字段:latitudelongitude

  • radiansLongitude (Math.toRadians(longitude))
  • sinRadiansLatitude (Math.sin(Math.toRadians(latitude))
  • cosRadiansLatitude (Math.cos(Math.toRadians(latitude))

然后,当我搜索所讨论的/的X单位内的地方时,我准备的陈述如下:latitudelongitude

from Location l where
    acos(
        sin(:latitude) * sinRadiansLatitude + 
        cos(:latitude) * cosRadiansLatitude * 
        cos(radiansLongitude - :longitude) 
        ) * YYYY < :distance
    and l.latitude>:minimumSearchLatitude
    and l.latitude<:maximumSearchLatitude 
    and l.longitude>:minimumSearchLongitude 
    and l.longitude<:maximumSearchLongitude 
    order by acos(
                sin(:latitude) * sinRadiansLatitude + 
                cos(:latitude) * cosRadiansLatitude * 
                cos(radiansLongitude - :longitude)  
        ) * YYYY asc

其中 = 3965 表示以英里为单位的距离,或 = 6367 可用于以公里为单位的距离。YYYYYYYY

最后,在数据库必须执行任何计算之前,我使用 / 参数从结果集中排除了大多数点。您可能需要也可能不需要它。如果您确实使用了此功能,则取决于您为这些参数选择哪些值,因为这将取决于您要搜索的内容。maximumSearchLatitudemaximumSearchLongitudeminimumSearchLongitudemaximumSearchLongitude

显然,在数据库中明智地应用索引是必要的。

使用这种方法的好处是,每次都不会改变但每次都需要的信息只计算一次,而每次执行搜索时计算每行的值,都会变得非常昂贵。radiansLongitudesinRadiansLatitudecosRadiansLatitude

另一种选择是使用地理空间索引,这意味着所有这些都由数据库为您处理。我不知道Hibernate与它的集成程度如何。

免责声明:我已经很久没有看过这个了,我不是GIS专家!


答案 2

您可以在查询本身而不是客户端进行服务器端计算,从而仅检索计算结果。这里(子孙的存档链接)是SQL中基于Haversine的实现的一个例子(抱歉,这篇文章太长了,我无法在这里复制+粘贴或总结,尽管它是一篇很棒的文章,很容易阅读)。

或者,您可以将数据库划分为多个区域(例如,具有极坐标的四边形树),并仅检索点附近的区域,从而为您提供一个较小的子集来针对客户端进行测试。同样,您可以根据距离计算粗略的纬度和经度边界框,并使用有关纬度和经度的数据库索引,并仅选择该范围内的地址以供计算考虑。

查询方法是一种更简单、更简洁的方法,由于初始距离过滤,因此具有良好的性能。我只会在由于某种原因无法实现前者的情况下才采用区域方法。


推荐