【问题标题】:Java JPA Order By with GPS CoordinatesJava JPA 使用 GPS 坐标排序
【发布时间】:2016-11-29 15:40:46
【问题描述】:

我正在使用带有 JPA 和 Hibernate 5.2.1 和 MySQL 数据库的 Java 8。

我有一张带有用户 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

然后我也有一个 user selected 坐标值:

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 |
 ----------     -------------------    -----------

我的Employee模型对象有位置

@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; 

【问题讨论】:

  • 您可能在这里寻找的公式称为 Haversine 公式,它计算球体上两点之间的距离。您可能希望在数据库中进行此计算,并且您可能还希望对数据库进行空间分区。
  • 谢谢蒂姆。我同意,我需要对数据库进行计算,因为它是按顺序进行的。我正在尝试使用 SQL/JPQL/HQL 进行此计算。我遇到的困难是每一行都知道要使用哪个坐标,以及计算本身。我目前正在努力,希望也能在这里得到一些帮助。
  • 查看here,了解有关Haversine 公式的讨论。
  • 谢谢,看看....
  • 只是一个问题:为什么不使用几何列类型(例如 JTS 点)存储信息?那么您将拥有可以完成所有这些工作的地理空间方法

标签: java sql hibernate jpa spatial


【解决方案1】:

我认为你有两个选择

  1. 在 MySql 中使用spatial support
  2. 在 hibernate-search 中使用 spatial support(位于 lucene 之上)

对于选项 1,您可能没有休眠支持,所以我猜您需要 Session.createSQLQuery(...) 和/或 Restrictions.sqlRestriction(...)

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

【讨论】:

  • 感谢 Lance,我会调查一下。
  • Lance,如果我使用空间支持,它会正确保存数据(即作为几何点),但这仍然不能解决我不认为的问题?我需要能够找到 n 个点中的最低点并按此排序。
  • 我个人认为 hibernate 是 Java 世界中最大的浪费时间之一。如果还不算太晚,我建议你一起放弃休眠并切换到mybatis
  • 我猜这类似于 iBatis。比 Hibernate 更不臃肿。我去看看,谢谢。
  • 我想你会使用st_within 来限制st_distance 的搜索和排序。例如select * from table where st_within(...) order by st_distance(...)。一些信息here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-06
  • 1970-01-01
相关资源
最近更新 更多