【问题标题】:Hibernate-Spatial Query for Points within an area区域内点的休眠空间查询
【发布时间】:2013-04-26 09:00:44
【问题描述】:

亲爱的 stackoverflow 读者,

我目前正在开发一个需要根据其坐标加载特定项目的应用程序。示例:我想要坐标 x 或其 15 公里范围内的所有商店。

我一直在 Java EE 6 中构建这个 Web 应用程序,并使用 Hibernate 3.3 将数据持久化到我的 Postgres 数据库。经过一番研究,我发现 Hibernate-Spatial 可以实现我的目标。我安装了 Postgis 并运行了 Hibernate-Spatial。

我正在使用 Hibernate 3.3、Hibernate-Spatial 1.0、PostgreSQL 9.2 和 postgis-jdbc 1.3.3。

我创建了一个具有位置字段的实体:

@Column(columnDefinition = "Geometry", nullable = true) 
@Type(type = "org.hibernatespatial.GeometryUserType")
private Point location;

最初我认为我可以创建一个 Circle 并基本上查询位于该圆圈中的每个点。但这似乎比我想象的要难。太难了,我开始认为我在使用 Hibernate-Spatial 时做出了错误的选择。

我的问题是是否可以通过使用 Hibernate-Spatial 来查询特定边界内的每个点(坐标 x 和 y 公里)。

我也对解决我的要求的其他可能性感兴趣。我一直在考虑以下几种可能性:

  • 只需在 PostgreSQL 上使用原生查询,将这些结果映射到实体并在应用程序的其他部分使用这些结果(基本上移除 Hibernate-Spatial 并使用原生查询)。
  • 切换到 Hibernate-Search 并使用 Lucene 完成我的任务。
  • 完全不同的东西

谁能提供一个例子,说明我如何在 Hibernate-Spatial 中实现我的愿望,或者我如何以另一种方式实现我的要求。

【问题讨论】:

    标签: hibernate postgresql postgis spatial hibernate-spatial


    【解决方案1】:

    通过下面提到的代码,您可以获得 50 到 110 米内的所有位置,因为我使用 0.001,您可以根据您的要求使用距离。

    GeometryFactory factory = new GeometryFactory(new PrecisionModel(), 4326);
            factory.createPoint(new Coordinate(longitude,latitude));
            Point comparisonPoint = factory.createPoint(new Coordinate(longitude,latitude));
            predicates.add(SpatialPredicates.distanceWithin(cb, geom from db), comparisonPoint, 0.001));
    

    distanceWithin() 函数以距离为单位,您必须将其转换为地理,但休眠空间不支持,因此还有另一种方法可以通过根据您的要求提供十进制距离来实现这一点。下面提到了链接小数点。

    用于十进制转换 链接https://en.wikipedia.org/wiki/Decimal_degrees

    用于创建geom并在数据库中添加扩展 链接https://www.compose.com/articles/geofile-everything-in-the-radius-with-postgis/

    【讨论】:

      【解决方案2】:

      对于 PostgreSQL/PostGIS 方言,Hibernate Spatial 支持 dwithin 函数。

      boolean dwithin(Geometry, Geometry, double) - 如果 几何图形彼此在指定的距离内

      解释Hibernate Spatial tutorial,查询看起来像这样:

      String wktCenterPoint = "POINT(10 15)"
      Geometry centerPoint = wktToGeometry(wktCenterPoint);    
      ...
      Query query = em.createQuery("select e from Event e where dwithin(e.location, :centerPoint, 15) = true", Event.class);
      ...
      

      这将返回距离中心点 15 个单位内的所有事件。

      但是,dwithin 中给出的距离将与基础数据集具有相同的单位,不一定是公里。如果数据集单位是米,则距离将被视为米。

      如果数据集是 lat-lng,则距离将为度数。如果是这种情况,并且您的搜索距离很短(15 公里很小),并且您位于低纬度地区,您可以将公里数近似为 0.009。这将为您在赤道上提供一个完美的搜索圈,但是当您向北或向南移动时,这个圈将变成一个椭圆,长轴指向南北。在 +/- 60 度纬度处,椭圆的高是宽的两倍。显然不理想,但它可能适用于您的情况。

      另一种选择是将数据集重新投影并存储在 PostgreSQL 中,作为以米为单位的投影数据集。如果在大比例地图上显示,这会扭曲您的数据,但您的搜索将按预期工作。

      【讨论】:

      • dwithin 在 MYSQL 中不起作用,有替代方案吗?
      • 这是我通常引导人们远离 MySQL 以进行空间使用的原因之一。最好的办法是自己计算与要素的距离,使用如下方式:gis.stackexchange.com/questions/31628/…
      【解决方案3】:

      上述答案不正确,该参数描述的距离不是以公里为单位(如果您在足够高的纬度上工作,您也不能将其转换为米或公里,以任何精度) .请记住,如果在经纬度坐标上使用任何空间函数,那么您实际上是将地图压缩为 equirectangle projection,然后在那里进行计算。

      DWITHIN 能够对球体进行计算,但只有在您提供地理数据时,它才会接受米作为其测量单位。

      Hibernate Spatial支持地理类型(this bug 已经 3 年没有解决了,所以不要屏住呼吸)。

      如果您使用多边形区域,则取决于您所在的位置(越接近赤道越好)以及您检查的区域的大小,坐标计算方式的失真将是相当大的几何坐标最小。

      所以多边形区域或多或少可以正常工作,但会有一点变形。

      长话短说,Hibernate Spatial 不支持一种简单的方法来存储地理数据并对其执行操作。它支持将数据存储为投影的更高级和更困难的方法,并在此基础上进行基本的笛卡尔数学。

      编辑:请参阅@lreeder 的更新答案,该答案已得到澄清。

      【讨论】:

      • 这更像是一条评论——不是吗?它并不是真正独立的答案。
      • 你是对的,它是!但我没有评论的声誉,所以我不能投票否决答案或表达任何不同意见。但答案有微妙的误导性,所以我必须做点什么!
      • 如果 OP 使用像 lat-lng 这样的未投影 CRS,那么您所说的所有内容都是正确的。但是,如果他或她正在使用预计的 CRS,或者愿意接受某种程度的错误,dwithin 将可以正常工作。我在原始答案中淡化了这种复杂性,但在当前答案中添加了更多细节。我确实认为我的回答为 OP 和其他有相同问题的人提供了一种潜在的解决方案。由于您的回答更多的是对我的回答的批评,而不是解决 OP 问题的答案,因此请考虑更新它以添加替代解决方案。跨度>
      猜你喜欢
      • 2022-08-15
      • 2013-11-30
      • 2016-12-03
      • 1970-01-01
      • 1970-01-01
      • 2018-03-20
      • 1970-01-01
      • 1970-01-01
      • 2015-01-06
      相关资源
      最近更新 更多