Java JPA按GPS坐标排序

时间:2016-07-26 06:16:14

标签: java sql hibernate jpa spatial

我正在使用Java 8和JPA以及Hibernate 5.2.1和MySQL数据库。

我有一张用户GPS坐标表:

第1行:

LAT_1: 28.85, LONG_1: -25.766667
LAT_2: 27.15, LONG_2: -26.133333

第2行:

LAT_1: 27.25, LONG_1: -26.234567
LAT_2: 28.98, LONG_2: -25.456666

然后我也有一个用户选择坐标值:

LAT_USER: 27.22, LONG_USER: -26.89998

我需要数据库查询中的结果集返回按距离最近的GPS点(asc)的距离排序的行

在此示例中,距离LAT_USER & LONG_USER最近的GPS点将是:

第1行

 LAT_2 & LONG_2

第2行

 LAT_1 & LONG_1

这可能吗?

到目前为止,这是我的基本代码:

    CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
    CriteriaQuery<T> criteriaQuery = criteriaBuilder.createQuery(entityClass);

    // from
    Root<T> from = criteriaQuery.from(entityClass);
    criteriaQuery.select(from);

    // order by
    List<Order> order = new ArrayList<Order>();
    // ????
    criteriaQuery.orderBy(order);

    List<T> results = (List<T>) entityManager.createQuery(criteriaQuery).setFirstResult(firstResult)
            .setMaxResults(maxResults).getResultList();
    return results;

我很感激任何人的帮助。

由于

更新

我的表结构如下(我有其他连接表,但这是为了简单起见):

 ----------     -------------------    -----------
| EMPLOYEE |   | EMPLOYEE_LOCATION |  | LOCATION  |
 ----------     -------------------    -----------
|ID        |   |EMP_ID             |  | ID        |
|          |   |LOC_ID             |  | LATITUDE  |
|          |   |                   |  | LONGITUDE |
 ----------     -------------------    -----------

我的员工模型对象有位置

@OneToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER)
@JoinTable
(
    name="employee_location",
    joinColumns={ @JoinColumn(name="EMP_ID", referencedColumnName="ID") },
    inverseJoinColumns={ @JoinColumn(name="LOC_ID", referencedColumnName="ID", unique=true) }
)
private Set<Location> locations;

我理解为了实现我需要的东西,我需要对数据库进行Haversine formula计算,因为我需要使用计算结果对结果集进行排序。

我知道这会导致相当复杂的查询,因为需要找到最低距离,并按此顺序

    SELECT e.id, 
    ( 6371 * acos( cos( radians(37) ) * cos( radians( l.LATITUDE) ) * cos( radians( l.LONGITUDE) - radians(-122) ) + sin( radians(37) ) * sin( radians( l.LATITUDE) ) ) ) AS distance
    FROM www.employee AS e 
    inner join
        www.employee_location as el
            on e.id=el.EMP_ID 
    inner join
        www.location as l
            on el.LOC_ID=l.ID
order by DISTANCE

这会正确返回ID和DISTANCE,但它会返回3个EMPLOYEES,因为该EMPLOYEE有3个LOCATIONS。当它在JPA中连线时(如上所述),这将返回1个EMPLOYEE和3个LOCATIONS。

有没有人知道我最好如何将它保存在JPA对象中并为Haversine formula添加自定义SQL(因为我有其他连接要简单得多。或者这不可能吗?)。然后,我需要按该雇员的最低LOCATION的距离订购。

更新

我会用这样的东西:

select ID, min(distance) as mindistance from (
select e.ID,
( 6371 * acos( cos( radians(37) ) * cos( radians( o.LATITUDE) ) * cos( radians( o.LONGITUDE) - radians(-122) ) + sin( radians(37) ) * sin( radians( o.LATITUDE) ) ) ) AS distance
from
    www.employee as e
inner join
    www.employee_location as eo
        on e.id=eo.EMP_ID 
inner join
    www.location as o
        on eo.LOC_ID=o.ID ) xxx
group by ID
order by mindistance; 

1 个答案:

答案 0 :(得分:0)

我认为你有两个选择

  1. 使用MySql中的spatial support
  2. 在hibernate-search中使用spatial support(位于lucene之上)
  3. 对于选项1,您可能无法获得hibernate支持,因此我猜测您需要Session.createSQLQuery(...)和/或Restrictions.sqlRestriction(...)

    我个人喜欢选项1,因为管理lucene索引会增加复杂性