Browse Source

Support source fallback for byte, short, and long fields (#88954)

This change adds source fallback support for byte, short, and long fields. These use the already 
existing class SourceValueFetcherSortedNumericIndexFieldData.
Jack Conradson 3 years ago
parent
commit
5194d29b1c

+ 5 - 0
docs/changelog/88954.yaml

@@ -0,0 +1,5 @@
+pr: 88954
+summary: "Support source fallback for byte, short, and long fields"
+area: Mapping
+type: enhancement
+issues: []

+ 370 - 4
modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/50_script_doc_values.yml

@@ -16,8 +16,8 @@ setup:
                         geo_point:
                             type: geo_point
                         geo_point_no_doc_values:
-                          type: geo_point
-                          doc_values: false
+                            type: geo_point
+                            doc_values: false
                         ip:
                             type: ip
                         keyword:
@@ -27,15 +27,24 @@ setup:
                             doc_values: false
                         long:
                             type: long
+                        long_no_doc_values:
+                            type: long
+                            doc_values: false
                         integer:
                             type: integer
                         integer_no_doc_values:
-                          type: integer
-                          doc_values: false
+                            type: integer
+                            doc_values: false
                         short:
                             type: short
+                        short_no_doc_values:
+                            type: short
+                            doc_values: false
                         byte:
                             type: byte
+                        byte_no_doc_values:
+                            type: byte
+                            doc_values: false
                         double:
                             type: double
                         float:
@@ -69,10 +78,13 @@ setup:
                 keyword: not split at all
                 keyword_no_doc_values: no doc values
                 long: 12348732141234
+                long_no_doc_values: 12348732141234
                 integer: 134134566
                 integer_no_doc_values: 134134566
                 short: 1324
+                short_no_doc_values: 1324
                 byte: 12
+                byte_no_doc_values: 12
                 double: 3.14159265358979
                 float: 3.141592654
                 half_float: 3.140625
@@ -101,10 +113,13 @@ setup:
               keyword: ["one string", "another string"]
               keyword_no_doc_values: ["no doc values 1", "no doc values 0", "no doc values 2"]
               long: [1152921504606846976, 576460752303423488]
+              long_no_doc_values: [576460752303423488, 1152921504606846976, -1152921504606846976]
               integer: [5, 17, 29]
               integer_no_doc_values: [17, 29, 5]
               short: [6, 18, 30, 45]
+              short_no_doc_values: [30, 45, 18, 6]
               byte: [16, 32, 64, 8, 4]
+              byte_no_doc_values: [16, 8, 32, 4, 64]
               double: [3.141592653588, 2.141592653587]
               float: [1.123, 2.234]
               half_float: [1.123, 2.234]
@@ -1081,6 +1096,84 @@ setup:
                             source: "doc['long'].value"
     - match: { hits.hits.0.fields.field.0: 12348732141234 }
 
+---
+"long_no_doc_values":
+  - do:
+      catch: bad_request
+      search:
+        rest_total_hits_as_int: true
+        body:
+          query: { term: { _id: "1" } }
+          script_fields:
+            field:
+              script:
+                source: "doc['long_no_doc_values'].get(0)"
+  - match: { error.failed_shards.0.reason.caused_by.type: "illegal_argument_exception" }
+
+  - do:
+      catch: bad_request
+      search:
+        rest_total_hits_as_int: true
+        body:
+          query: { term: { _id: "1" } }
+          script_fields:
+            field:
+              script:
+                source: "doc['long_no_doc_values'].value"
+  - match: { error.failed_shards.0.reason.caused_by.type: "illegal_argument_exception" }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "field('long_no_doc_values').get(-1)"
+  - match: { hits.hits.0.fields.field.0: 12348732141234 }
+  - match: { hits.hits.1.fields.field.0: -1 }
+  - match: { hits.hits.2.fields.field.0: -1152921504606846976 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "/* avoid yaml stash */ $('long_no_doc_values', -1)"
+  - match: { hits.hits.0.fields.field.0: 12348732141234 }
+  - match: { hits.hits.1.fields.field.0: -1 }
+  - match: { hits.hits.2.fields.field.0: -1152921504606846976 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "field('long_no_doc_values').get(2, -3)"
+  - match: { hits.hits.0.fields.field.0: -3 }
+  - match: { hits.hits.1.fields.field.0: -3 }
+  - match: { hits.hits.2.fields.field.0: 1152921504606846976 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "long total = 0; for (long i : field('long_no_doc_values')) { total += i; } total + field('long_no_doc_values').size();"
+  - match: { hits.hits.0.fields.field.0: 12348732141235 }
+  - match: { hits.hits.1.fields.field.0: 0 }
+  - match: { hits.hits.2.fields.field.0: 576460752303423491 }
+
 ---
 "integer":
     - do:
@@ -1342,6 +1435,123 @@ setup:
     - match: { hits.hits.1.fields.field.0: 0 }
     - match: { hits.hits.2.fields.field.0: 103 }
 
+---
+"short_no_doc_values":
+  - do:
+      catch: bad_request
+      search:
+        rest_total_hits_as_int: true
+        body:
+          query: { term: { _id: "1" } }
+          script_fields:
+            field:
+              script:
+                source: "doc['short_no_doc_values'].get(0)"
+  - match: { error.failed_shards.0.reason.caused_by.type: "illegal_argument_exception" }
+
+  - do:
+      catch: bad_request
+      search:
+        rest_total_hits_as_int: true
+        body:
+          query: { term: { _id: "1" } }
+          script_fields:
+            field:
+              script:
+                source: "doc['short_no_doc_values'].value"
+  - match: { error.failed_shards.0.reason.caused_by.type: "illegal_argument_exception" }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "field('short_no_doc_values').get(-1)"
+  - match: { hits.hits.0.fields.field.0: 1324 }
+  - match: { hits.hits.1.fields.field.0: -1 }
+  - match: { hits.hits.2.fields.field.0: 6 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "/* avoid yaml stash */ $('short_no_doc_values', -1)"
+  - match: { hits.hits.0.fields.field.0: 1324 }
+  - match: { hits.hits.1.fields.field.0: -1 }
+  - match: { hits.hits.2.fields.field.0: 6 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "short defaultShort = -1; field('short_no_doc_values').get(defaultShort)"
+  - match: { hits.hits.0.fields.field.0: 1324 }
+  - match: { hits.hits.1.fields.field.0: -1 }
+  - match: { hits.hits.2.fields.field.0: 6 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "short defaultShort = -1; $('short_no_doc_values', defaultShort)"
+  - match: { hits.hits.0.fields.field.0: 1324 }
+  - match: { hits.hits.1.fields.field.0: -1 }
+  - match: { hits.hits.2.fields.field.0: 6 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "field('short_no_doc_values').get(1, -3)"
+  - match: { hits.hits.0.fields.field.0: -3 }
+  - match: { hits.hits.1.fields.field.0: -3 }
+  - match: { hits.hits.2.fields.field.0: 18 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "short defaultShort = -3; field('short_no_doc_values').get(1, defaultShort)"
+  - match: { hits.hits.0.fields.field.0: -3 }
+  - match: { hits.hits.1.fields.field.0: -3 }
+  - match: { hits.hits.2.fields.field.0: 18 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "int total = 0; for (short s : field('short_no_doc_values')) { total += s; } total + field('short_no_doc_values').size();"
+  - match: { hits.hits.0.fields.field.0: 1325 }
+  - match: { hits.hits.1.fields.field.0: 0 }
+  - match: { hits.hits.2.fields.field.0: 103 }
+
 ---
 "byte":
     - do:
@@ -1496,6 +1706,162 @@ setup:
     - match: { hits.hits.1.fields.field.0: 0 }
     - match: { hits.hits.2.fields.field.0: 129 }
 
+---
+"byte_no_doc_values":
+  - do:
+      catch: bad_request
+      search:
+        rest_total_hits_as_int: true
+        body:
+          query: { term: { _id: "1" } }
+          script_fields:
+            field:
+              script:
+                source: "doc['byte_no_doc_values'].get(0)"
+  - match: { error.failed_shards.0.reason.caused_by.type: "illegal_argument_exception" }
+
+  - do:
+      catch: bad_request
+      search:
+        rest_total_hits_as_int: true
+        body:
+          query: { term: { _id: "1" } }
+          script_fields:
+            field:
+              script:
+                source: "doc['byte_no_doc_values'].value"
+  - match: { error.failed_shards.0.reason.caused_by.type: "illegal_argument_exception" }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "field('byte_no_doc_values').get((byte) 5)"
+  - match: { hits.hits.0.fields.field.0: 12 }
+  - match: { hits.hits.1.fields.field.0: 5 }
+  - match: { hits.hits.2.fields.field.0: 4 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "/* avoid yaml stash */ $('byte_no_doc_values', (byte) 5)"
+  - match: { hits.hits.0.fields.field.0: 12 }
+  - match: { hits.hits.1.fields.field.0: 5 }
+  - match: { hits.hits.2.fields.field.0: 4 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "byte defaultByte = 5; field('byte_no_doc_values').get(defaultByte)"
+  - match: { hits.hits.0.fields.field.0: 12 }
+  - match: { hits.hits.1.fields.field.0: 5 }
+  - match: { hits.hits.2.fields.field.0: 4 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "byte defaultByte = 5; $('byte_no_doc_values', defaultByte)"
+  - match: { hits.hits.0.fields.field.0: 12 }
+  - match: { hits.hits.1.fields.field.0: 5 }
+  - match: { hits.hits.2.fields.field.0: 4 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "field('byte_no_doc_values').get(5)"
+  - match: { hits.hits.0.fields.field.0: 12 }
+  - match: { hits.hits.1.fields.field.0: 5 }
+  - match: { hits.hits.2.fields.field.0: 4 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "/* avoid yaml stash */ $('byte_no_doc_values', 5)"
+  - match: { hits.hits.0.fields.field.0: 12 }
+  - match: { hits.hits.1.fields.field.0: 5 }
+  - match: { hits.hits.2.fields.field.0: 4 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "field('byte_no_doc_values').get(1, (byte) 7)"
+  - match: { hits.hits.0.fields.field.0: 7 }
+  - match: { hits.hits.1.fields.field.0: 7 }
+  - match: { hits.hits.2.fields.field.0: 8 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "byte defaultByte = 7; field('byte_no_doc_values').get(1, defaultByte)"
+  - match: { hits.hits.0.fields.field.0: 7 }
+  - match: { hits.hits.1.fields.field.0: 7 }
+  - match: { hits.hits.2.fields.field.0: 8 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "field('byte_no_doc_values').get(1, 7)"
+  - match: { hits.hits.0.fields.field.0: 7 }
+  - match: { hits.hits.1.fields.field.0: 7 }
+  - match: { hits.hits.2.fields.field.0: 8 }
+
+  - do:
+      search:
+        rest_total_hits_as_int: true
+        body:
+          sort: [ { rank: asc } ]
+          script_fields:
+            field:
+              script:
+                source: "int total = 0; for (byte s : field('byte_no_doc_values')) { total += s; } total + field('byte_no_doc_values').size();"
+  - match: { hits.hits.0.fields.field.0: 13 }
+  - match: { hits.hits.1.fields.field.0: 0 }
+  - match: { hits.hits.2.fields.field.0: 129 }
+
 ---
 "double":
     - do:

+ 45 - 0
server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java

@@ -708,6 +708,21 @@ public class NumberFieldMapper extends FieldMapper {
                 return new SortedNumericIndexFieldData.Builder(name, numericType(), ByteDocValuesField::new);
             }
 
+            @Override
+            public IndexFieldData.Builder getValueFetcherFieldDataBuilder(
+                String name,
+                SourceLookup sourceLookup,
+                ValueFetcher valueFetcher
+            ) {
+                return new SourceValueFetcherSortedNumericIndexFieldData.Builder(
+                    name,
+                    numericType().getValuesSourceType(),
+                    valueFetcher,
+                    sourceLookup,
+                    ByteDocValuesField::new
+                );
+            }
+
             @Override
             SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName) {
                 return NumberType.syntheticLongFieldLoader(fieldName, fieldSimpleName);
@@ -781,6 +796,21 @@ public class NumberFieldMapper extends FieldMapper {
                 return new SortedNumericIndexFieldData.Builder(name, numericType(), ShortDocValuesField::new);
             }
 
+            @Override
+            public IndexFieldData.Builder getValueFetcherFieldDataBuilder(
+                String name,
+                SourceLookup sourceLookup,
+                ValueFetcher valueFetcher
+            ) {
+                return new SourceValueFetcherSortedNumericIndexFieldData.Builder(
+                    name,
+                    numericType().getValuesSourceType(),
+                    valueFetcher,
+                    sourceLookup,
+                    ShortDocValuesField::new
+                );
+            }
+
             @Override
             SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName) {
                 return NumberType.syntheticLongFieldLoader(fieldName, fieldSimpleName);
@@ -1046,6 +1076,21 @@ public class NumberFieldMapper extends FieldMapper {
                 return new SortedNumericIndexFieldData.Builder(name, numericType(), LongDocValuesField::new);
             }
 
+            @Override
+            public IndexFieldData.Builder getValueFetcherFieldDataBuilder(
+                String name,
+                SourceLookup sourceLookup,
+                ValueFetcher valueFetcher
+            ) {
+                return new SourceValueFetcherSortedNumericIndexFieldData.Builder(
+                    name,
+                    numericType().getValuesSourceType(),
+                    valueFetcher,
+                    sourceLookup,
+                    LongDocValuesField::new
+                );
+            }
+
             @Override
             SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String fieldName, String fieldSimpleName) {
                 return syntheticLongFieldLoader(fieldName, fieldSimpleName);