mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-07-08 11:32:45 +00:00
DATAES-12 Merge Geo Location from branch 'master' of https://github.com/fmarchand/spring-data-elasticsearch
This commit is contained in:
parent
aa6a5e3753
commit
74a4035408
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core;
|
||||||
|
|
||||||
|
import org.elasticsearch.index.query.*;
|
||||||
|
import org.springframework.data.elasticsearch.core.geo.GeoBBox;
|
||||||
|
import org.springframework.data.elasticsearch.core.geo.GeoLocation;
|
||||||
|
import org.springframework.data.elasticsearch.core.query.Criteria;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.ListIterator;
|
||||||
|
|
||||||
|
import static org.elasticsearch.index.query.FilterBuilders.*;
|
||||||
|
import static org.springframework.data.elasticsearch.core.query.Criteria.OperationKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CriteriaFilterProcessor
|
||||||
|
*
|
||||||
|
* @author Franck Marchand
|
||||||
|
*/
|
||||||
|
class CriteriaFilterProcessor {
|
||||||
|
|
||||||
|
|
||||||
|
FilterBuilder createFilterFromCriteria(Criteria criteria) {
|
||||||
|
List<FilterBuilder> fbList = new LinkedList<FilterBuilder>();
|
||||||
|
FilterBuilder filter = null;
|
||||||
|
|
||||||
|
ListIterator<Criteria> chainIterator = criteria.getCriteriaChain().listIterator();
|
||||||
|
|
||||||
|
while (chainIterator.hasNext()) {
|
||||||
|
FilterBuilder fb = null;
|
||||||
|
Criteria chainedCriteria = chainIterator.next();
|
||||||
|
if(chainedCriteria.isOr()){
|
||||||
|
fb = orFilter(createFilterFragmentForCriteria(chainedCriteria).toArray(new FilterBuilder[]{ }));
|
||||||
|
fbList.add(fb);
|
||||||
|
}else if(chainedCriteria.isNegating()){
|
||||||
|
List<FilterBuilder> negationFilters = buildNegationFilter(criteria.getField().getName(), criteria.getFilterCriteriaEntries().iterator());
|
||||||
|
|
||||||
|
if(!negationFilters.isEmpty()) {
|
||||||
|
fbList.addAll(negationFilters);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
fbList.addAll(createFilterFragmentForCriteria(chainedCriteria));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!fbList.isEmpty()) {
|
||||||
|
if(fbList.size() == 1) {
|
||||||
|
filter =fbList.get(0);
|
||||||
|
} else {
|
||||||
|
filter = andFilter(fbList.toArray(new FilterBuilder[]{ }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private List<FilterBuilder> createFilterFragmentForCriteria(Criteria chainedCriteria) {
|
||||||
|
Iterator<Criteria.CriteriaEntry> it = chainedCriteria.getFilterCriteriaEntries().iterator();
|
||||||
|
List<FilterBuilder> filterList = new LinkedList<FilterBuilder>();
|
||||||
|
|
||||||
|
String fieldName = chainedCriteria.getField().getName();
|
||||||
|
Assert.notNull(fieldName,"Unknown field");
|
||||||
|
FilterBuilder filter = null;
|
||||||
|
|
||||||
|
while (it.hasNext()){
|
||||||
|
Criteria.CriteriaEntry entry = it.next();
|
||||||
|
filter = processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName);
|
||||||
|
filterList.add(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return filterList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private FilterBuilder processCriteriaEntry(OperationKey key, Object value, String fieldName) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
FilterBuilder filter = null;
|
||||||
|
|
||||||
|
switch (key){
|
||||||
|
case WITHIN: {
|
||||||
|
filter = geoDistanceFilter(fieldName);
|
||||||
|
|
||||||
|
Assert.isTrue(value instanceof Object[], "Value of a geo distance filter should be an array of two values.");
|
||||||
|
Object[] valArray = (Object[]) value;
|
||||||
|
Assert.noNullElements(valArray, "Geo distance filter takes 2 not null elements array as parameter.");
|
||||||
|
Assert.isTrue(valArray.length == 2, "Geo distance filter takes a 2-elements array as parameter.");
|
||||||
|
Assert.isTrue(valArray[0] instanceof GeoLocation, "First element of a geo distance filter must be a GeoLocation");
|
||||||
|
Assert.isTrue(valArray[1] instanceof String, "Second element of a geo distance filter must be a String");
|
||||||
|
|
||||||
|
GeoLocation loc = (GeoLocation)valArray[0];
|
||||||
|
String dist = (String)valArray[1];
|
||||||
|
|
||||||
|
((GeoDistanceFilterBuilder)filter).lat(loc.getLat()).lon(loc.getLon()).distance(dist);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case BBOX: {
|
||||||
|
filter = geoBoundingBoxFilter(fieldName);
|
||||||
|
|
||||||
|
Assert.isTrue(value instanceof Object[], "Value of a geo distance filter should be an array of two values.");
|
||||||
|
Object[] valArray = (Object[]) value;
|
||||||
|
Assert.noNullElements(valArray, "Geo bbox filter takes a not null element array as parameter.");
|
||||||
|
Assert.isTrue(valArray.length == 1, "Geo distance filter takes a 1-elements array as parameter.");
|
||||||
|
Assert.isTrue(valArray[0] instanceof GeoBBox, "single-element of a geo bbox filter must be a GeoBBox");
|
||||||
|
|
||||||
|
GeoBBox geoBBox = (GeoBBox)valArray[0];
|
||||||
|
((GeoBoundingBoxFilterBuilder)filter).topLeft(geoBBox.getTopLeft().getLat(), geoBBox.getTopLeft().getLon());
|
||||||
|
((GeoBoundingBoxFilterBuilder)filter).bottomRight(geoBBox.getBottomRight().getLat(), geoBBox.getBottomRight().getLon());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FilterBuilder> buildNegationFilter(String fieldName, Iterator<Criteria.CriteriaEntry> it){
|
||||||
|
List<FilterBuilder> notFilterList = new LinkedList<FilterBuilder>();
|
||||||
|
|
||||||
|
while (it.hasNext()){
|
||||||
|
Criteria.CriteriaEntry criteriaEntry = it.next();
|
||||||
|
FilterBuilder notFilter = notFilter(processCriteriaEntry(criteriaEntry.getKey(), criteriaEntry.getValue(), fieldName));
|
||||||
|
notFilterList.add(notFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
return notFilterList;
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,8 @@ import org.springframework.data.elasticsearch.core.query.Criteria;
|
|||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.ListIterator;
|
import java.util.ListIterator;
|
||||||
|
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||||
@ -32,106 +34,141 @@ import static org.springframework.data.elasticsearch.core.query.Criteria.Operati
|
|||||||
*
|
*
|
||||||
* @author Rizwan Idrees
|
* @author Rizwan Idrees
|
||||||
* @author Mohsin Husen
|
* @author Mohsin Husen
|
||||||
|
* @author Franck Marchand
|
||||||
*/
|
*/
|
||||||
class CriteriaQueryProcessor {
|
class CriteriaQueryProcessor {
|
||||||
|
|
||||||
QueryBuilder createQueryFromCriteria(Criteria criteria) {
|
|
||||||
BoolQueryBuilder query = boolQuery();
|
|
||||||
|
|
||||||
ListIterator<Criteria> chainIterator = criteria.getCriteriaChain().listIterator();
|
QueryBuilder createQueryFromCriteria(Criteria criteria) {
|
||||||
while (chainIterator.hasNext()) {
|
if(criteria == null)
|
||||||
Criteria chainedCriteria = chainIterator.next();
|
return null;
|
||||||
if (chainedCriteria.isOr()) {
|
|
||||||
query.should(createQueryFragmentForCriteria(chainedCriteria));
|
|
||||||
} else if (chainedCriteria.isNegating()) {
|
|
||||||
query.mustNot(createQueryFragmentForCriteria(chainedCriteria));
|
|
||||||
} else {
|
|
||||||
query.must(createQueryFragmentForCriteria(chainedCriteria));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return query;
|
|
||||||
}
|
|
||||||
|
|
||||||
private QueryBuilder createQueryFragmentForCriteria(Criteria chainedCriteria) {
|
List<QueryBuilder> shouldQueryBuilderList = new LinkedList<QueryBuilder>();
|
||||||
Iterator<Criteria.CriteriaEntry> it = chainedCriteria.getCriteriaEntries().iterator();
|
List<QueryBuilder> mustNotQueryBuilderList = new LinkedList<QueryBuilder>();
|
||||||
boolean singeEntryCriteria = (chainedCriteria.getCriteriaEntries().size() == 1);
|
List<QueryBuilder> mustQueryBuilderList = new LinkedList<QueryBuilder>();
|
||||||
|
|
||||||
String fieldName = chainedCriteria.getField().getName();
|
|
||||||
Assert.notNull(fieldName, "Unknown field");
|
|
||||||
QueryBuilder query = null;
|
|
||||||
|
|
||||||
if (singeEntryCriteria) {
|
ListIterator<Criteria> chainIterator = criteria.getCriteriaChain().listIterator();
|
||||||
Criteria.CriteriaEntry entry = it.next();
|
while (chainIterator.hasNext()) {
|
||||||
query = processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName);
|
Criteria chainedCriteria = chainIterator.next();
|
||||||
} else {
|
QueryBuilder queryFragmentForCriteria = createQueryFragmentForCriteria(chainedCriteria);
|
||||||
query = boolQuery();
|
|
||||||
while (it.hasNext()) {
|
|
||||||
Criteria.CriteriaEntry entry = it.next();
|
|
||||||
((BoolQueryBuilder) query).must(processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addBoost(query, chainedCriteria.getBoost());
|
if(queryFragmentForCriteria!=null) {
|
||||||
return query;
|
if(chainedCriteria.isOr()){
|
||||||
}
|
shouldQueryBuilderList.add(queryFragmentForCriteria);
|
||||||
|
}else if(chainedCriteria.isNegating()){
|
||||||
|
mustNotQueryBuilderList.add(queryFragmentForCriteria);
|
||||||
|
}else{
|
||||||
|
mustQueryBuilderList.add(queryFragmentForCriteria);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private QueryBuilder processCriteriaEntry(OperationKey key, Object value, String fieldName) {
|
BoolQueryBuilder query = null;
|
||||||
if (value == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
QueryBuilder query = null;
|
|
||||||
|
|
||||||
switch (key) {
|
if(!shouldQueryBuilderList.isEmpty() || !mustNotQueryBuilderList.isEmpty() || !mustQueryBuilderList.isEmpty()) {
|
||||||
case EQUALS:
|
|
||||||
query = fieldQuery(fieldName, value);
|
|
||||||
break;
|
|
||||||
case CONTAINS:
|
|
||||||
query = fieldQuery(fieldName, "*" + value + "*").analyzeWildcard(true);
|
|
||||||
break;
|
|
||||||
case STARTS_WITH:
|
|
||||||
query = fieldQuery(fieldName, value + "*").analyzeWildcard(true);
|
|
||||||
break;
|
|
||||||
case ENDS_WITH:
|
|
||||||
query = fieldQuery(fieldName, "*" + value).analyzeWildcard(true);
|
|
||||||
break;
|
|
||||||
case EXPRESSION:
|
|
||||||
query = queryString((String) value).field(fieldName);
|
|
||||||
break;
|
|
||||||
case BETWEEN:
|
|
||||||
Object[] ranges = (Object[]) value;
|
|
||||||
query = rangeQuery(fieldName).from(ranges[0]).to(ranges[1]);
|
|
||||||
break;
|
|
||||||
case FUZZY:
|
|
||||||
query = fuzzyQuery(fieldName, (String) value);
|
|
||||||
break;
|
|
||||||
case IN:
|
|
||||||
query = boolQuery();
|
|
||||||
Iterable<Object> collection = (Iterable<Object>) value;
|
|
||||||
for (Object item : collection) {
|
|
||||||
((BoolQueryBuilder) query).should(fieldQuery(fieldName, item));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return query;
|
query = boolQuery();
|
||||||
}
|
|
||||||
|
|
||||||
private QueryBuilder buildNegationQuery(String fieldName, Iterator<Criteria.CriteriaEntry> it) {
|
for(QueryBuilder qb : shouldQueryBuilderList) {
|
||||||
BoolQueryBuilder notQuery = boolQuery();
|
query.should(qb);
|
||||||
while (it.hasNext()) {
|
}
|
||||||
notQuery.mustNot(fieldQuery(fieldName, it.next().getValue()));
|
for(QueryBuilder qb : mustNotQueryBuilderList) {
|
||||||
}
|
query.mustNot(qb);
|
||||||
return notQuery;
|
}
|
||||||
}
|
for(QueryBuilder qb : mustQueryBuilderList) {
|
||||||
|
query.must(qb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void addBoost(QueryBuilder query, float boost) {
|
return query;
|
||||||
if (Float.isNaN(boost)) {
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (query instanceof BoostableQueryBuilder) {
|
|
||||||
((BoostableQueryBuilder) query).boost(boost);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
private QueryBuilder createQueryFragmentForCriteria(Criteria chainedCriteria) {
|
||||||
|
if(chainedCriteria.getQueryCriteriaEntries().isEmpty())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Iterator<Criteria.CriteriaEntry> it = chainedCriteria.getQueryCriteriaEntries().iterator();
|
||||||
|
boolean singeEntryCriteria = (chainedCriteria.getQueryCriteriaEntries().size() == 1);
|
||||||
|
|
||||||
|
String fieldName = chainedCriteria.getField().getName();
|
||||||
|
Assert.notNull(fieldName,"Unknown field");
|
||||||
|
QueryBuilder query = null;
|
||||||
|
|
||||||
|
if(singeEntryCriteria){
|
||||||
|
Criteria.CriteriaEntry entry = it.next();
|
||||||
|
query = processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName);
|
||||||
|
}else{
|
||||||
|
query = boolQuery();
|
||||||
|
while (it.hasNext()){
|
||||||
|
Criteria.CriteriaEntry entry = it.next();
|
||||||
|
((BoolQueryBuilder)query).must(processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addBoost(query, chainedCriteria.getBoost());
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private QueryBuilder processCriteriaEntry(OperationKey key, Object value, String fieldName) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
QueryBuilder query = null;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case EQUALS:
|
||||||
|
query = fieldQuery(fieldName, value);
|
||||||
|
break;
|
||||||
|
case CONTAINS:
|
||||||
|
query = fieldQuery(fieldName, "*" + value + "*").analyzeWildcard(true);
|
||||||
|
break;
|
||||||
|
case STARTS_WITH:
|
||||||
|
query = fieldQuery(fieldName, value + "*").analyzeWildcard(true);
|
||||||
|
break;
|
||||||
|
case ENDS_WITH:
|
||||||
|
query = fieldQuery(fieldName, "*" + value).analyzeWildcard(true);
|
||||||
|
break;
|
||||||
|
case EXPRESSION:
|
||||||
|
query = queryString((String) value).field(fieldName);
|
||||||
|
break;
|
||||||
|
case BETWEEN:
|
||||||
|
Object[] ranges = (Object[]) value;
|
||||||
|
query = rangeQuery(fieldName).from(ranges[0]).to(ranges[1]);
|
||||||
|
break;
|
||||||
|
case FUZZY:
|
||||||
|
query = fuzzyQuery(fieldName, (String) value);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
query = boolQuery();
|
||||||
|
Iterable<Object> collection = (Iterable<Object>) value;
|
||||||
|
for (Object item : collection) {
|
||||||
|
((BoolQueryBuilder) query).should(fieldQuery(fieldName, item));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
private QueryBuilder buildNegationQuery(String fieldName, Iterator<Criteria.CriteriaEntry> it) {
|
||||||
|
BoolQueryBuilder notQuery = boolQuery();
|
||||||
|
while (it.hasNext()) {
|
||||||
|
notQuery.mustNot(fieldQuery(fieldName, it.next().getValue()));
|
||||||
|
}
|
||||||
|
return notQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addBoost(QueryBuilder query, float boost) {
|
||||||
|
if (Float.isNaN(boost)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (query instanceof BoostableQueryBuilder) {
|
||||||
|
((BoostableQueryBuilder) query).boost(boost);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,9 @@ import org.elasticsearch.client.Requests;
|
|||||||
import org.elasticsearch.common.collect.MapBuilder;
|
import org.elasticsearch.common.collect.MapBuilder;
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.index.query.FilterBuilder;
|
||||||
import org.elasticsearch.index.query.QueryBuilder;
|
import org.elasticsearch.index.query.QueryBuilder;
|
||||||
|
import org.elasticsearch.index.query.QueryBuilders;
|
||||||
import org.elasticsearch.search.SearchHit;
|
import org.elasticsearch.search.SearchHit;
|
||||||
import org.elasticsearch.search.facet.Facet;
|
import org.elasticsearch.search.facet.Facet;
|
||||||
import org.elasticsearch.search.facet.FacetBuilder;
|
import org.elasticsearch.search.facet.FacetBuilder;
|
||||||
@ -180,8 +182,21 @@ public class ElasticsearchTemplate implements ElasticsearchOperations {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> Page<T> queryForPage(CriteriaQuery criteriaQuery, Class<T> clazz) {
|
public <T> Page<T> queryForPage(CriteriaQuery criteriaQuery, Class<T> clazz) {
|
||||||
QueryBuilder query = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria());
|
QueryBuilder elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria());
|
||||||
SearchResponse response = prepareSearch(criteriaQuery, clazz).setQuery(query).execute().actionGet();
|
FilterBuilder elasticsearchFilter = new CriteriaFilterProcessor().createFilterFromCriteria(criteriaQuery.getCriteria());
|
||||||
|
SearchRequestBuilder searchRequestBuilder = prepareSearch(criteriaQuery, clazz);
|
||||||
|
|
||||||
|
if (elasticsearchQuery != null) {
|
||||||
|
searchRequestBuilder.setQuery(elasticsearchQuery);
|
||||||
|
} else {
|
||||||
|
searchRequestBuilder.setQuery(QueryBuilders.matchAllQuery());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elasticsearchFilter != null)
|
||||||
|
searchRequestBuilder.setFilter(elasticsearchFilter);
|
||||||
|
|
||||||
|
SearchResponse response = searchRequestBuilder
|
||||||
|
.execute().actionGet();
|
||||||
return mapResults(response, clazz, criteriaQuery.getPageable());
|
return mapResults(response, clazz, criteriaQuery.getPageable());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core;
|
|||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.springframework.data.elasticsearch.annotations.*;
|
import org.springframework.data.elasticsearch.annotations.*;
|
||||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||||
|
import org.springframework.data.elasticsearch.core.geo.GeoLocation;
|
||||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||||
import org.springframework.data.util.ClassTypeInformation;
|
import org.springframework.data.util.ClassTypeInformation;
|
||||||
import org.springframework.data.util.TypeInformation;
|
import org.springframework.data.util.TypeInformation;
|
||||||
@ -71,6 +72,11 @@ class MappingBuilder {
|
|||||||
if (isEntity(field)) {
|
if (isEntity(field)) {
|
||||||
mapEntity(xContentBuilder, field.getType(), false, EMPTY, field.getName());
|
mapEntity(xContentBuilder, field.getType(), false, EMPTY, field.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(field.getType() == GeoLocation.class) {
|
||||||
|
applyGeoLocationFieldMapping(xContentBuilder, field);
|
||||||
|
}
|
||||||
|
|
||||||
Field singleField = field.getAnnotation(Field.class);
|
Field singleField = field.getAnnotation(Field.class);
|
||||||
MultiField multiField = field.getAnnotation(MultiField.class);
|
MultiField multiField = field.getAnnotation(MultiField.class);
|
||||||
if (isRootObject && singleField != null && isIdField(field, idFieldName)) {
|
if (isRootObject && singleField != null && isIdField(field, idFieldName)) {
|
||||||
@ -88,6 +94,12 @@ class MappingBuilder {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void applyGeoLocationFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field) throws IOException {
|
||||||
|
xContentBuilder.startObject(field.getName());
|
||||||
|
xContentBuilder.field("type", "geo_point")
|
||||||
|
.endObject();
|
||||||
|
}
|
||||||
|
|
||||||
private static void applyDefaultIdFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field)
|
private static void applyDefaultIdFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
xContentBuilder.startObject(field.getName())
|
xContentBuilder.startObject(field.getName())
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core.geo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geo bbox used for #{@link org.springframework.data.elasticsearch.core.query.Criteria}.
|
||||||
|
*
|
||||||
|
* @author Franck Marchand
|
||||||
|
*/
|
||||||
|
public class GeoBBox {
|
||||||
|
private GeoLocation topLeft;
|
||||||
|
private GeoLocation bottomRight;
|
||||||
|
|
||||||
|
public GeoBBox(GeoLocation topLeft, GeoLocation bottomRight) {
|
||||||
|
this.topLeft = topLeft;
|
||||||
|
this.bottomRight = bottomRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeoLocation getTopLeft() {
|
||||||
|
return topLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopLeft(GeoLocation topLeft) {
|
||||||
|
this.topLeft = topLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeoLocation getBottomRight() {
|
||||||
|
return bottomRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBottomRight(GeoLocation bottomRight) {
|
||||||
|
this.bottomRight = bottomRight;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core.geo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* geo-location used for #{@link org.springframework.data.elasticsearch.core.query.Criteria}.
|
||||||
|
*
|
||||||
|
* @author Franck Marchand
|
||||||
|
*/
|
||||||
|
public class GeoLocation {
|
||||||
|
private double lat;
|
||||||
|
private double lon;
|
||||||
|
|
||||||
|
public GeoLocation lat(double lat) {
|
||||||
|
setLat(lat);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeoLocation lon(double lon) {
|
||||||
|
setLon(lon);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeoLocation() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeoLocation(double latitude, double longitude) {
|
||||||
|
this.lat = latitude;
|
||||||
|
this.lon = longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLat() {
|
||||||
|
return lat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLat(double lat) {
|
||||||
|
this.lat = lat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLon() {
|
||||||
|
return lon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLon(double lon) {
|
||||||
|
this.lon = lon;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch.core.geo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geo polygon used for #{@link org.springframework.data.elasticsearch.core.query.Criteria}.
|
||||||
|
*
|
||||||
|
* @author Franck Marchand
|
||||||
|
*/
|
||||||
|
public class GeoPolygon {
|
||||||
|
private List<GeoLocation> points;
|
||||||
|
|
||||||
|
public GeoPolygon(List<GeoLocation> points) {
|
||||||
|
this.points = points;
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,8 @@ import java.util.Set;
|
|||||||
|
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||||
|
import org.springframework.data.elasticsearch.core.geo.GeoBBox;
|
||||||
|
import org.springframework.data.elasticsearch.core.geo.GeoLocation;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,6 +35,7 @@ import org.springframework.util.Assert;
|
|||||||
*
|
*
|
||||||
* @author Rizwan Idrees
|
* @author Rizwan Idrees
|
||||||
* @author Mohsin Husen
|
* @author Mohsin Husen
|
||||||
|
* @author Franck Marchand
|
||||||
*/
|
*/
|
||||||
public class Criteria {
|
public class Criteria {
|
||||||
|
|
||||||
@ -48,7 +51,9 @@ public class Criteria {
|
|||||||
|
|
||||||
private List<Criteria> criteriaChain = new ArrayList<Criteria>(1);
|
private List<Criteria> criteriaChain = new ArrayList<Criteria>(1);
|
||||||
|
|
||||||
private Set<CriteriaEntry> criteria = new LinkedHashSet<CriteriaEntry>();
|
private Set<CriteriaEntry> queryCriteria = new LinkedHashSet<CriteriaEntry>();
|
||||||
|
|
||||||
|
private Set<CriteriaEntry> filterCriteria = new LinkedHashSet<CriteriaEntry>();
|
||||||
|
|
||||||
public Criteria() {
|
public Criteria() {
|
||||||
}
|
}
|
||||||
@ -171,7 +176,7 @@ public class Criteria {
|
|||||||
Assert.notNull(criteria, "Cannot chain 'null' criteria.");
|
Assert.notNull(criteria, "Cannot chain 'null' criteria.");
|
||||||
|
|
||||||
Criteria orConnectedCritiera = new OrCriteria(this.criteriaChain, criteria.getField());
|
Criteria orConnectedCritiera = new OrCriteria(this.criteriaChain, criteria.getField());
|
||||||
orConnectedCritiera.criteria.addAll(criteria.criteria);
|
orConnectedCritiera.queryCriteria.addAll(criteria.queryCriteria);
|
||||||
return orConnectedCritiera;
|
return orConnectedCritiera;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,7 +197,7 @@ public class Criteria {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Criteria is(Object o) {
|
public Criteria is(Object o) {
|
||||||
criteria.add(new CriteriaEntry(OperationKey.EQUALS, o));
|
queryCriteria.add(new CriteriaEntry(OperationKey.EQUALS, o));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +210,7 @@ public class Criteria {
|
|||||||
*/
|
*/
|
||||||
public Criteria contains(String s) {
|
public Criteria contains(String s) {
|
||||||
assertNoBlankInWildcardedQuery(s, true, true);
|
assertNoBlankInWildcardedQuery(s, true, true);
|
||||||
criteria.add(new CriteriaEntry(OperationKey.CONTAINS, s));
|
queryCriteria.add(new CriteriaEntry(OperationKey.CONTAINS, s));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,7 +222,7 @@ public class Criteria {
|
|||||||
*/
|
*/
|
||||||
public Criteria startsWith(String s) {
|
public Criteria startsWith(String s) {
|
||||||
assertNoBlankInWildcardedQuery(s, true, false);
|
assertNoBlankInWildcardedQuery(s, true, false);
|
||||||
criteria.add(new CriteriaEntry(OperationKey.STARTS_WITH, s));
|
queryCriteria.add(new CriteriaEntry(OperationKey.STARTS_WITH, s));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,7 +235,7 @@ public class Criteria {
|
|||||||
*/
|
*/
|
||||||
public Criteria endsWith(String s) {
|
public Criteria endsWith(String s) {
|
||||||
assertNoBlankInWildcardedQuery(s, false, true);
|
assertNoBlankInWildcardedQuery(s, false, true);
|
||||||
criteria.add(new CriteriaEntry(OperationKey.ENDS_WITH, s));
|
queryCriteria.add(new CriteriaEntry(OperationKey.ENDS_WITH, s));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,8 +256,8 @@ public class Criteria {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Criteria fuzzy(String s) {
|
public Criteria fuzzy(String s) {
|
||||||
criteria.add(new CriteriaEntry(OperationKey.FUZZY, s));
|
queryCriteria.add(new CriteriaEntry(OperationKey.FUZZY, s));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -262,7 +267,7 @@ public class Criteria {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public Criteria expression(String s) {
|
public Criteria expression(String s) {
|
||||||
criteria.add(new CriteriaEntry(OperationKey.EXPRESSION, s));
|
queryCriteria.add(new CriteriaEntry(OperationKey.EXPRESSION, s));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,7 +297,7 @@ public class Criteria {
|
|||||||
throw new InvalidDataAccessApiUsageException("Range [* TO *] is not allowed");
|
throw new InvalidDataAccessApiUsageException("Range [* TO *] is not allowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
criteria.add(new CriteriaEntry(OperationKey.BETWEEN, new Object[] { lowerBound, upperBound }));
|
queryCriteria.add(new CriteriaEntry(OperationKey.BETWEEN, new Object[]{lowerBound, upperBound}));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,9 +346,37 @@ public class Criteria {
|
|||||||
*/
|
*/
|
||||||
public Criteria in(Iterable<?> values) {
|
public Criteria in(Iterable<?> values) {
|
||||||
Assert.notNull(values, "Collection of 'in' values must not be null");
|
Assert.notNull(values, "Collection of 'in' values must not be null");
|
||||||
criteria.add(new CriteriaEntry(OperationKey.IN, values));
|
queryCriteria.add(new CriteriaEntry(OperationKey.IN, values));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new CriteriaEntry for {@code location WITHIN distance}
|
||||||
|
* @param location {@link GeoLocation} center coordinates
|
||||||
|
* @param distance {@link String} radius as a string (e.g. : '100km').
|
||||||
|
* Distance unit :
|
||||||
|
* either mi/miles or km can be set
|
||||||
|
*
|
||||||
|
* @return Criteria the chaind criteria with the new 'within' criteria included.
|
||||||
|
*/
|
||||||
|
public Criteria within(GeoLocation location, String distance) {
|
||||||
|
Assert.notNull(location, "Location value for near criteria must not be null");
|
||||||
|
Assert.notNull(location, "Distance value for near criteria must not be null");
|
||||||
|
filterCriteria.add(new CriteriaEntry(OperationKey.WITHIN, new Object[]{location, distance}));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates new CriteriaEntry for {@code location BBOX bounding box}
|
||||||
|
* @param bbox {@link org.springframework.data.elasticsearch.core.geo.GeoBBox} center coordinates
|
||||||
|
*
|
||||||
|
* @return Criteria the chaind criteria with the new 'bbox' criteria included.
|
||||||
|
*/
|
||||||
|
public Criteria bbox(GeoBBox bbox) {
|
||||||
|
Assert.notNull(bbox, "bbox value for bbox criteria must not be null");
|
||||||
|
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{bbox}));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private void assertNoBlankInWildcardedQuery(String searchString, boolean leadingWildcard, boolean trailingWildcard) {
|
private void assertNoBlankInWildcardedQuery(String searchString, boolean leadingWildcard, boolean trailingWildcard) {
|
||||||
if (StringUtils.contains(searchString, CRITERIA_VALUE_SEPERATOR)) {
|
if (StringUtils.contains(searchString, CRITERIA_VALUE_SEPERATOR)) {
|
||||||
@ -361,10 +394,18 @@ public class Criteria {
|
|||||||
return this.field;
|
return this.field;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<CriteriaEntry> getCriteriaEntries() {
|
public Set<CriteriaEntry> getQueryCriteriaEntries() {
|
||||||
return Collections.unmodifiableSet(this.criteria);
|
return Collections.unmodifiableSet(this.queryCriteria);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<CriteriaEntry> getFilterCriteriaEntries() {
|
||||||
|
return Collections.unmodifiableSet(this.filterCriteria);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<CriteriaEntry> getFilterCriteria() {
|
||||||
|
return filterCriteria;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Conjunction to be used with this criteria (AND | OR)
|
* Conjunction to be used with this criteria (AND | OR)
|
||||||
*
|
*
|
||||||
@ -424,7 +465,7 @@ public class Criteria {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum OperationKey {
|
public enum OperationKey {
|
||||||
EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, EXPRESSION, BETWEEN, FUZZY, IN;
|
EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, EXPRESSION, BETWEEN, FUZZY, IN, WITHIN, BBOX, NEAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class CriteriaEntry {
|
public static class CriteriaEntry {
|
||||||
|
@ -35,47 +35,47 @@ public class CriteriaQuery extends AbstractQuery {
|
|||||||
this(criteria, null);
|
this(criteria, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CriteriaQuery(Criteria criteria, Pageable pageable) {
|
public CriteriaQuery(Criteria criteria, Pageable pageable) {
|
||||||
this.criteria = criteria;
|
this.criteria = criteria;
|
||||||
this.pageable = pageable;
|
this.pageable = pageable;
|
||||||
if (pageable != null) {
|
if (pageable != null) {
|
||||||
this.addSort(pageable.getSort());
|
this.addSort(pageable.getSort());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Query fromQuery(CriteriaQuery source) {
|
public static final Query fromQuery(CriteriaQuery source) {
|
||||||
return fromQuery(source, new CriteriaQuery());
|
return fromQuery(source, new CriteriaQuery());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T extends CriteriaQuery> T fromQuery(CriteriaQuery source, T destination) {
|
public static <T extends CriteriaQuery> T fromQuery(CriteriaQuery source, T destination) {
|
||||||
if (source == null || destination == null) {
|
if (source == null || destination == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source.getCriteria() != null) {
|
if (source.getCriteria() != null) {
|
||||||
destination.addCriteria(source.getCriteria());
|
destination.addCriteria(source.getCriteria());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source.getSort() != null) {
|
if (source.getSort() != null) {
|
||||||
destination.addSort(source.getSort());
|
destination.addSort(source.getSort());
|
||||||
}
|
}
|
||||||
|
|
||||||
return destination;
|
return destination;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public final <T extends CriteriaQuery> T addCriteria(Criteria criteria) {
|
public final <T extends CriteriaQuery> T addCriteria(Criteria criteria) {
|
||||||
Assert.notNull(criteria, "Cannot add null criteria.");
|
Assert.notNull(criteria, "Cannot add null criteria.");
|
||||||
if (this.criteria == null) {
|
if (this.criteria == null) {
|
||||||
this.criteria = criteria;
|
this.criteria = criteria;
|
||||||
} else {
|
} else {
|
||||||
this.criteria.and(criteria);
|
this.criteria.and(criteria);
|
||||||
}
|
}
|
||||||
return (T) this;
|
return (T) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Criteria getCriteria() {
|
public Criteria getCriteria() {
|
||||||
return this.criteria;
|
return this.criteria;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.apache.commons.collections.CollectionUtils.addAll;
|
import static org.apache.commons.collections.CollectionUtils.addAll;
|
||||||
import static org.springframework.data.elasticsearch.core.query.Query.DEFAULT_PAGE;
|
import static org.springframework.data.elasticsearch.core.query.AbstractQuery.DEFAULT_PAGE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MoreLikeThisQuery
|
* MoreLikeThisQuery
|
||||||
|
@ -17,7 +17,6 @@ package org.springframework.data.elasticsearch.core.query;
|
|||||||
|
|
||||||
import org.elasticsearch.index.query.FilterBuilder;
|
import org.elasticsearch.index.query.FilterBuilder;
|
||||||
import org.elasticsearch.index.query.QueryBuilder;
|
import org.elasticsearch.index.query.QueryBuilder;
|
||||||
import org.elasticsearch.search.facet.FacetBuilder;
|
|
||||||
import org.elasticsearch.search.sort.SortBuilder;
|
import org.elasticsearch.search.sort.SortBuilder;
|
||||||
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||||
|
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.springframework.data.elasticsearch;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
|
import org.springframework.data.elasticsearch.core.geo.GeoLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Franck Marchand
|
||||||
|
*/
|
||||||
|
@Document(indexName = "test-geo-index", type = "test-geo-type")
|
||||||
|
public class GeoAuthor {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private GeoLocation location;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public GeoLocation getLocation() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLocation(GeoLocation location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
}
|
@ -25,11 +25,13 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.PageImpl;
|
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
|
import org.springframework.data.elasticsearch.GeoAuthor;
|
||||||
import org.springframework.data.elasticsearch.SampleEntity;
|
import org.springframework.data.elasticsearch.SampleEntity;
|
||||||
import org.springframework.data.elasticsearch.SampleMappingEntity;
|
import org.springframework.data.elasticsearch.SampleMappingEntity;
|
||||||
|
import org.springframework.data.elasticsearch.core.geo.GeoBBox;
|
||||||
|
import org.springframework.data.elasticsearch.core.geo.GeoLocation;
|
||||||
import org.springframework.data.elasticsearch.core.query.*;
|
import org.springframework.data.elasticsearch.core.query.*;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
@ -42,12 +44,14 @@ import static org.elasticsearch.index.query.FilterBuilders.boolFilter;
|
|||||||
import static org.elasticsearch.index.query.FilterBuilders.termFilter;
|
import static org.elasticsearch.index.query.FilterBuilders.termFilter;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.fieldQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.fieldQuery;
|
||||||
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Rizwan Idrees
|
* @author Rizwan Idrees
|
||||||
* @author Mohsin Husen
|
* @author Mohsin Husen
|
||||||
|
* @author Franck Marchand
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
|
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
|
||||||
@ -56,12 +60,18 @@ public class ElasticsearchTemplateTests {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ElasticsearchTemplate elasticsearchTemplate;
|
private ElasticsearchTemplate elasticsearchTemplate;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() {
|
public void before(){
|
||||||
elasticsearchTemplate.deleteIndex(SampleEntity.class);
|
elasticsearchTemplate.deleteIndex(SampleEntity.class);
|
||||||
elasticsearchTemplate.createIndex(SampleEntity.class);
|
elasticsearchTemplate.createIndex(SampleEntity.class);
|
||||||
elasticsearchTemplate.refresh(SampleEntity.class, true);
|
elasticsearchTemplate.refresh(SampleEntity.class, true);
|
||||||
}
|
|
||||||
|
elasticsearchTemplate.deleteIndex(GeoAuthor.class);
|
||||||
|
elasticsearchTemplate.createIndex(GeoAuthor.class);
|
||||||
|
elasticsearchTemplate.refresh(GeoAuthor.class, true);
|
||||||
|
|
||||||
|
elasticsearchTemplate.putMapping(GeoAuthor.class);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldReturnCountForGivenSearchQuery() {
|
public void shouldReturnCountForGivenSearchQuery() {
|
||||||
@ -716,4 +726,85 @@ public class ElasticsearchTemplateTests {
|
|||||||
assertThat(elasticsearchTemplate.indexExists(clazz), is(false));
|
assertThat(elasticsearchTemplate.indexExists(clazz), is(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldPutMappingForGivenEntityWithGeoLocation()throws Exception{
|
||||||
|
//given
|
||||||
|
Class entity = GeoAuthor.class;
|
||||||
|
elasticsearchTemplate.createIndex(entity);
|
||||||
|
//when
|
||||||
|
assertThat(elasticsearchTemplate.putMapping(entity) , is(true)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldReturnListForGivenCriteriaWithGeoLocation(){
|
||||||
|
//given
|
||||||
|
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
|
||||||
|
//first document
|
||||||
|
String documentId = randomNumeric(5);
|
||||||
|
GeoAuthor geoAuthor1 = new GeoAuthor();
|
||||||
|
geoAuthor1.setId(documentId);
|
||||||
|
geoAuthor1.setName("Franck Marchand");
|
||||||
|
geoAuthor1.setLocation(new GeoLocation(45.7806d, 3.0875d)); // Clermont-Ferrand
|
||||||
|
|
||||||
|
IndexQuery indexQuery1 = new IndexQuery();
|
||||||
|
indexQuery1.setId(documentId);
|
||||||
|
indexQuery1.setObject(geoAuthor1);
|
||||||
|
indexQueries.add(indexQuery1);
|
||||||
|
|
||||||
|
//second document
|
||||||
|
String documentId2 = randomNumeric(5);
|
||||||
|
GeoAuthor geoAuthor2 = new GeoAuthor();
|
||||||
|
geoAuthor2.setId(documentId2);
|
||||||
|
geoAuthor2.setName("Mohsin Husen");
|
||||||
|
geoAuthor2.setLocation(new GeoLocation(51.5171d, 0.1062d)); // London
|
||||||
|
|
||||||
|
IndexQuery indexQuery2 = new IndexQuery();
|
||||||
|
indexQuery2.setId(documentId2);
|
||||||
|
indexQuery2.setObject(geoAuthor2);
|
||||||
|
|
||||||
|
indexQueries.add(indexQuery2);
|
||||||
|
|
||||||
|
//third document
|
||||||
|
String documentId3 = randomNumeric(5);
|
||||||
|
GeoAuthor geoAuthor3 = new GeoAuthor();
|
||||||
|
geoAuthor3.setId(documentId3);
|
||||||
|
geoAuthor3.setName("Rizwan Idrees");
|
||||||
|
geoAuthor3.setLocation(new GeoLocation(51.5171d, 0.1062d)); // London
|
||||||
|
|
||||||
|
IndexQuery indexQuery3 = new IndexQuery();
|
||||||
|
indexQuery3.setId(documentId3);
|
||||||
|
indexQuery3.setObject(geoAuthor3);
|
||||||
|
|
||||||
|
indexQueries.add(indexQuery3);
|
||||||
|
//when
|
||||||
|
elasticsearchTemplate.bulkIndex(indexQueries);
|
||||||
|
elasticsearchTemplate.refresh(GeoAuthor.class, true);
|
||||||
|
//when
|
||||||
|
CriteriaQuery geoLocationCriteriaQuery = new CriteriaQuery(
|
||||||
|
new Criteria("location").within(new GeoLocation(45.7806d, 3.0875d), "20km"));
|
||||||
|
|
||||||
|
|
||||||
|
List<GeoAuthor> geoAuthorsForGeoCriteria = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery,GeoAuthor.class);
|
||||||
|
//then
|
||||||
|
assertThat(geoAuthorsForGeoCriteria.size(),is(1));
|
||||||
|
assertEquals("Franck Marchand", geoAuthorsForGeoCriteria.get(0).getName());
|
||||||
|
|
||||||
|
// query/filter geo distance mixed query
|
||||||
|
CriteriaQuery geoLocationCriteriaQuery2 = new CriteriaQuery(
|
||||||
|
new Criteria("name").is("Mohsin Husen").and("location").within(new GeoLocation(51.5171d, 0.1062d), "20km"));
|
||||||
|
List<GeoAuthor> geoAuthorsForGeoCriteria2 = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery2,GeoAuthor.class);
|
||||||
|
|
||||||
|
assertThat(geoAuthorsForGeoCriteria2.size(),is(1));
|
||||||
|
assertEquals("Mohsin Husen", geoAuthorsForGeoCriteria2.get(0).getName());
|
||||||
|
|
||||||
|
// bbox query
|
||||||
|
CriteriaQuery geoLocationCriteriaQuery3 = new CriteriaQuery(
|
||||||
|
new Criteria("location").bbox(
|
||||||
|
new GeoBBox(new GeoLocation(53.5171d, 0),
|
||||||
|
new GeoLocation(49.5171d, 0.2062d))));
|
||||||
|
List<GeoAuthor> geoAuthorsForGeoCriteria3 = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery3,GeoAuthor.class);
|
||||||
|
|
||||||
|
assertThat(geoAuthorsForGeoCriteria3.size(),is(2));
|
||||||
|
assertThat(geoAuthorsForGeoCriteria3, containsInAnyOrder(hasProperty("name", equalTo("Mohsin Husen")), hasProperty("name",equalTo("Rizwan Idrees"))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,10 @@
|
|||||||
xsi:schemaLocation="http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch.xsd
|
xsi:schemaLocation="http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch.xsd
|
||||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||||
|
|
||||||
<elasticsearch:node-client id="client" local="true"
|
<!--<elasticsearch:node-client id="client" local="true" cluster-name="testCluster" http-enabled="false" />-->
|
||||||
cluster-name="testCluster" http-enabled="false" />
|
|
||||||
|
<elasticsearch:transport-client id="client" cluster-name="elasticsearch" cluster-nodes="127.0.1.1:9300" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</beans>
|
</beans>
|
Loading…
x
Reference in New Issue
Block a user