通过文本匹配和距离点对文档进行评分

Dan*_*ola 6 scoring elasticsearch

我有一个带有"商店"列表的ElasticSearch索引.

我希望允许客户通过两者搜索这些商店geo_distance(因此,搜索一个点并在该位置附近找到商店),以及文本匹配,例如商店名称/地址上的匹配.

我希望得到与这两个标准中的任何一个匹配的结果,并且我希望这些结果的顺序是两者的组合.文本匹配越强,越接近搜索点,结果越高.(显然,将会有一个将这两者结合起来的公式,这需要调整,而不是太担心那部分).

我的问题/我尝试过的:

  • geo_distance是一个filter,而不是一个query,所以我无法将两者结合起来query.

  • 可以使用bool => should匹配名称或位置的过滤器(而不是查询).这给了我想要的结果,但没有按顺序.

  • 我也可以_geo_distance作为sort条款的一部分,以便更接近该点的文档排名更高.

我没想到的是我如何采用_scoreElasticSearch在进行文本匹配时为文档提供的"常规" ,并将其与geo_distance分数结合起来.

通过在过滤器中进行文本匹配,它似乎不会影响文档的分数(这是有意义的).我不知道我怎么会在合并文本匹配query部分和geo_distance filter因此它是一个OR,而不是一个AND.

我想我最好的选择就是相当于:

{
  function_score: {
    query: {  ... },
    functions: [
      { geo_distance function },
      { multi_match_result score },
    ],
    score_mode: 'multiply'
  }
}
Run Code Online (Sandbox Code Playgroud)

但我不确定你可以做geo_distance分数功能,我不知道如何multi_match_result score作为分数功能,或者甚至可能.

任何指针将不胜感激.

我正在使用ElasticSearch v1.4,但如果需要我可以升级.

pic*_*ypg 8

但我不确定你可以将geo_distance作为分数函数,我不知道如何将multi_match_result分数作为分数函数,或者甚至可能.

你不能以你要求的方式真正做到这一点,但你可以轻松地做你想做的事.对于更简单的情况,您只需使用普通查询即可获得评分.

过滤器的问题在于它们是/否是问题,所以如果你在a中使用它们function_score,那么它可以提高分数,也可以不提高分数.您可能想要的是随着距离原点的距离增加而得分的降低.这是肯定/否定性质,阻止他们对比分产生影响.通过匹配过滤器隐含的相关性没有任何改善 - 它只是意味着它是答案的一部分,但是因此说它应该更接近顶部/底部是没有意义的.

这是衰变函数得分有帮助的地方.它适用于数字,dates和 - 最有用的 - geo_points.除了它接受的数据类型之外,它还可以使用高斯,指数或线性衰减函数进行衰减.你想要选择的那个是诚实的任意,你应该给那个选择最佳"体验"的人.我建议先从gauss.

"function_score": {
  "functions": [
    "gauss": {
      "my_geo_point_field": {
        "origin": "0, 1",
        "scale": "5km",
        "offset": "500m",
        "decay": 0.5
      }
    }
  ]
}
Run Code Online (Sandbox Code Playgroud)

需要注意的是originx, y格式(由于标准GeoJSON的),这是longitude, latitude.

衰变

每个值都会影响分数如何根据图形衰减(从文档中批发).如果你使用偏移量0,那么一旦它不完全在原点,分数就开始下降.通过偏移,它允许一些缓冲区被认为是一样好.

scale直接与以下内容相关联:一旦距离(+/- the )远离,decay分数将被该decay值砍掉.在上面的例子中,任何来自将获得一半的分数,作为在任何事情.scaleoriginoffset5kmoriginorigin

再次,请注意不同类型的衰变函数会改变评分的形状.

我希望这些结果的顺序是两者的结合.

这是bool/ shouldcompound查询的目的.根据每场比赛,您可以获得改进得分的OR行为.将此与上述相结合,您需要以下内容:

{
  "query": {
    "bool": {
      "should": [
        {
          "multi_match": { ... }
        },
        {
          "function_score": {
            "functions": [
              "gauss": {
                "my_geo_point_field": {
                  "origin": "0, 1",
                  "scale": "5km",
                  "offset": "500m",
                  "decay": 0.5
                }
              }
            ]
          }
        }
      ]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

注意:如果添加a must,则should行为从文字OR类似行为(至少1必须匹配)更改为完全可选行为(none必须匹配).

我正在使用ElasticSearch v1.4,但如果需要我可以升级.

从Elasticsearch 2.0开始,每个过滤器都是一个查询,每个查询也都是一个过滤器.唯一的区别在于它所使用的上下文.这不会改变我的答案,但除了我接下来的说法之外,它还可以帮助你.

ES 2.2+中的地理相关性能显着提高.您应该升级(并重新创建与地理相关的索引)以利用这些更改.ES 5.0也会有类似的好处!