ElasticSearch: Multi-level nested query "AND" syntax - elasticsearch

I've got an index similar to the example index shown in the elasticsearch doc multi-level nested query example:
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-nested-query.html#multi-level-nested-query-ex
Given these example docs:
{
"driver" : {
"last_name" : "McQueen",
"vehicle" : [
{
"make" : "Powell Motors",
"model" : "Canyonero"
},
{
"make" : "Miller-Meteor",
"model" : "Ecto-1"
}
]
}
}
{
"driver" : {
"last_name" : "Hudson",
"vehicle" : [
{
"make" : "Mifune",
"model" : "Mach Five"
},
{
"make" : "Miller-Meteor",
"model" : "Ecto-1"
}
]
}
}
I need to be able to find documents where the driver.vehicle.make matches two values, i.e. the driver who has both vehicle makes "Powell Motors" and "Miller-meteor" should match McQueen but not Hudson.
I've tried a query similar to the doc example's make and model query, but it returns 0 docs:
{
"query": {
"nested": {
"path": "driver",
"query": {
"nested": {
"path": "driver.vehicle",
"query": {
"bool": {
"must": [
{ "match": { "driver.vehicle.make": "Powell Motors" } },
{ "match": { "driver.vehicle.make": "Miller-Meteor" } }
]
}
}
}
}
}
}
}
Changing the "must" to a "should" returns both docs. I can't seem to find a query that will query the vehicle array for multiple value matches in the same doc.

The above query returns 0 documents, as there is no single document (inside driver.vehicle) in your example that has driver.vehicle.make value as "Powell Motors" and "Miller-meteor".
Note: Here single documents refer to each individual documents (or objects) inside driver.vehicle.
Therefore, when you are changing the must clause to should clause it returns those documents (in this case both the doc), that have driver.vehicle.make value as "Powell Motors" OR "Miller-meteor". must works as logical AND operator, and should works as logical OR operator.
According to your requirement, I believe you want those documents where driver who has vehicle makes "Powell Motors" OR "Miller-meteor" should match McQueen but not Hudson.
In this case, you need to combine a nested query with a normal query, which can be done using a bool query.
Your modified query will be
{
"query": {
"nested": {
"path": "driver",
"query": {
"bool": {
"must": [
{
"match": {
"driver.last_name": "McQueen"
}
},
{
"nested": {
"path": "driver.vehicle",
"query": {
"bool": {
"should": [
{
"match": {
"driver.vehicle.make": "Powell Motors"
}
},
{
"match": {
"driver.vehicle.make": "Miller-Meteor"
}
}
]
}
}
}
}
]
}
}
}
}
}
And the search result will be
"hits" : [
{
"_index" : "soidx1",
"_type" : "_doc",
"_id" : "1",
"_score" : 3.105637,
"_source" : {
"driver" : {
"last_name" : "McQueen",
"vehicle" : [
{
"make" : "Powell Motors",
"model" : "Canyonero"
},
{
"make" : "Miller-Meteor",
"model" : "Ecto-1"
}
]
}
}
}
]

Related

Search multi field with term query

