Elastic Search Nested Query with Nested Object - elasticsearch

This is the type of data I have stored on my index in elastic search.
I have to find Recipes with Main Ingredient Beef(and weight less than 1000) with Ingredients -(chilli powder and weight less than 250),(olive oil & weight less than 300 )and similarly for all other ingredients.
"Name": "Real beef burritos",
"Ingredients": [
{"name": "olive oil",
"id": 27,
"weight": 200},
{"name": "bonion","id": 3,"weight": 300},
{"name": "garlic",
"id": 2,
"weight": 100
},
{"name": "chilli powder",
"id": 35,
"weight": 150},
{"name": "coriander",
"id": 40,
"weight": 600},
{"name": "tortillas",
"id": 41,
"weight": 700}
],"Main_ingredient": {
"type": "Beef",
"id": 101,
"weight": 1000
}}}
Mapping of the index is
{"final":{"mappings":{"superb":{"properties":{"Cook Time":{"type":"long"},"Ingredients":{"type":"nested","properties":{"id":{"type":"short"},"name":{"type":"string"},"type":{"type":"string"},"weight":{"type":"short"}}},"Main_ingredient":{"properties":{"id":{"type":"long"},"type":{"type":"string"},"weight":{"type":"long"}}},"Name":{"type":"string"},"Prep Time":{"type":"long"},"Servings":{"type":"long"},"Tags":{"type":"string"},"Urls":{"type":"string"},"Views":{"type":"long"}}}}}}
My query is
{
"query": {
"bool": {
"must": [
{ "match": { "Main_ingredient.type": "Beef" }},
{"range":{"Main_ingredient.weight":{"lte":1000}}},
{
"nested": {
"path": "Ingredients",
"query": {
"bool": {
"must": [
{ "match": { "Ingredients.name": "garlic" }},
{ "range": { "Ingredients.weight":{"lte":400} }},
{ "match": { "Ingredients.name": "chilli powder" }},
{ "range": { "Ingredients.weight":{"lte":400} }}
]
}}}}
]
}}}
But it gives Null.Can anyone help me out .I think I am not using nested query properly

Try this:
{
"query": {
"bool": {
"must": [
{
"match": {
"Main_ingredient.type": "Beef"
}
},
{
"range": {
"Main_ingredient.weight": {
"lte": 1000
}
}
},
{
"nested": {
"path": "Ingredients",
"query": {
"bool": {
"must": [
{
"match": {
"Ingredients.name": "garlic"
}
},
{
"range": {
"Ingredients.weight": {
"lte": 400
}
}
}
]
}
}
}
},
{
"nested": {
"path": "Ingredients",
"query": {
"bool": {
"must": [
{
"match": {
"Ingredients.name": "chilli powder"
}
},
{
"range": {
"Ingredients.weight": {
"lte": 400
}
}
}
]
}
}
}
}
]
}
}
}

Related

Custom sort after score calculation and the value of specific field

Need help to understand sorting in a query where _score is either 0 or 1 based on some conditions
but there is also an additional_filed type integer, sort should be in the order of _score * additional_field
sample index
PUT /product_t
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"placed" :{
"type": "integer"
},
"store" : {
"type": "nested"
}
}
}
}
sample document
PUT /product_t/_doc/10
{
"name": "awesome",
"count_sold": 199,
"stock": [
{
"id": 1,
"count": 10
},
{
"id": 2,
"count": 5
},
{
"id": 3,
"count": 0
}
]
}
Query Used :
POST /product_t/_search
{
"from": 0,
"size": 100,
"timeout": "300ms",
"query": {
"bool": {
"filter": [
{
"match": {
"name": {
"value": "awesome"
}
}
},
{
"nested": {
"path": "stock",
"query": {
"bool": {
"must": [
{
"match": {
"stock.id": 3
}
}
]
}
}
}
}
],
"should": [
{
"constant_score": {
"filter": {
"nested": {
"path": "stock",
"query": {
"bool": {
"must": [
{
"match": {
"stock.id": 3
}
},
{
"range": {
"stock.count": {
"gt": 0
}
}
}
]
}
}
}
},
"boost": 1
}
},
{
"constant_score": {
"filter": {
"nested": {
"path": "stock",
"query": {
"bool": {
"must": [
{
"match": {
"stock.id": 3
}
},
{
"range": {
"stock.count": {
"lte": 0
}
}
}
]
}
}
}
},
"boost": 0
}
}
]
}
}
}
count_sold is additional field
You can use script sort
"sort": {
"_script": {
"type": "number",
"script": {
"lang": "painless",
"source": "doc['count_sold'].value * _score"
},
"order": "asc"
}
}

