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

Returning nested data in fields API #67432

Merged
merged 31 commits into from
Feb 5, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
3269017
Group nested fields output for fields API
Jan 21, 2021
412bb74
Use mappingLookup to get nested object mappers
Jan 25, 2021
e757f95
iter, adding tests
Jan 25, 2021
5357649
checkstyle
Jan 25, 2021
b35c194
delegate nested mapping lookup
Jan 27, 2021
b201103
rename NestedValueFetcher
Jan 27, 2021
c342c64
only one fetchValues method
Jan 27, 2021
1d074b0
Remove unpacking of lists
Jan 27, 2021
f3b26b5
Merge branch 'master' into wip-63709
Jan 27, 2021
d569c50
Add dotted notation to yaml test
Jan 29, 2021
9fb1c2f
Fix field pattern problem and simplify resolution of nested fields
Feb 1, 2021
fab2286
Handle ignored_fields in ValueFetchers
Feb 1, 2021
2f9b645
Merge branch 'master' into wip-63709
Feb 1, 2021
c12dc54
iter
Feb 2, 2021
d23d3d2
don't pass null for ignored_fields in ValueFetcher calls
Feb 2, 2021
0f5df41
iter
Feb 2, 2021
99dae0d
fix yaml test for flattened fields with unmapped option
Feb 2, 2021
c197423
Merge branch 'master' into wip-63709
Feb 2, 2021
8a012a9
Merge branch 'master' into wip-63709
Feb 3, 2021
84c33e3
change license header for new class
Feb 3, 2021
4834760
pass on LeafReaderContext to internal FieldFetcher inside NestedValue…
Feb 3, 2021
9ba6920
muting running yaml test in runtime-fields/qa
Feb 3, 2021
8eaa6d3
Revert "muting running yaml test in runtime-fields/qa"
Feb 3, 2021
ea13fad
narrow scope of field resolving in nested field fetchers
Feb 3, 2021
0f999b1
Muting failing yaml test when run from x-pack/plugin/runtime-fields/qa
Feb 3, 2021
915b86e
iter minor changes
Feb 4, 2021
c8438e1
Fix handling of unmapped fields under nested fields
Feb 4, 2021
dc6760e
forbiddenapis
Feb 4, 2021
8f3d940
take out changed necessary for DocValueFetcher support
Feb 4, 2021
6833a84
Correct nested parent path lookup
Feb 4, 2021
3d6fb53
iter
Feb 4, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,275 @@ Test unmapped fields inside disabled objects:
- match:
hits.hits.0.fields.f1\.a:
- b
---
Test nested fields:
- skip:
version: ' - 7.99.99'
reason: support was introduced in 8.0.0 and not backported yet
- do:
indices.create:
index: test
body:
mappings:
properties:
products:
type: nested
properties:
manufacturer:
type: keyword
base_price:
type: double
product_id:
type: integer

- do:
index:
index: test
id: 1
refresh: true
body:
products:
- { "manufacturer" : "Supersoft", "base_price" : 1.55, "product_id" : 12345}
- { "manufacturer" : "HyperSmart", "base_price" : 20.20, "product_id" : 54321}

- do:
search:
index: test
body:
_source: false
fields: [ "*" ]
- length: { hits.hits.0.fields : 1 }
- match:
hits.hits.0.fields.products.0: { "manufacturer" : ["Supersoft"], "base_price" : [1.55], "product_id" : [12345]}
- match:
hits.hits.0.fields.products.1: { "manufacturer" : ["HyperSmart"], "base_price" : [20.20], "product_id" : [54321]}

