2

我的弹性搜索中有两个字段,即最低本地价格最低价格

我想根据本地或全球国家将动态值映射到运行时的第三个字段价格

如果当地国家匹配,那么我想将最低本地价格值映射到价格字段。

如果全球国家匹配,那么我想将最低全球价格值映射到价格字段。

如果本地或全球国家/地区匹配,那么我想在价格字段上应用范围查询并将该文档提升 2.0

注意:这不是强制过滤器或查询,如果匹配则只想提升文档。

我尝试了以下解决方案,但对我不起作用。

查询一:

$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]]
                    ],
                    
                ]
            ]
        ];

他们都不为我工作,因为它可以提升文档。我知道过滤器不适用于boost,那么使用范围查询和boost进行动态字段映射的解决方案是什么?

请帮我解决这个问题。

先感谢您!

4

1 回答 1

0

runtime_mappings您可以(很可能)在不使用查询组合的情况下实现您想要bool的,方法如下。

让我们定义测试映射

我们需要澄清我们正在使用的映射,因为不同的字段类型需要不同的查询类型。

假设您的映射如下所示:

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是 type text,通常这些字段应该被索引,keyword但为了演示runtime_mappings我保留它的使用,text稍后将展示如何克服这个限制。

boolif与Elasticsearch相同

没有运行时映射的查询可能如下所示:

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
          }
        }
      ]
    }
  }
}

请注意我们如何创建一个country_en_name_keyword带有类型的新运行时字段keyword并使用term查找而不是match查询。

于 2022-02-02T10:45:11.057 回答