代码之家  ›  专栏  ›  技术社区  ›  Stefan Falk

@查询:函数ll\u to\u earth(双精度,双精度)不存在

  •  2
  • Stefan Falk  · 技术社区  · 6 年前

    我正在尝试实现以下查询,以便获取给定位置(lat、lng)的特定半径(米)内的位置:

    @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

    @Query(value = "" +
            "SELECT p " +
            "FROM PlaceEntity p " +
            "WHERE FUNCTION('earth_distance', " +
            "   FUNCTION('ll_to_earth', p.latitude, p.longitude), " +
            "   FUNCTION('ll_to_earth', latitude, longitude) " +
            ") < radius")
    

    同样的结果。

    正确的语法是什么?

    2 回复  |  直到 3 年前
        1
  •  7
  •   Stefan Falk    6 年前

    从…起 https://johanndutoit.net/searching-in-a-radius-using-postgres/ 我发现我必须安装一些扩展:

    开始 psql 外壳:

    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 显示如何在必要时提高性能。

        2
  •  1
  •   neshant sharma    4 年前

    创建扩展(如果多维数据集不存在) 如果不存在接地距离,则创建扩展

    对于任何需要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\u 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>?
    

    要使用本机查询分页获得结果,只需提供count查询-

    @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>