Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Multi-Valued Field Methods to Expressions #11105

Merged
merged 1 commit into from
May 14, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/reference/search/request/sort.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ to. The `mode` option can have the following values:
number based array fields.
`avg`:: Use the average of all values as sort value. Only applicable
for number based array fields.
`median`:: Use the median of all values as sort value. Only applicable
for number based array fields.

===== Sort mode example usage

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.script.expression;

import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
import org.elasticsearch.index.fielddata.AtomicNumericFieldData;
import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;

/**
* FunctionValues to get the count of the number of values in a field for a document.
*/
public class CountMethodFunctionValues extends DoubleDocValues {
SortedNumericDoubleValues values;

CountMethodFunctionValues(ValueSource parent, AtomicNumericFieldData fieldData) {
super(parent);

values = fieldData.getDoubleValues();
}

@Override
public double doubleVal(int doc) {
values.setDocument(doc);
return values.count();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.script.expression;

import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
import org.elasticsearch.index.fielddata.AtomicFieldData;
import org.elasticsearch.index.fielddata.AtomicNumericFieldData;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.search.MultiValueMode;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;

/**
* A ValueSource to create FunctionValues to get the count of the number of values in a field for a document.
*/
public class CountMethodValueSource extends ValueSource {
protected IndexFieldData<?> fieldData;

protected CountMethodValueSource(IndexFieldData<?> fieldData) {
Objects.requireNonNull(fieldData);

this.fieldData = fieldData;
}

@Override
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
AtomicFieldData leafData = fieldData.load(leaf);
assert(leafData instanceof AtomicNumericFieldData);

return new CountMethodFunctionValues(this, (AtomicNumericFieldData)leafData);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

FieldDataValueSource that = (FieldDataValueSource) o;

return fieldData.equals(that.fieldData);
}

@Override
public int hashCode() {
return fieldData.hashCode();
}

@Override
public String description() {
return "count: field(" + fieldData.getFieldNames().toString() + ")";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@

import org.apache.lucene.queries.function.ValueSource;
import org.elasticsearch.index.fielddata.AtomicNumericFieldData;
import org.elasticsearch.search.MultiValueMode;

class DateMethodFunctionValues extends FieldDataFunctionValues {
private final int calendarType;
private final Calendar calendar;

DateMethodFunctionValues(ValueSource parent, AtomicNumericFieldData data, int calendarType) {
super(parent, data);
DateMethodFunctionValues(ValueSource parent, MultiValueMode multiValueMode, AtomicNumericFieldData data, int calendarType) {
super(parent, multiValueMode, data);

this.calendarType = calendarType;
calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ROOT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,35 @@
import org.elasticsearch.index.fielddata.AtomicFieldData;
import org.elasticsearch.index.fielddata.AtomicNumericFieldData;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.search.MultiValueMode;

class DateMethodValueSource extends FieldDataValueSource {

protected final String methodName;
protected final int calendarType;

DateMethodValueSource(IndexFieldData<?> indexFieldData, String methodName, int calendarType) {
super(indexFieldData);
DateMethodValueSource(IndexFieldData<?> indexFieldData, MultiValueMode multiValueMode, String methodName, int calendarType) {
super(indexFieldData, multiValueMode);

Objects.requireNonNull(methodName);

this.methodName = methodName;
this.calendarType = calendarType;
}

@Override
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
AtomicFieldData leafData = fieldData.load(leaf);
assert(leafData instanceof AtomicNumericFieldData);

return new DateMethodFunctionValues(this, multiValueMode, (AtomicNumericFieldData)leafData, calendarType);
}

@Override
public String description() {
return methodName + ": field(" + fieldData.getFieldNames().toString() + ")";
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand All @@ -64,17 +78,4 @@ public int hashCode() {
result = 31 * result + calendarType;
return result;
}

@Override
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
AtomicFieldData leafData = fieldData.load(leaf);
assert(leafData instanceof AtomicNumericFieldData);

return new DateMethodFunctionValues(this, (AtomicNumericFieldData)leafData, calendarType);
}

@Override
public String description() {
return methodName + ": field(" + fieldData.getFieldNames().toString() + ")";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptEngineService;
import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.MultiValueMode;
import org.elasticsearch.search.lookup.SearchLookup;

import java.text.ParseException;
Expand All @@ -60,6 +61,13 @@ public class ExpressionScriptEngineService extends AbstractComponent implements
protected static final String GET_MINUTES_METHOD = "getMinutes";
protected static final String GET_SECONDS_METHOD = "getSeconds";

protected static final String MINIMUM_METHOD = "min";
protected static final String MAXIMUM_METHOD = "max";
protected static final String AVERAGE_METHOD = "avg";
protected static final String MEDIAN_METHOD = "median";
protected static final String SUM_METHOD = "sum";
protected static final String COUNT_METHOD = "count";

@Inject
public ExpressionScriptEngineService(Settings settings) {
super(settings);
Expand Down Expand Up @@ -156,7 +164,7 @@ public SearchScript search(Object compiledScript, SearchLookup lookup, @Nullable

IndexFieldData<?> fieldData = lookup.doc().fieldDataService().getForField((NumberFieldMapper)field);
if (methodname == null) {
bindings.add(variable, new FieldDataValueSource(fieldData));
bindings.add(variable, new FieldDataValueSource(fieldData, MultiValueMode.MIN));
} else {
bindings.add(variable, getMethodValueSource(field, fieldData, fieldname, methodname));
}
Expand All @@ -180,6 +188,18 @@ protected ValueSource getMethodValueSource(FieldMapper<?> field, IndexFieldData<
return getDateMethodValueSource(field, fieldData, fieldName, methodName, Calendar.MINUTE);
case GET_SECONDS_METHOD:
return getDateMethodValueSource(field, fieldData, fieldName, methodName, Calendar.SECOND);
case MINIMUM_METHOD:
return new FieldDataValueSource(fieldData, MultiValueMode.MIN);
case MAXIMUM_METHOD:
return new FieldDataValueSource(fieldData, MultiValueMode.MAX);
case AVERAGE_METHOD:
return new FieldDataValueSource(fieldData, MultiValueMode.AVG);
case MEDIAN_METHOD:
return new FieldDataValueSource(fieldData, MultiValueMode.MEDIAN);
case SUM_METHOD:
return new FieldDataValueSource(fieldData, MultiValueMode.SUM);
case COUNT_METHOD:
return new CountMethodValueSource(fieldData);
default:
throw new IllegalArgumentException("Member method [" + methodName + "] does not exist.");
}
Expand All @@ -190,7 +210,7 @@ protected ValueSource getDateMethodValueSource(FieldMapper<?> field, IndexFieldD
throw new IllegalArgumentException("Member method [" + methodName + "] can only be used with a date field type, not the field [" + fieldName + "].");
}

return new DateMethodValueSource(fieldData, methodName, calendarType);
return new DateMethodValueSource(fieldData, MultiValueMode.MIN, methodName, calendarType);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@
class FieldDataFunctionValues extends DoubleDocValues {
NumericDoubleValues dataAccessor;

FieldDataFunctionValues(ValueSource parent, AtomicNumericFieldData d) {
FieldDataFunctionValues(ValueSource parent, MultiValueMode m, AtomicNumericFieldData d) {
super(parent);
dataAccessor = MultiValueMode.MIN.select(d.getDoubleValues(), 0d);
dataAccessor = m.select(d.getDoubleValues(), 0d);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.elasticsearch.index.fielddata.AtomicFieldData;
import org.elasticsearch.index.fielddata.AtomicNumericFieldData;
import org.elasticsearch.index.fielddata.IndexFieldData;
import org.elasticsearch.search.MultiValueMode;

import java.io.IOException;
import java.util.Map;
Expand All @@ -36,18 +37,14 @@
class FieldDataValueSource extends ValueSource {

protected IndexFieldData<?> fieldData;
protected MultiValueMode multiValueMode;

protected FieldDataValueSource(IndexFieldData<?> d) {
protected FieldDataValueSource(IndexFieldData<?> d, MultiValueMode m) {
Objects.requireNonNull(d);
Objects.requireNonNull(m);

fieldData = d;
}

@Override
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
AtomicFieldData leafData = fieldData.load(leaf);
assert(leafData instanceof AtomicNumericFieldData);
return new FieldDataFunctionValues(this, (AtomicNumericFieldData)leafData);
multiValueMode = m;
}

@Override
Expand All @@ -57,12 +54,23 @@ public boolean equals(Object o) {

FieldDataValueSource that = (FieldDataValueSource) o;

return fieldData.equals(that.fieldData);
if (!fieldData.equals(that.fieldData)) return false;
return multiValueMode == that.multiValueMode;

}

@Override
public int hashCode() {
return fieldData.hashCode();
int result = fieldData.hashCode();
result = 31 * result + multiValueMode.hashCode();
return result;
}

@Override
public FunctionValues getValues(Map context, LeafReaderContext leaf) throws IOException {
AtomicFieldData leafData = fieldData.load(leaf);
assert(leafData instanceof AtomicNumericFieldData);
return new FieldDataFunctionValues(this, multiValueMode, (AtomicNumericFieldData)leafData);
}

@Override
Expand Down
Loading