PostgreSQL 9.4,在我的 JPA namedQuery 中使用 earth_distance

Posted

技术标签:

【中文标题】PostgreSQL 9.4,在我的 JPA namedQuery 中使用 earth_distance【英文标题】:PostgreSQL 9.4, use earth_distance in my JPA namedQuery 【发布时间】:2015-07-27 09:18:29 【问题描述】:

我有一个表格站点存储了我的站点信息以及纬度和经度。

ozssc=> \d site;
......
site_latitude         | double precision            | 
site_longitude        | double precision            | 
......

我添加到我的 PostgreSQL 服务器 9.4.3

 CREATE EXTENSION cube; 
 CREATE EXTENSION earthdistance;

所有函数都添加到我的数据库中,我将函数所有者更改为我的登录用户。

当我尝试 PSQL 到我的服务器并执行时:

ozssc=> select * from site s where earth_box('-28.175613','153.52578399999993',100000) @> ll_to_earth(s.site_latitude,s.site_longitude);
ERROR:  function earth_box(unknown, unknown, integer) does not exist
LINE 1: select * from site s where earth_box('-28.175613','153.52578...
                               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

当我尝试将 earth_box 函数放入 JPA 中的命名查询中时:

@NamedQuery(name = "SiteEntity.findByEarthDistance", query = "SELECT s FROM SiteEntity s WHERE earth_box((ll_to_earth( :positionLatitude, :positionLongitude), :range) @> ll_to_earth(s.siteLatitude,s.siteLongitude))"),

我的intelliJ抱怨没有功能匹配??

当我尝试将我的 JAVAEE 应用程序部署到我的 webLogic 12c 时,我发现错误如下:

Message icon - Error An error occurred during activation of changes, please see the log for details.
Message icon - Error Exception [EclipseLink-0] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.JPQLException Exception Description: Syntax error parsing [SELECT s FROM SiteEntity s WHERE earth_box((ll_to_earth( :positionLatitude, :positionLongitude), :range) > ll_to_earth(s.siteLatitude,s.siteLongitude))]. [33, 151] The expression is not a valid conditional expression.
Message icon - Error Substituted for missing class Exception [EclipseLink-0] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd) - org.eclipse.persistence.exceptions.JPQLException Exception Description: Syntax error parsing [SELECT s FROM SiteEntity s WHERE earth_box((ll_to_earth( :positionLatitude, :positionLongitude), :range) > ll_to_earth(s.siteLatitude,s.siteLongitude))]. [33, 151] The expression is not a valid conditional expression.

我现在迷失了方向,谁能帮帮我!!

再次编辑

我发现 PostgreSQL 9.4 的 earth_box 函数一定有一些 bug,它不能总是得到正确的结果集,我必须将其更改为 earth_distance 函数并使用多选投影才能使其正常工作,较新的 namedQuery 为:

@NamedQuery(name = "SiteEntity.findBySiteLNR", query = "SELECT s, FUNC('earth_distance', FUNC('ll_to_earth',:positionLatitude, :positionLongitude), FUNC('ll_to_earth',s.siteLatitude,s.siteLongitude)) AS dfcl " +
            "FROM SiteEntity s WHERE dfcl < :range ORDER BY dfcl"),

我没有使用休眠,而是使用 EclipseLink 和 JPA 2.1,EJB 容器是 Weblogic 12C,EJB 规范 3.1。

【问题讨论】:

【参考方案1】:

在解决这个问题大约 4 小时后,我找到了解决方案。主要是因为它是来自 JPA 的函数调用,所以必须知道一些技巧。

PSQL 语句为:

select * from site s where earth_box(ll_to_earth(-28.175613,153.52578399999993),100000) @> ll_to_earth(s.site_latitude,s.site_longitude);

而 JPA 将查询命名为:

@NamedQuery(name = "SiteEntity.findByEarthDistance", query = "SELECT s FROM SiteEntity s WHERE FUNC('earth_box', FUNC('ll_to_earth',:positionLatitude, :positionLongitude), :range) > FUNC('ll_to_earth',s.siteLatitude,s.siteLongitude)"),

JPA 中的嵌套函数调用也可以,谢谢!

【讨论】:

请告诉我为什么我仍然从数据库中获取所有字段,即使它们不在半径范围内?【参考方案2】:

我认为提示说明了一切:您需要添加显式类型转换。

您可以通过添加双分号和您想要将其转换为的类型来做到这一点。即

'-28.175613'::text

或者任何函数所期望的。

【讨论】:

【参考方案3】:

强烈建议使用 FUNCTION 而不是 FUNC(以前的实现:http://www.eclipse.org/eclipselink/documentation/2.6/jpa/extensions/jpql.htm#func)。 EclipseLink 支持 order by 和 group by FUNCTIONS,但它不支持 FUNC。

@NamedQuery(name = "SiteEntity.findByEarthDistance", query = "SELECT s FROM SiteEntity s WHERE FUNCTION('earth_box', FUNCTION('ll_to_earth',:positionLatitude, :positionLongitude), :range) > FUNCTION('ll_to_earth',s.siteLatitude,s.siteLongitude)")

【讨论】:

【参考方案4】:
@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,您需要 spring JPA 不解释的 '@

我本可以使用 native_query = true 但这不会为我提供分页支持,这就是我切换到 JPA 查询的原因。

所以如果你不需要分页,你可以使用下面的。

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

【讨论】:

以上是关于PostgreSQL 9.4,在我的 JPA namedQuery 中使用 earth_distance的主要内容,如果未能解决你的问题,请参考以下文章

为没有 Hibernate Annotations 的 PostgreSQL 文本类型更正 JPA Annotation

postgresql 和 jpa:关系不存在

带有 PostgreSQL 9.4 数据源的 WildFly 10 部署应用程序时出错

在 postgreSQL 中使用 jpa 存储库从序列中获取下一个值

记一次在线安装postgresql-9.4的问题

匹配两个数组列 postgresql-9.4-