Elasticsearch nested doc with AND condition - elasticsearch

The ES scheme we model a student document which contains multiple nested courses documents. I want to search for students who has course X and Y.
Mapping:
{
"index_classroom": {
"mappings": {
"content": {
"dynamic": "false",
"properties": {
"courses": {
"type": "nested",
"properties": {
"grade": {
"type": "integer"
},
"name": {
"type": "string",
"analyzer": "analyzer_keyword"
}
}
}
}
}
}
}
}
Sample docs:
{
"_index": "index_classroom",
"_type": "content",
"_id": "6170_130",
"_score": 0.72833073,
"_source": {
"courses": [
{
"name": "maths",
"grade": "A"
},
{
"name": "economics",
"grade": "A+"
}
]
}
}
I want to query all students who have taken Math and Economics (further to add is "and not Biology".)
Thanks!

This is your query:
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "courses",
"query": {
"match": {
"courses.name": "economics"
}
}
}
},
{
"nested": {
"path": "courses",
"query": {
"match": {
"courses.name": "maths"
}
}
}
}
],
"must_not": [
{
"nested": {
"path": "courses",
"query": {
"match": {
"courses.name": "Biology"
}
}
}
}
]
}
}
}

Related

Filter items which array contains all of given values in ElasticSearch

I have a doc structure like this:
{
"_index": "XXX",
"_id": 0,
"_type" : "_doc",
"_source": {
"events" : [
{"type": "A"},
{"type": "B"},
{"type": "C"}
]
}
},
{
"_index": "XXX",
"_id": 1,
"_type" : "_doc",
"_source": {
"events" : [
{"type": "A"},
{"type": "C"}
]
}
}
I would like to try get the doc have "A" and "B", so in this case, just the first doc.
But I'm not sure how to do it.
I tried this, but this one give me all of doc (seems like this is searching for any docs that contains "A")
{
"nested": {
"path": "events",
"query": {
"bool": {
"should": [
{"term": {"events.type": "A"}},
{"term": {"events.type": "B"}}
]
}
}
}
}
I also tried this way, but this one give me none of docs
{
"nested": {
"path": "events",
"query": {
"match": {
"events.type": {
"query" : "A B",
"operator": "AND"
}
}
}
}
},
The current one that is working for me is
{
"nested": {
"path": "events",
"query": {
"bool" : {
"filter": [
{
"term": {
"type": "A"
}
}
]
}
}
}
},
{
"nested": {
"path": "events",
"query": {
"bool" : {
"filter": [
{
"term": {
"type": "B"
}
}
]
}
}
}
}
I'm wondering that if there is an optimized way?
Thanks in advance!
You need multiple filters, but first of all events must be a nested field, so that all these filters are executed in a context of a single nested document (event).
Mapping
{
"mappings": {
"properties": {
"events": {
"type": "nested",
"properties": {
"type": {
"type": "keyword"
}
}
}
}
}
}
Query
{
"query": {
"nested": {
"path": "events",
"query": {
"bool": {
"filter": [
{
"term": {
"type": "A"
}
},
{
"term": {
"type": "B"
}
}
}
}
}
}
}
}

Elasticsearch nested path query into an object type

Having this template (abbreviated version).
{
"index_patterns": "index_pattern*",
"order": 1,
"version": 1,
"aliases": {
"some_alias": {}
},
"settings": {
"number_of_shards": 5,
},
"mappings": {
"dynamic": "false",
"properties": {
"someId": {
"type": "keyword"
},
"audience": {
"type": "object",
"properties": {
....
"ageRanges": {
"type": "nested",
"properties": {
"ageTo": {
"type": "integer"
},
"ageFrom": {
"type": "integer"
}
}
}
}
}
}
}
}
I need to query if the audience.ageRanges does not exist or if it does exist apply other filters.
Let's say we want to search if a document with specific someId value fits into the audience.ageRanges query clauses (removed for clarity).
It has some audience properties but no ageRanges.
"audience": {
"genders": [
"any"
],
"deviceType": "any"
}
Shouldn't the below query return the specific document?
{
"query": {
"bool": {
"must": [
{
"term": {
"someId": {
"value": "03183f31"
}
}
},
{
"nested": {
"path": "audience.ageRanges",
"query": {
"bool": {
"must_not": [
{
"exists": {
"field": "audience.ageRanges"
}
}
]
}
}
}
}
]
}
}
}
My results are 0, it is a bit confusing how it works.
Trying with a document id that does have audience.ageRanges items and changing the must_not nested query to must will return results.
Instead of putting must_not inside the nested query, you should put the nested query inside the must_not.
Consider a sample index data as
{
"someId":123,
"audience": {
"genders": [
"any"
],
"deviceType": "any"
}
}
You need to modify your search query as shown below -
Search Query:
{
"query": {
"bool": {
"must": [
{
"term": {
"someId": {
"value": "123"
}
}
},
{
"bool": {
"must_not": {
"nested": {
"path": "audience.ageRanges",
"query": {
"bool": {
"must": [
{
"exists": {
"field": "audience.ageRanges"
}
}
]
}
}
}
}
}
}
]
}
}
}
Search Result:
"hits": [
{
"_index": "65852173",
"_type": "_doc",
"_id": "1",
"_score": 0.2876821,
"_source": {
"someId": 123,
"audience": {
"genders": [
"any"
],
"deviceType": "any"
}
}
}
]

