Commit d7194be8 authored by Matija Obreza's avatar Matija Obreza

Updates for spatial queries

- ES query builder
- SPATIAL INDEX on accession_geo#georef
parent fdd2cb8a
......@@ -563,6 +563,12 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.lonnyj</groupId>
<artifactId>liquibase-spatial</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.genesys-pgr</groupId>
<artifactId>glis-client-resttemplate</artifactId>
......
......@@ -33,6 +33,7 @@ import com.querydsl.core.types.SubQueryExpression;
import com.querydsl.core.types.TemplateExpression;
import com.querydsl.core.types.Visitor;
import com.querydsl.core.types.dsl.NumberPath;
import com.querydsl.spatial.SpatialOps;
public class ElasticQueryBuilder implements Visitor<Void, Void> {
private static Logger LOG = LoggerFactory.getLogger(ElasticQueryBuilder.class);
......@@ -149,6 +150,15 @@ public class ElasticQueryBuilder implements Visitor<Void, Void> {
Path<?> path = (Path<?>) args.get(0);
PathMetadata pmd = path.getMetadata();
mustNotClauses.add(existsQuery(customizedPath(pmd.getParent().toString() + "." + pmd.getName())));
} else if (operator == SpatialOps.WITHIN) {
LOG.debug("WITHIN: {}", args);
for (Expression<?> expr : args) {
printExpression("WITHIN.. ", expr);
}
Path<?> a0 = (Path<?>) args.get(0);
Expression<?> a1 = args.get(1);
handleWithin(a0, a1);
} else {
LOG.error("Op {}: {}", operator, args);
}
......@@ -207,6 +217,16 @@ public class ElasticQueryBuilder implements Visitor<Void, Void> {
mustClauses.add(termsQuery(customizedPath(getParentPath(pmd.getParent()) + "." + pmd.getName()), toValues(value)));
}
}
private void handleWithin(Path<?> path, Expression<?> value) {
PathMetadata pmd = path.getMetadata();
if (pmd.getPathType() == PathType.COLLECTION_ANY) {
LOG.debug("Path ANY for {}={}", pmd.getParent(), value);
mustClauses.add(termsQuery(customizedPath(pmd.getParent().toString()), toValues(value)));
} else {
mustClauses.add(termsQuery(customizedPath(getParentPath(pmd.getParent()) + "." + pmd.getName()), toValues(value)));
}
}
private String getParentPath(Path<?> path) {
String pathValue = path.toString();
......
......@@ -29,10 +29,9 @@ import javax.persistence.PreUpdate;
import javax.persistence.Table;
import javax.persistence.Version;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import org.apache.commons.lang3.StringUtils;
import org.genesys.blocks.auditlog.annotations.Audited;
import org.genesys.blocks.model.BasicModel;
import org.genesys.blocks.model.JsonViews;
......@@ -55,7 +54,8 @@ import com.fasterxml.jackson.annotation.JsonView;
public class AccessionGeo extends BasicModel implements GeoReferencedEntity, AccessionRelated, SelfCleaning {
private static final long serialVersionUID = 8046638388176612388L;
private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory();
@Version
private long version = 0;
......@@ -71,6 +71,7 @@ public class AccessionGeo extends BasicModel implements GeoReferencedEntity, Acc
@JsonIgnore
@Type(type = "org.hibernate.spatial.GeometryType")
@Column(name = "georef", nullable = false)
private Point location;
private Double uncertainty;
......@@ -109,10 +110,11 @@ public class AccessionGeo extends BasicModel implements GeoReferencedEntity, Acc
}
if (this.longitude != null && this.latitude != null) {
String wkt = (new StringBuffer()).append("POINT (").append(this.longitude).append(" ").append(this.latitude).append(")").toString();
try {
this.location = (Point) new WKTReader().read(wkt);
} catch (ParseException ignored) {}
this.location = GEOMETRY_FACTORY.createPoint(new Coordinate(this.longitude, this.latitude));
} else {
// this.location = null;
// FIXME mysql is dumb: All parts of a SPATIAL index must be NOT NULL.
this.location = GEOMETRY_FACTORY.createPoint(new Coordinate(-666, -666));
}
tileIndex = WorldClimUtil.getWorldclim25Tile(this.longitude, this.latitude);
......
......@@ -17,12 +17,9 @@ package org.genesys2.server.service.filter;
import static org.genesys2.server.model.genesys.QAccessionGeo.accessionGeo;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;
import org.genesys.blocks.model.filters.BasicModelFilter;
import org.genesys.blocks.model.filters.NumberFilter;
import org.genesys2.server.model.genesys.AccessionGeo;
......@@ -30,11 +27,15 @@ import org.genesys2.server.model.genesys.QAccessionGeo;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Predicate;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Polygon;
/**
* The Class CountryFilter.
*/
public class AccessionGeoFilter extends BasicModelFilter<AccessionGeoFilter, AccessionGeo> {
private static final GeometryFactory GEOMETRY_FACTORY = new GeometryFactory();
/** The longitude. */
public NumberFilter<Double> longitude;
......@@ -51,7 +52,7 @@ public class AccessionGeoFilter extends BasicModelFilter<AccessionGeoFilter, Acc
public ClimateFilter climate;
/** The polygon. */
public List<Number[]> polygon;
public List<Double[]> polygon;
/**
* Builds the query.
......@@ -93,35 +94,19 @@ public class AccessionGeoFilter extends BasicModelFilter<AccessionGeoFilter, Acc
if (climate != null) {
and.and(climate.buildQuery(accessiongeo.climate));
}
if (polygon != null && !polygon.isEmpty()) {
Polygon polygonObject = buildPolygon(polygon);
if (polygonObject != null) {
and.and(accessiongeo.location.within(polygonObject));
}
if (polygon != null && polygon.size() > 2) {
and.and(accessiongeo.location.within(toPolygon(polygon)));
}
return and;
}
private Polygon buildPolygon(final List<Number[]> points) {
StringBuilder builder = new StringBuilder();
builder.append("POLYGON ((");
Iterator<Number[]> iterator = points.iterator();
while (iterator.hasNext()) {
Number[] point = iterator.next();
builder.append(point[0]).append(" ").append(point[1]);
if (iterator.hasNext()) {
builder.append(", ");
}
private static Polygon toPolygon(List<Double[]> polygon) {
List<Coordinate> arr = polygon.stream().map(p -> new Coordinate(p[0], p[1])).collect(Collectors.toList());
// close loop if not closed
if (! arr.get(arr.size() - 1).equals2D(arr.get(0))) {
arr.add(arr.get(0));
}
builder.append("))");
Polygon polygon = null;
try {
polygon = (Polygon) new WKTReader().read(builder.toString());
} catch (ParseException ignored) {}
return polygon;
return GEOMETRY_FACTORY.createPolygon(arr.toArray(new Coordinate[] {}));
}
}
......@@ -5541,22 +5541,6 @@ databaseChangeLog:
indexName: UK_tllx8suofq27njhc60y6h1ii9
tableName: tile_climate
- changeSet:
id: 1550231443014-1
author: mborodenko
changes:
- addColumn:
columns:
- column:
constraints:
nullable: true
name: point
type: geometry
tableName: accession_geo
- sql:
sql: >-
update accession_geo set point = GeomFromText(CONCAT('POINT (', longitude, ' ', latitude, ')')) where longitude is not null and latitude is not null
- changeSet:
id: 1550049944680-1
author: mborodenko
......@@ -5594,3 +5578,33 @@ databaseChangeLog:
name: createdDate
indexName: IX_accession_createdDate
tableName: accession
- changeSet:
id: 1550231443014-5
author: mborodenko & mobreza
changes:
- addColumn:
columns:
- column:
constraints:
nullable: true
name: georef
type: point
tableName: accession_geo
- sql:
sql: >-
update accession_geo set georef = POINT(latitude, longitude) where latitude is not null and longitude is not null
- sql:
sql: >-
update accession_geo set georef = POINT(-666, -666) where latitude is null or longitude is null
- addNotNullConstraint:
columnName: georef
columnDataType: point
tableName: accession_geo
- createSpatialIndex:
geometryType: Point
columns:
- column:
name: georef
indexName: IX_accessiongeo_georef
tableName: accession_geo
......@@ -320,7 +320,7 @@ public class AccessionControllerTest extends AbstractApiTest {
@Test
public void testFindAccessionInsidePolygon() throws Exception {
// specify points of polygon
List<Number[]> pointsList = new ArrayList<>();
List<Double[]> pointsList = new ArrayList<>();
pointsList.add(new Double[]{ 80D, 70D });
pointsList.add(new Double[]{ 80D, 90D });
pointsList.add(new Double[]{ 60D, 90D });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment