How to sort by field in elasticsearch? - sorting

I have a mysql query like this:
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID
FROM wp_posts
WHERE 1=1
AND wp_posts.ID IN (2991,2993,2989,2983,2987)
AND wp_posts.post_type = 'product'
AND ((wp_posts.post_status = 'publish'))
ORDER BY FIELD( wp_posts.ID, 2991,2993,2989,2983,2987 )
LIMIT 0, 10
And I want to note the specific line:
ORDER BY FIELD( wp_posts.ID, 2991,2993,2989,2983,2987 )
In elasticsearchwe can only have sort order by asc or desc: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-sort.html#_sort_order
So anyone can point me out on how to achieve the order by field (id, x,y,z) in elasticsearch query?

It's not as easy as SQL but you can use function_score and multiple matches for you'r values.
something like this:
{
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{
"terms": {
" ID": [
2991,
2993,
2989,
2983,
2987
]
}
},
{
"term": {
"post_type": {
"value": "product"
}
}
},
{
"term": {
"post_status": {
"value": "publish"
}
}
}
]
}
},
"boost": "5",
"functions": [
{
"filter": {
"match": {
"ID": 2991
}
},
"weight": 100
},
{
"filter": {
"match": {
"test": 2993
}
},
"weight": 99
},
{
"filter": {
"match": {
"test": 2989
}
},
"weight": 98
},
{
"filter": {
"match": {
"test": 2983
}
},
"weight": 97
},
{
"filter": {
"match": {
"test": 2987
}
},
"weight": 96
}
],
"score_mode": "max",
"boost_mode": "multiply"
}
}
}

Related

how to match multiple fields inside filter keyword in elastic search query?

I want to add one more field inside match inside function block in my query, but when i am adding, i am getting an error ------ "reason" : "[match] query doesn't support multiple fields, found [gender] and [id]",
How do i do it?
GET exp/_search
{
"_source": ["score","answer","gender","id"]
, "query": {
"function_score": {
"query": {
"match": {
"score": 10
}
},
"functions": [
{
"filter": {
"match":{
"gender":"male",
"id":1
}
},
"weight": 2
}
]
}
}
}
You can create bool query inside filter and it will be resolved your issue. match query does not support providing 2 diffrent field and values. You can use bool query for same purpose.
{
"_source": [
"score",
"answer",
"gender",
"id"
],
"query": {
"function_score": {
"query": {
"match": {
"score": 10
}
},
"functions": [
{
"filter": {
"bool": {
"must": [
{
"match": {
"gender": "male"
}
},
{
"match": {
"id": 1
}
}
]
}
},
"weight": 2
}
]
}
}
}
Also, If you want to apply two different boosting value for gender and id then you can give two filter clause as shown below:
{
"_source": [
"score",
"answer",
"gender",
"id"
],
"query": {
"function_score": {
"query": {
"match": {
"score": 10
}
},
"functions": [
{
"filter": {
"match": {
"gender": "male"
}
},
"weight": 2
},
{
"filter": {
"match": {
"id": 1
}
},
"weight": 1
}
]
}
}
}

ElasticSearch - Filtering data returned from nested query

