我的弹性搜索中有两个字段,分别是lowest_local_price和lowest_global_price。
我想在运行时将动态值映射到第三个字段price,基于本地或全球国家。
如果当地国家匹配,那么我想将lowest_local_price值映射到价格字段。
如果全球国家匹配,那么我想将lowest_global_price值映射到价格字段。
如果本地或全球国家/地区匹配,则我想在价格字段上应用范围查询,并将该文档提升2.0。
注意:这不是强制过滤或查询,如果匹配,则只想提升单据。
我已经尝试了以下解决方案,但对我不起作用。
查询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
]
]
];
查询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]]
],
]
]
];
他们都不为我工作,因为这可以提高医生的士气。我知道filter不适用于boost,那么使用范围查询和boost的动态字段映射的解决方案是什么?
请帮我解决这个问题。
提前谢谢!
您可以(很可能(通过使用bool
查询的组合在没有runtime_mappings
的情况下实现您想要的,方法如下。
让我们定义测试映射
我们需要澄清我们正在使用的映射,因为不同的字段类型需要不同的查询类型。
让我们假设您的映射如下:
PUT my-index-000001
{
"mappings": {
"dynamic": "runtime",
"properties": {
"country_en_name": {
"type": "text"
},
"lowest_local_price": {
"type": "float"
},
"global_rates": {
"properties": {
"UK": {
"properties":{
"lowest_global_price": {
"type": "float"
}
}
},
"FR": {
"properties":{
"lowest_global_price": {
"type": "float"
}
}
},
"US": {
"properties":{
"lowest_global_price": {
"type": "float"
}
}
}
}
}
}
}
}
注意,country_en_name
的类型为text
,通常情况下,这些字段应被索引为keyword
,但为了演示runtime_mappings
的使用,我将其保留为text
,并将在稍后展示如何克服这一限制。
对于Elasticsearch,bool
与if
相同
没有运行时映射的查询可能如下所示:
POST my-index-000001/_search
{
"query": {
"bool": {
"should": [
{
"match_all": {}
},
{
"bool": {
"should": [
{
"bool": {
"must": [
{
"match": {
"country_en_name": "UK"
}
},
{
"range": {
"lowest_local_price": {
"gte": 1000
}
}
}
]
}
},
{
"range": {
"global_rates.UK.lowest_global_price": {
"gte": 1000
}
}
}
],
"boost": 2
}
}
]
}
}
}
这可以解释为:
Any document
OR (
(document with country_en_name=UK AND lowest_local_price > X)
OR
(document with global_rates.UK.lowest_global_price > X)
)[boost this part of OR]
match_all
还需要返回与其他查询不匹配的文档。
查询的响应会是什么样子
让我们把一些文件放在ES:中
POST my-index-000001/_doc/1
{
"country_en_name": "UK",
"lowest_local_price": 1500,
"global_rates": {
"FR": {
"lowest_global_price": 1000
},
"US": {
"lowest_global_price": 1200
}
}
}
POST my-index-000001/_doc/2
{
"country_en_name": "FR",
"lowest_local_price": 900,
"global_rates": {
"UK": {
"lowest_global_price": 950
},
"US": {
"lowest_global_price": 1500
}
}
}
POST my-index-000001/_doc/3
{
"country_en_name": "US",
"lowest_local_price": 950,
"global_rates": {
"UK": {
"lowest_global_price": 1100
},
"FR": {
"lowest_global_price": 1000
}
}
}
现在,上面搜索查询的结果将类似于:
{
...
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 4.9616585,
"hits" : [
{
"_index" : "my-index-000001",
"_type" : "_doc",
"_id" : "1",
"_score" : 4.9616585,
"_source" : {
"country_en_name" : "UK",
"lowest_local_price" : 1500,
...
}
},
{
"_index" : "my-index-000001",
"_type" : "_doc",
"_id" : "3",
"_score" : 3.0,
"_source" : {
"country_en_name" : "US",
"lowest_local_price" : 950,
"global_rates" : {
"UK" : {
"lowest_global_price" : 1100
},
...
}
}
},
{
"_index" : "my-index-000001",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"country_en_name" : "FR",
"lowest_local_price" : 900,
"global_rates" : {
"UK" : {
"lowest_global_price" : 950
},
...
}
}
}
]
}
}
请注意,带有_id:2
的文档位于底部,因为它与任何增强的查询都不匹配。
runtime_mappings
有用吗
如果现有映射的数据类型不允许执行特定类型的查询,则运行时映射非常有用。在以前的版本(7.11之前(中,在这种情况下必须重新索引,但现在可以使用运行时映射(但查询更昂贵(。
在我们的案例中,我们将country_en_name
索引为text
,这适用于全文搜索,而不适用于精确查找。我们应该改为使用keyword
。这就是在runtime_mappings
:的帮助下查询的样子
POST my-index-000001/_search
{
"runtime_mappings": {
"country_en_name_keyword": {
"type": "keyword",
"script": {
"source": "emit(params['_source']['country_en_name'])"
}
}
},
"query": {
"bool": {
"should": [
{
"match_all": {}
},
{
"bool": {
"should": [
{
"bool": {
"must": [
{
"term": {
"country_en_name_keyword": "UK"
}
},
{
"range": {
"lowest_local_price": {
"gte": 1000
}
}
}
]
}
},
{
"range": {
"global_rates.UK.lowest_global_price": {
"gte": 1000
}
}
}
],
"boost": 2
}
}
]
}
}
}
请注意,我们创建了一个类型为keyword
的新运行时字段country_en_name_keyword
,并使用了term
查找而不是match
查询。