Elasticsearch Query: Final Result of Multiplication Using Evaluating Nested Objects and Functions
I have docs with some data and a specific list to skip in it (see mapping and data examples ):
I would like to write an ES request that does the following:
-
Calculate some "baseline" scores for documents (query 1):
{ "explain": true, "query": { "bool": { "should": [ { "constant_score": { "filter": { "term": { "type": "TYPE1" } } } }, { "function_score": { "linear": { "number": { "origin": 30, "scale": 20 } } } } ] } } }
-
At the end, multiply the score according to the missing percent of the specific id (In the example I used, omit the valut for A
"omit.id": "A"
). As a demonstration in Query 2, I computed this factor.{ "query": { "nested": { "path": "omit", "query": { "function_score": { "query": { "filtered": { "query": { "match_all": {} }, "filter": { "term": { "omit.id": "A" } } } }, "functions": [ { "linear": { "omit.percent": { "origin": 0, "scale": 50, "offset": 0, "decay": 0.5 } } } ], "score_mode": "multiply" } } } } }
To achieve this final multiplication, I ran into the following problems:
- If I compute the evaluation of a linear function inside a nested query (as per my interpretation), I cannot use any other field in the query
function_score
. - I cannot multiply the computed score by any other
function_score
that is encapsulated in a subquery.
I would like to ask for advice for solving this problem.
Note that perhaps I should get rid of this nested type and use key-value pairs instead. For example:
{
"omit": {
"A": {
"percent": 10
},
"B": {
"percent": 100
}
}
}
but unfortunately there will be a lot of keys, which will result in a huge (ever-growing) display, so I don't prefer this option.
source to share
At least I figured out a possible solution based on a "non-nested path". The complete script can be found here .
I changed the skip list as described in the question:
"omit": {
"A": {
"percent": 10
},
"B": {
"percent": 100
}
}
In addition, I set the flag enabled
on the false
that do not have these items in the map:
"omit": {
"type" : "object",
"enabled" : false
}
The last trick was to use script_score
as a function function_score
, because that's the only way I could use the value percent
on the _source.omit.A.percent
script:
{
"query": {
"function_score": {
"query": {
...
},
"script_score": {
"lang": "groovy",
"script": "if (_source.omit.A){(100-_source.omit.A.percent)/100} else {1}"
},
"score_mode": "multiply"
}
}
}
source to share