当前位置: 首页 > 知识库问答 >
问题:

Elasticsearch按子项排序

侯和惬
2023-03-14

两个实体:收集和产品。集合是Product的父级。

我需要通过产品的条款搜索,并显示每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"
  ]
}

好了,现在麻烦来了。

需要按价格排序。作为ASC,作为DESC。价格是产品的属性。

需要按照匹配产品的价格进行排序,所以不能把价格移到集合中。需要按价格排序作为一个集合作为产品。按匹配产品的最小(或最大)价格排序的集合。

需要排序的价格只有100%匹配的产品(好吧,部分匹配可以排序太,但后)。我是说,排序必须像按分数,价格排序一样

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

Collection1
100 - 200 - 800 - [99]
Collection2
300 - 500 - [10] - [20]
Collection3
400 - 450 - 500 - [100]

我发现不支持按孩子排序。以及重新计算分数的建议。但我用分数来按匹配排序。我的尝试是

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

但是我真的很困惑于我可以在答案中看到的结果。寻求帮助:)或者,也许,删除这个并创建一个嵌套索引

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

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

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,对于price48,对于price50(boost==1,queryNorm==1),因为有单个精度限制。

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

共有1个答案

林泰平
2023-03-14

感谢您的分享,将最新公式更新为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"

更新:得到另一个错误:

 "function score query returned an invalid score: NaN for doc: 1739"

将公式更改为ceil((log10(_score+1)+5)*100)*10000+(9999-ceil(log10(doc['price'].value+1)*1000))将+1添加到doc value以修复此问题

更新2:得到另一个错误:

 "function score query returned an invalid score: NaN for doc: 1739"

将公式更改为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)简化公式,这样我就可以理解了,它现在仍然有效:)

 类似资料:
  • 问题内容: 我有ElasticSearch 5,我想根据字段值进行排序。想象一下,具有类别(例如流派)的文档可能具有科幻,戏剧,喜剧等值,并且在进行搜索时,我想对值进行排序,以便首先出现喜剧,然后是科幻和戏剧。然后,我当然会按照其他条件在小组内订购。有人可以指出我该怎么做吗? 问题答案: 使用手动排序进行Elasticsearch排序 在可以根据字段的特定值分配顺序的情况下,这是可能的。 我已经使

  • 问题内容: 我的索引中有与- 相关的文档,并希望获取按孩子数排序的父母名单。有什么办法吗?我正在使用1.5.1 现在,通过使用功能,我可以轻松获得子文档的数量以及父查询的结果,但是似乎无法从脚本或搜索/评分功能访问值。有任何想法吗? 问题答案: 好吧,我终于找到了答案。感谢@doctorcal在#elasticsearch IRC 上的提示 正如我在这个问题提到的,我们可以使用每个家长让孩子的名单

  • 问题内容: 这是场景: 想象一下,注册用户使用创建了一个新实体,而其他注册用户创建了一个新实体,依此类推… 我想要做的是根据记录价格对记录进行排序,具体取决于前端用户选择的货币(欧元或美元)。 我无法编制索引,例如或,因为费率每小时都会变化,但是如果可能的话,更新10000条记录价格的最佳方法是什么? 1-以下是我的建议,它可行,但是我认为这可能是更好的方法,有什么建议吗? 2-如果没有,哪种性能

  • 问题内容: 我正在通过NEST c#使用ElasticSearch。我有很多关于人的信息 我希望能够按lastName以及长度的顺序对项目列表进行过滤和排序,因此名称中只有5个字符的人会出现在结果集的开头,然后是10个字符的人。 所以我想用一些伪代码做类似的事情 我是ElasticSearch的新手,所以任何示例都将非常有帮助。 问题答案: 您可以使用基于脚本的排序进行排序。 作为一个玩具示例,我

  • 问题内容: 我的方法有问题。例如,我有带有Text()的索引字段: 当我尝试执行带有排序的搜索查询时,出现错误: elasticsearch.exceptions.RequestError:TransportError(400,’search_phase_execution_exception’,’默认情况下,文本字段上的字段数据是禁用的。在[title]上设置fielddata = true以便

  • 我想按字段存在对我的ES搜索结果进行排序,假设我得到了字段“价格”,并希望所有有价格的结果都在顶部,所有没有价格的结果都在底部。我知道你可以做一个简单的排序并添加“缺失”:“_last”,例如: {“sort”:[{price':{missing':'u last',order':'asc'}}]} 但在这种情况下,结果也将按价格排序,我不想要它。 没有脚本有办法做到吗?