Elasticsearch - Range search by price and date does not work - elasticsearch

Range search by price and by date does not work for me. And I don’t understand where to look for an error in mapping or in request.
I have mapping for my fields in document:
"mappings": {
"properties": {
"sales" : {
"type" : "nested",
"properties" : {
"from" : {
"type" : "date",
"format" : "yyyy-MM-dd HH:mm:ss"
},
"price" : {
"type" : "double"
},
"to" : {
"type" : "date",
"format" : "yyyy-MM-dd HH:mm:ss"
}
}
}
}
}
This is my request by date:
"query": {
"bool": {
"must": [
{
"nested": {
"path": "sales",
"query": {
"bool": {
"must": [
{
"range": {
"date": {
"gte": "2019-09-01 12:37:55",
"lte": "2019-09-02 13:38:04"
}
}
}
]
}
}
}
}
]
}
}

You need to specify the field you want to search against. In your case, you want to filter by range from and to under sales nested object.
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "sales",
"query": {
"bool": {
"filter": [
{
"range": {
"sales.from": { #field for from date
"gte": "2019-09-01 12:37:55"
}
}
},
{
"range": {
"sales.to": { #field for to date
"lte": "2019-09-02 13:38:04"
}
}
}
]
}
}
}
}
]
}
}
}

Related

Elastic search combine must and must_not

I have a document that holds data for a product the mapping is as follow:
"mappings" : {
"properties" : {
"view_score" : {
"positive_score_impact" : true,
"type" : "rank_feature"
},
"recipients" : {
"dynamic" : false,
"type" : "nested",
"enabled" : true,
"properties" : {
"type" : {
"similarity" : "boolean",
"type" : "keyword"
},
"title" : {
"type" : "text",
"fields" : {
"key" : {
"type" : "keyword"
}
}
}
}
}
}
}
And I have 2 documents with the following data:
{
"view_score": 10,
"recipients": [{"type":"gender", "title":"male"}, {"type":"gender", "title":"female"}]
}
{
"view_score": 10,
"recipients": [{"type":"gender", "title":"female"}]
}
When a user searches for a product she can say "I prefer products for females" so The products which specifies gender as just female should come before products that specifies gender as male and female both.
I have the following query which gives more score to products with just female gender:
GET _search
{
"sort": [
"_score"
],
"query": {
"script_score": {
"query": {
"bool": {
"should": [
{
"nested": {
"path": "recipients",
"ignore_unmapped": true,
"query": {
"bool": {
"boost": 10,
"must": [
{
"term": {
"recipients.type": "gender"
}
},
{
"match": {
"recipients.title": "female"
}
}
],
"must_not": {
"bool": {
"filter": [
{
"term": {
"recipients.type": "gender"
}
},
{
"match": {
"recipients.title": "male"
}
}
]
}
}
}
}
}
}
]
}
},
"script": {
"source": "return _score;"
}
}
}
}
But if I add another query to should query it won't behave the same and gives the same score to products with one or two genders in their specifications.
here is my final query which wont work as expected:
GET _search
{
"sort": [
"_score"
],
"query": {
"script_score": {
"query": {
"bool": {
"should": [
{
"rank_feature": {
"field": "view_score",
"linear": {}
}
},
{
"nested": {
"path": "recipients",
"ignore_unmapped": true,
"query": {
"bool": {
"boost": 10,
"must": [
{
"term": {
"recipients.type": "gender"
}
},
{
"match": {
"recipients.title": "female"
}
}
],
"must_not": {
"bool": {
"filter": [
{
"term": {
"recipients.type": "gender"
}
},
{
"match": {
"recipients.title": "male"
}
}
]
}
}
}
}
}
}
]
}
},
"script": {
"source": "return _score;"
}
}
}
}
So my problem is how to combine these should clause together to give more weight to the products that specify only one gender.

Elasticseach wildcard query on nested types

