Elasticsearch range query on number in string format - elasticsearch

I have an Elasticsearch index as follows
{
"Price": "50.99"
},
{
"Price": "30.99"
},
{
"Price": "40.99"
},
{
"Price": "10.99"
}
I'm trying to fetch the documents based on a range of price. I want to return the documents with a price range of 30-100. But it is not returning any document.
GET index_name/_search
{
"query": {
"bool": {
"must": [
{ "range": {"Price": {"gte": 40, "lte": 100}}}
]
}
}
}
Since the Price is in String format I'm not able to fetch the documents. I don't have previledges to change the index. Is there a way to query it without changing the index?

Best way : Change the field type to float
But anyway if you want to keep the field type is string you can use painless script to do that. i.e
GET index_name/_search
{
"query": {
"bool": {
"must": {
"script": {
"script": {
"inline": "Float.parseFloat(doc['Price.keyword'].value) >= 40 && Float.parseFloat(doc['Price.keyword'].value) <= 100",
"lang": "painless"
}
}
}
}
}
}

Related

Elasticsearch - boost some documents on top if sorted on a field value

This is my current elastic query. Currently its sorted based on review_rating. I want some products to be boosted on top of it. Is there any way to update the script function to update the review_rating value so that product_id "abc-xyz" and "dfgh-rt" can be boosted on the top.
GET products/_search
{
"query": {
"boosting": {
"positive": {
"function_score": {
"query": {
"bool": {
"boost": "0.1",
"must": [
{
"match_all": {}
}
]
}
},
"boost_mode": "avg",
"score_mode": "sum",
"functions": [
{
"script_score": {
"script": {
"source": "double mscore;\n int initBoostFactor = params.initBoostFactor;\nif(params.boost_products.size()>0 && (doc[params.boost_field].size()!=0 && params.boost_products.contains(doc[params.boost_field].value))){\n mscore=(priority+1)*initBoostFactor;\n}\n return mscore",
"lang": "painless",
"params": {
"boost_products": [
"abc-xyz",
"dfgh-rt"
]
"initBoostFactor": 100,
"boost_field": "product_id"
}
}
}
}
]
}
}
}
},
"sort": [
{
"review_rating": {
"order": "desc"
}
}
]
}
You can use pinned query to achieve what you are looking for Pinned query promotes selected documents to rank higher than those matching a given query. This feature is typically used to guide searchers to curated documents that are promoted over and above any "organic" matches for a search. The promoted or "pinned" documents are identified using the document IDs stored in the _id field.
So your query should look like this:
GET /_search
{
"query": {
"pinned": {
"ids": [ "abc-xyz", "dfgh-rt"],
"organic": {
[-->your query here<--]
}
}
}
}

update and retrieve in a single query elasticsearch

I want to update the status field to "IN_PROGRESS" from "FAILED" to all the docs in one of the ElasticSearch index that matches this below query and retrieve updated docs.
{
"query": {
"bool": {
"must": {
"match": { "status": "FAILED" }
},
"filter": [
{
"range": {
"count": { "gte": "2" }
}
},
{
"range": {
"updated": { "gte": "now-2h" }
}
}
]
}
}
}
I know I can achieve this by two queries (update_by_query to update and GET to retrieve all the updated docs). .The Problem is that I want to update and retrieve all the updated docs in a single query .
Is there any efficient way where I can perform this in a single query.
You can use below query with "_source": false which will return _id for all the documents.
POST multiapi/_search
{
"_source": false,
"query": {
"term": {
"status.keyword": {
"value": "FAILED"
}
}
}
}
From response you can get all the _ids and pass to the below Ids query.
POST multiapi/_update_by_query
{
"query": {
"ids": {
"values": ["M1BbcX4Bo1YkEVbN1wG1","NFBbcX4Bo1YkEVbN3gHm"]
}
},
"script": {
"source": "ctx._source['status'] = 'IN_PROGRESS'"
}
}
Also, if your index have large documents set then use search_after to retrive more then 10k documents.

Elasticsearch compare field data

I have a problem. and I have a two field in elasticsearch mapping.I want to compare two field data and want to list the result 1 returns. How can I do this?
{
"query": {
"bool": {
"must": {
"range": {
"price": {
"gt": 100
}
}
},
"filter": {
"script": {
"script": "doc['departureDate'].value-doc['returnDate'].value==1"
}
}
}
}
}

ElasticSearch filtering by field1 THEN field2 THEN take max of field3

