Hibernate 区域内点的休眠空间查询

Hibernate 区域内点的休眠空间查询,hibernate,postgresql,postgis,spatial,hibernate-spatial,Hibernate,Postgresql,Postgis,Spatial,Hibernate Spatial,亲爱的读者: 我目前正在开发一个应用程序,它需要根据坐标加载特定的项目。示例:我想要坐标x或其15公里范围内的所有商店 我一直在用JavaEE6构建这个web应用程序,并使用Hibernate3.3对我的Postgres数据库进行数据持久化。经过一些研究,我发现Hibernate Spatial可以实现我的目标。我安装了Postgis并运行了Hibernate Spatial 我使用的是Hibernate 3.3、Hibernate Spatial 1.0、PostgreSQL 9.2和post

亲爱的读者:

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

我一直在用JavaEE6构建这个web应用程序,并使用Hibernate3.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;
起初我认为我可以创建一个圆,基本上可以查询圆中的每个点。但这似乎比我想象的要难。太难了,我开始认为我使用Hibernate Spatial是错误的选择

我的问题是,是否可以使用Hibernate Spatial查询特定边界内的每个点(坐标x和y km)

我还对解决我的需求的其他可能性感兴趣。我一直在考虑以下可能性:

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

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

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

布尔值dwithin(几何体,几何体,双精度)
-如果 几何图形之间的距离在指定范围内

解释一下,查询将如下所示:

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公里很小),并且您位于低纬度地区,那么您可以将大约1公里设置为0.009。这将给你一个完美的赤道搜索圆,但当你向北或向南移动时,这个圆将变成一个椭圆,长轴指向南北。在+/-60度纬度处,椭圆的高度将是其宽度的两倍。显然不太理想,但在你的情况下可能有效


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

上述答案是错误的,该参数所描述的距离不是以公里为单位的(如果您在足够高的纬度上工作,您也无法以任何精度将其转换为米或公里)。请记住,如果在经纬度坐标上使用任何空间函数,那么实际上就是将地图挤压成一个平面,然后在那里进行计算

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

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

如果使用多边形区域,则根据所处位置(离赤道越近越好)和所检查区域的大小,使用几何坐标计算坐标的方式产生的失真将相当小

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

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


编辑:见@lreeder的更新答案,该答案已被澄清

通过下面提到的代码,您可以获得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));
DistanceInside()函数获取必须转换为geograph的距离,但hibernate Spatial不支持,因此可以通过另一种方式实现此目的,方法是根据您的要求提供十进制距离。下面介绍了小数点的链接

十进制转换 链接

用于在数据库中创建geom和添加扩展
链接

这更像是一个评论,不是吗?这并不是唯一的答案。你是对的,是的!但是我没有评论的名声,所以我不能否决这个答案,也不能对它表示任何异议。但答案有点误导人,所以我不得不做点什么!如果OP使用的是未投影的CRS,如lat lng,您所说的一切都是正确的。然而,如果他或她正在使用预测的CRS,或者愿意接受某种程度的错误,那么dwithin将很好地工作。我在最初的答案中淡化了这种复杂性,但在当前的答案中添加了更多细节。我确实认为我的回答为OP和其他具有相同问题的人提供了一个潜在的解决方案。。因为你的答案更多地是对我的答案的批评,而不是解决OP问题的方法,请考虑更新它来添加一个替代的解决方案。DIN在MySQL中不起作用。还有别的选择吗?这就是为什么我通常引导人们远离MySQL空间使用的一个原因。你最好的办法是计算距离