Browse Source

Core: Fix script fields to be returned as a multivalued field when they produce a list.

This change is essentially the same as #3015 but on script fields.

Close #8592
Adrien Grand 11 years ago
parent
commit
8346e92ebb

+ 32 - 0
docs/reference/migration/migrate_2_0.asciidoc

@@ -56,3 +56,35 @@ The `memory` / `ram` store (`index.store.type`) option was removed in Elasticsea
 === Term Vectors API
 
 Usage of `/_termvector` is deprecated, and replaced in favor of `/_termvectors`.
+
+=== Script fields
+
+Script fields in 1.x were only returned as a single value. So even if the return
+value of a script used to be list, it would be returned as an array containing
+a single value that is a list too, such as:
+
+[source,json]
+---------------
+"fields": {
+  "my_field": [
+    [
+      "v1",
+      "v2"
+    ]
+  ]
+}
+---------------
+
+In elasticsearch 2.x, scripts that return a list of values are considered as
+multivalued fields. So the same example would return the following response,
+with values in a single array.
+
+[source,json]
+---------------
+"fields": {
+  "my_field": [
+    "v1",
+    "v2"
+  ]
+}
+---------------

+ 13 - 2
src/main/java/org/elasticsearch/search/fetch/script/ScriptFieldsFetchSubPhase.java

@@ -19,6 +19,7 @@
 package org.elasticsearch.search.fetch.script;
 
 import com.google.common.collect.ImmutableMap;
+
 import org.elasticsearch.ElasticsearchException;
 import org.elasticsearch.common.inject.Inject;
 import org.elasticsearch.search.SearchHitField;
@@ -29,7 +30,10 @@ import org.elasticsearch.search.internal.InternalSearchHitField;
 import org.elasticsearch.search.internal.SearchContext;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -86,10 +90,17 @@ public class ScriptFieldsFetchSubPhase implements FetchSubPhase {
 
             SearchHitField hitField = hitContext.hit().fields().get(scriptField.name());
             if (hitField == null) {
-                hitField = new InternalSearchHitField(scriptField.name(), new ArrayList<>(2));
+                final List<Object> values;
+                if (value == null) {
+                    values = Collections.emptyList();
+                } else if (value instanceof Collection) {
+                    values = new ArrayList<>((Collection<?>) value);
+                } else {
+                    values = Collections.singletonList(value);
+                }
+                hitField = new InternalSearchHitField(scriptField.name(), values);
                 hitContext.hit().fields().put(scriptField.name(), hitField);
             }
-            hitField.values().add(value);
         }
     }
 }

+ 1 - 1
src/test/java/org/elasticsearch/script/IndexLookupTests.java

@@ -385,7 +385,7 @@ public class IndexLookupTests extends ElasticsearchIntegrationTest {
         assertHitCount(sr, expectedHitSize);
         int nullCounter = 0;
         for (SearchHit hit : sr.getHits().getHits()) {
-            Object result = hit.getFields().get("tvtest").getValues().get(0);
+            Object result = hit.getFields().get("tvtest").getValues();
             Object expectedResult = expectedArray.get(hit.getId());
             assertThat("for doc " + hit.getId(), result, equalTo(expectedResult));
             if (expectedResult != null) {

+ 2 - 2
src/test/java/org/elasticsearch/search/fields/SearchFieldsTests.java

@@ -298,12 +298,12 @@ public class SearchFieldsTests extends ElasticsearchIntegrationTest {
         assertThat(sObj2Arr2.get(0).toString(), equalTo("arr_value1"));
         assertThat(sObj2Arr2.get(1).toString(), equalTo("arr_value2"));
 
-        sObj2Arr2 = response.getHits().getAt(0).field("s_obj2_arr2").value();
+        sObj2Arr2 = response.getHits().getAt(0).field("s_obj2_arr2").values();
         assertThat(sObj2Arr2.size(), equalTo(2));
         assertThat(sObj2Arr2.get(0).toString(), equalTo("arr_value1"));
         assertThat(sObj2Arr2.get(1).toString(), equalTo("arr_value2"));
 
-        List sObj2Arr3 = response.getHits().getAt(0).field("s_arr3").value();
+        List sObj2Arr3 = response.getHits().getAt(0).field("s_arr3").values();
         assertThat(((Map) sObj2Arr3.get(0)).get("arr3_field1").toString(), equalTo("arr3_value1"));
     }