Elasticsearch search document with nested document with optional fields

I'm trying to create query for nested object that contains year and month. Both of them are optional. If some field not exists we treat them as hit. I found one solution but it causes combinatorial explosion of terms so I'm trying to find a better solution.
Steps of reproduction:
Creating index with mapping
PUT /date-test
{
"mappings": {
"properties": {
"datesOfBirth": {
"type": "nested"
}
}
}
}
Add documents with nested objects
PUT /date-test/_doc/1
{
"name": "Object1",
"datesOfBirth": []
}
PUT /date-test/_doc/2
{
"name": "Object2",
"datesOfBirth": [
{
"year": 1990,
"month": 4
}
]
}
PUT /date-test/_doc/3
{
"name": "Object3",
"datesOfBirth": [
{
"year": 1995,
"month": 2
},
{
"year": 1998,
"month": 4
}
]
}
PUT /date-test/_doc/4
{
"name": "Object4",
"datesOfBirth": [
{
"month": 4
}
]
}
This query works as expected for year range 1994-1996 and month range 1-5 (objects 1, 3, 4 are returned):
POST /date-test/_search
{
"size": 1000,
"query": {
"bool" : {
"should": [
{ "bool": {"must_not": [ //match when all fields are absent
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.year" }} }},
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.month" }} }}
]
}},
{ "bool": {"must_not": [ //match when year is absent but month exists and match to range
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.year" }} }}
],
"should": [
{"nested": { "path": "datesOfBirth", "query": { "bool": { "must": [
{ "range": { "datesOfBirth.month": { "gte": 1, "lte": 5} } }
]
}}}}
]
}},
{ "bool": {"must_not": [ //match when month is absent but year exists and match to range
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.month" }} }}
],
"should": [
{"nested": { "path": "datesOfBirth", "query": { "bool": { "must": [
{ "range": { "datesOfBirth.year": { "gte": 1994, "lte": 1996} } }
]
}}}}
]
}},
{"nested": { "path": "datesOfBirth", "query": { "bool": { "must": [ //both fields exists and must match to given ranges
{ "range": { "datesOfBirth.year": { "gte": 1994, "lte": 1996} } },
{ "range": { "datesOfBirth.month": { "gte": 1, "lte": 5} } }
]
}}}}
],
"minimum_should_match": 1
}
}
}
Is there better way to achieve that behaviour? I'm using Elasticsearch 7.1.
I've also tried always set field but with null in case of value absence and add mapping for year and month where I define null_value: -1. Then I can remove part with combination of field absence.
Create index with mapping
PUT /date-test
{
"mappings": {
"properties": {
"datesOfBirth": {
"type": "nested",
"properties": {
"year": { "type": "integer", "null_value": -1 },
"month": { "type": "integer", "null_value": -1 }
}
}
}
}
}
Creating documents as follows:
PUT /date-test/_doc/7
{
"name": "SomeObjectWithoutYear",
"datesOfBirth": [
{
"year": null,
"month": 4
}
]
}
Then I can do query like this:
POST /date-test/_search
{
"size": 1000,
"query": {
"bool" : {
"should": [
{ "bool": {"must_not": [
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.year" }} }},
{ "nested": { "path": "datesOfBirth", "query": { "exists": { "field": "datesOfBirth.month" }} }}
]
}},
{"nested": { "path": "datesOfBirth", "query": { "bool": { "should": [
{ "match": { "datesOfBirth.year": { "query": -1 } } },
{ "match": { "datesOfBirth.month": { "query": -1 } } },
{ "range": { "datesOfBirth.year": { "gte": 1994, "lte": 1996} } },
{ "range": { "datesOfBirth.month": { "gte": 1, "lte": 5} } }
],
"minimum_should_match": 2
}}}}
],
"minimum_should_match": 1
}
}
}
But I'm wondering if it is the cleanest way to achieve that.

malformed query, expected [END_OBJECT] but found [FIELD_NAME]

