Unsure how to structure ElasticSearch Range Query with nested properties - elasticsearch

My object in ES looks like:
{
"_index": "myIndex",
"_type": "myType",
"_id": "75fd98d2-eca7-4a94-9dd8-1cc2c9b1fbbf",
"_version": 2,
"found": true,
"_source": {
"account_id": "100",
"import_ids": [
"4f4eef42-5493-464e-ac08-68a3a25a01fb"
],
"accept": "html",
"deleted_at": null,
"signup_form_ids": [
{
"timestamp": "2015-11-23T20:08:11.604000",
"signup_form_id": "1234"
}
],
"mailing_status": "active",
"group_ids": [
"0eddd2c0-ce70-4eb7-bcd8-9e41e41ac0b3"
],
"confirmed_opt_in_at": null,
"fields": [
{
"text_value": "My Company",
"name": "company"
},
{
"text_value": "Foo",
"name": "first-name"
},
{
"text_value": "Bar",
"name": "last_name"
},
{
"text_value": "555-555-5555",
"name": "phone"
}
],
"created_at": "2015-11-23T19:20:15.889000",
"last_modified_at": "2015-11-23T20:08:11.604000",
"bounce_count": 0,
"opted_out_at": null,
"archived_at": null,
"email": "example#example.com",
"opt_out_mailing_id": "None"
}
}
I am trying to run write a query that gives me all hits where the signup_form_ids.timestamp are lte now-7d/d. I'm looking at https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html#ranges-on-dates but unsure how to structure the query
This is what I have so far:
{
"query": {
"nested": {
"path": "signup_form_ids",
"bool": {
"must": [
{
"range": {
"timestamp" {
"lte": "now-7d/d"
}
}
}
]
}
},
"bool": {
"must": [
{
"bool": {
"must": []
}
},
{
"match": {
"account_id": "100"
}
},
{
"filtered": {
"filter": {
"missing": {
"field": "deleted_at"
}
}
}
}
]
}
},
"size": 500,
"from": 0
}

There are several things wrong here, and it's not entirely obvious which ones are artifacts of you adjusting your query to post here.
First, you're missing a colon after "timestamp" in your query. Also, you have an empty inner "bool". And your "range" query is inside a needless "bool". Also your "filtered" clause is redundant and you can just use the "filter" inside it.
But the main problems are that 1) your "nested" query needs to be inside your "bool" if you want all the conditions to apply, 2) your "nested" "range" filter needs to specify the full path to "timestamp" and 3) the "bool" inside your "nested" clause needs to be in a "filter".
So, making minimal adjustments to make the query work, the following query returns the document you posted (I changed the "lte" to "gte" so the document you posted would be returned, otherwise it doesn't match the query, yet):
POST /test_index/_search
{
"query": {
"bool": {
"must": [
{
"bool": {
"must": []
}
},
{
"match": {
"account_id": "100"
}
},
{
"filtered": {
"filter": {
"missing": {
"field": "deleted_at"
}
}
}
},
{
"nested": {
"path": "signup_form_ids",
"filter": {
"bool": {
"must": [
{
"range": {
"signup_form_ids.timestamp": {
"gte": "now-7d/d"
}
}
}
]
}
}
}
}
]
}
},
"size": 500,
"from": 0
}
If I clean it up to remove all the redundancies, I end up with:
POST /test_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"account_id": "100"
}
},
{
"missing": {
"field": "deleted_at"
}
},
{
"nested": {
"path": "signup_form_ids",
"filter": {
"range": {
"signup_form_ids.timestamp": {
"gte": "now-7d/d"
}
}
}
}
}
]
}
},
"size": 500,
"from": 0
}
Here is some code I used to play around with it:
http://sense.qbox.io/gist/ee96042c0505dfb07199b919d134b2a20c5a66fd

Related

Minimum should match with filter doesn't return any result

I have a complicated query which works fine.the proble is that I'm going to add a condition(filter) to it to filter the result.I need the exact result that I currently get with filtering based on the field called "field7".
"query": {
"bool": {
"should": [
{
"match_bool_prefix": {
"field1": {
"query": "test",
"fuzziness": "auto",
"boost": 1
}
}
},
{
"match": {
"field2": {
"query": "test",
"boost": 10
}
}
},
{
"exists": {
"field": "field3",
"boost": 15
}
},
{
"exists": {
"field": "field4",
"boost": 10
}
},
{
"match_phrase_prefix": {
"field5": {
"query": ""
}
}
}
],
"must": [
{
"bool": {
"filter": [
{
"match": {
"field6": "A"
}
},
{"terms": { "field7": [3,4,5]}}
]
}
}
],
"minimum_should_match": 3
}
},
"size": 20
I have to use "minimum_should_match": 3,to meet my requirements(If i remove it I get unrelated results) but when i use it with filter the result gets notthing.Is there any suggestion how to get current result and filter it based on field7?
#Paris I believe you can use filter term query for field7 since you want to apply filter on the result-set from should+must query. So basically this should suffice:
"query": {
"bool": {
"should": [
{
"match_bool_prefix": {
"field1": {
"query": "test",
"fuzziness": "auto",
"boost": 1
}
}
},
{
"match": {
"field2": {
"query": "test",
"boost": 10
}
}
},
{
"exists": {
"field": "field3",
"boost": 15
}
},
{
"exists": {
"field": "field4",
"boost": 10
}
},
{
"match_phrase_prefix": {
"field5": {
"query": ""
}
}
}
],
"must": {
{"match": {"field6": "A"}}
},
"filter": {
{"term" : {"field7" : 3}},
{"term" : {"field7" : 4}},
{"term" : {"field7" : 5}},
}
}
},
"size": 20

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": {}
}
}
]
}
}
]
}
}
]
}
}
}

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.

What is wrong with my elasticsearch query ? Getting a expected end object error

I'm trying to do a elasticsearch query that does geolocation filter and does some matching on nested documents, but I'm getting this error whenever I add in the nested query.
"[bool] malformed query, expected [END_OBJECT] but found [FIELD_NAME]"
{
"sort": [
{
"_score": {
"order": "desc"
}
}
],
"query": {
"bool": {
"filter": {
"geo_distance": {
"distance": "10km",
"geolocation": [
-73.980090948125,
40.747844918436
]
}
},
"must": {
"multi_match": {
"query": "New York",
"fields": [
"name^2",
"city",
"state",
"zip"
],
"type": "best_fields"
}
}
},
"nested": {
"path": "amenities",
"query": {
"bool": {
"must": [
{
"match": {
"amenities.name": "Pool"
}
}
]
}
}
}
},
"aggs": {
"reviews": {
"nested": {
"path": "reviews"
},
"aggs": {
"avg_rating": {
"avg": {
"field": "reviews.rating"
}
}
}
}
}
}
You just has misplaced the nested query, try like this:
{
"sort": [
{
"_score": {
"order": "desc"
}
}
],
"query": {
"bool": {
"filter": {
"geo_distance": {
"distance": "10km",
"geolocation": [
-73.980090948125,
40.747844918436
]
}
},
"must": [
{
"multi_match": {
"query": "New York",
"fields": [
"name^2",
"city",
"state",
"zip"
],
"type": "best_fields"
}
},
{
"nested": {
"path": "amenities",
"query": {
"match": {
"amenities.name": "Pool"
}
}
}
}
]
}
},
"aggs": {
"reviews": {
"nested": {
"path": "reviews"
},
"aggs": {
"avg_rating": {
"avg": {
"field": "reviews.rating"
}
}
}
}
}
}

Resources