我正在尝试使用Haversine公式在一个Spring Data JPA Query中找到接近于某个位置的实体,并使用Pageable进行操作,但我还没有完成它。
我的第一个尝试看起来像这样:
@Query("SELECT m, (6371 * acos(cos(radians(:latitude)) * cos(radians(m.latitude)) * cos(radians(m.longitude) - radians(:longitude)) + sin(radians(:latitude)) * sin(radians(m.latitude)))) as dist FROM Entity m WHERE dist < :distance ORDER BY dist DESC")
public List<Entity> findEntitiesByLocation(@Param("latitude") final double latitude, @Param("longitude") final double longitude, @Param("distance") final double distance, Pageable pageable);
但是它失败了,因为Spring/JPA似乎无法在where子句中使用别名。堆栈跟踪中的SQL看起来像这样
select (...),(haversine) as col_1_0_ where dist<? order by col_1_0_ DESC
因此,在where子句中别名不会被替换。使用“col_1_0_”(不带引号)代替dist也无效。
根据这个SO答案,至少MySQL是内向外解释的,在Where子句中使用别名是不可能的。一个建议的解决方案是使用HAVING代替WHERE,但即使在HAVING子句中,别名也无法被解析。
我知道可以将Haversine公式移到where子句中,但我仍然需要它在Order By子句中,并且我认为在Order By子句中使用相同的长Haversine公式可能会降低性能,因为我从几十万个实体中选择。
然后我尝试手动创建查询,但不知道如何将Pageable应用于此:
@Override
public List<Entity> findEntitiesByLocation(final double latitude, final double longitude, final double distance, Pageable pageable) {
final javax.persistence.Query query = this.entityManager.createQuery(SELECT_ENTITES_BY_DISTANCE);
query.setParameter("latitude", latitude);
query.setParameter("longitude", longitude);
query.setParameter("distance", distance);
final List<Entity> entities = query.getResultList();
// order by distance
entities .sort(new EntityDistanceComparator(latitude, longitude));
return entities ;
}
所以,我希望第一种使用 @Query 的方法能够起作用(这是我更喜欢的方式),或者使用 Pageable 的第二种方法。
m.latitude
不应该改为e.latitude
吗?非常感谢! - Cir0X