I have two fields in my elastic search which is lowest_local_price and lowest_global_price.
I want to map dynamic value to third field price on run time based on local or global country.
If local country matched then i want to map lowest_local_price value to price field.
If global country matched then i want to map lowest_global_price value to price field.
If local or global country matched then i want to apply range query on the price field and boost that doc by 2.0.
Note : This is not compulsary filter or query, if matched then just want to boost the doc.
I have tried below solution but does not work for me.
Query 1:
$params["body"] = [
"runtime_mappings" => [
"price" => [
"type" => "double",
"script" => [
"source" => "if (params['_source']['country_en_name'] == '$country_name' ) { emit(params['_source']['lowest_local_price']); } else { emit( params['_source']['global_rates']['$country->id']['lowest_global_price']); }"
]
]
],
"query" => [
"bool" => [
"filter" => [
"range" => [ "price" => [ "gte" => $min_price]]
],
"boost" => 2.0
]
]
];
Query 2:
$params["body"] = [
"runtime_mappings" => [
"price" => [
"type" => "double",
"script" => [
"source" => "if (params['_source']['country_en_name'] == '$country_name' ) { emit(params['_source']['lowest_local_price']); } else { emit( params['_source']['global_rates']['$country->id']['lowest_global_price']); }"
]
]
],
"query" => [
"bool" => [
"filter" => [
"range" => [ "price" => [ "gte" => $min_price, "boost" => 2.0]]
],
]
]
];
None of them working for me, because it can boost the doc. I know filter does not work with boost, then what is the solution for dynamic field mapping with range query and boost?
Please help me to solve this query.
Thank you in advance!
You can (most likely) achieve what you want without
runtime_mappings
by using a combination ofbool
queries, here's how.Let's define test mapping
We need to clarify what mapping we are working with, because different field types require different query types.
Let's assume that your mapping looks like this:
Note that
country_en_name
is of typetext
, in general such fields should be indexed askeyword
but for the sake of demonstration of the use ofruntime_mappings
I kept ittext
and will show later how to overcome this limitation.bool
is the same asif
for ElasticsearchThe query without runtime mappings might look like this:
This can be interpreted as the following:
The
match_all
is needed to return also documents that do not match the other queries.How will the response of the query look like?
Let's put some documents in the ES:
Now the result of the search query above will be something like:
Note that document with
_id:2
is on the bottom because it didn't match any of the boosted queries.Will
runtime_mappings
be of any use?Runtime mappings are useful in case there's an existing mapping with data types that do not permit to execute a certain type of query. In previous versions (before 7.11) one would have to do a reindex in such cases, but now it is possible to use runtime mappings (but the query is more expensive).
In our case, we have got
country_en_name
indexed astext
which is suited for full-text search and not for exact lookups. We should rather usekeyword
instead. This is how the query may look like with the help ofruntime_mappings
:Notice how we created a new runtime field
country_en_name_keyword
with typekeyword
and used aterm
lookup instead ofmatch
query.