I am struggling to get the information that I need from ElasticSearch.
My log statements are like this:
field1: Example
field2: Example2
field3: Example3
I would like to search a timeframe (using last 24 hours) to find all data that has this in field1 and that in field2.
There then may be multiple this.that.[field3] entries, so I want to only return the maximum of that field.
In fact, in my data, field3 is actually the key of the entry.
What is the best way of retrieving the information I need? I have managed to get the results returned using aggs, but the data is in buckets, and I am only interested in the data with the max value of field3.
I have added an example of the query that I am looking to do: https://jsonblob.com/54535d49e4b0d117eeaf6bb4
{
"size": 0,
"aggs": {
"agg_129": {
"filters": {
"filters": {
"CarName: Toyota": {
"query": {
"query_string": {
"query": "CarName: Toyota"
}
}
}
}
},
"aggs": {
"agg_130": {
"filters": {
"filters": {
"Attribute: TimeUsed": {
"query": {
"query_string": {
"query": "Attribute: TimeUsed"
}
}
}
}
},
"aggs": {
"agg_131": {
"terms": {
"field": "#timestamp",
"size": 0,
"order": {
"_count": "desc"
}
}
}
}
}
}
}
},
"query": {
"filtered": {
"query": {
"match_all": {}
},
"filter": {
"bool": {
"must": [
{
"range": {
"#timestamp": {
"gte": "2014-10-27T00:00:00.000Z",
"lte": "2014-10-28T23:59:59.999Z"
}
}
}
],
"must_not": []
}
}
}
}
}
So, that example above is showing only those that have CarName = Toyota and Attribute = TimeUsed.
My data is as follows:
There are x number of cars CarName and each car has y number of Attributes and each of those Attributes have a document with a timestamp.
To begin with, I was looking for a query for CarName.Attribute.timestamp (latest), however, if I am able to use just ONE query to get the latest timestamp for EVERY attribute for EVERY CarName, then that would decrease query calls from ~50 to one.
If you are using a ElasticSearch v1.3+, you can add a top_hits aggregation with parameter size:1 and descending sort on the field3 value.
This will return the whole document with maximum value on the field, as you wish.
This example in the documentation might do the trick.
Edit:
Ok, it seems you don't need the whole document, but only the maximum timestamp value. You can use a max aggregation instead of using a top_hits one.
The following query (not tested) should give you the maximum timestamp value for each top 10 Attribute value of each CarName top 10 value, in only one request.
terms aggregation is like a GROUP BY clause, and you should not have to query 50 times to retrieve the values of each CarName/Attribute combination : this is the point of nesting a terms aggregation for Attribute in the CarName aggregation.
Note that, to work properly, the CarName and Attribute fields should be not_analyzed. If it's not the case, you will have "funny" results in your buckets. The problem (and possible solution) is very well described here.
Feel free to change the size parameter of the terms aggregation to fit to your case.
{
"size": 0,
"aggs": {
"by_carnames": {
"terms": {
"field": "CarName",
"size": 10
},
"aggs": {
"by_attribute": {
"terms": {
"field": "Attribute",
"size": 10
},
"aggs": {
"max_timestamp": {
"max": {
"field": "#timestamp"
}
}
}
}
}
}
},
"query": {
"filtered": {
"filter": {
"bool": {
"must": [
{
"range": {
"#timestamp": {
"gte": "2014-10-27T00:00:00.000Z",
"lte": "2014-10-28T23:59:59.999Z"
}
}
}
]
}
}
}
}
}

search for a certain text between within a range of a certain timestamp with Elasticsearch

I have worked with Elasticsearch and have done some research on the Internet how to query data with a certain text and how to query data within a range of timestamp, using Elasticsearch PHP Client API. Now I would like to combine these two queries in one. Lets say search for a certain text and within a range of a certain timestamp. Can someone please tell me how to do that using Elasticsearch PHP Client API? Thanks in advanced! I have searched on the Internet but still cannot combine these two queries in one :-(
Here is an example of a bool query, the logic here is that the record must fall within a date range and should also contain the text in the textfield field. You could have both query conditions within the must clause.
{
"from": 0,
"size": 20,
"query": {
"bool": {
"must": [
{
"range": {
"datefield": {
"gte": "from",
"lte": "to"
}
}
}
],
"should": [
{
"match": {
"textfield": {
"query": "Name",
"boost": 10
}
}
}
]
}
}
}
UPDATE - OR MUST HAVE BOTH
{
"from": 0,
"size": 20,
"query": {
"bool": {
"must": [
{
"range": {
"datefield": {
"gte": "from",
"lte": "to"
}
}
},
{
"match": {
"textfield": {
"query": "Name",
"boost": 10
}
}
}
]
}
}
}

Resources