- do:
search:
index: test
body:
_source: false
fields: ["products.manufacturer", "products.base_price"]
- length: { hits.hits.0.fields : 1 }
- match:
hits.hits.0.fields.products.0: { "manufacturer" : ["Supersoft"], "base_price" : [1.55]}
- match:
hits.hits.0.fields.products.1: { "manufacturer" : ["HyperSmart"], "base_price" : [20.20]}
---
Test nested field inside object structure:
jtibshirani marked this conversation as resolved.
Show resolved Hide resolved
- skip:
version: ' - 7.99.99'
reason: support was introduced in 8.0.0 and not backported yet
- do:
indices.create:
index: test
body:
mappings:
properties:
obj:
type: object
properties:
products:
type: nested
properties:
manufacturer:
type: keyword
base_price:
type: double
product_id:
type: integer
other_obj_field:
type: keyword

- do:
index:
index: test
id: 1
refresh: true
body:
obj:
products:
- { "manufacturer" : "Supersoft", "base_price" : 1.55, "product_id" : 12345}
- { "manufacturer" : "HyperSmart", "base_price" : 20.20, "product_id" : 54321}
other_obj_field: other_value

- do:
search:
index: test
body:
_source: false
fields: [ "*" ]
- length: { hits.hits.0.fields : 2 }
- match:
hits.hits.0.fields.obj\.products.0: { "manufacturer" : ["Supersoft"], "base_price" : [1.55], "product_id" : [12345]}
- match:
hits.hits.0.fields.obj\.products.1: { "manufacturer" : ["HyperSmart"], "base_price" : [20.20], "product_id" : [54321]}
- match:
hits.hits.0.fields.obj\.other_obj_field.0: other_value

- do:
search:
index: test
body:
_source: false
fields: ["obj.other_obj_field"]
- match:
hits.hits.0.fields.obj\.other_obj_field.0: other_value
---
Test doubly nested fields:
- skip:
version: ' - 7.99.99'
reason: support was introduced in 8.0.0 and not backported yet
- do:
indices.create:
index: test
body:
mappings:
properties:
id:
type: keyword
user:
type: nested
properties:
first:
type: keyword
last:
type: keyword
fields:
keyword:
type : keyword
address:
type: nested
- do:
index:
index: test
id: 1
refresh: true
body:
id: abcd1234
user:
- { "first" : "John", "address" : { "city" : "Berlin" }, "account" : { "size" : 1213 }}
- { "first" : "Alice", "last" : "White", "address" : [{ "city" : "Toronto", "zip" : "1111" },{ "city" : "Ottawa", "zip" : "2222" }]}
- { "first" : "John", "last" : "Snow" }

- do:
search:
index: test
body:
_source: false
fields: [ { "field" : "*" } ]
- match:
hits.hits.0.fields.id:
- abcd1234
- is_false: hits.hits.0.fields.user\.first
- is_false: hits.hits.0.fields.user\.last
- is_false: hits.hits.0.fields.user\.account\.size
- match:
hits.hits.0.fields.user.0: { "first" : [ "John" ], "address" : [{ "city" : ["Berlin"], "city.keyword" : ["Berlin"]}], "account.size" : [1213] }
- match:
hits.hits.0.fields.user.1: { "first" : [ "Alice" ], "last" : [ "White" ], "last.keyword" : [ "White" ], "address" : [ { "zip" : [ "1111" ], "zip.keyword" : [ "1111" ], "city" : [ "Toronto" ], "city.keyword" : [ "Toronto" ] }, { "zip" : ["2222"], "zip.keyword" : ["2222"], "city" : ["Ottawa"], "city.keyword" : [ "Ottawa" ]}] }
- match:
hits.hits.0.fields.user.2: { "first" : [ "John" ], "last" : [ "Snow" ], "last.keyword" : [ "Snow" ] }

- do:
search:
index: test
body:
_source: false
fields: [ { "field" : "user.address*" } ]

- match:
hits.hits.0.fields.user.0: { "address" : [{ "city" : ["Berlin"], "city.keyword" : ["Berlin"]}] }
- match:
hits.hits.0.fields.user.1: { "address" : [ { "zip" : [ "1111" ], "zip.keyword" : [ "1111" ], "city" : [ "Toronto" ], "city.keyword" : [ "Toronto" ] }, { "zip" : ["2222"], "zip.keyword" : ["2222"], "city" : ["Ottawa"], "city.keyword" : [ "Ottawa" ]}] }
- length: { hits.hits.0.fields.user : 2 }