I have some documents in a index..
"hits" : [
{
"_index" : "siem-referencedata-table-table2d526444eff99b1706053853ef7",
"_type" : "_doc",
"_id" : "0table222cc244b04b59d9ecafb0476e6",
"_score" : 1.0,
"_source" : {
"column-name1" : "10.1.10.1",
"column-name2" : "range(100,200)",
"column-name3" : "nam3",
"create_time" : "2022-05-21 03:30:39",
"last_seen" : "2022-05-21 03:30:39",
"id" : "0table222cc244b04b59d9ecafb0476e6"
}
},...
I want to search documents with three fields column-name1, column-name2 and column-name3.
I use below query with term to search exact considered word:
{
"query": {
"bool": {
"must": [
{
"term": {
"column-name1": {"value":"10.1.10.1"}
}
},
{
"term": {
"column-name2": {"value":"range(100,200)"}
}
},
{
"term": {
"column-name3": {"value":"nam3"}
}
}
]
}
}
}
It works without "column-name2": {"value":"range(100,200)"}.. what should I do with range ability? Is there another way to handle this?
The query solved with adding keyword to filed as below:
{
"query": {
"bool": {
"must": [
{
"term": {
"column-name1.keyword": {"value":"10.1.10.1"}
}
},
{
"term": {
"column-name2.keyword": {"value":"range(100,200)"}
}
},
{
"term": {
"column-name3.keyword": {"value":"nam3"}
}
}
]
}
}
}
Thank from Barkha Jain!

How to search first element in array in elasticsearch?

I want to search an object on only the first element in an array and ignore the rest.
For example, for data below if I wanted to only search the model for the first element in the vehicle array.
{
"drivers" : [
{
"last_name" : "McQueen",
"vehicle" : [
{
"make" : "Powell Motors",
"model" : "Canyonero"
},
{
"make" : "Miller-Meteor",
"model" : "Ecto-1"
}
]
},
{
"last_name" : "Buzz",
"vehicle" : [
{
"make" : "Powell Motors",
"model" : "Canyonero"
},
{
"make" : "Miller-Meteor",
"model" : "Ecto-1"
}
]
}
}
I know I can do a nested query like this but the problem here is that all the vehicles are searched. I only want the 0th element in the vehicle list to be searched and the rest to be ignored.
{
"query": {
"nested": {
"path": "driver",
"query": {
"nested": {
"path": "driver.vehicle",
"query": {
"bool": {
"must": [
{ "match": { "drivers.vehicle.model": "Canyonero" } }
]
}
}
}
}
}
}
}
Ideally I want something like { drivers.vehicle[0].model": "Canyonero" } to search for the first vehicle in the list everytime. Is there any way I can effectively do this?
Check out this answer -- doing this is certainly possible but quite onerous.
I'd instead recommend using
ingest pipelines whereby the first vehicle will be extracted to a new root-level field or
updating by query where you do the same as above but execute at will as opposed to only upon ingest.

Search Documents Containing Certain Nested Objects in Elasticsearch

My documents in Elasticsearch index have following format:
{
timestamp: "123456789",
tags: [
{ key:"tag1", "value": "val1" }, ...
]
}
I want get all documents which contain for example { key:"tag1" } and { key:"tag2", "value": "val2" } in their tags field.
How can I do this?
You can try with a bool query, where you specify how many nested query you need in the must section:
GET test_nested/test/_search
{
"query": {
"bool": {
"must": [
{"nested" : {
"path" : "tags",
"query" : {
"bool" : {
"must" : [
{ "match" : {"tags.key" : "tag1"} }
]
}
}
}},
{"nested" : {
"path" : "tags",
"query" : {
"bool" : {
"must" : [
{ "match" : {"tags.key" : "tag2"} },
{ "match" : {"tags.value" : "val2"} }
]
}
}
}}
]
}
}
}
In this case i have one nested query for selecting all documents with key "tag1" and the second nested query to select all documents with the "tag2" and "value2".

Elasticsearch: How to get an exact match in a nested field

The mapping contains nested fields which shouldn't be analyzed (not sure if the 'not_analyzed' value is accurate). Is it possible to do an exact match on a nested field? In the query below the "metadata.value": "2014.NWJSD.47" still gets analyzed. Elasticsearch breaks up the string into several terms ("2014", "NWJSD", "47"). I tried to use "term" instead of "match" but this didn't return any result.
"mappings" : {
"metadata" : {
"type" : "nested",
"properties" : {
"name" : {
"type" : "text",
"index" : "not_analyzed"
},
"value" : {
"type" : "text",
"index" : "not_analyzed"
}
}
}
}
The Query:
"query": {
"bool": {
"must": [
{
"nested": {
"path": "metadata",
"query": {
"bool": {
"must": [
{
"match": {
"metadata.name": "number"
}
},
{
"match": {
"metadata.value": "2014.NWJSD.47"
}
}
]
}
}
}
}
]
}
}
Try to use keyword instead of text in your mapping like:
{
"mappings": {
"your_type_name": {
"properties": {
"metadata" : {
"type" : "nested",
"properties" : {
"name" : {
"type" : "keyword"
},
"value" : {
"type" :"keyword"
}
}
}
}
}
}
}
These fields won't be analyzed. Then you should reindex your data and to query your data you should replace match (which is analyzed query) with term.
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "metadata",
"query": {
"bool": {
"must": [
{
"term": {
"metadata.name": "number"
}
},
{
"term": {
"metadata.value": "2014.NWJSD.47"
}
}
]
}
}
}
}
]
}
}
}
I think you are looking for a query string query.
You can freely disable "analyze" option for that field in mapping option and reindex everything again but you could also check this query out:
as written here:
GET /_search
{
"query": {
"query_string" : {
"query" : "your string"
}
}
}

Highlighting on has_child query

In some of our types, we have a parent child setup and we want to search on parent fields and also on the child fields (and return parent) and we do query like below. When there is a has_child match is there any way to get highlighting information from the child match even though the parent is being returned. As an example, if we have mapping like the following:
PUT nested2
{
"mappings":{
"discussion":{
"properties" : {
"title":{
"type":"string"
}
}
},
"discussionPost":{
"_parent":{
"type" : "discussion"
},
"properties" : {
"post" : {
"type" : "string"
}
}
}
}
}
And we issue a query like below, highlight information is returned if there is a match on parent field but not if the parent is being returned due to a has_child match:
POST nested2/discussion/_search
{
"query": {
"bool": {
"should": [
{
"prefix": {
"_all" : "cat"
}
},
{
"has_child" : {
"type" : "discussionPost",
"score_mode" : "sum",
"query" : {
"prefix": {
"_all" : "cat"
}
}
}
}
],
"minimum_should_match": 1
}
},
"highlight":{
"fields":{
"*":{}
}
}
}
Is it possible to get highlight information on what matched in the child when has_child query is being issued on the parent?
Regards
LT
It is possible to do this using inner_hits inside the has_child query clause:
{
"query": {
"bool": {
"should": [
{
"has_child" : {
"inner_hits": {
"_source": false,
"highlight":{
"order": "score",
"fields": {"*":{}}
}
},
"type" : "discussionPost",
"score_mode" : "sum",
"query" : {
"prefix": {
"_all" : "cat"
}
}
}
}
],
"minimum_should_match": 1
}
}
}

Resources