Skip to content

Commit

Permalink
DATAES-12 Merge Geo Location from branch 'master' of https://github.c…
Browse files Browse the repository at this point in the history
  • Loading branch information
akonczak committed Jun 13, 2013
1 parent aa6a5e3 commit 74a4035
Show file tree
Hide file tree
Showing 15 changed files with 807 additions and 264 deletions.
@@ -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;
}
}
Expand Up @@ -22,6 +22,8 @@
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.QueryBuilders.*;
Expand All @@ -32,106 +34,141 @@
*
* @author Rizwan Idrees
* @author Mohsin Husen
* @author Franck Marchand
*/
class CriteriaQueryProcessor {

QueryBuilder createQueryFromCriteria(Criteria criteria) {
BoolQueryBuilder query = boolQuery();

ListIterator<Criteria> chainIterator = criteria.getCriteriaChain().listIterator();
while (chainIterator.hasNext()) {
Criteria chainedCriteria = chainIterator.next();
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) {
Iterator<Criteria.CriteriaEntry> it = chainedCriteria.getCriteriaEntries().iterator();
boolean singeEntryCriteria = (chainedCriteria.getCriteriaEntries().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);
}

}

QueryBuilder createQueryFromCriteria(Criteria criteria) {
if(criteria == null)
return null;

List<QueryBuilder> shouldQueryBuilderList = new LinkedList<QueryBuilder>();
List<QueryBuilder> mustNotQueryBuilderList = new LinkedList<QueryBuilder>();
List<QueryBuilder> mustQueryBuilderList = new LinkedList<QueryBuilder>();


ListIterator<Criteria> chainIterator = criteria.getCriteriaChain().listIterator();
while (chainIterator.hasNext()) {
Criteria chainedCriteria = chainIterator.next();
QueryBuilder queryFragmentForCriteria = createQueryFragmentForCriteria(chainedCriteria);

if(queryFragmentForCriteria!=null) {
if(chainedCriteria.isOr()){
shouldQueryBuilderList.add(queryFragmentForCriteria);
}else if(chainedCriteria.isNegating()){
mustNotQueryBuilderList.add(queryFragmentForCriteria);
}else{
mustQueryBuilderList.add(queryFragmentForCriteria);
}
}
}

BoolQueryBuilder query = null;

if(!shouldQueryBuilderList.isEmpty() || !mustNotQueryBuilderList.isEmpty() || !mustQueryBuilderList.isEmpty()) {

query = boolQuery();

for(QueryBuilder qb : shouldQueryBuilderList) {
query.should(qb);
}
for(QueryBuilder qb : mustNotQueryBuilderList) {
query.mustNot(qb);
}
for(QueryBuilder qb : mustQueryBuilderList) {
query.must(qb);
}
}

return query;
}


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);
}

}

}

0 comments on commit 74a4035

Please sign in to comment.