Explorar o código

Merge pull request #13060 from andrestc/enhancement/functionscore-unmapped

Make FunctionScore work on unmapped field with `missing` parameter
Adrien Grand %!s(int64=10) %!d(string=hai) anos
pai
achega
f0b7fa2f31

+ 8 - 1
core/src/main/java/org/elasticsearch/common/lucene/search/function/FieldValueFactorFunction.java

@@ -22,6 +22,7 @@ package org.elasticsearch.common.lucene.search.function;
 import org.apache.lucene.index.LeafReaderContext;
 import org.apache.lucene.search.Explanation;
 import org.elasticsearch.ElasticsearchException;
+import org.elasticsearch.index.fielddata.FieldData;
 import org.elasticsearch.index.fielddata.IndexNumericFieldData;
 import org.elasticsearch.index.fielddata.SortedNumericDoubleValues;
 
@@ -54,7 +55,13 @@ public class FieldValueFactorFunction extends ScoreFunction {
 
     @Override
     public LeafScoreFunction getLeafScoreFunction(LeafReaderContext ctx) {
-        final SortedNumericDoubleValues values = this.indexFieldData.load(ctx).getDoubleValues();
+        final SortedNumericDoubleValues values;
+        if(indexFieldData == null) {
+            values = FieldData.emptySortedNumericDoubles(ctx.reader().maxDoc());
+        } else {
+            values = this.indexFieldData.load(ctx).getDoubleValues();
+        }
+
         return new LeafScoreFunction() {
 
             @Override

+ 9 - 3
core/src/main/java/org/elasticsearch/index/query/functionscore/fieldvaluefactor/FieldValueFactorFunctionParser.java

@@ -19,11 +19,13 @@
 
 package org.elasticsearch.index.query.functionscore.fieldvaluefactor;
 
+import org.apache.lucene.document.FieldType;
 import org.elasticsearch.ElasticsearchException;
 import org.elasticsearch.common.lucene.search.function.FieldValueFactorFunction;
 import org.elasticsearch.common.lucene.search.function.ScoreFunction;
 import org.elasticsearch.common.xcontent.XContentParser;
 import org.elasticsearch.index.fielddata.IndexNumericFieldData;
+import org.elasticsearch.index.fielddata.plain.DoubleArrayIndexFieldData;
 import org.elasticsearch.index.mapper.FieldMapper;
 import org.elasticsearch.index.mapper.MappedFieldType;
 import org.elasticsearch.index.query.QueryParseContext;
@@ -86,11 +88,15 @@ public class FieldValueFactorFunctionParser implements ScoreFunctionParser {
 
         SearchContext searchContext = SearchContext.current();
         MappedFieldType fieldType = searchContext.mapperService().smartNameFieldType(field);
+        IndexNumericFieldData fieldData = null;
         if (fieldType == null) {
-            throw new ElasticsearchException("Unable to find a field mapper for field [" + field + "]");
+            if(missing == null) {
+                throw new ElasticsearchException("Unable to find a field mapper for field [" + field + "]. No 'missing' value defined.");
+            }
+        } else {
+            fieldData = searchContext.fieldData().getForField(fieldType);
         }
-        return new FieldValueFactorFunction(field, boostFactor, modifier, missing,
-                (IndexNumericFieldData)searchContext.fieldData().getForField(fieldType));
+        return new FieldValueFactorFunction(field, boostFactor, modifier, missing, fieldData);
     }
 
     @Override

+ 9 - 0
core/src/test/java/org/elasticsearch/search/functionscore/FunctionScoreFieldValueIT.java

@@ -104,6 +104,15 @@ public class FunctionScoreFieldValueIT extends ESIntegTestCase {
                 .get();
         assertOrderedSearchHits(response, "1", "2", "3");
 
+        // field is not mapped but we're defaulting it to 100 so all documents should have the same score
+        response = client().prepareSearch("test")
+                .setExplain(randomBoolean())
+                .setQuery(functionScoreQuery(matchAllQuery(),
+                        fieldValueFactorFunction("notmapped").modifier(FieldValueFactorFunction.Modifier.RECIPROCAL).missing(100)))
+                .get();
+        assertEquals(response.getHits().getAt(0).score(), response.getHits().getAt(2).score(), 0);
+
+
         // n divided by 0 is infinity, which should provoke an exception.
         try {
             response = client().prepareSearch("test")