2016-09-12 7 views
0

Я пытаюсь использовать Predicates в Hibernate-Spatial для поиска в радиусе X миль (определяется пользователем).Предикаты в Hibernate-Spatial + PostGIS для поиска в радиусе мили с широтой/долготой

Хотя такого рода вопрос задавали раньше, только один раз перед этим с помощью Predicates и может не быть текущим, поскольку он не работает. И я должен иметь возможность использовать предикаты и NOT HQL.

Я нашел через другой ответ, как настроить предикат для ключевого слова WITHIN PostGIS, но не смог выполнить запрос.

После установки в конце я указываю вывод ошибки и версии пакета.

Вот что я имею в моей схеме:

CREATE EXTENSION Postgis; 

CREATE TABLE "user" (
    id    bigint NOT NULL, 
    search_radius int, 
    latitude   double precision, 
    longitude  double precision, 
    location   geography(point, 4326), 

    PRIMARY KEY (id) 
); 

В моей модели:

import com.vividsolutions.jts.geom.Point; 
import com.vividsolutions.jts.io.ParseException; 
import com.vividsolutions.jts.io.WKTReader; 
import org.hibernate.annotations.Type; 

@Entity 
@Table(name = "`user`") 
public class User implements UserDetails { 
    @Id 
    private Long id; 
    private Integer searchRadius = 125; 
    private Double latitude; 
    private Double longitude; 
    @Column(name = "location", columnDefinition = "geography(Point, 4326)", nullable = true) 
    @Type(type = "jts_geometry") 
    private Point location; 

    ... 

    private void updateLocation() { 
     if (latitude != null && longitude != null) { 
      try { 
       location = (Point) new WKTReader().read("POINT(" + latitude + " " + longitude + ")"); 
       location.setSRID(Location.SRID); 
      } catch (ParseException e) { 
       e.printStackTrace(); 
       throw new RuntimeException(e); 
      } 
     } 
    } 
} 

Где место обновление называется внутри сеттеры LAT/LNG.

Предикат, который я получил от Using JPA Criteria Api and hibernate spatial 4 together

import com.vividsolutions.jts.geom.Geometry; 
import com.vividsolutions.jts.geom.Point; 
import java.io.Serializable; 
import javax.persistence.criteria.Expression; 
import org.hibernate.jpa.criteria.CriteriaBuilderImpl; 
import org.hibernate.jpa.criteria.ParameterRegistry; 
import org.hibernate.jpa.criteria.Renderable; 
import org.hibernate.jpa.criteria.compile.RenderingContext; 
import org.hibernate.jpa.criteria.predicate.AbstractSimplePredicate; 

public class WithinPredicate extends AbstractSimplePredicate implements Expression<Boolean>, Serializable { 
    private final Expression<Point> matchExpression; 
    private final Expression<Geometry> area; 

    public WithinPredicate(CriteriaBuilderImpl criteriaBuilder, Expression<Point> matchExpression, Expression<Geometry> area) { 
     super(criteriaBuilder); 
     this.matchExpression = matchExpression; 
     this.area = area; 
    } 

    public Expression<Point> getMatchExpression() { 
     return matchExpression; 
    } 

    public Expression<Geometry> getArea() { 
     return area; 
    } 

    public void registerParameters(ParameterRegistry registry) { 
     // Nothing to register 
    } 

    @Override 
    public String render(boolean isNegated, RenderingContext renderingContext) { 
     StringBuilder buffer = new StringBuilder(); 
     buffer.append(" within(") 
      .append(((Renderable) getMatchExpression()).render(renderingContext)) 
      .append(", ") 
      .append(((Renderable) getArea()).render(renderingContext)) 
      .append(") = true "); 
     String bo = buffer.toString(); 

     return bo; 
    } 
} 

и создания запроса, используя завод WithinPredicate и круг.

import com.xxxx.repository.WithinPredicate; 
import com.vividsolutions.jts.geom.Coordinate; 
import com.vividsolutions.jts.geom.Geometry; 
import com.vividsolutions.jts.util.GeometricShapeFactory; 

@Service 
class ... { 
    public List<User> fetchFor(User user) { 
     ... 
     Geometry radius = createCircle(user.getLatitude(), user.getLongitude(), user.getSearchRadius()); 
     radius.setSRID(Location.SRID); 
     p = b.and(p, new WithinPredicate(
      (CriteriaBuilderImpl) b, 
      u.get(User_.location), 
      new LiteralExpression<Geometry>((CriteriaBuilderImpl) b, radius) 
     )); 
    } 

    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().getBoundary(); 
    } 
} 

К сожалению, ошибка я получаю на выходе:

2016-09-09 14:03:30.862 WARN 56393 --- [   main] o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 0, SQLState: 42883 
2016-09-09 14:03:30.862 ERROR 56393 --- [   main] o.h.engine.jdbc.spi.SqlExceptionHelper : ERROR: function st_within(geography, bytea) does not exist 
    Hint: No function matches the given name and argument types. You might need to add explicit type casts. 
    Position: 336 

Hibernate-пространственной версии в Gradle:

compile('org.hibernate:hibernate-spatial:5.0.9.Final') 

Я подозреваю, что проблема обусловлена, возможно, модели/схема установлена ​​на тип «География (точка, 4326)», но shapeFactory, создающий радиус типа «Геометрия (точка, 4326)».

Действительно оцените любую помощь по этому вопросу. Благодарю.

ответ

1

Я только прочитал часть из вас вопрос, однако некоторые вещи подняли несколько красных флагов:

  • Вам нужно перевернуть порядок оси в (XY), или (долгота широта)
  • ST_Within существует только для geometry типов, а не для geography
  • Чтобы найти точки в пределах области, не создают несовершенное буферизованный точку
  • Вы найдете ST_DWithin быстрее и хорошо поддерживается для geography тип; для радиуса, просто закройте ваши мили до метров

 Смежные вопросы

  • Нет связанных вопросов^_^