一种方法是检索所有地址并逐个检查它们到后端的所选地址,但是有没有办法最小化从数据库检索的项目数量,而不是使用内存?最好的做法是什么?
想象一下,我有30万条记录,我必须检索它们,并计算他们到所选点的距离?正如詹姆斯所建议的,我可以在不同地区记录记录,并计算距离,那么哪种方法可以很好地跟踪,通过查询或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; }
This question和this one提供了通过MysqL计算距离的方法,但哪个方法是更好的Java或MysqL我很困惑.
解决方法
>弧度长度(Math.toRadians(经度))
> sinRadiansLatitude(Math.sin(Math.toRadians(纬度))
> cosRadiansLatitude(Math.cos(Math.toRadians(latitude))
那么当我搜索有关纬度/经度X单位内的地方时,我的准备声明如下:
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
其中YYYY = 3965可以给出距离以英里或YYYY = 6367可以用于距离公里.
最后,在数据库执行任何计算之前,我已经使用maximumSearchLatitude / maximumSearchLongitude / minimumSearchLongitude / maximumSearchLongitude参数来排除结果集中的大部分点.你可能会也可能不需要这个.如果你这样做,这将取决于你为这些参数选择什么值,因为它将取决于你正在搜索的内容.
显然,数据库中索引的明智应用是必要的.
使用这种方法的好处是,每次都不需要更改的信息只能计算一次,而每次执行搜索时计算每行的弧度长度,sinRadiansLatitude,cosRadiansLatitude的值将非常快速地计算.
另一个选项是使用geospatial index,这意味着所有这些都由数据库为您处理.我不知道Hibernate如何整合.
免责声明:自从我看了这么久以后,我不是GIS专家!