5

亲爱的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 km 从那里开始)。

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

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

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

4

3 回答 3

7

对于 PostgreSQL/PostGIS 方言,Hibernate Spatial 支持该dwithin功能。

boolean dwithin(Geometry, Geometry, double)- 如果几何在彼此之间的指定距离内,则返回 true

解释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 中,作为以米为单位的投影数据集。如果在大比例地图上显示,这会扭曲您的数据,但您的搜索将按预期工作。

于 2013-05-18T16:14:22.800 回答
3

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

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

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

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

因此,多边形区域或多或少可以正常工作,但会有一点失真。

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

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

于 2013-12-13T23:51:37.783 回答
0

通过下面提到的代码,您可以获得 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 并在数据库 LINK中添加扩展名:https ://www.compose.com/articles/geofile-everything-in-the-radius-with-postgis/

于 2020-11-29T19:39:56.173 回答