How can i do both search across all field and search with field specified in Elastic search?

I'm very new to elastic search, how do I write a query which search for a keyword (ie. test keyword) in all fields in the document, and one more keyword which search in a specific field.
this can be done using query_string but we can't do search in nested fields with nested field specified, So i'm using LUQUM to convert lucene query to Elasticsearch DSL.
Below is the sample usecase:
I have a mapping:
"mappings": {
"properties": {
"grocery_name":{
"type": "text"
},
"items": {
"type": "nested",
"properties": {
"name": {
"type": "text"
},
"stock": {
"type": "integer"
},
"category": {
"type": "text"
}
}
}
}
}
}
and the data looks like below
{
"grocery_name": "Elastic Eats",
"items": [
{
"name": "Red banana",
"stock": "12",
"category": "fruit"
},
{
"name": "Cavendish banana",
"stock": "10",
"category": "fruit"
},
{
"name": "peach",
"stock": "10",
"category": "fruit"
},
{
"name": "carrot",
"stock": "9",
"category": "vegetable"
},
{
"name": "broccoli",
"stock": "5",
"category": "vegetable"
}
]
}
How can I query to get all items where the item name matches banana from grocery_name: Elastic Eats ?
tried with * and _all, it didn't work.
example query:
{
"query": {
"bool": {
"must": [
{
"match_phrase": {
"grocery_name": {
"query": "Elastic Eats"
}
}
},
{
"match": {
"*": {
"query": "banana",
"zero_terms_query": "all"
}
}
}
]
}
}
}
I'm sure I'm missing something obvious, but I have read the manual and I'm getting no joy at all.
UPDATE:
enabling include_in_parent for nested object works for below query, but it will internally duplicates data which will definitely impact on memory.
{
"query": {
"bool": {
"must": [
{
"match_phrase": {
"grocery_name": {
"query": "Elastic Eats"
}
}
},
{
"multi_match": {
"query": "banana"
}
}
]
}
}
}
Is there any other way to do this?
You need to use a nested match query with inner_hits resulting in an inner nested query to automatically match the relevant nesting level, rather than root
Search Query
{
"query": {
"bool": {
"filter": [
{
"term": {
"grocery_name": "elastic"
}
},
{
"nested": {
"path": "items",
"query": {
"bool": {
"must": [
{
"match": {
"items.name": "banana"
}
}
]
}
},
"inner_hits": {}
}
}
]
}
}
}
Search Result:
"inner_hits": {
"items": {
"hits": {
"total": {
"value": 2,
"relation": "eq"
},
"max_score": 0.744874,
"hits": [
{
"_index": "stof_64273970",
"_type": "_doc",
"_id": "1",
"_nested": {
"field": "items",
"offset": 0
},
"_score": 0.744874,
"_source": {
"name": "Red banana",
"stock": "12",
"category": "fruit"
}
},
{
"_index": "stof_64273970",
"_type": "_doc",
"_id": "1",
"_nested": {
"field": "items",
"offset": 1
},
"_score": 0.744874,
"_source": {
"name": "Cavendish banana",
"stock": "10",
"category": "fruit"
}
}
]
}
Update 1:
On the basis of your comments, you can use multi match query, for your use case
If no fields are provided, the multi_match query defaults to the
index.query.default_field index settings, which in turn defaults to *.
(*) extracts all fields in the mapping that are eligible to term queries and filters the metadata fields. All extracted fields are then
combined to build a query.
Search Query:
{
"query": {
"bool": {
"filter": [
{
"term": {
"grocery_name": "elastic"
}
},
{
"nested": {
"path": "items",
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "banana" <-- note this
}
}
]
}
},
"inner_hits": {}
}
}
]
}
}
}
Update 2:
You need to use a combination of multiple bool queries like this:
{
"query": {
"bool": {
"must": [
{
"match_phrase": {
"grocery_name": {
"query": "Elastic Eats"
}
}
},
{
"bool": {
"should": [
{
"bool": {
"must": [
{
"multi_match": {
"query": "banana"
}
}
]
}
},
{
"bool": {
"must": [
{
"nested": {
"path": "items",
"query": {
"bool": {
"must": [
{
"multi_match": {
"query": "banana"
}
}
]
}
},
"inner_hits": {}
}
}
]
}
}
]
}
}
]
}
}
}

