Elasticsearch按孩子排序

Dmi*_*sIr 24 elasticsearch

两个实体:集合和产品.收集是产品的父母.

我需要按照产品的条款进行搜索,并展示每个产品有4个产品.

收藏品和产品可以部分匹配,但最先匹配.如果匹配不满,则某些条款具有优先权.

示例:搜索"color:red"和"material:stone"需要首先显示红色宝石,然后显示任何其他红色(这是关于集合匹配和产品匹配).

所以,所有这些都通过以下要求解决:

{
  "query": {
    "has_child": {
      "type": "products",
      "query": {
        "bool": {
          "should": [
            {
              "constant_score": {
                "filter": {
                  "match_all": {}
                },
                "boost": 1
              }
            },
            {
              "constant_score": {
                "filter": {
                  "terms": { "_name": "colors", "colors": [5] }
                },
                "boost": 1.2
              }
            },
            {
              "constant_score": {
                "filter": {
                  "terms": { "_name": "materials", "productTypes": [6] }
                },
                "boost": 1
              }
            }
          ]
        }
      },
      "score_mode": "max",
      "inner_hits": {
        "size": 4,
        "sort": [
          "_score"
        ]
      }
    }
  },
  "sort": [
    "_score"
  ]
}
Run Code Online (Sandbox Code Playgroud)

好的,现在麻烦了.

需要按价格排序.作为ASC,作为DESC.价格是产品的财产.

需要按匹配产品的价格排序,因此无法将价格转移到收集.需要按价格排序作为产品的集合.按照匹配产品的最小(或最大)价格排序的集合.

需要按价格排序只有100%匹配的产品(嗯,部分匹配也可以排序,但之后).我的意思是,排序必须像ORDER BY _score,price

例如,我想得到的,按价格排序asc,[nn]表示部分匹配的产品:

Collection1
100 - 200 - 800 - [99]
Collection2
300 - 500 - [10] - [20]
Collection3
400 - 450 - 500 - [100]
Run Code Online (Sandbox Code Playgroud)

我发现不支持按孩子排序.并建议重新计算得分.但我正在使用得分排序.我的尝试是

{
  "query": {
    "has_child": {
      "type": "products",
      "query": {
        "function_score": {
          "query": {
            "bool": {
              "should": [
                ... same query as above ...
              ]
            }
          },
          "functions": [
            {
              "script_score": {
                "script": "ceil(_score * 100) * 100000 + (99999 - doc['price'].value/100)",
                "lang": "expression"
              }
            }
          ]
        }
      },
      "score_mode": "max",
      "inner_hits": {
        "size": 4,
        "sort": [
          "_score",
          {
            "price": {
              "order": "desc"
            }
          }
        ]
      }
    }
  },
  "sort": [
    "_score"
  ]
}
Run Code Online (Sandbox Code Playgroud)

但我真的对结果得分感到困惑,我可以在回答中看到.请求帮助:)或者,可能是,删除它并创建嵌套索引?

UPD:发现分数有问题.默认情况下,弹性组合得分和script_score的结果.所以得分是ceil(_score * 100) * 100000 + (99999 - doc['price'].value/100) * _score- 这可能打破了想法,但很容易用boost_mode参数来修复function_score.结果查询:

{
  "query": {
    "has_child": {
      "type": "products",
      "query": {
        "function_score": {
          "query": {
            "bool": {
              "should": [
                ... same query as above ...
              ]
            }
          },
          "functions": [
            {
              "script_score": {
                "script": "ceil((log10(_score)+10) * 100) * 100000 + (99999 - doc['price'].value)",
                "lang": "expression"
              }
            }
          ],
          "boost_mode": "replace"
        }
      },
      "score_mode": "max",
      "inner_hits": {
        "size": 4,
        "sort": [
          "_score",
          {
            "price": {
              "order": "desc"
            }
          }
        ]
      }
    }
  },
  "sort": [
    "_score"
  ]
}
Run Code Online (Sandbox Code Playgroud)

boost_mode == 'replace表示"使用功能结果作为分数".另外,使用log10来确定_score中有多少位数.按价格排序DESC需要将公式更改为ceil((log10(_score)+10) * 100) * 100000 + (doc['price'].value)

UPD2

由于单精度限制,公式ceil((log10(_score)+10) * 100) * 100000 + (99999 - doc['price'].value)返回100099952价格48和价格50(boost == 1,queryNorm == 1).

新公式ceil((log10(_score)+5) * 100) * 10000 + (9999 - ceil(log10(doc['price'].value) * 1000))- 减少了得分的位数,并从价格转换为lg价格和减少的位数.欢迎反馈.

gat*_*isr 2

感谢分享,更新了最新公式以ceil((log10(_score+1)+5) * 100) * 10000 + (9999 - ceil(log10(doc['price'].value +1) * 1000))添加 +1 来评分,因为在某些情况下它会返回如下错误:

 "function score query returned an invalid score: -Infinity for doc: 4580"
Run Code Online (Sandbox Code Playgroud)

更新:出现另一个错误:

 "function score query returned an invalid score: NaN for doc: 1739"
Run Code Online (Sandbox Code Playgroud)

更改公式以ceil((log10(_score+1)+5) * 100) * 10000 + (9999 - ceil(log10(doc['price'].value +1) * 1000))向文档值添加 +1 来解决此问题

更新 2:出现另一个错误:

 "function score query returned an invalid score: NaN for doc: 1739"
Run Code Online (Sandbox Code Playgroud)

更改公式以ceil((log10(_score+1)+5) * 100) * 10000 + (9999 - ceil(log10(doc['price'].value > 0 ? doc['price'].value : 1) * 1000))用表达式替换 +1

更新 3:出现另一个错误:

不再有错误消息,现在很难找到,但它与之前的类似:(

将公式更改为ceil(_score+1) + ceil((doc['price'].value > 0 ? doc['price'].value : 1) * 100)简化公式,这样我就可以理解并且它今天仍然有效:)