Elasticsearch: multiple sorts for nested fields - sorting

have a situation where treatment has a price and hospital may or may not want to display it.
so there is a price field PLUS a lp_low_priority field.
value of lp_low_priority is 1(true) when price is not set(price is_null).
hospital doc is saved with its nested treatments.
when user searches for treatment he get list of hospitals with minimum price of the treatment.
now the sort works fine.
BUT i want the hospital with that treatment with the lp_low_priority = 1 to come at last.
Code to search is like
{
"sort": [
{
"treatments.lowest_price": {
"nested_filter": {
"term": {
"treatments.treatment_slug": "heart-surgery"
}
},
"mode": "avg",
"order": "asc"
}
},
{
"treatments.lp_low_priority": {
"order": "asc",
"nested_filter": {
"term": {
"treatments.treatment_slug": "heart-surgery"
}
},
"mode": "max"
}
}
],
"query": {
"filtered": {
"filter": [
{
"term": {
"treatments.treatment_slug": "heart-surgery"
}
},
{
"term": {
"treatments.status": "active"
}
},
{
"term": {
"treatments.treatment_status": "active"
}
},
{
"term": {
"hospital_status": "active"
}
},
{
"terms": {
"location.country": [
"India"
]
}
}
]
}
}
}
the result is way too weird.
if I only use
{
"sort": [
{
"treatments.lowest_price": {
"nested_filter": {
"term": {
"treatments.treatment_slug": "heart-surgery"
}
},
"mode": "avg",
"order": "asc"
}
}
The sorting is in order but then you see the lp_low_priority come first in order, which is OK(but not the requirement).
Can i even use more than one sorts for nested fields.

Related

Elastic search sort with match word if it is exist

I have the following document structure example:
{
'is_creator' : 1,
'is_verified_by_id' : 0,
'is_verified' : 0,
'country' : 'US'
}
currently i do have the following sorting filter
["is_creator" => "desc"],
["is_verified" => "desc"]
so it will sort the creator users first then the verified ones and etc..
Question:
How i can search the results with same sorting method but for selected country first then other countries, for example i want to apply the same sort but the country must be US then other countries, like this order:
- Creators from the same country (US).
- Creators from rest countries (other countries).
- Verified by Admin from same country (US)
- Verified by Admin rest countries (other countries).
- Verified by ID from same country (US)
- Verified by ID from rest countries (other countries)
- Not verified from same country (US)
- Not verified from rest countries (other countries)
i hope the question is understandable.
Thanks !
In elastic search you can use bool query to in combination with term query to search.
Below are the queries you asked:
- Creators from the same country (US).
Use must block of bool query to specify that the result docs must meet the specified condition
GET <INDEX_NAME>/_search
{
"query": {
"bool": {
"must": [
{ "term": { "country": { "value": "US" } } }
]
}
},
"sort": [
{ "is_creator": { "order": "desc" } },
{ "is_verified": { "order": "desc" } }
]
}
- Creators from rest countries (other countries)
Use must_not block of bool query to specify that the result docs must not meet the specified condition
GET <INDEX_NAME>/_search
{
"query": {
"bool": {
"must_not": [
{ "term": { "country": { "value": "US" } } }
]
}
},
"sort": [
{ "is_creator": { "order": "desc" } },
{ "is_verified": { "order": "desc" } }
]
}
- Verified by Admin from same country (US)
Add one more term for admin verification in must block
GET <INDEX_NAME>/_search
{
"query": {
"bool": {
"must": [
{ "term": { "country": { "value": "US" } } },
{ "term": { "is_verified": { "value": 1 } } }
]
}
},
"sort": [
{ "is_creator": { "order": "desc" } },
{ "is_verified": { "order": "desc" } }
]
}
- Verified by Admin rest countries (other countries).
Add is_verified to must block and country to must_not to get the only the verified docs for all countries other than the specified country
GET <INDEX_NAME>/_search
{
"query": {
"bool": {
"must": [
{ "term": { "is_verified": { "value": 1 } } }
],
"must_not": [
{ "term": { "country": { "value": "US" } } }
]
}
},
"sort": [
{ "is_creator": { "order": "desc" } },
{ "is_verified": { "order": "desc" } }
]
}
- Verified by ID from same country (US)
Add is_verified_by_id and country to the must block to get the only the verified by id docs for the specified country
GET <INDEX_NAME>/_search
{
"query": {
"bool": {
"must": [
{ "term": { "country": { "value": "US" } } },
{ "term": { "is_verified_by_id": { "value": 1 } } }
]
}
},
"sort": [
{ "is_creator": { "order": "desc" } },
{ "is_verified": { "order": "desc" } }
]
}
- Verified by ID from rest countries (other countries)
Add is_verified_by_id to must block and country to must_not to get the only the verified by id docs for all countries other than the specified country
GET <INDEX_NAME>/_search
{
"query": {
"bool": {
"must": [
{ "term": { "is_verified_by_id": { "value": 1 } } }
],
"must_not": [
{ "term": { "country": { "value": "US" } } }
]
}
},
"sort": [
{ "is_creator": { "order": "desc" } },
{ "is_verified": { "order": "desc" } }
]
}
- Not verified from same country (US)
Add is_verified to must_not block and country to must to get the non verified docs for the specified country
GET <INDEX_NAME>/_search
{
"query": {
"bool": {
"must": [
{ "term": { "country": { "value": "US" } } }
],
"must_not": [
{ "term": { "is_verified": { "value": 1 } } }
]
}
},
"sort": [
{ "is_creator": { "order": "desc" } },
{ "is_verified": { "order": "desc" } }
]
}
- Not verified from rest countries (other countries)
Add is_verified and country to must_not block to get the non verified docs for the countries other than the specified one
GET <INDEX_NAME>/_search
{
"query": {
"bool": {
"must_not": [
{ "term": { "is_verified": { "value": 1 } } },
{ "term": { "country": { "value": "US" } } }
]
}
},
"sort": [
{ "is_creator": { "order": "desc" } },
{ "is_verified": { "order": "desc" } }
]
}

Elasticsearch matched results on top and remaining after them

I am using elasticsearch in my application and I am new to Elasticsearch.
I have an index called files with some tags associated to it. I want to query them using tags. something like this may be
{
"query": {
"terms": {
"tags": [
"xxx",
"yyy"
]
}
},
"sort": [
{
"created_at": {
"order": "desc"
}
}
]
}
The above query results only matched ones. But I need all the results with matched results on top. And also sort by created_at. How to do it?
I TRIED THIS:
{
"query": {
"bool": {
"should": [
{
"terms": {
"name": [
"cool",
"co"
]
}
}
],
"minimum_should_match": 0
}
},
"sort": [
{
"_score": {
"order": "desc"
}
},
{
"created_at": {
"order": "desc"
}
}
]
}
But results zero always.
You can use bool queries with should.
Since you want all the docs, you can use a match_all. should only affects the scoring and not whether documents are included or not.
{
"query": {
"bool": {
"must" :
{
"match_all": { }
}
},
"should": [
{ "terms" : {
"tags": [
"xxx",
"yyy"
]
} }]
},
"sort": [
{ "_score":
{ "order": "desc"
}
},
{ "created_at":
{ "order": "desc"
}
}
]
}
Also, sort can take an array so you can pass in your multiple parameters basis which the results should be sorted.

Querying multiple indices but limit the results from a single index - Elasticsearch 6.x

All, I am using ES 6.7 and trying to return the results from a single index while querying two indices( customer, payment) and doing a terms lookup against user-customers index. The index I want data from(customer) has more fields than the second index. But for some reason, I only see results from the payment index. The fields customerName, customerNumber, state, address only exist on customer index. But I only want customers that has totalCredits > 0(This exists only on payment index) ordered by the logic in the sort array. I tried adding an _index filter( setting this to customer) but dint help. Adding source filtering doesn't help either. Is this doable in ES 6.7?. Am I left with the option of adding the fields in the sort array to the payment index or are there some other options?
ES query
GET customer,payment/_search
{
"sort": [
{
"customerName": {
"order": "asc",
"unmapped_type": "keyword"
}
},
{
"customerNumber": {
"order": "asc"
}
},
{
"state": {
"order": "asc",
"unmapped_type": "keyword"
}
},
{
"address": {
"order": "asc",
"unmapped_type": "keyword"
}
}
],
"query": {
"bool": {
"filter": [
{
"bool": {
"must_not": [
{
"terms": {
"status": [
"pending"
]
}
}
]
}
}
],
"must": [
{
"terms": {
"customerNumber": {
"index": "user-customers",
"type": "_doc",
"id": "rennish#emial.com",
"path": "users"
}
}
},
{
"range": {
"totalCredits": {
"gt": 0
}
}
}
]
}
}
}

elasticsearch to apply a sort to a query, the select top N for aggregate

The query below aggregates over the entire result of the query, and size only affects what is returned rather than what is aggregated.
How would I modify the search so that only the top N results after sort is processed by the average aggregation?
It seems such a simple requirement that I'm expecting it to be possible but so far all my efforts have failed, and similar questions on SO have gone unanswered.
{
"size": 0,
"query": {
"constant_score": {
"filter": {
"bool": {
"must": [
{
"term": {
"jobType": "LiveEventScoring"
}
},
{
"term": {
"host": "MTVMDANS"
}
},
{
"term": {
"dataSourceCode": "AU_VIRT"
}
},
{
"term": {
"measurement": "EventDataLoadFromCacheDuration"
}
}
]
}
}
}
},
"sort": {
"timestamp": {
"order": "desc"
}
},
"aggs": {
"avgDuration": {
"avg": {
"field": "elapsedMs"
}
}
}
}

How to do nested AND and OR filters in ElasticSearch?

My filters are grouped together into categories.
I would like to retrieve documents where a document can match any filter in a category, but if two (or more) categories are set, then the document must match any of the filters in ALL categories.
If written in pseudo-SQL it would be:
SELECT * FROM Documents WHERE (CategoryA = 'A') AND (CategoryB = 'B' OR CategoryB = 'C')
I've tried Nested filters like so:
{
"sort": [{
"orderDate": "desc"
}],
"size": 25,
"query": {
"match_all": {}
},
"filter": {
"and": [{
"nested": {
"path":"hits._source",
"filter": {
"or": [{
"term": {
"progress": "incomplete"
}
}, {
"term": {
"progress": "completed"
}
}]
}
}
}, {
"nested": {
"path":"hits._source",
"filter": {
"or": [{
"term": {
"paid": "yes"
}
}, {
"term": {
"paid": "no"
}
}]
}
}
}]
}
}
But evidently I don't quite understand the ES syntax. Is this on the right track or do I need to use another filter?
This should be it (translated from given pseudo-SQL)
{
"sort": [
{
"orderDate": "desc"
}
],
"size": 25,
"query":
{
"filtered":
{
"filter":
{
"and":
[
{ "term": { "CategoryA":"A" } },
{
"or":
[
{ "term": { "CategoryB":"B" } },
{ "term": { "CategoryB":"C" } }
]
}
]
}
}
}
}
I realize you're not mentioning facets but just for the sake of completeness:
You could also use a filter as the basis (like you did) instead of a filtered query (like I did). The resulting json is almost identical with the difference being:
a filtered query will filter both the main results as well as facets
a filter will only filter the main results NOT the facets.
Lastly, Nested filters (which you tried using) don't relate to 'nesting filters' like you seemed to believe, but related to filtering on nested-documents (parent-child)
Although I have not understand completely your structure this might be what you need.
You have to think tree-wise. You create a bool where you must (=and) fulfill the embedded bools. Each embedded checks if the field does not exist or else (using should here instead of must) the field must (terms here) be one of the values in the list.
Not sure if there is a better way, and do not know the performance.
{
"sort": [
{
"orderDate": "desc"
}
],
"size": 25,
"query": {
"query": { #
"match_all": {} # These three lines are not necessary
}, #
"filtered": {
"filter": {
"bool": {
"must": [
{
"bool": {
"should": [
{
"not": {
"exists": {
"field": "progress"
}
}
},
{
"terms": {
"progress": [
"incomplete",
"complete"
]
}
}
]
}
},
{
"bool": {
"should": [
{
"not": {
"exists": {
"field": "paid"
}
}
},
{
"terms": {
"paid": [
"yes",
"no"
]
}
}
]
}
}
]
}
}
}
}
}

Resources