I'm trying to run a wildcard query on a nested type in ElasticSearch. I have records with the following structure:
{
"field_1": "value_1",
"nested_field_1": [
{
"field_type": "some_field_type",
"field_value": "some_value"
},
{
"field_type": "another_field_type",
"field_value": "another_value"
}
]
}
I want to be able to run wildcard query on the nested_field, either on field_value or on field_type.
I can query for an exact match with this syntax:
"query": {
"nested": {
"path": "nested_field_1",
"query": {
"bool": {
"must": [
{
"match": {
"nested_field_1.field_value": "another_value"
}
}
]
}
}
}
}
}
But replacing the match with wildcard doesn't yield any results.
Any help would be welcome.
So I just tried your example and it gives me the result and used elasticsearch official wildcard query doc.
Index Def
{
"mappings": {
"properties": {
"field_1": {
"type": "text"
},
"nested_field_1" :{
"type" : "nested",
"properties" : {
"field_type" :{
"type" : "text"
},
"field_value" :{
"type" : "integer" --> created as interfere field
}
}
}
}
}
}
Index doc
{
"field_1": "value_1",
"nested_field_1": [
{
"field_type": "some_field_type",
"field_value": 20
},
{
"field_type": "another_field_type",
"field_value": 40
}
]
}
Wildcard search query
{
"query": {
"nested": {
"path": "nested_field_1",
"query": {
"bool": {
"must": [
{
"wildcard": { --> note
"nested_field_1.field_type": {
"value": "another_field_type"
}
}
}
]
}
}
}
}
}
Search result
"nested_field_1": [
{
"field_type": "some_field_type",
"field_value": 20
},
{
"field_type": "another_field_type",
"field_value": 40
}
]
}

Elasticsearch querying number of dates in array matching query

I have documents in the following form
PUT test_index/_doc/1
{
"dates" : [
"2018-07-15T14:12:12",
"2018-09-15T14:12:12",
"2018-11-15T14:12:12",
"2019-01-15T14:12:12",
"2019-03-15T14:12:12",
"2019-04-15T14:12:12",
"2019-05-15T14:12:12"],
"message" : "hello world"
}
How do I query for documents such that there are n number of dates within the dates array falling in between two specified dates?
For example: Find all documents with 3 dates in the dates array falling in between "2018-05-15T14:12:12" and "2018-12-15T14:12:12" -- this should return the above document as "2018-07-15T14:12:12", "2018-09-15T14:12:12" and "2018-11-15T14:12:12" fall between "2018-05-15T14:12:12" and "2018-12-15T14:12:12".
I recently faced the same problem. However came up with two solutions.
1) If you do not want to change your current mapping, you could query for the documents using query_string. Also note you will have to create the query object according to the range that you have. ("\"2019-04-08\" OR \"2019-04-09\" OR \"2019-04-10\" ")
{
"query": {
"query_string": {
"default_field": "dates",
"query": "\"2019-04-08\" OR \"2019-04-09\" OR \"2019-04-10\" "
}
}
}
However,this type of a query only makes sense if the range is short.
2) So the second way is the nested method. But you will have to change your current mapping in such a way.
{
"properties": {
"dates": {
"type": "nested",
"properties": {
"key": {
"type": "date",
"format": "YYYY-MM-dd"
}
}
}
}
}
So your query will look something like this :-
{
"query": {
"nested": {
"path": "dates",
"query": {
"bool": {
"must": [
{
"range": {
"dates.key": {
"gte": "2018-04-01",
"lte": "2018-12-31"
}
}
}
]
}
}
}
}
}
You can create dates as a nested document and use bucket selector aggregation.
{
"empId":1,
"dates":[
{
"Days":"2019-01-01"
},
{
"Days":"2019-01-02"
}
]
}
Mapping:
"mappings" : {
"properties" : {
"empId" : {
"type" : "keyword"
},
"dates" : {
"type" : "nested",
"properties" : {
"Days" : {
"type" : "date"
}
}
}
}
}
GET profile/_search
{
"query": {
"bool": {
"filter": {
"nested": {
"path": "dates",
"query": {
"range": {
"dates.Days": {
"format": "yyyy-MM-dd",
"gte": "2019-05-01",
"lte": "2019-05-30"
}
}
}
}
}
}
},
"aggs": {
"terms_parent_id": {
"terms": {
"field": "empId"
},
"aggs": {
"availabilities": {
"nested": {
"path": "dates"
},
"aggs": {
"avail": {
"range": {
"field": "dates.Days",
"ranges": [
{
"from": "2019-05-01",
"to": "2019-05-30"
}
]
},
"aggs": {
"count_Total": {
"value_count": {
"field": "dates.Days"
}
}
}
},
"max_hourly_inner": {
"max_bucket": {
"buckets_path": "avail>count_Total"
}
}
}
},
"bucket_selector_page_id_term_count": {
"bucket_selector": {
"buckets_path": {
"children_count": "availabilities>max_hourly_inner"
},
"script": "params.children_count>=19;" ---> give the number of days that should match
}
},
"hits": {
"top_hits": {
"size": 10
}
}
}
}
}
}
I found my own answer to this, although I'm not sure how efficient it is compared to the other answers:
GET test_index/_search
{
"query":{
"bool" : {
"filter" : {
"script" : {
"script" : {"source":"""
int count = 0;
for (int i=0; i<doc['dates'].length; ++i) {
if (params.first_date < doc['dates'][i].toInstant().toEpochMilli() && doc['dates'][i].toInstant().toEpochMilli() < params.second_date) {
count += 1;
}
}
if (count >= 2) {
return true
} else {
return false
}
""",
"lang":"painless",
"params": {
"first_date": 1554818400000,
"second_date": 1583020800000
}
}
}
}
}
}
}
where the parameters are the two dates in epoch time. I've chosen 2 matches here, but obviously you can generalise to any number.

