【问题标题】:Diversifying search results in ElasticSearch 7.5ElasticSearch 7.5 中的多样化搜索结果
【发布时间】:2020-05-03 07:03:34
【问题描述】:

我有一个包含不同目录产品的搜索索引。现在,当我搜索给定的搜索词时,通常会返回如下结果:

Catalog 1 - Product 1
Catalog 1 - Product 2
Catalog 1 - Product 3
...
Catalog 1 - Product x
Catalog 2 - Product 1
...

这不是最优的,因为我想将用户指向其他目录,同时,也不需要他浏览包含同一目录的所有产品的多个搜索结果页面。所以我尝试使用diversified_sampler-aggregation,它与一个孩子top_hits-aggregation 一起使用,似乎正是我想要的解决方案:

POST /myIndex/_search?typed_keys=true
{
  "query": {
    "query_string": {
      "fields": [
        "title^2",
        "description^2",
        "descriptionOriginal^0.01"
      ],
      "query": "*someSearchTerm*"
    }
  },
  "size": 0,
  "aggs": {
    "aggDiversifiedSampler": {
      "diversified_sampler": {
        "shard_size": 100000,
        "field": "catalogId",
        "max_docs_per_value": 3
      },
      "aggs": {
        "aggTopHits": {
          "top_hits": {
            "from": 0,
            "size": 50,
            "sort": [
              {
                "_score": {
                  "order": "desc"
                }
              }
            ]
          }
        }
      }
    }
  }
}

分页是通过内部 top_hits-aggregation 的“size”和“from”属性完成的。搜索结果可以从内部 top_hits-aggregation 的值集合中获取 - 因此我将查询本身的大小设置为 0。

这似乎有效 - 乍一看,但仔细查看结果会发现,并非所有搜索结果都已返回。结果现在看起来像这样:

Catalog 1 - Product 1
Catalog 1 - Product 2
Catalog 1 - Product 3
Catalog 2 - Product 1
Catalog 2 - Product 2
Catalog 2 - Product 3
...
Catalog x - Product 1
Catalog x - Product 2
Catalog x - Product 3

...然后就结束了。

看起来,diversively_sampler 在到达最后一个目录后并没有回滚,因此不会出现来自单个目录的进一步结果。我想要的是这样的:

Catalog 1 - Product 1
Catalog 1 - Product 2
Catalog 1 - Product 3
Catalog 2 - Product 1
Catalog 2 - Product 2
Catalog 2 - Product 3
...
Catalog x - Product 1
Catalog x - Product 2
Catalog x - Product 3
Catalog 1 - Product 4
Catalog 1 - Product 5
Catalog 1 - Product 6
Catalog 2 - Product 4
Catalog 2 - Product 5
Catalog 2 - Product 6
...

有什么想法吗?我使用多元化采样器的技术并没有一成不变,但我想不出别的办法。也许是一些花哨的基于脚本的查询排序?不知道。基于客户端的重新排序不是一种选择,因为我不希望弹性搜索方式的分页被破坏。我需要分页来保持性能 - 搜索索引大约 18GB,包含 900k 文档...

【问题讨论】:

    标签: elasticsearch elasticsearch-aggregation elasticsearch-7


    【解决方案1】:

    我想我找到了一个没有使用脚本排序的 compatible_sampler-aggregation 的解决方案:

    POST /myIndex/_search?typed_keys=true
    {
      "query": {
        "query_string": {
          "fields": [
            "title^2",
            "description^2",
            "descriptionOriginal^0.01"
          ],
          "query": "*someSearchTerm*"
        }
      },
      "sort": [{
          "_script": {
            "script": {
              "source": "Math.round(_score / params.fuzziness) * params.fuzziness",
              "params": {
                "fuzziness": 2
              }
            },
            "type": "number",
            "order": "desc"
          }
        }, {
          "_script": {
            "script": {
              "source": "if(doc['catalogId'].value != params.cid) {params.cid=doc['catalogId'].value;params.sort=0;return params.count=0;} else {return (++params.count % params.grpSize == 0) ?++params.sort : params.sort;}",
              "params": {
                "cid": 0,
                "sort": 0,
                "count": 0,
                "grpSize": 3
              }
            },
            "type": "number",
            "order": "asc"
          }
        }, {
          "_score": {
            "order": "desc"
          }
        }
      ]
    }
    

    在第一个脚本排序中,我对文档进行了预排序,以便某个 _score 范围内的结果放在一起。这是由模糊参数控制的。然后我使用脚本排序在这些范围内进行排序,以便始终获取每个目录 ID 的下 3 个(由参数 grpSize 控制)文档,然后增加排序顺序。 (不知道将 script-params 用作“全局”变量是否危险......我对此感到有点不舒服......)

    下面是更易读的脚本:

    if(doc['catalogId'].value != params.cid) {
      params.cid = doc['catalogId'].value;
      params.sort = 0;
      return params.count = 0;
    } else {
      return (++params.count % params.grpSize == 0) ? ++params.sort : params.sort;
    }
    

    最后但并非最不重要的一点是,具有相同 _score-range 和 sort-order 的文档将按照它们的真实 _score 进行排序。

    该解决方案不涉及真正的性能影响(至少在我的索引上)并且提供了我想要的相当结果。

    请随时发表想法和优化!

    【讨论】:

      猜你喜欢
      • 2016-03-17
      • 2015-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多