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

Scoring documents by both textual match and distance to a point

我有一个包含 "shops" 列表的 ElasticSearch 索引。

我想允许客户通过 geo_distance(因此,搜索一个点并找到该位置附近的商店)和文本匹配来搜索这些商店,例如商店名称/地址的匹配。

我希望获得符合这两个条件的 之一的结果,并且我希望这些结果的顺序是两者的组合。文本匹配越强,越接近搜索点,结果就越高。 (显然,将有一个公式可以将这两者结合起来,这需要进行调整,但不要太担心那部分)。

我的问题/我尝试过的方法:

我还没有弄清楚的是,在进行文本匹配时,我将如何获取 ElasticSearch 为文档提供的 "regular" _score,并将其与 geo_distance 分数相结合。

通过在过滤器中进行文本匹配,它似乎不会影响文档的分数(这是有道理的)。而且我不知道如何将 query 部分中的文本匹配与 geo_distance filter 结合起来,所以它是 OR 而不是 AND

我想我最好的选择是:

{
  function_score: {
    query: {  ... },
    functions: [
      { geo_distance function },
      { multi_match_result score },
    ],
    score_mode: 'multiply'
  }
}

但我不确定您是否可以将 geo_distance 作为评分函数,而且我不知道如何将 multi_match_result score 作为评分函数,或者它是否可能。

任何指点将不胜感激。

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

but I'm not sure you can do geo_distance as a score function, and I don't know how to have multi_match_result score as a score function, or if it's even possible.

你不能真正按照你要求的方式去做,但你可以很容易地做你想做的事。对于更简单的情况,您只需使用普通查询即可获得评分。

过滤器的问题在于它们是 yes/no 个问题,因此如果您在 function_score 中使用它们,那么它要么提高分数,要么不提高分数。您可能想要的是随着与原点距离的增加而降低分数。正是 yes/no 的性质阻止了它们对分数的影响。匹配过滤器所暗示的相关性没有任何改进——这只是意味着它是答案的一部分,但说它应该更接近 top/bottom 结果是没有意义的。

这是 Decay function score 的帮助所在。它适用于数字、dates,以及——这里最有用的——geo_points。除了它接受的数据类型之外,它还可以使用高斯、指数或线性衰减函数进行衰减。你想选的那个真的是随意的,你应该给选出最好的那一个"experience"。我建议从 gauss.

开始
"function_score": {
  "functions": [
    "gauss": {
      "my_geo_point_field": {
        "origin": "0, 1",
        "scale": "5km",
        "offset": "500m",
        "decay": 0.5
      }
    }
  ]
}

请注意 originx, y 格式(由于标准 GeoJSON),即 longitude, latitude.

每个值都会影响分数如何根据图表衰减(从文档中大量获取)。如果您使用 0 的偏移量,那么一旦它不 恰好 在原点,分数就会开始下降。使用偏移量,它允许一些缓冲区被认为同样好。

scaledecay 直接相关,因为一旦距离 scale 距离 scale origin(+/- offset)。在上面的 my 示例中,origin 中的任何 5km 将获得 origin.

中任何分数的一半

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

I'd like the order of these results to be a combination of both.

这是 bool / should 复合查询的目的。您会根据每场比赛获得分数提高的 OR 行为。结合上面的内容,你会想要这样的东西:

{
  "query": {
    "bool": {
      "should": [
        {
          "multi_match": { ... }
        },
        {
          "function_score": {
            "functions": [
              "gauss": {
                "my_geo_point_field": {
                  "origin": "0, 1",
                  "scale": "5km",
                  "offset": "500m",
                  "decay": 0.5
                }
              }
            ]
          }
        }
      ]
    }
  }
}

注意:如果添加 must,则 should 行为会从字面 OR 类行为(至少 1 个必须匹配)变为完全可选的行为(none 必须匹配)。

I'm working with ElasticSearch v1.4, but I can upgrade if necessary.

从 Elasticsearch 2.0 开始,每个过滤器都是一个查询,每个查询也是一个过滤器。唯一的区别是它所使用的 context 。这不会改变我在这里的答案,但除了我接下来要说的内容之外,它可能会在将来对您有所帮助。

Geo-related performance increased dramatically in ES 2.2+。您应该升级(并重新创建与地理相关的索引)以利用这些更改。 ES 5.0 也会有类似的好处!