问题 Hibernate Spatial - 在X公里范围内查询?


我是Hibernate Spatial的新手,我正在尝试对给定半径内的对象执行简单查询。我使用Google地图和其他来源的数据在我的数据库中创建了许多条目,其中包含与纬度和经度相对应的属性。此属性在我的Entity类中定义如下:

@Column
@Type(type = "org.hibernate.spatial.GeometryType")
private Point coordinates = null;

我现在试图弄清楚如何搜索坐标在半径范围内的所有实体对象 X 从给定点开始的公里数。例如,我想找到落在该点半径50公里范围内的物体(12.34567,-76.54321)。但是,我找不到任何可以解释如何在Hibernate Spatial中执行此操作的示例或教程。

任何人都可以给我任何关于如何构建这样的查询的信息吗?


4896
2017-11-17 01:41


起源



答案:


看到 这个资源 有关“空间查询”的教程,这是一种特殊的方言和 JTS库 (开源)。

基本上,您执行以下操作(从引用的页面复制/粘贴):

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import util.JPAUtil;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.Date;
import java.util.List;

.......

private List find(String wktFilter) {
    Geometry filter = wktToGeometry(wktFilter);
    EntityManager em = JPAUtil.createEntityManager();
    em.getTransaction().begin();
    Query query = em.createQuery("select e from Event e where within(e.location, :filter) = true", Event.class);
    query.setParameter("filter", filter);
    return query.getResultList();
}

private Geometry wktToGeometry(String wktPoint) {
    WKTReader fromText = new WKTReader();
    Geometry geom = null;
    try {
        geom = fromText.read(wktPoint);
    } catch (ParseException e) {
        throw new RuntimeException("Not a WKT string:" + wktPoint);
    }
    return geom;
}

要生成圆,请参阅 这个资源 (搜索“弧,圆和曲线”)。 再次从那里复制/粘贴:

//this method replaces the above wktToGeometry() method
private static Geometry createCircle(double x, double y, final double RADIUS) {
  GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
  shapeFactory.setNumPoints(32);
  shapeFactory.setCentre(new Coordinate(x, y));//there are your coordinates
  shapeFactory.setSize(RADIUS * 2);//this is how you set the radius
  return shapeFactory.createCircle();
}

除此之外,你总是有解决方法,在其中添加一些额外的字段(映射为insertable=false, updatable=false)映射到使用的相同列 org.hibernate.spatial.GeometryType 然后在查询中使用它们。要计算距离,请检查 欧几里德距离公式


15
2017-11-21 22:05



该页面上显示的示例显示查询给定多边形内的点。我是否必须在查询中指定多边形?理想情况下,我能够给它一个点(纬度/经度)和半径,并在我的查询中使用它而不是多边形。如何使用JTS / Hibernate Spatial声明几何? - Shadowman
嗯,圆是一个特殊的几何,但不是一个多边形。请参阅我的更新示例,了解如何创建圆圈。 - Andrei I
好的,这一切都有道理。我会试一试。不幸的是,我遇到了这个错误(stackoverflow.com/questions/20079825/...)这使得测试无法进行,直到我得到解决。 - Shadowman
我终于摆脱了我的错误并开始测试你的答案。这一切都对我有意义,但我认为我在设置半径大小时遇到​​了问题。我想查询特定的纬度/经度并获得12公里范围内的物体。如何将12 KM转换为“shapeFactory.setSize()”行正确解释的度量单位?我的初步测试表明我做错了。 - Shadowman
我有完全相同的事情......你怎么能确定半径是米/公里的单位等等? - simonC


答案:


看到 这个资源 有关“空间查询”的教程,这是一种特殊的方言和 JTS库 (开源)。

基本上,您执行以下操作(从引用的页面复制/粘贴):

import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import util.JPAUtil;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.Date;
import java.util.List;

.......

private List find(String wktFilter) {
    Geometry filter = wktToGeometry(wktFilter);
    EntityManager em = JPAUtil.createEntityManager();
    em.getTransaction().begin();
    Query query = em.createQuery("select e from Event e where within(e.location, :filter) = true", Event.class);
    query.setParameter("filter", filter);
    return query.getResultList();
}

private Geometry wktToGeometry(String wktPoint) {
    WKTReader fromText = new WKTReader();
    Geometry geom = null;
    try {
        geom = fromText.read(wktPoint);
    } catch (ParseException e) {
        throw new RuntimeException("Not a WKT string:" + wktPoint);
    }
    return geom;
}

要生成圆,请参阅 这个资源 (搜索“弧,圆和曲线”)。 再次从那里复制/粘贴:

//this method replaces the above wktToGeometry() method
private static Geometry createCircle(double x, double y, final double RADIUS) {
  GeometricShapeFactory shapeFactory = new GeometricShapeFactory();
  shapeFactory.setNumPoints(32);
  shapeFactory.setCentre(new Coordinate(x, y));//there are your coordinates
  shapeFactory.setSize(RADIUS * 2);//this is how you set the radius
  return shapeFactory.createCircle();
}

除此之外,你总是有解决方法,在其中添加一些额外的字段(映射为insertable=false, updatable=false)映射到使用的相同列 org.hibernate.spatial.GeometryType 然后在查询中使用它们。要计算距离,请检查 欧几里德距离公式


15
2017-11-21 22:05



该页面上显示的示例显示查询给定多边形内的点。我是否必须在查询中指定多边形?理想情况下,我能够给它一个点(纬度/经度)和半径,并在我的查询中使用它而不是多边形。如何使用JTS / Hibernate Spatial声明几何? - Shadowman
嗯,圆是一个特殊的几何,但不是一个多边形。请参阅我的更新示例,了解如何创建圆圈。 - Andrei I
好的,这一切都有道理。我会试一试。不幸的是,我遇到了这个错误(stackoverflow.com/questions/20079825/...)这使得测试无法进行,直到我得到解决。 - Shadowman
我终于摆脱了我的错误并开始测试你的答案。这一切都对我有意义,但我认为我在设置半径大小时遇到​​了问题。我想查询特定的纬度/经度并获得12公里范围内的物体。如何将12 KM转换为“shapeFactory.setSize()”行正确解释的度量单位?我的初步测试表明我做错了。 - Shadowman
我有完全相同的事情......你怎么能确定半径是米/公里的单位等等? - simonC