Elasticsearch use filter on index only when index has field

There are 2 indexes: categories, posts.
categories
name
body
posts
name
body
publish_at
publish_until
I want to do a query on both indexes with a filter on publish_at and publish_until for the posts index.
http://localhost:9200/categories,posts/_search
{
"query": {
"bool": {
"must": {
"multi_match": {
"query": "keyword",
"fields": [
"name^3",
"body"
]
}
},
"filter": [{
"bool": {
"must": [
{
"range": {
"publish_at": {
"lte" : "now"
}
}
},
{
"range": {
"publish_until": {
"gt" : "now"
}
}
}
]
}
}]
}
}
}
This query only gives me posts as results. I also want categories in my results.
How do I apply the date range filters to only indexes with publish_at and publish_until fields and skip the date range filters for the other indexes?
Ok after a day of fiddling with bool I got it working:
{
"query": {
"bool" : {
"must" : [
{
"multi_match": {
"query": "keyword",
"fields": [
"name^3",
"body"
]
}
},
{
"bool": {
"should": [
{
"bool": {
"must": [
{
"range": {
"publish_at": {
"lte" : "now"
}
}
},
{
"range": {
"publish_until": {
"gt" : "now"
}
}
}
]
}
},
{
"bool": {
"must_not": [
{
"exists": {
"field": "publish_at"
}
},
{
"exists": {
"field": "publish_until"
}
}
]
}
}
]
}
}
]
}
}
}

ElasticSearch date range

I have the following query:
{
"query": {
"query_string": {
"query": "searchTerm",
"default_operator": "AND"
}
},
"facets": {
"counts": {
"date_histogram": {
"field": "firstdate",
"interval": "hour"
}
}
}
and I would like to add a date range to it, so as to retrieve values for the field firstdate which are within a specific from/to interval. Any suggestions on how to do it? Many thanks!
you just need to add a range filter to your query:
{
"query":{
"filtered": {
"query": {
"query_string": {"query": "searchTerm", "default_operator": "AND" }
},
"filter" : {
"range": {"firstdate": {"gte": "2014-10-21T20:03:12.963","lte": "2014-11-24T20:03:12.963"}}
}
}
},
"facets": {
"counts": {
"date_histogram": {
"field": "firstdate",
"interval": "hour"
}
}
}
}
Boolean query will work too,
{
"query" :{
"bool" : {
"must" : {
"range": {"firstdate": {"gte": "2014-10-21T20:03:12.963","lte": "2014-11-24T20:03:12.963"}}
},
"must" : {
"query_string": {
"query": "searchTerm",
"default_operator": "AND"
}
}
}
},
"facets": {
"counts": {
"date_histogram": {
"field": "firstdate",
"interval": "hour"
}
}
}
}
This query displays the results which appears in the given date range. "date_field_name" is the field name on which you want to set date range filters.
GET index_name/_search
{
"query": {
"bool": {
"must":[
{
"range": {
"date_field_name": {
"gte": "2019-09-23 18:30:00",
"lte": "2019-09-24 18:30:00"
}
}
}
]
}
},
"size": 10
}
https://your_elasticsearch/your_index PUT
{
"mappings": {
"properties": {
"created_at": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
}
https://your_elasticsearch/your_index/_search POST
{
"query": {
"bool": {
"filter": [
{
"range": {
"created_at": {
"gte": "2020-04-01 08:03:12",
"lte": "2020-04-01 20:03:12"
}
}
}
]
}
}
}

Resources