【问题标题】:How to add between filter on nested script_score?如何在嵌套 script_score 的过滤器之间添加?
【发布时间】:2021-02-16 14:06:04
【问题描述】:

我正在使用给定的货币汇率动态过滤价格,并使用脚本生成的分数对其进行排序。但是有一件事我不知道该怎么做是范围过滤器。

例如,我只想让 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 版。

【问题讨论】:

    标签: elasticsearch elasticsearch-query elasticsearch-painless elasticsearch-scripting


    【解决方案1】:

    您可以再次重复该分数计算器,这次是在它自己的布尔值 script query 中。

    现在,由于您的货币转换脚本重复了太多次,您可以store it 并在每次需要时通过其 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"
      }
    }
    

    注意,如果final_rangeparams 中提供,则脚本返回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"
          }
        }
      ]
    }
    

    【讨论】:

    • 感谢@Joe,它现在按预期工作!非常感谢!
    • 你明白了??
    猜你喜欢
    • 2019-12-25
    • 2020-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-22
    • 2018-03-29
    • 2017-07-27
    相关资源
    最近更新 更多