使用 Haversine 公式在 Spring 中获取最近的位置

Get nearest position with Haversine Formula in Spring

我有一个实体,它在数据库中有两列,如下所示:

@Column(name = "latitude", nullable = false)
private float currentPositionLatitude;

@Column(name = "longitude", nullable = false)
private float currentPositionLongitude;

而且我的数据库 (PostgresQl) 中有多个实体条目,所有条目都具有不同的纬度和经度。现在我想给出一个点(纬度、经度)和一个半径,并显示该点附近的所有实体。 我首先在 Spring Jpa 中使用这样的 Harversine 公式进行了尝试:

   String HAVERSINE_PART = "(6371 * acos(cos(radians(:latitude)) * cos(radians(s.latitude)) *" +
        " cos(radians(s.longitude) - radians(:longitude)) + sin(radians(:latitude)) * sin(radians(s.latitude))))";

    @Query("SELECT currentPositionLatitude,currentPositionLongitude FROM Entity WHERE  '%:HAVERSINE_PART%' < :distance ORDER BY '%:HAVERSINE_PART%' DESC")
      public List<Entity> findEntiryWithLocation(
      @Param("currentPositionLatitude") final float latitude,
      @Param("currentPositionLongitude") final float longitude, @Param("distance") final double distance )

这没有用,所以我尝试了:

    @Query("SELECT s FROM Entity s WHERE " + HAVERSINE_PART + " < :distance ORDER BY "+ HAVERSINE_PART + " DESC")
List<Entity> findEntityWithInDistance(
@Param("latitude") double latitude,
 @Param("longitude") double longitude,
 @Param("distance") double distanceWithInKM );

这也没有用,所以我尝试了:

@Query(value = "SELECT *, earth_distance(ll_to_earth(:latitude, :longitude), ll_to_earth(latitude, longitude)) as distance FROM Car WHERE  (earth_box(ll_to_earth(:latitude, :longitude), :radiusInMeters) @> ll_to_earth(latitude, longitude))ORDER BY distance ASC",
nativeQuery = true)
List<Entity> getPlacesNear ( @Param("latitude") float latitude,
                             @Param("longitude")float longitude,
                             @Param("radiusInMeters") float radiusInMeters);

已编译,但当我尝试在我的控制器中输入值时出现错误:jdbc错误:2022 无方言映射

这里是我的服务和控制器方法(数据类型可能已经改变):

public List<Entity>showNearestEntityByDistances(float latitude, float longitude, float distance){
        return EntityRepository.getPlacesNear(latitude,longitude,distance);
    }

和端点:

@GetMapping("/location")
public List<Entity>showEntityNearby(@RequestParam float latitude,@RequestParam float longitude,@RequestParam float distance){
  

    return carService.showNearestEntitysByDistances(latitude,longitude,distance);
}

我已经看过了: https://www.postgresql.org/docs/current/earthdistance.htmlpostgresql jpa earth_distance query

但是没有用。有谁知道我做错了什么? 谢谢。

以下对我有用:

首先,运行:

 create extension cube;

 create extension earthdistance; 

这会安装扩展,除其他外,无需安装 PostGIS 即可启用 location-based 查询

然后,不要将纬度和经度存储在单独的列中,而是将它们一起存储在 'point' 类型的列中,请记住首先是经度,而不是您期望的纬度,例如

  create table Entity (city varchar(100), location point);

并存储您的数据,例如

insert into places(name, location) values ('lambertville', point((74.9429,40.3659)));
    
insert into places(name, location) values ('ny', point(74.0060, 40.7128));
    
insert into places(name, location) values ('phila', point( 75.1652, 39.9526));

(请注意,新泽西州兰伯特维尔位于费城和纽约之间 half-way 左右)。

然后,例如,如果您想要 select 与另一个实体之间的距离小于一定距离的实体,您可以执行以下操作:

select * from places 
 where 
location <@> (select location from places where name = 'ny') < 70  
  and name != 'ny';

或者,如果您已经有了坐标,并且想找到一定距离内的实体,

select * from places 
 where 
location <@> point(74.0060, 40.7128) < 70    
  and name != 'ny';

我没有检查这些查询是否可以适应 JPA @Query 注释,YMMV。

我做了一些改变:

 @Query(value = "SELECT * FROM Entity s WHERE " + HAVERSINE_PART + " < :distance ORDER BY "+ HAVERSINE_PART + " DESC",nativeQuery = true)
List<Entity> findEntityWithInDistance(
@Param("latitude") double latitude,
 @Param("longitude") double longitude,
 @Param("distance") double distanceWithInKM );