Elasticsearch has_child returning no results

I'm trying to get all child of a parent document but not getting any result with has_child query,
{
"index": "index_x",
"include_type_name": true,
"body": {
"mappings": {
"agents": {
"properties": {
"id": {
"type": "keyword"
},
"listings": {
"type": "join",
"eager_global_ordinals": true,
"relations": {
"agent": "listing"
}
},
"name": {
"type": "object"
}
}
}
}
}
}
here's my query
{
"query": {
"bool": {
"must": [
{
"term": {
"_id": <id>
}
},
{
"has_child": {
"type": "listing",
"query": {
"match_all": {}
},
"inner_hits": {}
}
}
]
}
}
}
however, when I run this query I'm getting child results just fine
{
"query": {
"bool": {
"must": [
{
"parent_id": {
"type":"listing",
"id": <id>
}
}
]
}
}
}
Same with has_parent query, not getting any results.
I'm using Elasticsearch 7.7
Sounds like you want to use the has_parent query. Here is minimal example of how it can work on ESv7.7:
PUT /so
{
"mappings": {
"properties" : {
"my-join-field" : {
"type" : "join",
"relations": {
"parent": "child"
}
},
"tag" : {
"type" : "keyword"
}
}
}
}
POST /so/_doc/1
{
"my-join-field": "parent",
"tag": "Adult"
}
POST /so/_doc/2?routing=1
{
"my-join-field": {
"name": "child",
"parent": "1"
},
"tag": "Youth"
}
POST /so/_doc/3?routing=1
{
"my-join-field": {
"name": "child",
"parent": "1"
},
"tag": "Youth2"
}
GET /so/_search
{
"query": {
"has_parent": {
"parent_type": "parent",
"query": {
"match": {
"tag": "Adult"
}
}
}
}
}

Filtering by nested object field value in Elasticsearch

I want to filter the document by nested field value. My document is like this and I want to filter it by Color parameter:
{
"_index": "myindex",
"_type": "product",
"_id": "984984",
"_source": {
"id": "98418",
"name": "Product1",
..
"parameters": {
"Color": [
"Black",
"Gold"
]
}
}
}
My mapping is:
{
"myindex": {
"mappings": {
"product": {
"properties": {
..
"parameters": {
"type": "nested",
"properties": {
"Color": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
..
}
}
}
}
}
}
And my filter query is following:
{
"query": {
"bool": {
"filter": {
"nested": {
"path": "parameters",
"query": {
"term": {
"parameters.Color":"Gold"
}
}
}
}
}
}
}
But unfortunatelly I'm getting zero documents and I do not understand why?
Thank you
EDIT
Event this is working:
{
"query": {
"nested": {
"path": "parameters",
"query": {
"bool": {
"must": [
{ "match": { "parameters.Color": "Gold" }}
]
}
}
}
}
}
..but this is not:
{
"query": {
"nested": {
"path": "parameters",
"query": {
"bool": {
"filter": [
{ "term": { "parameters.Color": "Gold" }}
]
}
}
}
}
}
Why??
Your term query is looking for an exact match and the match query is analyzed before searching. If you are using the standard analyzer it will lowercase your terms when it analyzes them.
You could use the keyword field if you need to do an exact match.
{
"query": {
"bool": {
"filter": {
"nested": {
"path": "parameters",
"query": {
"term": {
"parameters.Color.keyword":"Gold"
}
}
}
}
}
}
}

Resources