Java springboot规范接近度复杂三角查询

问题描述

我正在创建一个应用程序,用户可以在其中通过许多各种(可选)过滤器过滤结果,其中一种是按接近度进行搜索。我正在使用org.springframework.data.jpa.domain.Specification根据提供的参数动态构建查询,其中大多数参数都是简单的ge / le一些整数值。 我的where子句:(location_lng / lat是数据库中的值,其中数字与查询一起提供坐标,并且

SELECT *
FROM rental 
WHERE(
    6371 * acos(
      cos( radians(52.2477331) ) * cos( radians( location_lat ) )
      *
      cos( radians( location_lng ) - radians(21.0136079) )
      +
      sin( radians(52.2477331) )
      *
      sin( radians( location_lat ) )
    )
  ) < 10

我使用这种方法在后端即时查询存储库中

public Page<RentalDTO> getByCriteria(RentalSearchCriteria cr,Optional<Integer> page,Optional<String> sort,Optional<Integer> size,Optional<Sort.Direction> order) {
        return rentalRepository.findAll(
                where(
                        priceFrom(cr.getPriceFrom())
                                .and(inProximity(cr.getdist(),cr.getLat(),cr.getLng()))
                                .and(priceto(cr.getPriceto()))
                                .and(sizefrom(cr.getSizefrom()))
                                .and(sizeto(cr.getSizeto()))
                                .and(buildFrom(cr.getBuildFrom()))
                                .and(builtTo(cr.getBuildTo()))
                                .and(roomFrom(cr.getRoomFrom()))
                                .and(roomTo(cr.getRoomTo()))
                                .and(moveInAt(cr.getMoveInTo()))
                                .and(tagsIncluded(cr.getFeatures()))
                ),PageRequest.of(
                        page.orElse(0),size.orElse(3),order.orElse(Sort.Direction.ASC),sort.orElse("price"))
        ).map(RentalDTO::createFrom);
    }

和说明(此为空):

    public static Specification<Rental> inProximity(Integer distance,Double lat,Double lng) {
        if (distance == null || lat == null || lng == null) {
            return null;
        } else {
            return (root,query,cb) -> {
                return null; // todo 
            };
        }
    }

查询使用分组方式,而其他查询则不使用分组方式,但是肯定应该有某种方法可以使分组不使用分组方式,因为我不需要检查整个表来计算特定行的距离,可能需要一些子查询或这样,不是很确定如何解决这个问题。

解决方法

我最终创建了一个postgreSQL函数,并在规范中使用了该函数:

create or replace function distance(lat double precision,lng double precision,db_lat double precision,db_lng double precision)
  returns double precision as $dist$ 
  begin 
  return 
  6371 * acos(
      cos(radians(lat)) * cos(radians(db_lat))
      *
      cos(radians(db_lng) - radians(lng))
      +
      sin(radians(lat))
      *
      sin(radians(db_lat))
    );
    
    
    end;
    $dist$ language plpgsql;

Springboot:

    public static Specification<Rental> inProximity(Double distance,Double lat,Double lng) {
        if (distance == null || lat == null || lng == null) {
            return null;
        } else {
            return (root,query,cb) ->
                    cb.lessThanOrEqualTo(
                            cb.function("distance",Double.class,cb.literal(lat),cb.literal(lng),root.get("locationLat"),root.get("locationLng")),distance
                    );
        }
    }