I am have a set of data in the following structure:
[
{
"productId": "ProductId1",
"customerNumbers": [
"customer": {
"name": "Prod1Cust1",
"totalOrders": 23
},
"customer": {
"name": "Prod2Cust1",
"totalOrders": 5
},
"customer": {
"name": "Prod3Cust1",
"totalOrders": 5
}
]
},
{
"productId": "ProductId2",
"customerNumbers": [
"customer": {
"name": "Prod2Cust1",
"totalOrders": 23
},
"customer": {
"name": "Prod2Cust1",
"totalOrders": 5
}
]
}
]
and I need to fetch all the records which have a prefix of "Prod1 as in name field(in the example avoid, only first record should be returned i.e. ProductId1). Also, when the data is returned, I need to just fetch just the customer number whose prefix is Prod1 i.e:
Correct Output:
{
"productId": "ProductId1",
"customerNumbers": [
"customer": {
"name": "Prod1Cust1",
"totalOrders": 23
}
]
}
Instead of:
{
"productId": "ProductId1",
"customerNumbers": [
"customer": {
"name": "Prod1Cust1",
"totalOrders": 23
},
"customer": {
"name": "Prod2Cust1",
"totalOrders": 5
},
"customer": {
"name": "Prod3Cust1",
"totalOrders": 5
}
]
}
I'm able to fetch the records whose Name prefix is "Prod1" using nested query coupled with MatchPhrasePrefixQuery (this returns me result with all the customer numbers). How can I further filter the data to get customer numbers whose Name prefix is "Prod1".
Following is my current query:
{
"from": 0,
"size": 10,
"sort": [
{
"name.keyword": {
"missing": "_first",
"order": "asc"
}
}
],
"query": {
"bool": {
"must": [
{
"bool": {
"must": [
{
"nested": {
"query": {
"bool": {
"must": [
{
"match": {
"customerNumbers.name": {
"query": "Prod1",
"type": "phrase_prefix"
}
}
}
]
}
},
"path": "customerNumbers"
}
}
]
}
}
]
}
}
}
P.S: I'm using ElasticSearch 5.x with Nest.
Try using inner_hits:
PUT products
{"mappings":{"_doc":{"properties":{"customerNumbers":{"type":"nested"}}}}}
POST products/_doc
{"productId":"ProductId1","customerNumbers":[{"name":"Prod1Cust1","totalOrders":23},{"name":"Prod2Cust1","totalOrders":5},{"name":"Prod3Cust1","totalOrders":5}]}
POST products/_doc
{"productId":"ProductId2","customerNumbers":[{"name":"Prod2Cust1","totalOrders":23},{"name":"Prod2Cust1","totalOrders":5}]}
GET products/_search
{
"_source": "inner_hits",
"from": 0,
"size": 10,
"query": {
"bool": {
"must": [
{
"bool": {
"must": [
{
"nested": {
"path": "customerNumbers",
"query": {
"bool": {
"must": [
{
"match_phrase_prefix": {
"customerNumbers.name": {
"query": "Prod1"
}
}
}
]
}
},
"inner_hits": {}
}
}
]
}
}
]
}
}
}
yielding the following hits
[
{
"_index":"products",
"_type":"_doc",
"_id":"tyQGo3EBdiyDG0RsTa0N",
"_score":0.9808292,
"_source":{
},
"inner_hits":{
"customerNumbers":{
"hits":{
"total":1,
"max_score":0.9808292,
"hits":[
{
"_index":"products",
"_type":"_doc",
"_id":"tyQGo3EBdiyDG0RsTa0N",
"_nested":{
"field":"customerNumbers",
"offset":0
},
"_score":0.9808292,
"_source":{
"name":"Prod1Cust1", <-----
"totalOrders":23
}
}
]
}
}
}
}
]

elasticsearch boost query in feild having multiple value

I have some document in elasticsearch index. Here is the sample document
DOC1
{
"feild1":["hi","hello","goodmorning"]
"feild2":"some string"
"feild3":{}
}
DOC2
{
"feild1":["hi","goodmorning"]
"feild2":"some string"
"feild3":{}
}
DOC3
{
"feild1":["hi","hello"]
"feild2":"some string"
"feild3":{}
}
I want to query for feild1 having values "hi" and "hello" if both is present then that document should come first if any one is present then it should come after that.
for example:
result should be in order of DOC1, DOC3, DOC2. I tried with boost query. but it is retuning not in the order that I want. Here is the query that I am trying.
{
"query": {
"bool": {
"must": [
{
"match_phrase": {
"avail_status": true
}
},
{
"bool": {
"should": [
{
"constant_score": {
"filter": {
"terms": {
"feild1": [
"hi"
]
}
},
"boost": 20
}
},
{
"constant_score": {
"filter": {
"terms": {
"feild1": [
"hello"
]
}
},
"boost": 18
}
}
]
}
}
]
}
}
}
this is returning me first those document having "hi" and then those having "hello". Thanks in advance!
To add extra boost for documents with larger field1, you can put funtion_score script score.
Mappings
{
"mappings": {
"document_type" : {
"properties": {
"field1" : {
"type": "text",
"fielddata": true
},
"field2" : {
"type": "text"
},
"field3" : {
"type": "text"
}
}
}
}
}
Index documents
POST custom_score_index1/document_type
{
"feild1":["hi","hello","goodmorning"],
"feild2":"some string",
"feild3":{}
}
POST custom_score_index1/document_type
{
"feild1":["hi","goodmorning"],
"feild2":"some string",
"feild3":{}
}
POST custom_score_index1/document_type
{
"feild1":["hi","hello"],
"feild2":"some string",
"feild3":{}
}
Query with function score add extra _score for larger size for field1
POST custom_score_index1/document_type/_search
{
"query": {
"function_score": {
"query": {
"bool": {
"must": [{
"match_phrase": {
"avail_status": true
}
},
{
"bool": {
"should": [{
"constant_score": {
"filter": {
"terms": {
"feild1": [
"hi"
]
}
},
"boost": 20
}
},
{
"constant_score": {
"filter": {
"terms": {
"feild1": [
"hello"
]
}
},
"boost": 18
}
}
]
}
}
]
}
},
"functions": [{
"script_score": {
"script": {
"inline": "_score + 10000 * doc['field1'].length"
}
}
}],
"score_mode": "sum",
"boost_mode": "sum"
}
}
}

