From 5a499315e858980830fba6b414f244a06b3b3a40 Mon Sep 17 00:00:00 2001 From: Artur Konczak Date: Mon, 24 Jun 2013 12:55:52 +0100 Subject: [PATCH] DATAES-12 added support for GeoPoint --- .../GeoPointField.java} | 19 +- .../core/CriteriaFilterProcessor.java | 104 ++- .../core/ElasticsearchOperations.java | 10 + .../core/ElasticsearchTemplate.java | 5 + .../elasticsearch/core/MappingBuilder.java | 19 +- .../geo/{GeoBBox.java => GeoEnvelope.java} | 22 +- .../geo/{GeoLocation.java => GeoPoint.java} | 25 +- .../elasticsearch/core/query/Criteria.java | 769 ++++++++++-------- .../data/elasticsearch/ArticleBuilder.java | 47 -- .../core/ElasticsearchTemplateTests.java | 94 +-- .../facet/ArticleEntity.java} | 8 +- .../core/facet/ArticleEntityBuilder.java | 47 ++ .../ElasticsearchTemplateFacetTests.java | 50 +- .../core/geo/AuthorMarkerAnnotatedEntity.java | 77 ++ .../AuthorMarkerAnnotatedEntityBuilder.java | 53 ++ .../geo/AuthorMarkerEntity.java} | 21 +- .../core/geo/AuthorMarkerEntityBuilder.java | 48 ++ .../geo/ElasticsearchTemplateGeoTests.java | 236 ++++++ src/test/resources/infrastructure.xml | 6 +- 19 files changed, 1038 insertions(+), 622 deletions(-) rename src/main/java/org/springframework/data/elasticsearch/{core/geo/GeoPolygon.java => annotations/GeoPointField.java} (59%) rename src/main/java/org/springframework/data/elasticsearch/core/geo/{GeoBBox.java => GeoEnvelope.java} (67%) rename src/main/java/org/springframework/data/elasticsearch/core/geo/{GeoLocation.java => GeoPoint.java} (70%) delete mode 100644 src/test/java/org/springframework/data/elasticsearch/ArticleBuilder.java rename src/test/java/org/springframework/data/elasticsearch/{Article.java => core/facet/ArticleEntity.java} (92%) create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/facet/ArticleEntityBuilder.java rename src/test/java/org/springframework/data/elasticsearch/core/{ => facet}/ElasticsearchTemplateFacetTests.java (86%) create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerAnnotatedEntity.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerAnnotatedEntityBuilder.java rename src/test/java/org/springframework/data/elasticsearch/{GeoAuthor.java => core/geo/AuthorMarkerEntity.java} (68%) create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerEntityBuilder.java create mode 100644 src/test/java/org/springframework/data/elasticsearch/core/geo/ElasticsearchTemplateGeoTests.java diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoPolygon.java b/src/main/java/org/springframework/data/elasticsearch/annotations/GeoPointField.java similarity index 59% rename from src/main/java/org/springframework/data/elasticsearch/core/geo/GeoPolygon.java rename to src/main/java/org/springframework/data/elasticsearch/annotations/GeoPointField.java index 46ae5d862..bdb8025bb 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoPolygon.java +++ b/src/main/java/org/springframework/data/elasticsearch/annotations/GeoPointField.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -13,19 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.elasticsearch.core.geo; +package org.springframework.data.elasticsearch.annotations; -import java.util.List; +import java.lang.annotation.*; /** - * Geo polygon used for #{@link org.springframework.data.elasticsearch.core.query.Criteria}. - * - * @author Franck Marchand + * @author Artur Konczak */ -public class GeoPolygon { - private List points; +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Documented +public @interface GeoPointField { - public GeoPolygon(List points) { - this.points = points; - } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/CriteriaFilterProcessor.java b/src/main/java/org/springframework/data/elasticsearch/core/CriteriaFilterProcessor.java index 381a4273b..0d2cdc9e7 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/CriteriaFilterProcessor.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/CriteriaFilterProcessor.java @@ -16,8 +16,8 @@ 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.geo.GeoEnvelope; +import org.springframework.data.elasticsearch.core.geo.GeoPoint; import org.springframework.data.elasticsearch.core.query.Criteria; import org.springframework.util.Assert; @@ -46,25 +46,25 @@ class CriteriaFilterProcessor { while (chainIterator.hasNext()) { FilterBuilder fb = null; Criteria chainedCriteria = chainIterator.next(); - if(chainedCriteria.isOr()){ - fb = orFilter(createFilterFragmentForCriteria(chainedCriteria).toArray(new FilterBuilder[]{ })); + if (chainedCriteria.isOr()) { + fb = orFilter(createFilterFragmentForCriteria(chainedCriteria).toArray(new FilterBuilder[]{})); fbList.add(fb); - }else if(chainedCriteria.isNegating()){ + } else if (chainedCriteria.isNegating()) { List negationFilters = buildNegationFilter(criteria.getField().getName(), criteria.getFilterCriteriaEntries().iterator()); - if(!negationFilters.isEmpty()) { + if (!negationFilters.isEmpty()) { fbList.addAll(negationFilters); } - }else { + } else { fbList.addAll(createFilterFragmentForCriteria(chainedCriteria)); } } - if(!fbList.isEmpty()) { - if(fbList.size() == 1) { - filter =fbList.get(0); + if (!fbList.isEmpty()) { + if (fbList.size() == 1) { + filter = fbList.get(0); } else { - filter = andFilter(fbList.toArray(new FilterBuilder[]{ })); + filter = andFilter(fbList.toArray(new FilterBuilder[]{})); } } @@ -77,10 +77,10 @@ class CriteriaFilterProcessor { List filterList = new LinkedList(); String fieldName = chainedCriteria.getField().getName(); - Assert.notNull(fieldName,"Unknown field"); + Assert.notNull(fieldName, "Unknown field"); FilterBuilder filter = null; - while (it.hasNext()){ + while (it.hasNext()) { Criteria.CriteriaEntry entry = it.next(); filter = processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName); filterList.add(filter); @@ -96,36 +96,53 @@ class CriteriaFilterProcessor { } FilterBuilder filter = null; - switch (key){ - case WITHIN: { + 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[0] instanceof GeoPoint || valArray[0] instanceof String, "First element of a geo distance filter must be a GeoLocation or String"); 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]; + String dist = (String) valArray[1]; + if (valArray[0] instanceof GeoPoint) { + GeoPoint loc = (GeoPoint) valArray[0]; + ((GeoDistanceFilterBuilder) filter).lat(loc.getLat()).lon(loc.getLon()).distance(dist); + } else { + String loc = (String) valArray[0]; + if (loc.contains(",")) { + String c[] = loc.split(","); + ((GeoDistanceFilterBuilder) filter).lat(Double.parseDouble(c[0])).lon(Double.parseDouble(c[1])).distance(dist); + } else { + ((GeoDistanceFilterBuilder) filter).geohash(loc).distance(dist); + } + + } - ((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."); + Assert.isTrue(value instanceof Object[], "Value of a bbox filter should be an array of one or 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()); + if (valArray.length == 1) { + //GeoEnvelop + oneParameterBBox((GeoBoundingBoxFilterBuilder) filter, valArray[0]); + } else if (valArray.length == 2) { + //2x GeoPoint + //2x String + twoParameterBBox((GeoBoundingBoxFilterBuilder) filter, valArray); + } else { + //error + Assert.isTrue(false, "Geo distance filter takes a 1-elements array(GeoEnvelop) or 2-elements array(GeoPoints or Strings(geohash))."); + } break; } @@ -134,12 +151,43 @@ class CriteriaFilterProcessor { return filter; } - private List buildNegationFilter(String fieldName, Iterator it){ + private void oneParameterBBox(GeoBoundingBoxFilterBuilder filter, Object value) { + Assert.isTrue(value instanceof GeoEnvelope, "single-element of a geo bbox filter must be type of GeoEnvelop"); + GeoEnvelope geoBBox = (GeoEnvelope) value; + filter.topLeft(geoBBox.getTopLeft().getLat(), geoBBox.getTopLeft().getLon()); + filter.bottomRight(geoBBox.getBottomRight().getLat(), geoBBox.getBottomRight().getLon()); + } + + private static boolean isType(Object[] array, Class clazz) { + for (Object o : array) { + if (!clazz.isInstance(o)) { + return false; + } + } + return true; + } + + private void twoParameterBBox(GeoBoundingBoxFilterBuilder filter, Object[] values) { + Assert.isTrue(isType(values, GeoPoint.class) || isType(values, String.class), " both elements of geo bbox filter must be type of GeoPoint or String(geohash)"); + if (values[0] instanceof GeoPoint) { + GeoPoint topLeft = (GeoPoint) values[0]; + GeoPoint bottomRight = (GeoPoint) values[1]; + filter.topLeft(topLeft.getLat(), topLeft.getLon()); + filter.bottomRight(bottomRight.getLat(), bottomRight.getLon()); + } else { + String topLeft = (String) values[0]; + String bottomRight = (String) values[1]; + filter.topLeft(topLeft); + filter.bottomRight(bottomRight); + } + } + + private List buildNegationFilter(String fieldName, Iterator it) { List notFilterList = new LinkedList(); - while (it.hasNext()){ + while (it.hasNext()) { Criteria.CriteriaEntry criteriaEntry = it.next(); - FilterBuilder notFilter = notFilter(processCriteriaEntry(criteriaEntry.getKey(), criteriaEntry.getValue(), fieldName)); + FilterBuilder notFilter = notFilter(processCriteriaEntry(criteriaEntry.getKey(), criteriaEntry.getValue(), fieldName)); notFilterList.add(notFilter); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchOperations.java b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchOperations.java index e8b0a0fed..4db37b176 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchOperations.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchOperations.java @@ -133,6 +133,16 @@ public interface ElasticsearchOperations { */ List queryForList(StringQuery query, Class clazz); + /** + * Execute the search query against elasticsearch and return result as {@link List} + * + * @param query + * @param clazz + * @param + * @return + */ + List queryForList(SearchQuery query, Class clazz); + /** * Execute the query against elasticsearch and return ids * diff --git a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java index 0f2453b55..4d6bb04eb 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplate.java @@ -170,6 +170,11 @@ public class ElasticsearchTemplate implements ElasticsearchOperations { return queryForPage(query, clazz).getContent(); } + @Override + public List queryForList(SearchQuery query, Class clazz) { + return queryForPage(query, clazz).getContent(); + } + @Override public List queryForIds(SearchQuery query) { SearchRequestBuilder request = prepareSearch(query).setQuery(query.getQuery()).setNoFields(); diff --git a/src/main/java/org/springframework/data/elasticsearch/core/MappingBuilder.java b/src/main/java/org/springframework/data/elasticsearch/core/MappingBuilder.java index 7cb1f6fc5..cc6de328f 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/MappingBuilder.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/MappingBuilder.java @@ -18,7 +18,7 @@ package org.springframework.data.elasticsearch.core; import org.elasticsearch.common.xcontent.XContentBuilder; import org.springframework.data.elasticsearch.annotations.*; import org.springframework.data.elasticsearch.core.facet.FacetRequest; -import org.springframework.data.elasticsearch.core.geo.GeoLocation; +import org.springframework.data.elasticsearch.core.geo.GeoPoint; import org.springframework.data.mapping.model.SimpleTypeHolder; import org.springframework.data.util.ClassTypeInformation; import org.springframework.data.util.TypeInformation; @@ -48,6 +48,7 @@ class MappingBuilder { public static final String INDEX_VALUE_NOT_ANALYZED = "not_analyzed"; public static final String TYPE_VALUE_STRING = "string"; public static final String TYPE_VALUE_OBJECT = "object"; + public static final String TYPE_VALUE_GEO_POINT = "geo_point"; private static SimpleTypeHolder SIMPLE_TYPE_HOLDER = new SimpleTypeHolder(); @@ -73,12 +74,14 @@ class MappingBuilder { mapEntity(xContentBuilder, field.getType(), false, EMPTY, field.getName()); } - if(field.getType() == GeoLocation.class) { - applyGeoLocationFieldMapping(xContentBuilder, field); - } - Field singleField = field.getAnnotation(Field.class); MultiField multiField = field.getAnnotation(MultiField.class); + GeoPointField geoPoint = field.getAnnotation(GeoPointField.class); + + if (field.getType() == GeoPoint.class || geoPoint != null) { + applyGeoPointFieldMapping(xContentBuilder, field); + } + if (isRootObject && singleField != null && isIdField(field, idFieldName)) { applyDefaultIdFieldMapping(xContentBuilder, field); } else if (multiField != null) { @@ -94,10 +97,10 @@ class MappingBuilder { } - private static void applyGeoLocationFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field) throws IOException { + private static void applyGeoPointFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field) throws IOException { xContentBuilder.startObject(field.getName()); - xContentBuilder.field("type", "geo_point") - .endObject(); + xContentBuilder.field(FIELD_TYPE, TYPE_VALUE_GEO_POINT) + .endObject(); } private static void applyDefaultIdFieldMapping(XContentBuilder xContentBuilder, java.lang.reflect.Field field) diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoBBox.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoEnvelope.java similarity index 67% rename from src/main/java/org/springframework/data/elasticsearch/core/geo/GeoBBox.java rename to src/main/java/org/springframework/data/elasticsearch/core/geo/GeoEnvelope.java index 817398aba..16c00f248 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoBBox.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoEnvelope.java @@ -15,35 +15,27 @@ */ 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 class GeoEnvelope { - public GeoBBox(GeoLocation topLeft, GeoLocation bottomRight) { + private GeoPoint topLeft; + private GeoPoint bottomRight; + + public GeoEnvelope(GeoPoint topLeft, GeoPoint bottomRight) { this.topLeft = topLeft; this.bottomRight = bottomRight; } - public GeoLocation getTopLeft() { + public GeoPoint getTopLeft() { return topLeft; } - public void setTopLeft(GeoLocation topLeft) { - this.topLeft = topLeft; - } - - public GeoLocation getBottomRight() { + public GeoPoint getBottomRight() { return bottomRight; } - public void setBottomRight(GeoLocation bottomRight) { - this.bottomRight = bottomRight; - } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoLocation.java b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoPoint.java similarity index 70% rename from src/main/java/org/springframework/data/elasticsearch/core/geo/GeoLocation.java rename to src/main/java/org/springframework/data/elasticsearch/core/geo/GeoPoint.java index 33a4267f8..75eae5ce1 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoLocation.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/geo/GeoPoint.java @@ -20,24 +20,16 @@ package org.springframework.data.elasticsearch.core.geo; * * @author Franck Marchand */ -public class GeoLocation { +public class GeoPoint { + private double lat; private double lon; - public GeoLocation lat(double lat) { - setLat(lat); - return this; + private GeoPoint() { + //required by mapper to instantiate object } - public GeoLocation lon(double lon) { - setLon(lon); - return this; - } - - public GeoLocation() { - } - - public GeoLocation(double latitude, double longitude) { + public GeoPoint(double latitude, double longitude) { this.lat = latitude; this.lon = longitude; } @@ -46,15 +38,8 @@ public class GeoLocation { return lat; } - public void setLat(double lat) { - this.lat = lat; - } - public double getLon() { return lon; } - public void setLon(double lon) { - this.lon = lon; - } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/Criteria.java b/src/main/java/org/springframework/data/elasticsearch/core/query/Criteria.java index 7acc77b4e..42bc08712 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/Criteria.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/query/Criteria.java @@ -25,341 +25,341 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.elasticsearch.core.geo.GeoBBox; -import org.springframework.data.elasticsearch.core.geo.GeoLocation; +import org.springframework.data.elasticsearch.core.geo.GeoEnvelope; +import org.springframework.data.elasticsearch.core.geo.GeoPoint; import org.springframework.util.Assert; /** * Criteria is the central class when constructing queries. It follows more or less a fluent API style, which allows to * easily chain together multiple criteria. - * + * * @author Rizwan Idrees * @author Mohsin Husen * @author Franck Marchand */ public class Criteria { - public static final String WILDCARD = "*"; - public static final String CRITERIA_VALUE_SEPERATOR = " "; + public static final String WILDCARD = "*"; + public static final String CRITERIA_VALUE_SEPERATOR = " "; - private static final String OR_OPERATOR = " OR "; - private static final String AND_OPERATOR = " AND "; + private static final String OR_OPERATOR = " OR "; + private static final String AND_OPERATOR = " AND "; - private Field field; - private float boost = Float.NaN; - private boolean negating = false; + private Field field; + private float boost = Float.NaN; + private boolean negating = false; - private List criteriaChain = new ArrayList(1); + private List criteriaChain = new ArrayList(1); - private Set queryCriteria = new LinkedHashSet(); + private Set queryCriteria = new LinkedHashSet(); private Set filterCriteria = new LinkedHashSet(); - public Criteria() { - } + public Criteria() { + } - /** - * Creates a new CriterSimpleFieldia for the Filed with provided name - * - * @param fieldname - */ - public Criteria(String fieldname) { - this(new SimpleField(fieldname)); - } + /** + * Creates a new CriterSimpleFieldia for the Filed with provided name + * + * @param fieldname + */ + public Criteria(String fieldname) { + this(new SimpleField(fieldname)); + } - /** - * Creates a new Criteria for the given field - * - * @param field - */ - public Criteria(Field field) { - Assert.notNull(field, "Field for criteria must not be null"); - Assert.hasText(field.getName(), "Field.name for criteria must not be null/empty"); + /** + * Creates a new Criteria for the given field + * + * @param field + */ + public Criteria(Field field) { + Assert.notNull(field, "Field for criteria must not be null"); + Assert.hasText(field.getName(), "Field.name for criteria must not be null/empty"); - this.criteriaChain.add(this); - this.field = field; - } + this.criteriaChain.add(this); + this.field = field; + } - protected Criteria(List criteriaChain, String fieldname) { - this(criteriaChain, new SimpleField(fieldname)); - } + protected Criteria(List criteriaChain, String fieldname) { + this(criteriaChain, new SimpleField(fieldname)); + } - protected Criteria(List criteriaChain, Field field) { - Assert.notNull(criteriaChain, "CriteriaChain must not be null"); - Assert.notNull(field, "Field for criteria must not be null"); - Assert.hasText(field.getName(), "Field.name for criteria must not be null/empty"); + protected Criteria(List criteriaChain, Field field) { + Assert.notNull(criteriaChain, "CriteriaChain must not be null"); + Assert.notNull(field, "Field for criteria must not be null"); + Assert.hasText(field.getName(), "Field.name for criteria must not be null/empty"); - this.criteriaChain.addAll(criteriaChain); - this.criteriaChain.add(this); - this.field = field; - } + this.criteriaChain.addAll(criteriaChain); + this.criteriaChain.add(this); + this.field = field; + } - /** - * Static factory method to create a new Criteria for field with given name - * - * @param field - * @return - */ - public static Criteria where(String field) { - return where(new SimpleField(field)); - } + /** + * Static factory method to create a new Criteria for field with given name + * + * @param field + * @return + */ + public static Criteria where(String field) { + return where(new SimpleField(field)); + } - /** - * Static factory method to create a new Criteria for provided field - * - * @param field - * @return - */ - public static Criteria where(Field field) { - return new Criteria(field); - } + /** + * Static factory method to create a new Criteria for provided field + * + * @param field + * @return + */ + public static Criteria where(Field field) { + return new Criteria(field); + } - /** - * Chain using {@code AND} - * - * @param field - * @return - */ - public Criteria and(Field field) { - return new Criteria(this.criteriaChain, field); - } + /** + * Chain using {@code AND} + * + * @param field + * @return + */ + public Criteria and(Field field) { + return new Criteria(this.criteriaChain, field); + } - /** - * Chain using {@code AND} - * - * @param fieldName - * @return - */ - public Criteria and(String fieldName) { - return new Criteria(this.criteriaChain, fieldName); - } + /** + * Chain using {@code AND} + * + * @param fieldName + * @return + */ + public Criteria and(String fieldName) { + return new Criteria(this.criteriaChain, fieldName); + } - /** - * Chain using {@code AND} - * - * @param criteria - * @return - */ - public Criteria and(Criteria criteria) { - this.criteriaChain.add(criteria); - return this; - } + /** + * Chain using {@code AND} + * + * @param criteria + * @return + */ + public Criteria and(Criteria criteria) { + this.criteriaChain.add(criteria); + return this; + } - /** - * Chain using {@code AND} - * - * @param criterias - * @return - */ - public Criteria and(Criteria... criterias) { - this.criteriaChain.addAll(Arrays.asList(criterias)); - return this; - } + /** + * Chain using {@code AND} + * + * @param criterias + * @return + */ + public Criteria and(Criteria... criterias) { + this.criteriaChain.addAll(Arrays.asList(criterias)); + return this; + } - /** - * Chain using {@code OR} - * - * @param field - * @return - */ - public Criteria or(Field field) { - return new OrCriteria(this.criteriaChain, field); - } + /** + * Chain using {@code OR} + * + * @param field + * @return + */ + public Criteria or(Field field) { + return new OrCriteria(this.criteriaChain, field); + } - /** - * Chain using {@code OR} - * - * @param criteria - * @return - */ - public Criteria or(Criteria criteria) { - Assert.notNull(criteria, "Cannot chain 'null' criteria."); + /** + * Chain using {@code OR} + * + * @param criteria + * @return + */ + public Criteria or(Criteria criteria) { + Assert.notNull(criteria, "Cannot chain 'null' criteria."); - Criteria orConnectedCritiera = new OrCriteria(this.criteriaChain, criteria.getField()); - orConnectedCritiera.queryCriteria.addAll(criteria.queryCriteria); - return orConnectedCritiera; - } + Criteria orConnectedCritiera = new OrCriteria(this.criteriaChain, criteria.getField()); + orConnectedCritiera.queryCriteria.addAll(criteria.queryCriteria); + return orConnectedCritiera; + } - /** - * Chain using {@code OR} - * - * @param fieldName - * @return - */ - public Criteria or(String fieldName) { - return or(new SimpleField(fieldName)); - } + /** + * Chain using {@code OR} + * + * @param fieldName + * @return + */ + public Criteria or(String fieldName) { + return or(new SimpleField(fieldName)); + } - /** - * Crates new CriteriaEntry without any wildcards - * - * @param o - * @return - */ - public Criteria is(Object o) { - queryCriteria.add(new CriteriaEntry(OperationKey.EQUALS, o)); - return this; - } + /** + * Crates new CriteriaEntry without any wildcards + * + * @param o + * @return + */ + public Criteria is(Object o) { + queryCriteria.add(new CriteriaEntry(OperationKey.EQUALS, o)); + return this; + } - /** - * Crates new CriteriaEntry with leading and trailing wildcards
- * NOTE: mind your schema as leading wildcards may not be supported and/or execution might be slow. - * - * @param s - * @return - */ - public Criteria contains(String s) { - assertNoBlankInWildcardedQuery(s, true, true); - queryCriteria.add(new CriteriaEntry(OperationKey.CONTAINS, s)); - return this; - } + /** + * Crates new CriteriaEntry with leading and trailing wildcards
+ * NOTE: mind your schema as leading wildcards may not be supported and/or execution might be slow. + * + * @param s + * @return + */ + public Criteria contains(String s) { + assertNoBlankInWildcardedQuery(s, true, true); + queryCriteria.add(new CriteriaEntry(OperationKey.CONTAINS, s)); + return this; + } - /** - * Crates new CriteriaEntry with trailing wildcard - * - * @param s - * @return - */ - public Criteria startsWith(String s) { - assertNoBlankInWildcardedQuery(s, true, false); - queryCriteria.add(new CriteriaEntry(OperationKey.STARTS_WITH, s)); - return this; - } + /** + * Crates new CriteriaEntry with trailing wildcard + * + * @param s + * @return + */ + public Criteria startsWith(String s) { + assertNoBlankInWildcardedQuery(s, true, false); + queryCriteria.add(new CriteriaEntry(OperationKey.STARTS_WITH, s)); + return this; + } - /** - * Crates new CriteriaEntry with leading wildcard
- * NOTE: mind your schema and execution times as leading wildcards may not be supported. - * - * @param s - * @return - */ - public Criteria endsWith(String s) { - assertNoBlankInWildcardedQuery(s, false, true); - queryCriteria.add(new CriteriaEntry(OperationKey.ENDS_WITH, s)); - return this; - } + /** + * Crates new CriteriaEntry with leading wildcard
+ * NOTE: mind your schema and execution times as leading wildcards may not be supported. + * + * @param s + * @return + */ + public Criteria endsWith(String s) { + assertNoBlankInWildcardedQuery(s, false, true); + queryCriteria.add(new CriteriaEntry(OperationKey.ENDS_WITH, s)); + return this; + } - /** - * Crates new CriteriaEntry with trailing - - * - * @return - */ - public Criteria not() { - this.negating = true; - return this; - } + /** + * Crates new CriteriaEntry with trailing - + * + * @return + */ + public Criteria not() { + this.negating = true; + return this; + } - /** - * Crates new CriteriaEntry with trailing ~ - * - * @param s - * @return - */ - public Criteria fuzzy(String s) { + /** + * Crates new CriteriaEntry with trailing ~ + * + * @param s + * @return + */ + public Criteria fuzzy(String s) { queryCriteria.add(new CriteriaEntry(OperationKey.FUZZY, s)); return this; - } + } - /** - * Crates new CriteriaEntry allowing native elasticsearch expressions - * - * @param s - * @return - */ - public Criteria expression(String s) { - queryCriteria.add(new CriteriaEntry(OperationKey.EXPRESSION, s)); - return this; - } + /** + * Crates new CriteriaEntry allowing native elasticsearch expressions + * + * @param s + * @return + */ + public Criteria expression(String s) { + queryCriteria.add(new CriteriaEntry(OperationKey.EXPRESSION, s)); + return this; + } - /** - * Boost positive hit with given factor. eg. ^2.3 - * - * @param boost - * @return - */ - public Criteria boost(float boost) { - if (boost < 0) { - throw new InvalidDataAccessApiUsageException("Boost must not be negative."); - } - this.boost = boost; - return this; - } + /** + * Boost positive hit with given factor. eg. ^2.3 + * + * @param boost + * @return + */ + public Criteria boost(float boost) { + if (boost < 0) { + throw new InvalidDataAccessApiUsageException("Boost must not be negative."); + } + this.boost = boost; + return this; + } - /** - * Crates new CriteriaEntry for {@code RANGE [lowerBound TO upperBound]} - * - * @param lowerBound - * @param upperBound - * @return - */ - public Criteria between(Object lowerBound, Object upperBound) { - if (lowerBound == null && upperBound == null) { - throw new InvalidDataAccessApiUsageException("Range [* TO *] is not allowed"); - } + /** + * Crates new CriteriaEntry for {@code RANGE [lowerBound TO upperBound]} + * + * @param lowerBound + * @param upperBound + * @return + */ + public Criteria between(Object lowerBound, Object upperBound) { + if (lowerBound == null && upperBound == null) { + throw new InvalidDataAccessApiUsageException("Range [* TO *] is not allowed"); + } - queryCriteria.add(new CriteriaEntry(OperationKey.BETWEEN, new Object[]{lowerBound, upperBound})); - return this; - } + queryCriteria.add(new CriteriaEntry(OperationKey.BETWEEN, new Object[]{lowerBound, upperBound})); + return this; + } - /** - * Crates new CriteriaEntry for {@code RANGE [* TO upperBound]} - * - * @param upperBound - * @return - */ - public Criteria lessThanEqual(Object upperBound) { - between(null, upperBound); - return this; - } + /** + * Crates new CriteriaEntry for {@code RANGE [* TO upperBound]} + * + * @param upperBound + * @return + */ + public Criteria lessThanEqual(Object upperBound) { + between(null, upperBound); + return this; + } - /** - * Crates new CriteriaEntry for {@code RANGE [lowerBound TO *]} - * - * @param lowerBound - * @return - */ - public Criteria greaterThanEqual(Object lowerBound) { - between(lowerBound, null); - return this; - } + /** + * Crates new CriteriaEntry for {@code RANGE [lowerBound TO *]} + * + * @param lowerBound + * @return + */ + public Criteria greaterThanEqual(Object lowerBound) { + between(lowerBound, null); + return this; + } - /** - * Crates new CriteriaEntry for multiple values {@code (arg0 arg1 arg2 ...)} - * - * @param values - * @return - */ - public Criteria in(Object... values) { - if (values.length == 0 || (values.length > 1 && values[1] instanceof Collection)) { - throw new InvalidDataAccessApiUsageException("At least one element " - + (values.length > 0 ? ("of argument of type " + values[1].getClass().getName()) : "") - + " has to be present."); - } - return in(Arrays.asList(values)); - } + /** + * Crates new CriteriaEntry for multiple values {@code (arg0 arg1 arg2 ...)} + * + * @param values + * @return + */ + public Criteria in(Object... values) { + if (values.length == 0 || (values.length > 1 && values[1] instanceof Collection)) { + throw new InvalidDataAccessApiUsageException("At least one element " + + (values.length > 0 ? ("of argument of type " + values[1].getClass().getName()) : "") + + " has to be present."); + } + return in(Arrays.asList(values)); + } - /** - * Crates new CriteriaEntry for multiple values {@code (arg0 arg1 arg2 ...)} - * - * @param values the collection containing the values to match against - * @return - */ - public Criteria in(Iterable values) { - Assert.notNull(values, "Collection of 'in' values must not be null"); + /** + * Crates new CriteriaEntry for multiple values {@code (arg0 arg1 arg2 ...)} + * + * @param values the collection containing the values to match against + * @return + */ + public Criteria in(Iterable values) { + Assert.notNull(values, "Collection of 'in' values must not be null"); queryCriteria.add(new CriteriaEntry(OperationKey.IN, values)); 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 * + * @param location {@link org.springframework.data.elasticsearch.core.geo.GeoPoint} 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) { + public Criteria within(GeoPoint 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})); @@ -367,125 +367,172 @@ public class Criteria { } /** - * Creates new CriteriaEntry for {@code location BBOX bounding box} - * @param bbox {@link org.springframework.data.elasticsearch.core.geo.GeoBBox} center coordinates + * Creates new CriteriaEntry for {@code geoLocation WITHIN distance} * + * @param geoLocation {@link String} center point + * supported formats: + * lat on = > "41.2,45.1", + * geohash = > "asd9as0d" + * @param distance {@link String} radius as a string (e.g. : '100km'). + * Distance unit : + * either mi/miles or km can be set + * @return + */ + public Criteria within(String geoLocation, String distance) { + Assert.isTrue(StringUtils.isNotBlank(geoLocation), "geoLocation value must not be null"); + filterCriteria.add(new CriteriaEntry(OperationKey.WITHIN, new Object[]{geoLocation, distance})); + return this; + } + + /** + * Creates new CriteriaEntry for {@code location BBOX bounding box} + * + * @param bbox {@link org.springframework.data.elasticsearch.core.geo.GeoEnvelope} bounding box(left top corner + right bottom corner) * @return Criteria the chaind criteria with the new 'bbox' criteria included. */ - public Criteria bbox(GeoBBox bbox) { + public Criteria bbox(GeoEnvelope 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) { - if (StringUtils.contains(searchString, CRITERIA_VALUE_SEPERATOR)) { - throw new InvalidDataAccessApiUsageException("Cannot constructQuery '" + (leadingWildcard ? "*" : "") + "\"" - + searchString + "\"" + (trailingWildcard ? "*" : "") + "'. Use epxression or mulitple clauses instead."); - } - } - /** - * Field targeted by this Criteria - * - * @return - */ - public Field getField() { - return this.field; - } + /** + * Creates new CriteriaEntry for bounding box created from points + * + * @param topLeft left top corner of bounding box + * @param bottomRight right bottom corner of bounding box + * @return Criteria the chaind criteria with the new 'bbox' criteria included. + */ + public Criteria bbox(String topLeft, String bottomRight) { + Assert.isTrue(StringUtils.isNotBlank(topLeft), "topLeft point must not be empty"); + Assert.isTrue(StringUtils.isNotBlank(bottomRight), "bottomRight point must not be empty"); + filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{topLeft, bottomRight})); + return this; + } - public Set getQueryCriteriaEntries() { - return Collections.unmodifiableSet(this.queryCriteria); - } + /** + * Creates new CriteriaEntry for bounding box created from points + * + * @param topLeft left top corner of bounding box + * @param bottomRight right bottom corner of bounding box + * @return Criteria the chaind criteria with the new 'bbox' criteria included. + */ + public Criteria bbox(GeoPoint topLeft, GeoPoint bottomRight) { + Assert.notNull(topLeft, "topLeft point must not be null"); + Assert.notNull(bottomRight, "bottomRight point must not be null"); + filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{topLeft, bottomRight})); + return this; + } - public Set getFilterCriteriaEntries() { - return Collections.unmodifiableSet(this.filterCriteria); - } + private void assertNoBlankInWildcardedQuery(String searchString, boolean leadingWildcard, boolean trailingWildcard) { + if (StringUtils.contains(searchString, CRITERIA_VALUE_SEPERATOR)) { + throw new InvalidDataAccessApiUsageException("Cannot constructQuery '" + (leadingWildcard ? "*" : "") + "\"" + + searchString + "\"" + (trailingWildcard ? "*" : "") + "'. Use epxression or mulitple clauses instead."); + } + } + + /** + * Field targeted by this Criteria + * + * @return + */ + public Field getField() { + return this.field; + } + + public Set getQueryCriteriaEntries() { + return Collections.unmodifiableSet(this.queryCriteria); + } + + public Set getFilterCriteriaEntries() { + return Collections.unmodifiableSet(this.filterCriteria); + } public Set getFilterCriteria() { return filterCriteria; } - /** - * Conjunction to be used with this criteria (AND | OR) - * - * @return - */ - public String getConjunctionOperator() { - return AND_OPERATOR; - } + /** + * Conjunction to be used with this criteria (AND | OR) + * + * @return + */ + public String getConjunctionOperator() { + return AND_OPERATOR; + } - public List getCriteriaChain() { - return Collections.unmodifiableList(this.criteriaChain); - } + public List getCriteriaChain() { + return Collections.unmodifiableList(this.criteriaChain); + } - public boolean isNegating() { - return this.negating; - } + public boolean isNegating() { + return this.negating; + } - public boolean isAnd() { - return AND_OPERATOR == getConjunctionOperator(); - } + public boolean isAnd() { + return AND_OPERATOR == getConjunctionOperator(); + } - public boolean isOr() { - return OR_OPERATOR == getConjunctionOperator(); - } + public boolean isOr() { + return OR_OPERATOR == getConjunctionOperator(); + } - public float getBoost() { - return this.boost; - } + public float getBoost() { + return this.boost; + } - static class OrCriteria extends Criteria { + static class OrCriteria extends Criteria { - public OrCriteria() { - super(); - } + public OrCriteria() { + super(); + } - public OrCriteria(Field field) { - super(field); - } + public OrCriteria(Field field) { + super(field); + } - public OrCriteria(List criteriaChain, Field field) { - super(criteriaChain, field); - } + public OrCriteria(List criteriaChain, Field field) { + super(criteriaChain, field); + } - public OrCriteria(List criteriaChain, String fieldname) { - super(criteriaChain, fieldname); - } + public OrCriteria(List criteriaChain, String fieldname) { + super(criteriaChain, fieldname); + } - public OrCriteria(String fieldname) { - super(fieldname); - } + public OrCriteria(String fieldname) { + super(fieldname); + } - @Override - public String getConjunctionOperator() { - return OR_OPERATOR; - } + @Override + public String getConjunctionOperator() { + return OR_OPERATOR; + } - } + } - public enum OperationKey { - EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, EXPRESSION, BETWEEN, FUZZY, IN, WITHIN, BBOX, NEAR; - } + public enum OperationKey { + EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, EXPRESSION, BETWEEN, FUZZY, IN, WITHIN, BBOX, NEAR; + } - public static class CriteriaEntry { + public static class CriteriaEntry { - private OperationKey key; - private Object value; + private OperationKey key; + private Object value; - CriteriaEntry(OperationKey key, Object value) { - this.key = key; - this.value = value; - } + CriteriaEntry(OperationKey key, Object value) { + this.key = key; + this.value = value; + } - public OperationKey getKey() { - return key; - } + public OperationKey getKey() { + return key; + } - public Object getValue() { - return value; - } + public Object getValue() { + return value; + } - } + } } diff --git a/src/test/java/org/springframework/data/elasticsearch/ArticleBuilder.java b/src/test/java/org/springframework/data/elasticsearch/ArticleBuilder.java deleted file mode 100644 index bba9a5844..000000000 --- a/src/test/java/org/springframework/data/elasticsearch/ArticleBuilder.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.springframework.data.elasticsearch; - -import org.springframework.data.elasticsearch.core.query.IndexQuery; - -/** - * Simple type to test facets - */ -public class ArticleBuilder { - - private Article resutl; - - public ArticleBuilder(String id) { - resutl = new Article(id); - } - - public ArticleBuilder title(String title) { - resutl.setTitle(title); - return this; - } - - public ArticleBuilder addAuthor(String author) { - resutl.getAuthors().add(author); - return this; - } - - public ArticleBuilder addPublishedYear(Integer year) { - resutl.getPublishedYears().add(year); - return this; - } - - public ArticleBuilder score(int score) { - resutl.setScore(score); - return this; - } - - public Article build() { - return resutl; - } - - public IndexQuery buildIndex() { - IndexQuery indexQuery = new IndexQuery(); - indexQuery.setId(resutl.getId()); - indexQuery.setObject(resutl); - return indexQuery; - } - -} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java index bd20de851..06bc93ad1 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java @@ -27,11 +27,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; -import org.springframework.data.elasticsearch.GeoAuthor; import org.springframework.data.elasticsearch.SampleEntity; 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.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -46,7 +43,8 @@ import static org.elasticsearch.index.query.QueryBuilders.fieldQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; /** * @author Rizwan Idrees @@ -65,12 +63,6 @@ public class ElasticsearchTemplateTests { elasticsearchTemplate.deleteIndex(SampleEntity.class); elasticsearchTemplate.createIndex(SampleEntity.class); elasticsearchTemplate.refresh(SampleEntity.class, true); - - elasticsearchTemplate.deleteIndex(GeoAuthor.class); - elasticsearchTemplate.createIndex(GeoAuthor.class); - elasticsearchTemplate.refresh(GeoAuthor.class, true); - - elasticsearchTemplate.putMapping(GeoAuthor.class); } @Test @@ -725,86 +717,4 @@ public class ElasticsearchTemplateTests { // then 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 indexQueries = new ArrayList(); - //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 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 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 geoAuthorsForGeoCriteria3 = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery3,GeoAuthor.class); - - assertThat(geoAuthorsForGeoCriteria3.size(),is(2)); - assertThat(geoAuthorsForGeoCriteria3, containsInAnyOrder(hasProperty("name", equalTo("Mohsin Husen")), hasProperty("name",equalTo("Rizwan Idrees")))); - } } diff --git a/src/test/java/org/springframework/data/elasticsearch/Article.java b/src/test/java/org/springframework/data/elasticsearch/core/facet/ArticleEntity.java similarity index 92% rename from src/test/java/org/springframework/data/elasticsearch/Article.java rename to src/test/java/org/springframework/data/elasticsearch/core/facet/ArticleEntity.java index 89b46ca2b..77847b317 100644 --- a/src/test/java/org/springframework/data/elasticsearch/Article.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/facet/ArticleEntity.java @@ -1,4 +1,4 @@ -package org.springframework.data.elasticsearch; +package org.springframework.data.elasticsearch.core.facet; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.*; @@ -15,7 +15,7 @@ import static org.springframework.data.elasticsearch.annotations.FieldType.Strin * Simple type to test facets */ @Document(indexName = "articles", type = "article", shards = 1, replicas = 0, refreshInterval = "-1") -public class Article { +public class ArticleEntity { @Id private String id; @@ -36,11 +36,11 @@ public class Article { private int score; - public Article() { + private ArticleEntity(){ } - public Article(String id) { + public ArticleEntity(String id) { this.id = id; } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/facet/ArticleEntityBuilder.java b/src/test/java/org/springframework/data/elasticsearch/core/facet/ArticleEntityBuilder.java new file mode 100644 index 000000000..4b55b7328 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/facet/ArticleEntityBuilder.java @@ -0,0 +1,47 @@ +package org.springframework.data.elasticsearch.core.facet; + +import org.springframework.data.elasticsearch.core.query.IndexQuery; + +/** + * Simple type to test facets + */ +public class ArticleEntityBuilder { + + private ArticleEntity result; + + public ArticleEntityBuilder(String id) { + result = new ArticleEntity(id); + } + + public ArticleEntityBuilder title(String title) { + result.setTitle(title); + return this; + } + + public ArticleEntityBuilder addAuthor(String author) { + result.getAuthors().add(author); + return this; + } + + public ArticleEntityBuilder addPublishedYear(Integer year) { + result.getPublishedYears().add(year); + return this; + } + + public ArticleEntityBuilder score(int score) { + result.setScore(score); + return this; + } + + public ArticleEntity build() { + return result; + } + + public IndexQuery buildIndex() { + IndexQuery indexQuery = new IndexQuery(); + indexQuery.setId(result.getId()); + indexQuery.setObject(result); + return indexQuery; + } + +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateFacetTests.java b/src/test/java/org/springframework/data/elasticsearch/core/facet/ElasticsearchTemplateFacetTests.java similarity index 86% rename from src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateFacetTests.java rename to src/test/java/org/springframework/data/elasticsearch/core/facet/ElasticsearchTemplateFacetTests.java index 47c29c16d..dda6f7f80 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateFacetTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/facet/ElasticsearchTemplateFacetTests.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.elasticsearch.core; +package org.springframework.data.elasticsearch.core.facet; import org.elasticsearch.index.query.FilterBuilders; import org.elasticsearch.search.facet.FacetBuilders; @@ -21,8 +21,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.elasticsearch.Article; -import org.springframework.data.elasticsearch.ArticleBuilder; +import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; +import org.springframework.data.elasticsearch.core.FacetedPage; import org.springframework.data.elasticsearch.core.facet.request.NativeFacetRequest; import org.springframework.data.elasticsearch.core.facet.request.RangeFacetRequestBuilder; import org.springframework.data.elasticsearch.core.facet.request.TermFacetRequestBuilder; @@ -62,21 +62,21 @@ public class ElasticsearchTemplateFacetTests { @Before public void before() { - elasticsearchTemplate.deleteIndex(Article.class); - elasticsearchTemplate.createIndex(Article.class); - elasticsearchTemplate.putMapping(Article.class); - elasticsearchTemplate.refresh(Article.class, true); + elasticsearchTemplate.deleteIndex(ArticleEntity.class); + elasticsearchTemplate.createIndex(ArticleEntity.class); + elasticsearchTemplate.putMapping(ArticleEntity.class); + elasticsearchTemplate.refresh(ArticleEntity.class, true); - IndexQuery article1 = new ArticleBuilder("1").title("article four").addAuthor(RIZWAN_IDREES).addAuthor(ARTUR_KONCZAK).addAuthor(MOHSIN_HUSEN).addAuthor(JONATHAN_YAN).score(10).buildIndex(); - IndexQuery article2 = new ArticleBuilder("2").title("article three").addAuthor(RIZWAN_IDREES).addAuthor(ARTUR_KONCZAK).addAuthor(MOHSIN_HUSEN).addPublishedYear(YEAR_2000).score(20).buildIndex(); - IndexQuery article3 = new ArticleBuilder("3").title("article two").addAuthor(RIZWAN_IDREES).addAuthor(ARTUR_KONCZAK).addPublishedYear(YEAR_2001).addPublishedYear(YEAR_2000).score(30).buildIndex(); - IndexQuery article4 = new ArticleBuilder("4").title("article one").addAuthor(RIZWAN_IDREES).addPublishedYear(YEAR_2002).addPublishedYear(YEAR_2001).addPublishedYear(YEAR_2000).score(40).buildIndex(); + IndexQuery article1 = new ArticleEntityBuilder("1").title("article four").addAuthor(RIZWAN_IDREES).addAuthor(ARTUR_KONCZAK).addAuthor(MOHSIN_HUSEN).addAuthor(JONATHAN_YAN).score(10).buildIndex(); + IndexQuery article2 = new ArticleEntityBuilder("2").title("article three").addAuthor(RIZWAN_IDREES).addAuthor(ARTUR_KONCZAK).addAuthor(MOHSIN_HUSEN).addPublishedYear(YEAR_2000).score(20).buildIndex(); + IndexQuery article3 = new ArticleEntityBuilder("3").title("article two").addAuthor(RIZWAN_IDREES).addAuthor(ARTUR_KONCZAK).addPublishedYear(YEAR_2001).addPublishedYear(YEAR_2000).score(30).buildIndex(); + IndexQuery article4 = new ArticleEntityBuilder("4").title("article one").addAuthor(RIZWAN_IDREES).addPublishedYear(YEAR_2002).addPublishedYear(YEAR_2001).addPublishedYear(YEAR_2000).score(40).buildIndex(); elasticsearchTemplate.index(article1); elasticsearchTemplate.index(article2); elasticsearchTemplate.index(article3); elasticsearchTemplate.index(article4); - elasticsearchTemplate.refresh(Article.class, true); + elasticsearchTemplate.refresh(ArticleEntity.class, true); } @Test @@ -86,7 +86,7 @@ public class ElasticsearchTemplateFacetTests { String facetName = "fauthors"; SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).withFacet(new TermFacetRequestBuilder(facetName).fields("authors.untouched").build()).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(4))); @@ -117,7 +117,7 @@ public class ElasticsearchTemplateFacetTests { .withFilter(FilterBuilders.notFilter(FilterBuilders.termFilter("title", "four"))) .withFacet(new TermFacetRequestBuilder(facetName).applyQueryFilter().fields("authors.untouched").build()).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(3))); @@ -143,7 +143,7 @@ public class ElasticsearchTemplateFacetTests { .withFilter(FilterBuilders.notFilter(FilterBuilders.termFilter("title", "four"))) .withFacet(new TermFacetRequestBuilder(facetName).applyQueryFilter().fields("authors.untouched").excludeTerms(RIZWAN_IDREES, ARTUR_KONCZAK).build()).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(3))); @@ -165,7 +165,7 @@ public class ElasticsearchTemplateFacetTests { SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()) .withFacet(new TermFacetRequestBuilder(facetName).fields("authors.untouched").ascTerm().build()).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(4))); @@ -196,7 +196,7 @@ public class ElasticsearchTemplateFacetTests { SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()) .withFacet(new TermFacetRequestBuilder(facetName).fields("authors.untouched").ascCount().build()).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(4))); @@ -226,7 +226,7 @@ public class ElasticsearchTemplateFacetTests { SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()) .withFacet(new TermFacetRequestBuilder(facetName).fields("publishedYears").descCount().build()).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(4))); @@ -256,7 +256,7 @@ public class ElasticsearchTemplateFacetTests { SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()) .withFacet(new TermFacetRequestBuilder(facetName).fields("publishedYears", "authors.untouched").ascTerm().build()).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(4))); @@ -305,7 +305,7 @@ public class ElasticsearchTemplateFacetTests { .withFacet(new TermFacetRequestBuilder(stringFacetName).fields("authors.untouched").ascTerm().build()) .build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(4))); @@ -352,7 +352,7 @@ public class ElasticsearchTemplateFacetTests { SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()) .withFacet(new NativeFacetRequest(FacetBuilders.termsFacet(facetName).field("publishedYears"))).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(4))); @@ -381,7 +381,7 @@ public class ElasticsearchTemplateFacetTests { .withFilter(FilterBuilders.notFilter(FilterBuilders.termFilter("title", "four"))) .withFacet(new TermFacetRequestBuilder(facetName).applyQueryFilter().fields("authors.untouched").regex("Art.*").build()).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(3))); @@ -403,7 +403,7 @@ public class ElasticsearchTemplateFacetTests { .withFilter(FilterBuilders.notFilter(FilterBuilders.termFilter("title", "four"))) .withFacet(new TermFacetRequestBuilder(facetName).applyQueryFilter().fields("authors.untouched").allTerms().build()).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(3))); @@ -423,7 +423,7 @@ public class ElasticsearchTemplateFacetTests { .to(YEAR_2000).range(YEAR_2000, YEAR_2002).from(YEAR_2002).build() ).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(4))); @@ -460,7 +460,7 @@ public class ElasticsearchTemplateFacetTests { .to(YEAR_2000).range(YEAR_2000, YEAR_2002).from(YEAR_2002).build() ).build(); // when - FacetedPage
result = elasticsearchTemplate.queryForPage(searchQuery, Article.class); + FacetedPage result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class); // then assertThat(result.getNumberOfElements(), is(equalTo(4))); diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerAnnotatedEntity.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerAnnotatedEntity.java new file mode 100644 index 000000000..fad86fbca --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerAnnotatedEntity.java @@ -0,0 +1,77 @@ +/* + * 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 org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.Document; +import org.springframework.data.elasticsearch.annotations.GeoPointField; + +/** + * @author Franck Marchand + */ +@Document(indexName = "test-geo-index", type = "geo-annotation-point-type", indexStoreType = "memory", shards = 1, replicas = 0, refreshInterval = "-1") +public class AuthorMarkerAnnotatedEntity { + + @Id + private String id; + private String name; + + @GeoPointField + private String location; + + @GeoPointField + private double[] additionalLocation; + + private AuthorMarkerAnnotatedEntity() { + + } + + public AuthorMarkerAnnotatedEntity(String id) { + this.id = id; + } + + 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 String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public double[] getAdditionalLocation() { + return additionalLocation; + } + + public void setAdditionalLocation(double... additionalLocation) { + this.additionalLocation = additionalLocation; + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerAnnotatedEntityBuilder.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerAnnotatedEntityBuilder.java new file mode 100644 index 000000000..2912d88f5 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerAnnotatedEntityBuilder.java @@ -0,0 +1,53 @@ +/* + * 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 org.springframework.data.elasticsearch.core.query.IndexQuery; + +public class AuthorMarkerAnnotatedEntityBuilder { + + private AuthorMarkerAnnotatedEntity result; + + public AuthorMarkerAnnotatedEntityBuilder(String id) { + result = new AuthorMarkerAnnotatedEntity(id); + } + + public AuthorMarkerAnnotatedEntityBuilder name(String name) { + result.setName(name); + return this; + } + + public AuthorMarkerAnnotatedEntityBuilder location(String location) { + result.setLocation(location); + return this; + } + + public AuthorMarkerAnnotatedEntityBuilder additionalLocation(double... location) { + result.setAdditionalLocation(location); + return this; + } + + public AuthorMarkerAnnotatedEntity build() { + return result; + } + + public IndexQuery buildIndex() { + IndexQuery indexQuery = new IndexQuery(); + indexQuery.setId(result.getId()); + indexQuery.setObject(result); + return indexQuery; + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/GeoAuthor.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerEntity.java similarity index 68% rename from src/test/java/org/springframework/data/elasticsearch/GeoAuthor.java rename to src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerEntity.java index 671e7d101..007e04955 100644 --- a/src/test/java/org/springframework/data/elasticsearch/GeoAuthor.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerEntity.java @@ -13,23 +13,30 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.data.elasticsearch; +package org.springframework.data.elasticsearch.core.geo; import org.springframework.data.annotation.Id; import org.springframework.data.elasticsearch.annotations.Document; -import org.springframework.data.elasticsearch.core.geo.GeoLocation; +import org.springframework.data.elasticsearch.core.geo.GeoPoint; /** * @author Franck Marchand */ -@Document(indexName = "test-geo-index", type = "test-geo-type") -public class GeoAuthor { +@Document(indexName = "test-geo-index", type = "geo-class-point-type", indexStoreType = "memory", shards = 1, replicas = 0, refreshInterval = "-1") +public class AuthorMarkerEntity { @Id private String id; private String name; - private GeoLocation location; + private GeoPoint location; + + private AuthorMarkerEntity(){ + } + + public AuthorMarkerEntity(String id){ + this.id = id; + } public String getId() { return id; @@ -47,11 +54,11 @@ public class GeoAuthor { this.name = name; } - public GeoLocation getLocation() { + public GeoPoint getLocation() { return location; } - public void setLocation(GeoLocation location) { + public void setLocation(GeoPoint location) { this.location = location; } } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerEntityBuilder.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerEntityBuilder.java new file mode 100644 index 000000000..294b6fd8c --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/AuthorMarkerEntityBuilder.java @@ -0,0 +1,48 @@ +/* + * 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 org.springframework.data.elasticsearch.core.query.IndexQuery; + +public class AuthorMarkerEntityBuilder { + + private AuthorMarkerEntity result; + + public AuthorMarkerEntityBuilder(String id) { + result = new AuthorMarkerEntity(id); + } + + public AuthorMarkerEntityBuilder name(String name) { + result.setName(name); + return this; + } + + public AuthorMarkerEntityBuilder location(double latitude, double longitude) { + result.setLocation(new GeoPoint(latitude, longitude)); + return this; + } + + public AuthorMarkerEntity build() { + return result; + } + + public IndexQuery buildIndex() { + IndexQuery indexQuery = new IndexQuery(); + indexQuery.setId(result.getId()); + indexQuery.setObject(result); + return indexQuery; + } +} diff --git a/src/test/java/org/springframework/data/elasticsearch/core/geo/ElasticsearchTemplateGeoTests.java b/src/test/java/org/springframework/data/elasticsearch/core/geo/ElasticsearchTemplateGeoTests.java new file mode 100644 index 000000000..d2222b158 --- /dev/null +++ b/src/test/java/org/springframework/data/elasticsearch/core/geo/ElasticsearchTemplateGeoTests.java @@ -0,0 +1,236 @@ +/* + * 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 org.elasticsearch.index.query.FilterBuilders; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; +import org.springframework.data.elasticsearch.core.query.Criteria; +import org.springframework.data.elasticsearch.core.query.CriteriaQuery; +import org.springframework.data.elasticsearch.core.query.IndexQuery; +import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertEquals; + +/** + * @author Rizwan Idrees + * @author Mohsin Husen + * @author Franck Marchand + * @author Artur Konczak + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("classpath:elasticsearch-template-test.xml") +public class ElasticsearchTemplateGeoTests { + + @Autowired + private ElasticsearchTemplate elasticsearchTemplate; + + @Before + public void before() { + + } + + private void loadClassBaseEntities() { + elasticsearchTemplate.deleteIndex(AuthorMarkerEntity.class); + elasticsearchTemplate.createIndex(AuthorMarkerEntity.class); + elasticsearchTemplate.refresh(AuthorMarkerEntity.class, true); + elasticsearchTemplate.putMapping(AuthorMarkerEntity.class); + + List indexQueries = new ArrayList(); + indexQueries.add(new AuthorMarkerEntityBuilder("1").name("Franck Marchand").location(45.7806d, 3.0875d).buildIndex()); + indexQueries.add(new AuthorMarkerEntityBuilder("2").name("Mohsin Husen").location(51.5171d, 0.1062d).buildIndex()); + indexQueries.add(new AuthorMarkerEntityBuilder("3").name("Rizwan Idrees").location(51.5171d, 0.1062d).buildIndex()); + elasticsearchTemplate.bulkIndex(indexQueries); + elasticsearchTemplate.refresh(AuthorMarkerEntity.class, true); + } + + private void loadAnnotationBaseEntities() { + elasticsearchTemplate.deleteIndex(AuthorMarkerAnnotatedEntity.class); + elasticsearchTemplate.createIndex(AuthorMarkerAnnotatedEntity.class); + elasticsearchTemplate.refresh(AuthorMarkerAnnotatedEntity.class, true); + elasticsearchTemplate.putMapping(AuthorMarkerAnnotatedEntity.class); + + List indexQueries = new ArrayList(); + double[] latLonArray = {0.100000, 51.000000}; + String lonLatString = "51.000000, 0.100000"; + String geohash = "u1044k2bd6u"; + indexQueries.add(new AuthorMarkerAnnotatedEntityBuilder("2").name("Mohsin Husen").location(geohash.substring(3)).additionalLocation(latLonArray).buildIndex()); + indexQueries.add(new AuthorMarkerAnnotatedEntityBuilder("1").name("Artur Konczak").location(lonLatString).additionalLocation(latLonArray).buildIndex()); + indexQueries.add(new AuthorMarkerAnnotatedEntityBuilder("3").name("Rizwan Idrees").location(geohash).additionalLocation(latLonArray).buildIndex()); + + elasticsearchTemplate.bulkIndex(indexQueries); + elasticsearchTemplate.refresh(AuthorMarkerEntity.class, true); + } + + @Test + public void shouldPutMappingForGivenEntityWithGeoLocation() throws Exception { + //given + Class entity = AuthorMarkerEntity.class; + elasticsearchTemplate.createIndex(entity); + //when + assertThat(elasticsearchTemplate.putMapping(entity), is(true)); + } + + @Test + public void shouldFindAuthorMarkersInRangeForGivenCriteriaQuery() { + //given + loadClassBaseEntities(); + CriteriaQuery geoLocationCriteriaQuery = new CriteriaQuery( + new Criteria("location").within(new GeoPoint(45.7806d, 3.0875d), "20km")); + //when + List geoAuthorsForGeoCriteria = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery, AuthorMarkerEntity.class); + + //then + assertThat(geoAuthorsForGeoCriteria.size(), is(1)); + assertEquals("Franck Marchand", geoAuthorsForGeoCriteria.get(0).getName()); + } + + @Test + public void shouldFindSelectedAuthorMarkerInRangeForGivenCriteriaQuery() { + //given + loadClassBaseEntities(); + CriteriaQuery geoLocationCriteriaQuery2 = new CriteriaQuery( + new Criteria("name").is("Mohsin Husen").and("location").within(new GeoPoint(51.5171d, 0.1062d), "20km")); + //when + List geoAuthorsForGeoCriteria2 = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery2, AuthorMarkerEntity.class); + + //then + assertThat(geoAuthorsForGeoCriteria2.size(), is(1)); + assertEquals("Mohsin Husen", geoAuthorsForGeoCriteria2.get(0).getName()); + } + + @Test + public void shouldFindStringAnnotatedGeoMarkersInRangeForGivenCriteriaQuery() { + //given + loadAnnotationBaseEntities(); + CriteriaQuery geoLocationCriteriaQuery = new CriteriaQuery( + new Criteria("location").within(new GeoPoint(51.000000, 0.100000), "1km")); + //when + List geoAuthorsForGeoCriteria = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery, AuthorMarkerAnnotatedEntity.class); + + //then + assertThat(geoAuthorsForGeoCriteria.size(), is(1)); + //TODO: result should be 3 not 1 - geohash points don't work + assertEquals("Artur Konczak", geoAuthorsForGeoCriteria.get(0).getName()); + } + + @Test + public void shouldFindDoubleAnnotatedGeoMarkersInRangeForGivenCriteriaQuery() { + //given + loadAnnotationBaseEntities(); + CriteriaQuery geoLocationCriteriaQuery = new CriteriaQuery( + new Criteria("additionalLocation").within(new GeoPoint(51.001000, 0.10100), "1km")); + //when + List geoAuthorsForGeoCriteria = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery, AuthorMarkerAnnotatedEntity.class); + + //then + assertThat(geoAuthorsForGeoCriteria.size(), is(3)); + } + + @Test + public void shouldFindAnnotatedGeoMarkersInRangeForGivenCriteriaQuery() { + //given + loadAnnotationBaseEntities(); + CriteriaQuery geoLocationCriteriaQuery = new CriteriaQuery( + new Criteria("additionalLocation").within("51.001000, 0.10100", "1km")); + //when + List geoAuthorsForGeoCriteria = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery, AuthorMarkerAnnotatedEntity.class); + + //then + assertThat(geoAuthorsForGeoCriteria.size(), is(3)); + } + + @Test + public void shouldFindAnnotatedGeoMarkersInRangeForGivenCriteriaQueryUsingGeohashLocation() { + //given + loadAnnotationBaseEntities(); + CriteriaQuery geoLocationCriteriaQuery = new CriteriaQuery( + new Criteria("additionalLocation").within("u1044", "1km")); + //when + List geoAuthorsForGeoCriteria = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery, AuthorMarkerAnnotatedEntity.class); + + //then + assertThat(geoAuthorsForGeoCriteria.size(), is(3)); + } + + @Test + public void shouldFindAllMarkersForNativeSearchQuery() { + //Given + loadAnnotationBaseEntities(); + NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder().withFilter(FilterBuilders.geoBoundingBoxFilter("additionalLocation").topLeft("52, -1").bottomRight("50,1")); + //When + List geoAuthorsForGeoCriteria = elasticsearchTemplate.queryForList(queryBuilder.build(), AuthorMarkerAnnotatedEntity.class); + //Then + assertThat(geoAuthorsForGeoCriteria.size(), is(3)); + } + + @Test + public void shouldFindAuthorMarkersInBoxForGivenCriteriaQueryUsingGeoEnvelop() { + //given + loadClassBaseEntities(); + CriteriaQuery geoLocationCriteriaQuery3 = new CriteriaQuery( + new Criteria("location").bbox( + new GeoEnvelope(new GeoPoint(53.5171d, 0), + new GeoPoint(49.5171d, 0.2062d)))); + //when + List geoAuthorsForGeoCriteria3 = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery3, AuthorMarkerEntity.class); + + //then + assertThat(geoAuthorsForGeoCriteria3.size(), is(2)); + assertThat(geoAuthorsForGeoCriteria3, containsInAnyOrder(hasProperty("name", equalTo("Mohsin Husen")), hasProperty("name", equalTo("Rizwan Idrees")))); + } + + @Test + public void shouldFindAuthorMarkersInBoxForGivenCriteriaQueryUsingString() { + //given + loadClassBaseEntities(); + CriteriaQuery geoLocationCriteriaQuery3 = new CriteriaQuery( + new Criteria("location").bbox("53.5171d, 0", "49.5171d, 0.2062d")); + //when + List geoAuthorsForGeoCriteria3 = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery3, AuthorMarkerEntity.class); + + //then + assertThat(geoAuthorsForGeoCriteria3.size(), is(2)); + assertThat(geoAuthorsForGeoCriteria3, containsInAnyOrder(hasProperty("name", equalTo("Mohsin Husen")), hasProperty("name", equalTo("Rizwan Idrees")))); + } + + @Test + public void shouldFindAuthorMarkersInBoxForGivenCriteriaQueryUsingGeoPoints() { + //given + loadClassBaseEntities(); + CriteriaQuery geoLocationCriteriaQuery3 = new CriteriaQuery( + new Criteria("location").bbox( + new GeoPoint(53.5171d, 0), + new GeoPoint(49.5171d, 0.2062d))); + //when + List geoAuthorsForGeoCriteria3 = elasticsearchTemplate.queryForList(geoLocationCriteriaQuery3, AuthorMarkerEntity.class); + + //then + assertThat(geoAuthorsForGeoCriteria3.size(), is(2)); + assertThat(geoAuthorsForGeoCriteria3, containsInAnyOrder(hasProperty("name", equalTo("Mohsin Husen")), hasProperty("name", equalTo("Rizwan Idrees")))); + } + +} diff --git a/src/test/resources/infrastructure.xml b/src/test/resources/infrastructure.xml index c9207190f..7c17a094d 100644 --- a/src/test/resources/infrastructure.xml +++ b/src/test/resources/infrastructure.xml @@ -5,10 +5,8 @@ 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"> - - - - + + \ No newline at end of file