在 ElasticSearch 7.5 中使搜索结果多样化



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

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

这不是最佳的,因为我想将用户指向其他目录,而无需让他浏览包含同一目录的所有产品的多页搜索结果。所以我尝试使用diversified_sampler聚合,它与子top_hits聚合相结合,似乎正是解决方案,我想要:

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聚合的"大小"和"from"属性完成的。搜索结果可以从内部top_hits聚合的值集合中获取 - 因此我将查询本身的大小设置为 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的技术不是一成不变的,但我无法想出别的东西。也许是对查询进行一些花哨的基于脚本的排序?不知道。基于客户端的重新排序不是一种选择,因为我不希望弹性搜索分页被破坏。我需要分页来保持性能 - 搜索索引约为 18GB,包含 900k 个文档......

我想我找到了一种没有使用脚本排序的diversified_sampler聚合的解决方案:

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范围和排序顺序的文档按其实际_score进行排序。

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

请随时发布想法和优化!

相关内容

  • 没有找到相关文章

最新更新