浏览代码

FunctionScore should work on unampped fields when missing parameter is specified

André Carvalho 10 年之前
父节点
当前提交
345b2b98cf

+ 14 - 3
core/src/main/java/org/elasticsearch/common/lucene/search/function/FieldValueFactorFunction.java

@@ -54,13 +54,24 @@ 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 = null;
+        } else {
+            values = this.indexFieldData.load(ctx).getDoubleValues();
+        }
+
         return new LeafScoreFunction() {
 
             @Override
             public double score(int docId, float subQueryScore) {
-                values.setDocument(docId);
-                final int numValues = values.count();
+                final int numValues;
+                if(values == null){
+                    numValues = 0;
+                } else {
+                    values.setDocument(docId);
+                    numValues = values.count();
+                }
                 double value;
                 if (numValues > 0) {
                     value = values.valueAt(0);

+ 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")