ElasticSearch 7.5 中的多样化搜索结果
Diversifying search results in 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-aggregation which, in conjunction with a 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 的值集合中获取 - 因此我将查询本身的大小设置为 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-wise 分页被破坏。我需要分页来保持性能 - 搜索索引大约 18GB,包含 900k 文档...
我想我找到了一个没有 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 个(由参数 grpSize 控制)文档,然后递增排序顺序。 (不知道将脚本参数用作 "global" 变量是否危险...我对此感到有点不舒服...)
以下是更易读的脚本:
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 和排序顺序的文档正在按其真实 _score 排序。
该解决方案不涉及真正的性能影响(至少在我的索引上)并且提供了我想要的结果。
欢迎大家post提意见和优化!
我有一个包含不同目录产品的搜索索引。现在,当我搜索给定的搜索词时,经常会返回如下结果:
Catalog 1 - Product 1
Catalog 1 - Product 2
Catalog 1 - Product 3
...
Catalog 1 - Product x
Catalog 2 - Product 1
...
这不是最佳选择,因为我想将用户指向其他目录,同时又不想让他浏览包含同一目录所有产品的多个搜索结果页面。所以我尝试使用diversified_sampler-aggregation which, in conjunction with a 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 的值集合中获取 - 因此我将查询本身的大小设置为 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-wise 分页被破坏。我需要分页来保持性能 - 搜索索引大约 18GB,包含 900k 文档...
我想我找到了一个没有 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 个(由参数 grpSize 控制)文档,然后递增排序顺序。 (不知道将脚本参数用作 "global" 变量是否危险...我对此感到有点不舒服...)
以下是更易读的脚本:
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 和排序顺序的文档正在按其真实 _score 排序。
该解决方案不涉及真正的性能影响(至少在我的索引上)并且提供了我想要的结果。
欢迎大家post提意见和优化!