The original query looks like this
{
"query": {
"bool": {
"must": [
{
"has_parent": {
"parent_type": "doc",
"query": {
"bool": {
"must": [
{
"terms": {
"id": [
713
]
}
},
{
"range": {
"created": {
"lte": "now/d"
}
}
},
{
"range": {
"expires": {
"gte": "now/d"
}
}
}
]
}
}
}
},
{
"term": {
"doc_type": "item"
}
},
{
"bool": {
"should": [
{
"term": {
"have_prices": true
}
},
{
"term": {
"is_folder": true
}
}
]
}
}
],
"must_not": {
"exists": {
"field": "folder"
}
}
}
},
"sort": [
{
"is_folder": {
"order": "desc"
}
},
{
"title_low.order": {
"order": "asc"
}
}
],
"size": 1000
}
And I got some result
"hits": {
"total": 19,
"max_score": null,
"hits": [
{
"_index": "prices",
"_type": "doc",
"_id": "item-6800004",
"_score": null,
"_routing": "1",
"_source": {
"id": 6800004,
"id_pricedoc": 713,
"title": "\"водка №1\" 1",
"title_low": "\"водка №1\" 1",
"supplier": {
"id": 7831,
"type": null
},
"supplier_nom": {
"id": 1375697,
"market_nom": {
"id": null
},
"codes": null,
"sup_code": "7a6713a5-73c1-3acb-9b62-9e38b2314dce",
"manufacturer": {
"id": null,
"title": null
}
},
"is_folder": false,
"folder": null,
"path": null,
"pricedoc_created": "2016-03-21",
"prices": [
{
"currency": "RUR",
"id_offer": 15735967,
"id_prcknd": 167,
"value": "391.50"
}
],
"have_prices": true,
"market": {
"title": null,
"uuid": null,
"folder": null,
"path": null
},
"_join_field_name": "doc_type",
"doc_type": {
"name": "item",
"parent": "doc-713"
}
},
"sort": [
0,
"\"водка №1\" 1"
]
}
Now I also would like get result where "id_prcknd": 167
Modified query looks like this
{
"query": {
"bool": {
"must": [
{
"has_parent": {
"parent_type": "doc",
"query": {
"bool": {
"must": [
{
"terms": {
"id": [
713
]
}
},
{
"range": {
"created": {
"lte": "now/d"
}
}
},
{
"range": {
"expires": {
"gte": "now/d"
}
}
}
]
}
}
}
},
{
"term": {
"doc_type": "item"
}
},
{
"bool": {
"should": [
{
"term": {
"have_prices": true
}
},
{
"term": {
"is_folder": true
}
}
]
}
}
],
"must_not": {
"exists": {
"field": "folder"
}
}
},
"nested": {
"path": "prices",
"query": {
"bool": {
"must": [
{
"match": {
"prices.id_prcknd": 167
}
}
]
}
}
},
"sort": [
{
"is_folder": {
"order": "desc"
}
},
{
"title_low.order": {
"order": "asc"
}
}
],
"size": 1000
}}
But I got an error Elasticsearch malformed query, expected [END_OBJECT] but found [FIELD_NAME]
Where am I wrong?
I wanna match objects where "id_prcknd": 167
The stackoverflow says the I post mostly the code, but it's because of large queries in elastic search.
What Elasticsearch was trying to say is that it did not expect to see other keys but bool in the dictionary (the value under "query").
In your example code you have something like this:
{
"query": {
"bool": {
"must": [
{...},
{...},
{...}
],
"must_not": {...},
"nested": {...}, // this should go under "must"
"sort": [...], // this should go on the same level as "query"
"size": 1000 // this should go on the same level as "query"
}
}
"bool" here refers to a bool query, and should be the only key in the dictionary.
What you should do is to move "nested" into its own dictionary and the fourth element of the must array (if I understood the logic of what you are trying to achieve correctly). Please note that also "sort" and "size" should be moved - this time, to the same level as "query".
The full query will look like this:
{
"query": {
"bool": {
"must": [
{
"has_parent": {
"parent_type": "doc",
"query": {
"bool": {
"must": [
{
"terms": {
"id": [
713
]
}
},
{
"range": {
"created": {
"lte": "now/d"
}
}
},
{
"range": {
"expires": {
"gte": "now/d"
}
}
}
]
}
}
}
},
{
"term": {
"doc_type": "item"
}
},
{
"bool": {
"should": [
{
"term": {
"have_prices": true
}
},
{
"term": {
"is_folder": true
}
}
]
}
},
{
"nested": {
"path": "prices",
"query": {
"bool": {
"must": [
{
"match": {
"prices.id_prcknd": 167
}
}
]
}
}
}
}
],
"must_not": {
"exists": {
"field": "folder"
}
}
}
},
"sort": [
{
"is_folder": {
"order": "desc"
}
},
{
"title_low.order": {
"order": "asc"
}
}
],
"size": 1000
}
Your json is incorrect: Error:Expecting closing } at end[Code 22, Structure 183]
Use a json validator (https://jsonformatter.curiousconcept.com/) for example.

ElasticSearch Function Score Query

Following is my function_score query. I want to give additional score to documents where the product quality is better.
But _score in the search response is always 0. What am I missing? Thx.
When I remove bool query and replace it with just a term filter, the score is non zero. I am guessing it is about the query bool but can not figure out why.
Elasticsearch version is 2.4
{
"from": 0,
"size": 20,
"query": {
"function_score": {
"query": {
"bool": {
"filter": [
{
"bool": {
"should": {
"terms": {
"categories.category1Id": [
63
]
}
}
}
}
]
}
},
"functions": [
{
"gauss": {
"updatedDate": {
"origin": "2016-10-03 05:10:18",
"scale": "0.5h",
"decay": 0.1,
"offset": "1h"
}
}
},
{
"filter": {
"term": {
"productQuality": "EXCELLENT"
}
},
"weight": 7
},
{
"filter": {
"term": {
"productQuality": "HIGH"
}
},
"weight": 5
},
{
"filter": {
"term": {
"productQuality": "MEDIUM"
}
},
"weight": 3
},
{
"filter": {
"term": {
"productQuality": "LOW"
}
},
"weight": 1
}
],
"score_mode": "sum"
}
}
}
As what #Val said.
bool.filter assigns a score of 0 to all documents, as no scoring query has been specified (link).
If you need the score, you can add "must": {"match_all": {}} in your query. match_all will assign 1.0 to all documents (link).
Here is your query with match_all:
{
"from": 0,
"size": 20,
"query": {
"function_score": {
"query": {
"bool": {
"must": {
"match_all": {}
},
"filter": [
{
"bool": {
"should": {
"terms": {
"categories.category1Id": [
63
]
}
}
}
}
]
}
},
"functions": [
{
"gauss": {
"updatedDate": {
"origin": "2016-10-03 05:10:18",
"scale": "0.5h",
"decay": 0.1,
"offset": "1h"
}
}
},
{
"filter": {
"term": {
"productQuality": "EXCELLENT"
}
},
"weight": 7
},
{
"filter": {
"term": {
"productQuality": "HIGH"
}
},
"weight": 5
},
{
"filter": {
"term": {
"productQuality": "MEDIUM"
}
},
"weight": 3
},
{
"filter": {
"term": {
"productQuality": "LOW"
}
},
"weight": 1
}
],
"score_mode": "sum"
}
}
}

Using Elasticsearch, how do I do a filtered query on both my document properties and nested document properties?

Here is an example document source.
{
"tags": [
"meow",
"cats",
"feline"
],
"visible": 1,
"for_sale": "y",
"title": "Cat Meow",
"stock": [{
"department": "mens",
"size": "small"
}, {
"department": "mens",
"size": "medium"
}]
}
I want to find documents that are 'stock.department=mens' and 'stock.size=medium' and also are 'for_sale=y'
Here is the query that I've come up with so far. I can't figure out how to filter by for_sale=y.
{
"size": 5,
"query": {
"filtered": {
"query": {
"multi_match": {
"fields": ["title", "tags"],
"query": "cat"
}
},
"filter": {
"nested": {
"path": "stock",
"filter": {
"bool": {
"must": [{
"term": {
"stock.size": "medium"
}
}, {
"term": {
"stock.department": "mens"
}
}]
}
}
}
}
}
}
}
This is what I've come up with. If anyone has any critiques or improvements please share them.
{
"size": 5,
"query": {
"filtered": {
"query": {
"multi_match": {
"fields": ["title", "tags"],
"query": "cat"
}
},
"filter": {
"bool": {
"must": [{
"term": {
"for_sale": "y"
}
}, {
"term": {
"visible": 1
}
}, {
"nested": {
"path": "stock",
"filter": {
"bool": {
"must": [{
"term": {
"stock.size": "medium"
}
}, {
"term": {
"stock.department": "mens"
}
}]
}
}
}
}]
}
}
}
}
}

Resources