我正在尝试实现以下查询,以便在给定位置(lat,lng)的情况下获取特定半径(以米为单位)内的位置:
SUPERUSER_ID
但是,运行它会抛出:
@RepositoryRestResource(collectionResourceRel = "places", path = "places")
public interface PlaceRepository extends JpaRepository<PlaceEntity, Long> {
@Query(value = "" +
"SELECT p " +
"FROM PlaceEntity p " +
"WHERE earth_distance( " +
" ll_to_earth(p.latitude, p.longitude), " +
" ll_to_earth(latitude, longitude) " +
") < radius")
List<PlaceEntity> findByLocationAndRadius(@Param("latitude") Float latitude,
@Param("longitude") Float longitude,
@Param("radius") Integer radius);
}
我还尝试更改集Caused by: org.postgresql.util.PSQLException: ERROR: function ll_to_earth(double precision, double precision) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
Position: 343
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2284)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2003)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:200)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:424)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:161)
at org.postgresql.jdbc.PgPreparedStatement.executeQuery(PgPreparedStatement.java:114)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeQuery(ProxyPreparedStatement.java:52)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeQuery(HikariProxyPreparedStatement.java)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:60)
... 76 more
以及将nativeQuery = true
更改为
@Query
具有相同的结果。
这个的正确语法是什么?
答案 0 :(得分:1)
从https://johanndutoit.net/searching-in-a-radius-using-postgres/我发现我必须安装一些扩展程序:
启动psql
shell:
psql postgres -h localhost -d <database-name>
执行:
<database-name>=# CREATE EXTENSION cube;
<database-name>=# CREATE EXTENSION earthdistance;
此外,正确设置nativeQuery = true
和参考参数:
@Query(value = "" +
"SELECT * " +
"FROM place " +
"WHERE earth_distance( " +
" ll_to_earth(place.latitude, place.longitude), " +
" ll_to_earth(:latitude, :longitude) " +
") < :radius", nativeQuery = true)
List<PlaceEntity> findByLocationAndRadius(@Param("latitude") Float latitude,
@Param("longitude") Float longitude,
@Param("radius") Integer radius);
注意:这可能会变慢。 link显示了如何在必要时提高效果。
答案 1 :(得分:1)
如果不存在则创建扩展多维数据集 如果地球距离不存在,请创建扩展
对于需要相同JPA版本的任何人
@Query(
"""
FROM Place pl
WHERE
FUNCTION('cube_contains',
FUNCTION('earth_box',
FUNCTION('ll_to_earth', :latitude, :longitude),
:radiusInMeters),
FUNCTION('ll_to_earth', pl.latitude, pl.longitude)
) = TRUE
""")
fun getPlacesNear(
pageable: Pageable,
@Param("latitude") latitude: Double,
@Param("longitude") longitude: Double,
@Param("radiusInMeters") radiusInMeters: Int
): Page<Place>
这就像传呼和距离支持的魅力
出于某些奇怪的原因
@Query(
"""
FROM Place pl
WHERE
FUNCTION('ll_to_earth', pl.latitude, pl.longitude)
< FUNCTION('earth_box', FUNCTION('ll_to_earth', :latitude, :longitude), :radiusInMeters)
""")
https://www.postgresql.org/docs/9.5/cube.html#CUBE-GIST-OPERATORS
由于某些奇怪的原因,“ <”无法正常工作,因为在postgres中无法正确解释“ <”,并且给出了错误的结果。
对于postgres,您需要'@ <'符号,该符号不会被Spring JPA解释,因此我不得不切换到使用cube_contains函数
要获得没有分页的结果-
@Query(
"""SELECT *, earth_distance(ll_to_earth(:latitude, :longitude), ll_to_earth(latitude, longitude)) as distance
FROM place
WHERE (earth_box(ll_to_earth(:latitude, :longitude), :radiusInMeters) @> ll_to_earth(latitude, longitude))
ORDER BY distance ASC
""", nativeQuery = true)
fun getPlacesNear(
@Param("latitude") latitude: Double,
@Param("longitude") longitude: Double,
@Param("radiusInMeters") radiusInMeters: Int
): List<Place>?
要获得与本机查询分页的结果,只需提供计数查询-
@Query(
value = """SELECT *, earth_distance(ll_to_earth(:latitude, :longitude), ll_to_earth(latitude, longitude)) distance
FROM place
WHERE earth_distance(ll_to_earth(:latitude, :longitude), ll_to_earth(latitude, longitude)) < :radiusInMeters
""",
countQuery = """
SELECT COUNT(*) FROM place WHERE (earth_box(ll_to_earth(:latitude, :longitude), :radiusInMeters) @> ll_to_earth(latitude, longitude))
""", nativeQuery = true)
fun getPlacesNear(
pageable: Pageable,
@Param("latitude") latitude: Double,
@Param("longitude") longitude: Double,
@Param("radiusInMeters") radiusInMeters: Int
): Page<Place>