elasticsearch 如何在嵌套的script_score上添加中间过滤器?

qnzebej0  于 2023-01-12  发布在  ElasticSearch
关注(0)|答案(1)|浏览(117)

我正在用给定的汇率动态地过滤价格,并用脚本生成的分数对它们进行排序。但是有一件事我不知道如何做,那就是范围过滤。
例如,我只想获得product_platforms仅匹配10到100之间的分数。
索引请求。

PUT /test_products
{
  "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 0,
      "analysis": {
        "filter": {
          "autocomplete_filter": {
            "type": "edge_ngram",
            "min_gram": "2",
            "max_gram": "15"
          }
        },
        "analyzer": {
          "autocomplete": {
            "type": "custom",
            "tokenizer": "standard",
            "filter": [
              "lowercase",
              "autocomplete_filter"
            ]
          }
        }
      }
    },
  "mappings": {
    "properties": {
      "id": {
        "type": "keyword",
        "doc_values": true
      },
      "name": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword"
          },
          "raw": {
            "type": "keyword"
          }
        },
        "analyzer": "autocomplete",
        "search_analyzer": "standard"
      },
      "product_platforms": {
        "type": "nested",
        "properties": {
          "id": {
            "type": "long"
          },
          "platform_id": {
            "type": "long"
          },
          "price": {
            "type": "float"
          },
          "currency_id": {
            "type": "long"
          },
          "currency_code": {
            "enabled": false
          },
          "sku": {
            "type": "keyword"
          },
          "quantity": {
            "type": "long"
          }
        }
      }
    }
  }
}

插入测试文档:

POST /test_products/_bulk?pretty&refresh
{"index":{"_id": 1}}
{"id": 1, "name": "1. Product", "product_platforms": [{"id": 11, "platform_id": 3, "price": 100, "currency_id": 1, "currency_code": "TRY", "sku": "URN_1_1", "quantity": 1},{"id": 12, "platform_id": 3, "price": 75, "currency_id": 2, "currency_code": "USD", "sku": "URN_1_2", "quantity": 1},{"id": 13, "platform_id": 2, "price": 15, "currency_id": 2, "currency_code": "USD", "sku": "URN_1_3", "quantity": 1}]}
{"index":{"_id": 2}}
{"id": 2, "name": "2. Product", "product_platforms": [{"id": 21, "platform_id": 3, "price": 50, "currency_id": 1, "currency_code": "TRY", "sku": "URN_2_1", "quantity": 1},{"id": 22, "platform_id": 3, "price": 25, "currency_id": 2, "currency_code": "USD", "sku": "URN_2_2", "quantity": 1},{"id": 23, "platform_id": 3, "price": 75, "currency_id": 1, "currency_code": "TRY", "sku": "URN_2_3", "quantity": 1}, {"id": 24, "platform_id": 3, "price": 20, "currency_id": 2, "currency_code": "USD", "sku": "URN_2_4", "quantity": 1}]}

下面是我的搜索查询:

GET /test_products/_search
{
  "query": {
    "nested": {
      "path": "product_platforms",
      "score_mode": "max",
      "query": {
        "function_score": {
          "query": {
            "bool": {
              "must": [
                {
                  "term": {
                    "product_platforms.platform_id": {
                      "value": "3"
                    }
                  }
                }
              ]
            }
          },
          "boost_mode": "replace",
          "script_score": {
            "script": {
              "source": """

              doc['product_platforms.price'].value * (doc['product_platforms.currency_id'].value == 2 ? params.rate_usd : (doc['product_platforms.currency_id'].value == 3 ? params.rate_eur : params.rate_try))         """,
              "params": {
                "rate_try": 1,
                "rate_usd": 7,
                "rate_eur": 8
              }
            }
          }
        }
      },
      "inner_hits": {
        "name": "product_platforms",
        "_source": true,
        "size": 5,
        "sort": {
          "_script": {
            "type": "number",
            "script": {
              "lang": "painless",
              "source": """                 doc['product_platforms.price'].value * (doc['product_platforms.currency_id'].value == 2 ? params.rate_usd : (doc['product_platforms.currency_id'].value == 3 ? params.rate_eur : params.rate_try))               """,
              "params": {
                "rate_try": 1,
                "rate_usd": 7,
                "rate_eur": 8
              }
            },
            "order": "desc"
          }
        }
      }
    }
  },
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    }
  ]
}

顺便说一句,我使用的是7.10版本。

5sxhfpxr

5sxhfpxr1#

您可以再次重复这个分数计算器,这次使用它自己的布尔值script query
现在,由于您的货币转换脚本重复了太多次,您可以存储它,并在每次需要它时通过其ID引用它。当然,您将保持汇率参数化,但整个过程将更具可读性和可维护性。
因此,让我们先保存脚本:

POST _scripts/product-platforms-converter
{
  "script": {
    "source": """
      def price = doc['product_platforms.price'].value;
      def currency_id = doc['product_platforms.currency_id'].value;
    
      def converted_price = price * (currency_id == 2 
            ? params.rate_usd : (currency_id == 3 
                ? params.rate_eur : params.rate_try)); 
              
      if (params.final_range != null) {
        def is_in_range = converted_price >= params.final_range.gte 
            && converted_price <= params.final_range.lte;
        
        return is_in_range;
      }
      
      return converted_price;
      """,
    "lang": "painless"
  }
}

请注意,如果params中提供了final_range,则脚本返回boolean;如果不是,它只返回converted_price
之后,原始查询可以重写为:

GET /test_products/_search
{
  "query": {
    "nested": {
      "path": "product_platforms",
      "score_mode": "max",
      "query": {
        "function_score": {
          "query": {
            "bool": {
              "must": [
                {
                  "term": {
                    "product_platforms.platform_id": {
                      "value": "3"
                    }
                  }
                },
                {
                  "script": {
                    "script": {
                      "id": "product-platforms-converter",
                      "params": {
                        "rate_try": 1,
                        "rate_usd": 7,
                        "rate_eur": 8,
                        "final_range": {             <--- the desired "range" query
                          "gte": 10,
                          "lte": 100
                        }
                      }
                    }
                  }
                }
              ]
            }
          },
          "boost_mode": "replace",
          "script_score": {
            "script": {
              "id": "product-platforms-converter",
              "params": {
                "rate_try": 1,
                "rate_usd": 7,
                "rate_eur": 8
              }
            }
          }
        }
      },
      "inner_hits": {
        "name": "product_platforms",
        "_source": true,
        "size": 5,
        "sort": {
          "_script": {
            "type": "number",
            "script": {
              "id": "product-platforms-converter",
              "params": {
                "rate_try": 1,
                "rate_usd": 7,
                "rate_eur": 8
              }
            },
            "order": "desc"
          }
        }
      }
    }
  },
  "sort": [
    {
      "_score": {
        "order": "desc"
      }
    }
  ]
}

相关问题