add geo distance sort option, refactor java level sort API to have sort builders (similar to facets)
This commit is contained in:
parent
8b19d353c1
commit
ff8d743337
|
@ -33,8 +33,9 @@ import org.elasticsearch.search.Scroll;
|
|||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.facets.AbstractFacetBuilder;
|
||||
import org.elasticsearch.search.highlight.HighlightBuilder;
|
||||
import org.elasticsearch.search.sort.SortBuilder;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -262,32 +263,18 @@ public class SearchRequestBuilder extends BaseRequestBuilder<SearchRequest, Sear
|
|||
* @param field The name of the field
|
||||
* @param order The sort ordering
|
||||
*/
|
||||
public SearchRequestBuilder addSort(String field, SearchSourceBuilder.Order order) {
|
||||
public SearchRequestBuilder addSort(String field, SortOrder order) {
|
||||
sourceBuilder().sort(field, order);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sort script.
|
||||
* Adds a generic sort builder.
|
||||
*
|
||||
* @param script The script to execute.
|
||||
* @param type The type of the result (can either be "string" or "number").
|
||||
* @param order The order.
|
||||
* @see org.elasticsearch.search.sort.SortBuilders
|
||||
*/
|
||||
public SearchRequestBuilder addSortScript(String script, String type, SearchSourceBuilder.Order order) {
|
||||
return addSortScript(script, type, order, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sort script.
|
||||
*
|
||||
* @param script The script to execute.
|
||||
* @param type The type of the result (can either be "string" or "number").
|
||||
* @param order The order.
|
||||
* @param params Optional parameters to the script.
|
||||
*/
|
||||
public SearchRequestBuilder addSortScript(String script, String type, SearchSourceBuilder.Order order, @Nullable Map<String, Object> params) {
|
||||
sourceBuilder().sortScript(script, type, order, params);
|
||||
public SearchRequestBuilder addSort(SortBuilder sort) {
|
||||
sourceBuilder().sort(sort);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search licenses this
|
||||
* file to you 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.elasticsearch.common.lucene.geo;
|
||||
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.search.FieldComparator;
|
||||
import org.apache.lucene.search.FieldComparatorSource;
|
||||
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
||||
import org.elasticsearch.index.field.data.FieldData;
|
||||
import org.elasticsearch.index.field.data.NumericFieldData;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.index.mapper.xcontent.XContentGeoPointFieldMapper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
// LUCENE MONITOR: Monitor against FieldComparator.Double
|
||||
public class GeoDistanceDataComparator extends FieldComparator {
|
||||
|
||||
public static FieldComparatorSource comparatorSource(String fieldName, double lat, double lon, DistanceUnit unit, GeoDistance geoDistance,
|
||||
FieldDataCache fieldDataCache, MapperService mapperService) {
|
||||
return new InnerSource(fieldName, lat, lon, unit, geoDistance, fieldDataCache, mapperService);
|
||||
}
|
||||
|
||||
private static class InnerSource extends FieldComparatorSource {
|
||||
|
||||
protected final String fieldName;
|
||||
|
||||
protected final double lat;
|
||||
|
||||
protected final double lon;
|
||||
|
||||
protected final DistanceUnit unit;
|
||||
|
||||
protected final GeoDistance geoDistance;
|
||||
|
||||
protected final FieldDataCache fieldDataCache;
|
||||
|
||||
private final MapperService mapperService;
|
||||
|
||||
private InnerSource(String fieldName, double lat, double lon, DistanceUnit unit, GeoDistance geoDistance,
|
||||
FieldDataCache fieldDataCache, MapperService mapperService) {
|
||||
this.fieldName = fieldName;
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.unit = unit;
|
||||
this.geoDistance = geoDistance;
|
||||
this.fieldDataCache = fieldDataCache;
|
||||
this.mapperService = mapperService;
|
||||
}
|
||||
|
||||
@Override public FieldComparator newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws IOException {
|
||||
return new GeoDistanceDataComparator(numHits, fieldname, lat, lon, unit, geoDistance, fieldDataCache, mapperService);
|
||||
}
|
||||
}
|
||||
|
||||
protected final String fieldName;
|
||||
|
||||
protected final String indexLatFieldName;
|
||||
|
||||
protected final String indexLonFieldName;
|
||||
|
||||
protected final double lat;
|
||||
|
||||
protected final double lon;
|
||||
|
||||
protected final DistanceUnit unit;
|
||||
|
||||
protected final GeoDistance geoDistance;
|
||||
|
||||
protected final FieldDataCache fieldDataCache;
|
||||
|
||||
protected final FieldData.Type fieldDataType;
|
||||
|
||||
protected NumericFieldData latFieldData;
|
||||
|
||||
protected NumericFieldData lonFieldData;
|
||||
|
||||
|
||||
private final double[] values;
|
||||
private double bottom;
|
||||
|
||||
public GeoDistanceDataComparator(int numHits, String fieldName, double lat, double lon, DistanceUnit unit, GeoDistance geoDistance,
|
||||
FieldDataCache fieldDataCache, MapperService mapperService) {
|
||||
values = new double[numHits];
|
||||
|
||||
this.fieldName = fieldName;
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
this.unit = unit;
|
||||
this.geoDistance = geoDistance;
|
||||
this.fieldDataCache = fieldDataCache;
|
||||
|
||||
FieldMapper mapper = mapperService.smartNameFieldMapper(fieldName + XContentGeoPointFieldMapper.Names.LAT_SUFFIX);
|
||||
if (mapper == null) {
|
||||
throw new ElasticSearchIllegalArgumentException("No mapping found for field [" + fieldName + "] for geo distance sort");
|
||||
}
|
||||
this.indexLatFieldName = mapper.names().indexName();
|
||||
|
||||
mapper = mapperService.smartNameFieldMapper(fieldName + XContentGeoPointFieldMapper.Names.LON_SUFFIX);
|
||||
if (mapper == null) {
|
||||
throw new ElasticSearchIllegalArgumentException("No mapping found for field [" + fieldName + "] for geo distance sort");
|
||||
}
|
||||
this.indexLonFieldName = mapper.names().indexName();
|
||||
this.fieldDataType = mapper.fieldDataType();
|
||||
}
|
||||
|
||||
@Override public void setNextReader(IndexReader reader, int docBase) throws IOException {
|
||||
latFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, indexLatFieldName);
|
||||
lonFieldData = (NumericFieldData) fieldDataCache.cache(fieldDataType, reader, indexLonFieldName);
|
||||
}
|
||||
|
||||
@Override public int compare(int slot1, int slot2) {
|
||||
final double v1 = values[slot1];
|
||||
final double v2 = values[slot2];
|
||||
if (v1 > v2) {
|
||||
return 1;
|
||||
} else if (v1 < v2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int compareBottom(int doc) {
|
||||
double distance;
|
||||
if (!latFieldData.hasValue(doc) || !lonFieldData.hasValue(doc)) {
|
||||
// is this true? push this to the "end"
|
||||
distance = Double.MAX_VALUE;
|
||||
} else {
|
||||
distance = geoDistance.calculate(lat, lon, latFieldData.doubleValue(doc), lonFieldData.doubleValue(doc), unit);
|
||||
}
|
||||
final double v2 = distance;
|
||||
if (bottom > v2) {
|
||||
return 1;
|
||||
} else if (bottom < v2) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void copy(int slot, int doc) {
|
||||
double distance;
|
||||
if (!latFieldData.hasValue(doc) || !lonFieldData.hasValue(doc)) {
|
||||
// is this true? push this to the "end"
|
||||
distance = Double.MAX_VALUE;
|
||||
} else {
|
||||
distance = geoDistance.calculate(lat, lon, latFieldData.doubleValue(doc), lonFieldData.doubleValue(doc), unit);
|
||||
}
|
||||
values[slot] = distance;
|
||||
}
|
||||
|
||||
@Override public void setBottom(final int bottom) {
|
||||
this.bottom = values[bottom];
|
||||
}
|
||||
|
||||
@Override public Comparable value(int slot) {
|
||||
return Double.valueOf(values[slot]);
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ import org.elasticsearch.rest.*;
|
|||
import org.elasticsearch.rest.action.support.RestActions;
|
||||
import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -191,11 +192,9 @@ public class RestSearchAction extends BaseRestHandler {
|
|||
String sortField = sort.substring(0, delimiter);
|
||||
String reverse = sort.substring(delimiter + 1);
|
||||
if ("asc".equals(reverse)) {
|
||||
searchSourceBuilder.sort(sortField, SearchSourceBuilder.Order.ASC);
|
||||
searchSourceBuilder.sort(sortField, SortOrder.ASC);
|
||||
} else if ("desc".equals(reverse)) {
|
||||
searchSourceBuilder.sort(sortField, SearchSourceBuilder.Order.DESC);
|
||||
} else {
|
||||
searchSourceBuilder.sort(sortField, reverse.equals("reverse"));
|
||||
searchSourceBuilder.sort(sortField, SortOrder.DESC);
|
||||
}
|
||||
} else {
|
||||
searchSourceBuilder.sort(sort);
|
||||
|
|
|
@ -31,16 +31,15 @@ import org.elasticsearch.common.xcontent.builder.XContentBuilder;
|
|||
import org.elasticsearch.index.query.xcontent.XContentQueryBuilder;
|
||||
import org.elasticsearch.search.facets.AbstractFacetBuilder;
|
||||
import org.elasticsearch.search.highlight.HighlightBuilder;
|
||||
import org.elasticsearch.search.query.SortParseElement;
|
||||
import org.elasticsearch.search.sort.SortBuilder;
|
||||
import org.elasticsearch.search.sort.SortBuilders;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.common.collect.Lists.*;
|
||||
|
||||
/**
|
||||
* A search source builder allowing to easily build search source. Simple construction
|
||||
* using {@link org.elasticsearch.search.builder.SearchSourceBuilder#searchSource()}.
|
||||
|
@ -50,11 +49,6 @@ import static org.elasticsearch.common.collect.Lists.*;
|
|||
*/
|
||||
public class SearchSourceBuilder implements ToXContent {
|
||||
|
||||
public static enum Order {
|
||||
ASC,
|
||||
DESC
|
||||
}
|
||||
|
||||
/**
|
||||
* A static factory method to construct a new search source.
|
||||
*/
|
||||
|
@ -81,9 +75,7 @@ public class SearchSourceBuilder implements ToXContent {
|
|||
|
||||
private Boolean explain;
|
||||
|
||||
private List<SortTuple> sortFields;
|
||||
|
||||
private List<ScriptSortTuple> sortScripts;
|
||||
private List<SortBuilder> sorts;
|
||||
|
||||
private List<String> fieldNames;
|
||||
|
||||
|
@ -159,18 +151,8 @@ public class SearchSourceBuilder implements ToXContent {
|
|||
* @param name The name of the field
|
||||
* @param order The sort ordering
|
||||
*/
|
||||
public SearchSourceBuilder sort(String name, Order order) {
|
||||
boolean reverse = false;
|
||||
if (name.equals(SortParseElement.SCORE_FIELD_NAME)) {
|
||||
if (order == Order.ASC) {
|
||||
reverse = true;
|
||||
}
|
||||
} else {
|
||||
if (order == Order.DESC) {
|
||||
reverse = true;
|
||||
}
|
||||
}
|
||||
return sort(name, reverse);
|
||||
public SearchSourceBuilder sort(String name, SortOrder order) {
|
||||
return sort(SortBuilders.fieldSort(name).order(order));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,36 +161,17 @@ public class SearchSourceBuilder implements ToXContent {
|
|||
* @param name The name of the field to sort by
|
||||
*/
|
||||
public SearchSourceBuilder sort(String name) {
|
||||
return sort(name, false);
|
||||
return sort(SortBuilders.fieldSort(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a sort script.
|
||||
*
|
||||
* @param script The script to execute.
|
||||
* @param type The type of the result (can either be "string" or "number").
|
||||
* @param order The order.
|
||||
* @param params Optional parameters to the script.
|
||||
* Adds a sort builder.
|
||||
*/
|
||||
public SearchSourceBuilder sortScript(String script, String type, Order order, @Nullable Map<String, Object> params) {
|
||||
if (sortScripts == null) {
|
||||
sortScripts = Lists.newArrayList();
|
||||
public SearchSourceBuilder sort(SortBuilder sort) {
|
||||
if (sorts == null) {
|
||||
sorts = Lists.newArrayList();
|
||||
}
|
||||
sortScripts.add(new ScriptSortTuple(script, type, params, order == Order.DESC));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a sort against the given field name and if it should be revered or not.
|
||||
*
|
||||
* @param name The name of the field to sort by
|
||||
* @param reverse Should the sort be reversed or not
|
||||
*/
|
||||
public SearchSourceBuilder sort(String name, boolean reverse) {
|
||||
if (sortFields == null) {
|
||||
sortFields = newArrayListWithCapacity(2);
|
||||
}
|
||||
sortFields.add(new SortTuple(name, reverse));
|
||||
sorts.add(sort);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -378,35 +341,14 @@ public class SearchSourceBuilder implements ToXContent {
|
|||
builder.endObject();
|
||||
}
|
||||
|
||||
if (sortFields != null || sortScripts != null) {
|
||||
builder.field("sort");
|
||||
builder.startObject();
|
||||
if (sortFields != null) {
|
||||
for (SortTuple sortTuple : sortFields) {
|
||||
builder.field(sortTuple.fieldName());
|
||||
builder.startObject();
|
||||
if (sortTuple.reverse()) {
|
||||
builder.field("reverse", true);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
if (sorts != null) {
|
||||
builder.startArray("sort");
|
||||
for (SortBuilder sort : sorts) {
|
||||
builder.startObject();
|
||||
sort.toXContent(builder, params);
|
||||
builder.endObject();
|
||||
}
|
||||
if (sortScripts != null) {
|
||||
for (ScriptSortTuple scriptSort : sortScripts) {
|
||||
builder.startObject("_script");
|
||||
builder.field("script", scriptSort.script());
|
||||
builder.field("type", scriptSort.type());
|
||||
if (scriptSort.params() != null) {
|
||||
builder.field("params");
|
||||
builder.map(scriptSort.params());
|
||||
}
|
||||
if (scriptSort.reverse()) {
|
||||
builder.field("reverse", true);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
||||
builder.endObject();
|
||||
builder.endArray();
|
||||
}
|
||||
|
||||
if (indexBoost != null) {
|
||||
|
@ -457,52 +399,4 @@ public class SearchSourceBuilder implements ToXContent {
|
|||
return params;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SortTuple {
|
||||
private final String fieldName;
|
||||
private final boolean reverse;
|
||||
|
||||
private SortTuple(String fieldName, boolean reverse) {
|
||||
this.fieldName = fieldName;
|
||||
this.reverse = reverse;
|
||||
}
|
||||
|
||||
public String fieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
public boolean reverse() {
|
||||
return reverse;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ScriptSortTuple {
|
||||
private final String script;
|
||||
private final String type;
|
||||
private final Map<String, Object> params;
|
||||
private final boolean reverse;
|
||||
|
||||
private ScriptSortTuple(String script, String type, Map<String, Object> params, boolean reverse) {
|
||||
this.script = script;
|
||||
this.type = type;
|
||||
this.params = params;
|
||||
this.reverse = reverse;
|
||||
}
|
||||
|
||||
public String script() {
|
||||
return script;
|
||||
}
|
||||
|
||||
public String type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Map<String, Object> params() {
|
||||
return params;
|
||||
}
|
||||
|
||||
public boolean reverse() {
|
||||
return reverse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ public class GeoDistanceFacetBuilder extends AbstractFacetBuilder {
|
|||
}
|
||||
|
||||
/**
|
||||
* The geo distance type used to compute the distnace.
|
||||
* The geo distance type used to compute the distance.
|
||||
*/
|
||||
public GeoDistanceFacetBuilder geoDistance(GeoDistance geoDistance) {
|
||||
this.geoDistance = geoDistance;
|
||||
|
|
|
@ -23,12 +23,17 @@ import org.apache.lucene.search.FieldComparatorSource;
|
|||
import org.apache.lucene.search.Sort;
|
||||
import org.apache.lucene.search.SortField;
|
||||
import org.elasticsearch.common.collect.Lists;
|
||||
import org.elasticsearch.common.lucene.geo.GeoDistance;
|
||||
import org.elasticsearch.common.lucene.geo.GeoDistanceDataComparator;
|
||||
import org.elasticsearch.common.lucene.geo.GeoHashUtils;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
import org.elasticsearch.common.xcontent.XContentParser;
|
||||
import org.elasticsearch.index.field.function.FieldsFunction;
|
||||
import org.elasticsearch.index.field.function.script.ScriptFieldsFunction;
|
||||
import org.elasticsearch.index.field.function.sort.DoubleFieldsFunctionDataComparator;
|
||||
import org.elasticsearch.index.field.function.sort.StringFieldsFunctionDataComparator;
|
||||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.mapper.xcontent.XContentGeoPointFieldMapper;
|
||||
import org.elasticsearch.search.SearchParseElement;
|
||||
import org.elasticsearch.search.SearchParseException;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
|
@ -50,6 +55,7 @@ public class SortParseElement implements SearchParseElement {
|
|||
public static final String SCRIPT_FIELD_NAME = "_script";
|
||||
public static final String SCORE_FIELD_NAME = "_score";
|
||||
public static final String DOC_FIELD_NAME = "_doc";
|
||||
public static final String GEO_DISTANCE_FIELD_NAME = "_geo_distance";
|
||||
|
||||
public SortParseElement() {
|
||||
}
|
||||
|
@ -60,6 +66,7 @@ public class SortParseElement implements SearchParseElement {
|
|||
if (token == XContentParser.Token.START_ARRAY) {
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
if (token == XContentParser.Token.START_OBJECT) {
|
||||
//TODO move to pluggable parsers, similar to facets. Builders already exists...
|
||||
addCompoundSortField(parser, context, sortFields);
|
||||
} else if (token == XContentParser.Token.VALUE_STRING) {
|
||||
addSortField(context, sortFields, parser.text(), false);
|
||||
|
@ -80,9 +87,6 @@ public class SortParseElement implements SearchParseElement {
|
|||
String fieldName = parser.currentName();
|
||||
boolean reverse = false;
|
||||
String innerJsonName = null;
|
||||
String script = null;
|
||||
String type = null;
|
||||
Map<String, Object> params = null;
|
||||
token = parser.nextToken();
|
||||
if (token == XContentParser.Token.VALUE_STRING) {
|
||||
String direction = parser.text();
|
||||
|
@ -91,6 +95,11 @@ public class SortParseElement implements SearchParseElement {
|
|||
} else if (direction.equals("desc")) {
|
||||
reverse = !SCORE_FIELD_NAME.equals(fieldName);
|
||||
}
|
||||
addSortField(context, sortFields, fieldName, reverse);
|
||||
} else if (GEO_DISTANCE_FIELD_NAME.equals(fieldName)) {
|
||||
addGeoDistanceSortField(parser, context, sortFields);
|
||||
} else if (SCRIPT_FIELD_NAME.equals(fieldName)) {
|
||||
addScriptSortField(parser, context, sortFields);
|
||||
} else {
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
|
@ -104,34 +113,9 @@ public class SortParseElement implements SearchParseElement {
|
|||
} else if ("desc".equals(parser.text())) {
|
||||
reverse = !SCORE_FIELD_NAME.equals(fieldName);
|
||||
}
|
||||
} else if ("script".equals(innerJsonName)) {
|
||||
script = parser.text();
|
||||
} else if ("type".equals(innerJsonName)) {
|
||||
type = parser.text();
|
||||
} else if ("params".equals(innerJsonName)) {
|
||||
params = parser.map();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SCRIPT_FIELD_NAME.equals(fieldName)) {
|
||||
if (script == null) {
|
||||
throw new SearchParseException(context, "_script sorting requires setting the script to sort by");
|
||||
}
|
||||
if (type == null) {
|
||||
throw new SearchParseException(context, "_script sorting requires setting the type of the script");
|
||||
}
|
||||
FieldsFunction fieldsFunction = new ScriptFieldsFunction(script, context.scriptService(), context.mapperService(), context.fieldDataCache());
|
||||
FieldComparatorSource fieldComparatorSource;
|
||||
if ("string".equals(type)) {
|
||||
fieldComparatorSource = StringFieldsFunctionDataComparator.comparatorSource(fieldsFunction, params);
|
||||
} else if ("number".equals(type)) {
|
||||
fieldComparatorSource = DoubleFieldsFunctionDataComparator.comparatorSource(fieldsFunction, params);
|
||||
} else {
|
||||
throw new SearchParseException(context, "custom script sort type [" + type + "] not supported");
|
||||
}
|
||||
sortFields.add(new SortField(fieldName, fieldComparatorSource, reverse));
|
||||
} else {
|
||||
addSortField(context, sortFields, fieldName, reverse);
|
||||
}
|
||||
}
|
||||
|
@ -159,4 +143,137 @@ public class SortParseElement implements SearchParseElement {
|
|||
sortFields.add(new SortField(fieldName, fieldMapper.fieldDataType().newFieldComparatorSource(context.fieldDataCache()), reverse));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* "_script" : {
|
||||
* "script" : "doc[...]",
|
||||
* "order" : "asc"
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
private void addScriptSortField(XContentParser parser, SearchContext context, List<SortField> sortFields) throws IOException {
|
||||
String script = null;
|
||||
String type = null;
|
||||
Map<String, Object> params = null;
|
||||
boolean reverse = false;
|
||||
|
||||
XContentParser.Token token;
|
||||
String currentName = parser.currentName();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if ("reverse".equals(currentName)) {
|
||||
reverse = parser.booleanValue();
|
||||
} else if ("order".equals(currentName)) {
|
||||
reverse = "desc".equals(parser.text());
|
||||
} else if ("script".equals(currentName)) {
|
||||
script = parser.text();
|
||||
} else if ("type".equals(currentName)) {
|
||||
type = parser.text();
|
||||
} else if ("params".equals(currentName)) {
|
||||
params = parser.map();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (script == null) {
|
||||
throw new SearchParseException(context, "_script sorting requires setting the script to sort by");
|
||||
}
|
||||
if (type == null) {
|
||||
throw new SearchParseException(context, "_script sorting requires setting the type of the script");
|
||||
}
|
||||
FieldsFunction fieldsFunction = new ScriptFieldsFunction(script, context.scriptService(), context.mapperService(), context.fieldDataCache());
|
||||
FieldComparatorSource fieldComparatorSource;
|
||||
if ("string".equals(type)) {
|
||||
fieldComparatorSource = StringFieldsFunctionDataComparator.comparatorSource(fieldsFunction, params);
|
||||
} else if ("number".equals(type)) {
|
||||
fieldComparatorSource = DoubleFieldsFunctionDataComparator.comparatorSource(fieldsFunction, params);
|
||||
} else {
|
||||
throw new SearchParseException(context, "custom script sort type [" + type + "] not supported");
|
||||
}
|
||||
sortFields.add(new SortField("_script", fieldComparatorSource, reverse));
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* "_geo_distance" : {
|
||||
* "pin.location" : {
|
||||
*
|
||||
* },
|
||||
* "order" : "asc"
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
private void addGeoDistanceSortField(XContentParser parser, SearchContext context, List<SortField> sortFields) throws IOException {
|
||||
String fieldName = null;
|
||||
double lat = Double.NaN;
|
||||
double lon = Double.NaN;
|
||||
DistanceUnit unit = DistanceUnit.KILOMETERS;
|
||||
GeoDistance geoDistance = GeoDistance.ARC;
|
||||
boolean reverse = false;
|
||||
|
||||
|
||||
XContentParser.Token token;
|
||||
String currentName = parser.currentName();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentName = parser.currentName();
|
||||
} else if (token == XContentParser.Token.START_ARRAY) {
|
||||
token = parser.nextToken();
|
||||
lat = parser.doubleValue();
|
||||
token = parser.nextToken();
|
||||
lon = parser.doubleValue();
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
|
||||
|
||||
}
|
||||
fieldName = currentName;
|
||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
||||
// the json in the format of -> field : { lat : 30, lon : 12 }
|
||||
fieldName = currentName;
|
||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||
if (token == XContentParser.Token.FIELD_NAME) {
|
||||
currentName = parser.currentName();
|
||||
} else if (token.isValue()) {
|
||||
if (currentName.equals(XContentGeoPointFieldMapper.Names.LAT)) {
|
||||
lat = parser.doubleValue();
|
||||
} else if (currentName.equals(XContentGeoPointFieldMapper.Names.LON)) {
|
||||
lon = parser.doubleValue();
|
||||
} else if (currentName.equals(XContentGeoPointFieldMapper.Names.GEOHASH)) {
|
||||
double[] values = GeoHashUtils.decode(parser.text());
|
||||
lat = values[0];
|
||||
lon = values[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (token.isValue()) {
|
||||
if ("reverse".equals(currentName)) {
|
||||
reverse = parser.booleanValue();
|
||||
} else if ("order".equals(currentName)) {
|
||||
reverse = "desc".equals(parser.text());
|
||||
} else if (currentName.equals("unit")) {
|
||||
unit = DistanceUnit.fromString(parser.text());
|
||||
} else if (currentName.equals("distance_type") || currentName.equals("distanceType")) {
|
||||
geoDistance = GeoDistance.fromString(parser.text());
|
||||
} else {
|
||||
// assume the value is the actual value
|
||||
String value = parser.text();
|
||||
int comma = value.indexOf(',');
|
||||
if (comma != -1) {
|
||||
lat = Double.parseDouble(value.substring(0, comma).trim());
|
||||
lon = Double.parseDouble(value.substring(comma + 1).trim());
|
||||
} else {
|
||||
double[] values = GeoHashUtils.decode(value);
|
||||
lat = values[0];
|
||||
lon = values[1];
|
||||
}
|
||||
|
||||
fieldName = currentName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sortFields.add(new SortField(fieldName, GeoDistanceDataComparator.comparatorSource(fieldName, lat, lon, unit, geoDistance, context.fieldDataCache(), context.mapperService()), reverse));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search licenses this
|
||||
* file to you 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.elasticsearch.search.sort;
|
||||
|
||||
import org.elasticsearch.common.xcontent.builder.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class FieldSortBuilder extends SortBuilder {
|
||||
|
||||
private final String fieldName;
|
||||
|
||||
private SortOrder order;
|
||||
|
||||
public FieldSortBuilder(String fieldName) {
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
public FieldSortBuilder order(SortOrder order) {
|
||||
this.order = order;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public void toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject(fieldName);
|
||||
if (order == SortOrder.DESC) {
|
||||
builder.field("reverse", true);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search licenses this
|
||||
* file to you 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.elasticsearch.search.sort;
|
||||
|
||||
import org.elasticsearch.common.lucene.geo.GeoDistance;
|
||||
import org.elasticsearch.common.unit.DistanceUnit;
|
||||
import org.elasticsearch.common.xcontent.builder.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class GeoDistanceSortBuilder extends SortBuilder {
|
||||
|
||||
final String fieldName;
|
||||
|
||||
private double lat;
|
||||
private double lon;
|
||||
private String geohash;
|
||||
|
||||
private GeoDistance geoDistance;
|
||||
private DistanceUnit unit;
|
||||
private SortOrder order;
|
||||
|
||||
public GeoDistanceSortBuilder(String fieldName) {
|
||||
this.fieldName = fieldName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The point to create the range distance facets from.
|
||||
*
|
||||
* @param lat latitude.
|
||||
* @param lon longitude.
|
||||
*/
|
||||
public GeoDistanceSortBuilder point(double lat, double lon) {
|
||||
this.lat = lat;
|
||||
this.lon = lon;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The geohash of the geo point to create the range distance facets from.
|
||||
*/
|
||||
public GeoDistanceSortBuilder geohash(String geohash) {
|
||||
this.geohash = geohash;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The geo distance type used to compute the distance.
|
||||
*/
|
||||
public GeoDistanceSortBuilder geoDistance(GeoDistance geoDistance) {
|
||||
this.geoDistance = geoDistance;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The distance unit to use. Defaults to {@link org.elasticsearch.common.unit.DistanceUnit#KILOMETERS}
|
||||
*/
|
||||
public GeoDistanceSortBuilder unit(DistanceUnit unit) {
|
||||
this.unit = unit;
|
||||
return this;
|
||||
}
|
||||
|
||||
public GeoDistanceSortBuilder order(SortOrder order) {
|
||||
this.order = order;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public void toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject("_geo_distance");
|
||||
|
||||
if (geohash != null) {
|
||||
builder.field(fieldName, geohash);
|
||||
} else {
|
||||
builder.startArray(fieldName).value(lat).value(lon).endArray();
|
||||
}
|
||||
|
||||
if (unit != null) {
|
||||
builder.field("unit", unit);
|
||||
}
|
||||
if (geoDistance != null) {
|
||||
builder.field("distance_type", geoDistance.name().toLowerCase());
|
||||
}
|
||||
if (order == SortOrder.DESC) {
|
||||
builder.field("reverse", true);
|
||||
}
|
||||
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search licenses this
|
||||
* file to you 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.elasticsearch.search.sort;
|
||||
|
||||
import org.elasticsearch.common.xcontent.builder.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class ScoreSortBuilder extends SortBuilder {
|
||||
|
||||
private SortOrder order;
|
||||
|
||||
public ScoreSortBuilder order(SortOrder order) {
|
||||
this.order = order;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public void toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject("_score");
|
||||
if (order == SortOrder.ASC) {
|
||||
builder.field("reverse", true);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search licenses this
|
||||
* file to you 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.elasticsearch.search.sort;
|
||||
|
||||
import org.elasticsearch.common.collect.Maps;
|
||||
import org.elasticsearch.common.xcontent.builder.XContentBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class ScriptSortBuilder extends SortBuilder {
|
||||
|
||||
private final String script;
|
||||
|
||||
private final String type;
|
||||
|
||||
private SortOrder order;
|
||||
|
||||
private Map<String, Object> params;
|
||||
|
||||
public ScriptSortBuilder(String script, String type) {
|
||||
this.script = script;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public ScriptSortBuilder param(String name, Object value) {
|
||||
if (params == null) {
|
||||
params = Maps.newHashMap();
|
||||
}
|
||||
params.put(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ScriptSortBuilder order(SortOrder order) {
|
||||
this.order = order;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public void toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startObject("_script");
|
||||
builder.field("script", script);
|
||||
builder.field("type", type);
|
||||
if (order == SortOrder.DESC) {
|
||||
builder.field("reverse", true);
|
||||
}
|
||||
if (this.params != null) {
|
||||
builder.field("params");
|
||||
builder.map(this.params);
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search licenses this
|
||||
* file to you 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.elasticsearch.search.sort;
|
||||
|
||||
import org.elasticsearch.common.xcontent.ToXContent;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public abstract class SortBuilder implements ToXContent {
|
||||
|
||||
public abstract SortBuilder order(SortOrder order);
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search licenses this
|
||||
* file to you 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.elasticsearch.search.sort;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class SortBuilders {
|
||||
|
||||
public static ScoreSortBuilder scoreSort() {
|
||||
return new ScoreSortBuilder();
|
||||
}
|
||||
|
||||
public static FieldSortBuilder fieldSort(String field) {
|
||||
return new FieldSortBuilder(field);
|
||||
}
|
||||
|
||||
public static ScriptSortBuilder scriptSort(String script, String type) {
|
||||
return new ScriptSortBuilder(script, type);
|
||||
}
|
||||
|
||||
public static GeoDistanceSortBuilder geoDistanceSort(String fieldName) {
|
||||
return new GeoDistanceSortBuilder(fieldName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Licensed to Elastic Search and Shay Banon under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. Elastic Search licenses this
|
||||
* file to you 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.elasticsearch.search.sort;
|
||||
|
||||
/**
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public enum SortOrder {
|
||||
ASC,
|
||||
DESC
|
||||
}
|
|
@ -32,6 +32,7 @@ import org.elasticsearch.search.SearchHit;
|
|||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.facets.FacetBuilders;
|
||||
import org.elasticsearch.search.facets.query.QueryFacet;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.test.integration.AbstractNodesTests;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
|
@ -110,7 +111,7 @@ public class TransportTwoServersSearchTests extends AbstractNodesTests {
|
|||
@Test public void testDfsQueryThenFetchWithSort() throws Exception {
|
||||
SearchSourceBuilder source = searchSource()
|
||||
.query(termQuery("multi", "test"))
|
||||
.from(0).size(60).explain(true).sort("age", false);
|
||||
.from(0).size(60).explain(true).sort("age", SortOrder.ASC);
|
||||
|
||||
SearchResponse searchResponse = client.search(searchRequest("test").source(source).searchType(DFS_QUERY_THEN_FETCH).scroll(new Scroll(timeValueMinutes(10)))).actionGet();
|
||||
assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0));
|
||||
|
@ -162,7 +163,7 @@ public class TransportTwoServersSearchTests extends AbstractNodesTests {
|
|||
@Test public void testQueryThenFetchWithSort() throws Exception {
|
||||
SearchSourceBuilder source = searchSource()
|
||||
.query(termQuery("multi", "test"))
|
||||
.from(0).size(60).explain(true).sort("age", false);
|
||||
.from(0).size(60).explain(true).sort("age", SortOrder.ASC);
|
||||
|
||||
SearchResponse searchResponse = client.search(searchRequest("test").source(source).searchType(QUERY_THEN_FETCH).scroll(new Scroll(timeValueMinutes(10)))).actionGet();
|
||||
assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0));
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.elasticsearch.search.internal.InternalSearchResponse;
|
|||
import org.elasticsearch.search.query.QuerySearchRequest;
|
||||
import org.elasticsearch.search.query.QuerySearchResult;
|
||||
import org.elasticsearch.search.query.QuerySearchResultProvider;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.test.integration.AbstractNodesTests;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
|
@ -178,7 +179,7 @@ public class TwoInstanceEmbeddedSearchTests extends AbstractNodesTests {
|
|||
@Test public void testDfsQueryThenFetchWithSort() throws Exception {
|
||||
SearchSourceBuilder sourceBuilder = searchSource()
|
||||
.query(termQuery("multi", "test"))
|
||||
.from(0).size(60).explain(true).sort("age", false);
|
||||
.from(0).size(60).explain(true).sort("age", SortOrder.ASC);
|
||||
|
||||
List<DfsSearchResult> dfsResults = newArrayList();
|
||||
for (ShardsIterator shardsIt : indicesService.searchShards(clusterService.state(), new String[]{"test"}, null)) {
|
||||
|
@ -320,7 +321,7 @@ public class TwoInstanceEmbeddedSearchTests extends AbstractNodesTests {
|
|||
@Test public void testSimpleFacets() {
|
||||
SearchSourceBuilder sourceBuilder = searchSource()
|
||||
.query(termQuery("multi", "test"))
|
||||
.from(0).size(20).explain(true).sort("age", false)
|
||||
.from(0).size(20).explain(true).sort("age", SortOrder.ASC)
|
||||
.facet(FacetBuilders.queryFacet("all", termQuery("multi", "test")))
|
||||
.facet(FacetBuilders.queryFacet("test1", termQuery("name", "test1")));
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.elasticsearch.search.internal.InternalSearchResponse;
|
|||
import org.elasticsearch.search.query.QuerySearchRequest;
|
||||
import org.elasticsearch.search.query.QuerySearchResult;
|
||||
import org.elasticsearch.search.query.QuerySearchResultProvider;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.test.integration.AbstractNodesTests;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
|
@ -183,7 +184,7 @@ public class TwoInstanceUnbalancedShardsEmbeddedSearchTests extends AbstractNode
|
|||
@Test public void testDfsQueryFetchWithSort() throws Exception {
|
||||
SearchSourceBuilder sourceBuilder = searchSource()
|
||||
.query(termQuery("multi", "test"))
|
||||
.from(0).size(60).explain(true).sort("age", false);
|
||||
.from(0).size(60).explain(true).sort("age", SortOrder.ASC);
|
||||
|
||||
List<DfsSearchResult> dfsResults = newArrayList();
|
||||
for (ShardsIterator shardsIt : indicesService.searchShards(clusterService.state(), new String[]{"test"}, null)) {
|
||||
|
@ -326,7 +327,7 @@ public class TwoInstanceUnbalancedShardsEmbeddedSearchTests extends AbstractNode
|
|||
@Test public void testSimpleFacets() {
|
||||
SearchSourceBuilder sourceBuilder = searchSource()
|
||||
.query(termQuery("multi", "test"))
|
||||
.from(0).size(20).explain(true).sort("age", false)
|
||||
.from(0).size(20).explain(true).sort("age", SortOrder.ASC)
|
||||
.facet(queryFacet("all").query(termQuery("multi", "test")))
|
||||
.facet(queryFacet("test1").query(termQuery("name", "test1")));
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ package org.elasticsearch.test.integration.search.geo;
|
|||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.sort.SortBuilders;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.test.integration.AbstractNodesTests;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
|
@ -133,5 +135,35 @@ public class GeoDistanceTests extends AbstractNodesTests {
|
|||
for (SearchHit hit : searchResponse.hits()) {
|
||||
assertThat(hit.id(), anyOf(equalTo("1"), equalTo("3"), equalTo("4"), equalTo("5")));
|
||||
}
|
||||
|
||||
// SORTING
|
||||
|
||||
searchResponse = client.prepareSearch().setQuery(matchAllQuery())
|
||||
.addSort(SortBuilders.geoDistanceSort("location").point(40.7143528, -74.0059731).order(SortOrder.ASC))
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(7l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(7));
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo("1"));
|
||||
assertThat(searchResponse.hits().getAt(1).id(), equalTo("3"));
|
||||
assertThat(searchResponse.hits().getAt(2).id(), equalTo("4"));
|
||||
assertThat(searchResponse.hits().getAt(3).id(), equalTo("5"));
|
||||
assertThat(searchResponse.hits().getAt(4).id(), equalTo("6"));
|
||||
assertThat(searchResponse.hits().getAt(5).id(), equalTo("2"));
|
||||
assertThat(searchResponse.hits().getAt(6).id(), equalTo("7"));
|
||||
|
||||
searchResponse = client.prepareSearch().setQuery(matchAllQuery())
|
||||
.addSort(SortBuilders.geoDistanceSort("location").point(40.7143528, -74.0059731).order(SortOrder.DESC))
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(7l));
|
||||
assertThat(searchResponse.hits().hits().length, equalTo(7));
|
||||
assertThat(searchResponse.hits().getAt(6).id(), equalTo("1"));
|
||||
assertThat(searchResponse.hits().getAt(5).id(), equalTo("3"));
|
||||
assertThat(searchResponse.hits().getAt(4).id(), equalTo("4"));
|
||||
assertThat(searchResponse.hits().getAt(3).id(), equalTo("5"));
|
||||
assertThat(searchResponse.hits().getAt(2).id(), equalTo("6"));
|
||||
assertThat(searchResponse.hits().getAt(1).id(), equalTo("2"));
|
||||
assertThat(searchResponse.hits().getAt(0).id(), equalTo("7"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ package org.elasticsearch.test.integration.search.scriptfield;
|
|||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.common.collect.MapBuilder;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.test.integration.AbstractNodesTests;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
|
@ -32,7 +33,6 @@ import java.util.Map;
|
|||
import static org.elasticsearch.client.Requests.*;
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.*;
|
||||
import static org.elasticsearch.index.query.xcontent.QueryBuilders.*;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
|
@ -77,7 +77,7 @@ public class ScriptFieldSearchTests extends AbstractNodesTests {
|
|||
logger.info("running doc['num1'].value");
|
||||
SearchResponse response = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addSort("num1", Order.ASC)
|
||||
.addSort("num1", SortOrder.ASC)
|
||||
.addScriptField("sNum1", "doc['num1'].value")
|
||||
.addScriptField("date1", "doc['date'].date.millis")
|
||||
.execute().actionGet();
|
||||
|
@ -98,7 +98,7 @@ public class ScriptFieldSearchTests extends AbstractNodesTests {
|
|||
Map<String, Object> params = MapBuilder.<String, Object>newMapBuilder().put("factor", 2.0).map();
|
||||
response = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addSort("num1", Order.ASC)
|
||||
.addSort("num1", SortOrder.ASC)
|
||||
.addScriptField("sNum1", "doc['num1'].value * factor", params)
|
||||
.execute().actionGet();
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.elasticsearch.test.integration.search.scriptfilter;
|
|||
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.test.integration.AbstractNodesTests;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
|
@ -30,7 +31,6 @@ import static org.elasticsearch.client.Requests.*;
|
|||
import static org.elasticsearch.common.xcontent.XContentFactory.*;
|
||||
import static org.elasticsearch.index.query.xcontent.FilterBuilders.*;
|
||||
import static org.elasticsearch.index.query.xcontent.QueryBuilders.*;
|
||||
import static org.elasticsearch.search.builder.SearchSourceBuilder.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
|
@ -75,7 +75,7 @@ public class ScriptFilterSearchTests extends AbstractNodesTests {
|
|||
logger.info("running doc['num1'].value > 1");
|
||||
SearchResponse response = client.prepareSearch()
|
||||
.setQuery(filtered(matchAllQuery(), scriptFilter("doc['num1'].value > 1")))
|
||||
.addSort("num1", Order.ASC)
|
||||
.addSort("num1", SortOrder.ASC)
|
||||
.addScriptField("sNum1", "doc['num1'].value")
|
||||
.execute().actionGet();
|
||||
|
||||
|
@ -88,7 +88,7 @@ public class ScriptFilterSearchTests extends AbstractNodesTests {
|
|||
logger.info("running doc['num1'].value > param1");
|
||||
response = client.prepareSearch()
|
||||
.setQuery(filtered(matchAllQuery(), scriptFilter("doc['num1'].value > param1").addParam("param1", 2)))
|
||||
.addSort("num1", Order.ASC)
|
||||
.addSort("num1", SortOrder.ASC)
|
||||
.addScriptField("sNum1", "doc['num1'].value")
|
||||
.execute().actionGet();
|
||||
|
||||
|
@ -99,7 +99,7 @@ public class ScriptFilterSearchTests extends AbstractNodesTests {
|
|||
logger.info("running doc['num1'].value > param1");
|
||||
response = client.prepareSearch()
|
||||
.setQuery(filtered(matchAllQuery(), scriptFilter("doc['num1'].value > param1").addParam("param1", -1)))
|
||||
.addSort("num1", Order.ASC)
|
||||
.addSort("num1", SortOrder.ASC)
|
||||
.addScriptField("sNum1", "doc['num1'].value")
|
||||
.execute().actionGet();
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ package org.elasticsearch.test.integration.search.sort;
|
|||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.search.ShardSearchFailure;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.elasticsearch.test.integration.AbstractNodesTests;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
|
@ -30,6 +30,7 @@ import org.testng.annotations.Test;
|
|||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.*;
|
||||
import static org.elasticsearch.index.query.xcontent.QueryBuilders.*;
|
||||
import static org.elasticsearch.search.sort.SortBuilders.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
|
@ -83,7 +84,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
SearchResponse searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSort("svalue", SearchSourceBuilder.Order.ASC)
|
||||
.addSort("svalue", SortOrder.ASC)
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
|
@ -95,7 +96,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSortScript("doc['svalue'].value", "string", SearchSourceBuilder.Order.ASC)
|
||||
.addSort(scriptSort("doc['svalue'].value", "string").order(SortOrder.ASC))
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
|
@ -105,7 +106,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSort("svalue", SearchSourceBuilder.Order.DESC)
|
||||
.addSort("svalue", SortOrder.DESC)
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
|
@ -115,7 +116,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSortScript("doc['svalue'].value", "string", SearchSourceBuilder.Order.DESC)
|
||||
.addSort(scriptSort("doc['svalue'].value", "string").order(SortOrder.DESC))
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
|
@ -125,7 +126,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSort("ivalue", SearchSourceBuilder.Order.ASC)
|
||||
.addSort("ivalue", SortOrder.ASC)
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
|
@ -137,7 +138,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSortScript("doc['ivalue'].value", "number", SearchSourceBuilder.Order.ASC)
|
||||
.addSort(scriptSort("doc['ivalue'].value", "number").order(SortOrder.ASC))
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
|
@ -147,7 +148,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSort("ivalue", SearchSourceBuilder.Order.DESC)
|
||||
.addSort("ivalue", SortOrder.DESC)
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
|
@ -159,7 +160,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSortScript("doc['ivalue'].value", "number", SearchSourceBuilder.Order.DESC)
|
||||
.addSort(scriptSort("doc['ivalue'].value", "string").order(SortOrder.DESC))
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
|
@ -169,7 +170,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSort("dvalue", SearchSourceBuilder.Order.ASC)
|
||||
.addSort("dvalue", SortOrder.ASC)
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
|
@ -179,7 +180,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSort("dvalue", SearchSourceBuilder.Order.DESC)
|
||||
.addSort("dvalue", SortOrder.DESC)
|
||||
.execute().actionGet();
|
||||
|
||||
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
|
||||
|
@ -217,7 +218,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
SearchResponse searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSort("svalue", SearchSourceBuilder.Order.ASC)
|
||||
.addSort("svalue", SortOrder.ASC)
|
||||
.execute().actionGet();
|
||||
|
||||
if (searchResponse.failedShards() > 0) {
|
||||
|
@ -236,7 +237,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(matchAllQuery())
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSort("svalue", SearchSourceBuilder.Order.DESC)
|
||||
.addSort("svalue", SortOrder.DESC)
|
||||
.execute().actionGet();
|
||||
|
||||
if (searchResponse.failedShards() > 0) {
|
||||
|
@ -256,7 +257,7 @@ public class SimpleSortTests extends AbstractNodesTests {
|
|||
searchResponse = client.prepareSearch()
|
||||
.setQuery(termQuery("id", "2"))
|
||||
.addScriptField("id", "doc['id'].value")
|
||||
.addSort("svalue", SearchSourceBuilder.Order.DESC)
|
||||
.addSort("svalue", SortOrder.DESC)
|
||||
.execute().actionGet();
|
||||
|
||||
if (searchResponse.failedShards() > 0) {
|
||||
|
|
Loading…
Reference in New Issue