elasticsearch - 在ElasticSearch 7.5中多样化搜索结果

标签 elasticsearch elasticsearch-aggregation elasticsearch-7

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

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

这不是最佳选择,因为我也希望将用户指向其他目录,而不用让他浏览包含同一目录下所有产品的多个搜索结果页面。所以我想使用diversified_sampler-aggregation,它与 child 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的values-collection中获取搜索结果-因此我将查询本身的大小设置为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

...然后结束。

似乎diversified_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
...

有任何想法吗?我使用diversified_sampler的技术并没有固定下来,但是我无法提出其他建议。可能是一些基于脚本的查询排序?不知道基于客户端的重新排序不是一种选择,因为我不希望在Elasticsearch方面进行分页。我需要分页以保持性能-搜索索引约为18GB,其中包含90万个文档...

最佳答案

我想我找到了没有使用脚本排序的diversified_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个(由param grpSize控制)文档,然后递增排序顺序。 (不知道将脚本参数用作“全局”变量是否危险……我对此感到有点不舒服……)

这是更具可读性的脚本:
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进行排序。

该解决方案不涉及实际的性能影响(至少对我的索引有影响),并且可以提供非常理想的结果。

请随时发布想法和优化!

关于elasticsearch - 在ElasticSearch 7.5中多样化搜索结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59769609/

相关文章:

elasticsearch - 如何在ElasticSearch中排序和限制聚合

elasticsearch - Elasticsearch中的日志聚合

elasticsearch - Elasticsearch 标记我的查询字符串(电子邮件地址)。怎么阻止呢?

elasticsearch - 日期范围内的搜索间隔示例

elasticsearch - ElasticSearch:字段键上的聚合

spring-boot - 为什么我们需要将日志消息发送到elasticsearch?

python - Elasticsearch 中的自定义直方图聚合

elasticsearch - 查询 Elasticsearch 文档,其中嵌套对象中的属性值为空

ElasticSearch 启动错误——默认发现设置不适合生产使用;

elasticsearch - Elasticsearch 7-防止字段可搜索