elasticsearch: Add weight for each match of array

I want to add a weight for each match (instead of adding a weight once if one of those matched):
Having docs like this:
[{
"username": "xyz",
"categories": [
{
"category.id": 1
},
{
"category.id": 2
}
]
}, {
"username": "xyz2",
"categories": [
{
"category.id": 1
}
]
}]
And currently, I have this query:
{
"query": {
"filtered": {
"query": {
"function_score": {
"query": {
"bool": {}
},
"score_mode": "sum",
"boost_mode": "sum",
"functions": [
{
"weight": 1.1,
"filter": {
"terms": {
"category.id": [
1,
2
]
}
}
}
]
}
},
"filter": {
"bool": {
"must_not": [
{
"terms": {
"_id": [
8
]
}
}
]
}
}
}
},
"from": 0,
"size": 30
}
With this query, both entries would receive a single weight of 1.1, but I want the first entry to get 2 * 1.1 because 2 categories are matched. How could I achieve that?
EDIT: Sorry, I missed to add elastic search version. It's 1.7.2.
This might be a bit cumbersome, since for multiple IDs that query will need to have multiple statements, but I don't think there is any other way. Also, notice that your field referencing is not complete - it should be categories.category.id to be correct. Also, be careful when upgrading with dots in field names. This changed in some releases over time.
{
"query": {
"filtered": {
"query": {
"function_score": {
"query": {
"match_all": {}
},
"score_mode": "sum",
"boost_mode": "sum",
"functions": [
{
"weight": 1.1,
"filter": {
"term": {
"categories.category.id": 1
}
}
},
{
"weight": 1.1,
"filter": {
"term": {
"categories.category.id": 2
}
}
}
]
}
},
"filter": {
"bool": {
"must_not": [
{
"terms": {
"_id": [
8
]
}
}
]
}
}
}
},
"from": 0,
"size": 30
}

Elasticsearch must_not filter not works with a big bunch of values

I have the next query that include some filters:
{
"from": 0,
"query": {
"function_score": {
"query": {
"filtered": {
"filter": {
"bool": {
"must": [
{
"term": {
"idpais": [
115
]
}
},
{
"term": {
"tipo": [
1
]
}
}
],
"must_not": [
{
"term": {
"idregistro": [
5912471,
3433876,
9814443,
11703069,
6333176,
8288242,
9924922,
6677850,
11852501,
12530205,
4703469,
12776479,
12287659,
11823679,
12456304,
12777457,
10977614,
...
]
}
}
]
}
},
"query": {
"bool": {
"should": [
{
"match_phrase": {
"area": "Coordinator"
}
},
{
"match_phrase": {
"company": {
"boost": 5,
"query": "IBM"
}
}
},
{
"match_phrase": {
"topic": "IT and internet stuff"
}
},
{
"match_phrase": {
"institution": {
"boost": 5,
"query": "University of my city"
}
}
}
]
}
}
}
},
"script_score": {
"params": {
"idpais": 115,
"idprovincia": 0,
"relationships": []
},
"script_id": "ScoreUsuarios"
}
}
},
"size": 24,
"sort": [
{
"_script": {
"order": "desc",
"script_id": "SortUsuarios",
"type": "number"
}
}
]
}
The must_not filter has a big bunch of values to exclude (around 200 values), but it looks like elasticsearch ignores those values and it includes on the result set. If I try to set only a few values (10 to 20 values) then elasticsearch applies the must_not filter.
Exists some restriction a bout the amount of values in the filters? Exists some way to remove a big amount of results from the query?
terms query is used for passing a list of values not term query.You have to use it like below in your must filter.
{
"query": {
"terms": {
"field_name": [
"VALUE1",
"VALUE2"
]
}
}
}

Resources