区域内点的Hibernate-Spatial查询

时间:2013-05-02 08:47:07

标签: hibernate postgresql postgis spatial hibernate-spatial

亲爱的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上使用Native查询,将这些结果映射到实体并在应用程序的其他部分使用它们(基本上删除Hibernate-Spatial并使用本机查询)。
  • 切换到Hibernate-Search并使用Lucene完成我的任务。
  • 完全不同的东西

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

3 个答案:

答案 0 :(得分:6)

对于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 Km很小),并且您处于低纬度,那么您可以将Km近似为0.009。这将在赤道上为您提供一个完美的搜索圆,但是当您向北或向南移动时,这个圆将变成椭圆形,长轴指向北方和南方。在纬度+/- 60度时,椭圆的高度是宽度的两倍。显然不理想,但它可能适用于您的情况。

另一种方法是将数据集重新投影并存储在PostgreSQL中,作为投影数据集,单位为米。如果在地图上大规模显示,这会使您的数据失真,但您的搜索将按预期工作。

答案 1 :(得分:3)

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

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

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

如果你正在使用多边形区域,那么取决于你所处的位置(越接近赤道越好)并且根据你正在检查的区域的大小,坐标计算方式的失真将是公平的最小的几何坐标。

因此,多边形区域或多或少会有一点失真。

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

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

答案 2 :(得分: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()函数以距离为单位进行距离转换,该距离必须转换为地理坐标,但是休眠Spatial不支持,因此还有另一种方法可以根据需要以十进制距离提供距离。小数点。

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

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