---
Test nested fields with unmapped subfields:
- skip:
version: ' - 7.99.99'
reason: support was introduced in 8.0.0 and not backported yet
- do:
indices.create:
index: test
body:
mappings:
properties:
id:
type: keyword
user:
type: nested
properties:
first:
type: keyword
address:
type: object
enabled: false
- do:
index:
index: test
id: 1
refresh: true
body:
id: abcd1234
user:
- { "first" : "John", "address" : { "city" : "Berlin" }}

- do:
search:
index: test
body:
_source: false
fields:
- { "field" : "*", "include_unmapped" : true }
- match:
hits.hits.0.fields.id:
- abcd1234
- is_false: hits.hits.0.fields.user\.first
- is_false: hits.hits.0.fields.user\.last
- is_false: hits.hits.0.fields.user\.account\.size
- match:
hits.hits.0.fields.user.0: { "first" : [ "John" ], "address.city" : ["Berlin"]}
---
Test nested fields with ignored subfields:
cbuescher marked this conversation as resolved.
Show resolved Hide resolved
- skip:
version: ' - 7.99.99'
reason: support was introduced in 8.0.0 and not backported yet
- do:
indices.create:
index: test
body:
mappings:
properties:
malformed_outside:
type: integer
ignore_malformed: true
user:
type: nested
properties:
malformed_inside:
type: integer
ignore_malformed: true
first:
type: keyword
- do:
index:
index: test
id: 1
refresh: true
body:
malformed_outside : "bad_value_1"
user:
- { "first" : "John", "malformed_inside" : "bad_value_2"}

- do:
search:
index: test
body:
_source: false
fields:
- { "field" : "*", "include_unmapped" : true }
- is_false: hits.hits.0.fields.malformed_outside
- match:
hits.hits.0.fields.user:
- { "first" : [ "John" ] }
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,10 @@ public void testSimpleNested() throws Exception {
assertThat(innerHits.getAt(0).getHighlightFields().get("comments.message").getFragments()[0].string(),
equalTo("<em>fox</em> eat quick"));
assertThat(innerHits.getAt(0).getExplanation().toString(), containsString("weight(comments.message:fox in"));
assertThat(innerHits.getAt(0).getFields().get("comments.message").getValue().toString(), equalTo("fox eat quick"));
assertThat(
innerHits.getAt(0).getFields().get("comments").getValue(),
equalTo(Collections.singletonMap("message", Collections.singletonList("fox eat quick")))
);
cbuescher marked this conversation as resolved.
Show resolved Hide resolved
assertThat(innerHits.getAt(0).getFields().get("script").getValue().toString(), equalTo("5"));

response = client().prepareSearch("articles")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -121,6 +122,32 @@ public static Object extractValue(Map<?, ?> map, String... pathElements) {
return XContentMapValues.extractValue(pathElements, 0, map, null);
}

/**
* For the provided nested path, return its value in the xContent map.
*
* @param nestedPath the nested field value's path in the map.
*
* @return the list associated with the path in the map or {@code null} if the path does not exits.
*/
@SuppressWarnings("unchecked")
public static List<?> extractNestedValue(String nestedPath, Map<?, ?> map) {
Object extractedValue = XContentMapValues.extractValue(nestedPath, map);
List<?> nestedParsedSource = null;
if (extractedValue != null) {
if (extractedValue instanceof List) {
// nested field has an array value in the _source
nestedParsedSource = (List<?>) extractedValue;
} else if (extractedValue instanceof Map) {
// nested field has an object value in the _source. This just means the nested field has just one inner object,
// which is valid, but uncommon.
nestedParsedSource = Collections.singletonList(extractedValue);
} else {
throw new IllegalStateException("extracted source isn't an object or an array");
}
}
return nestedParsedSource;
}

/**
* For the provided path, return its value in the xContent map.
*
Expand Down
Loading