如何通过字段值限制 ElasticSearch 结果?
How to limit ElasticSearch results by a field value?
我们有一个系统可以使用映射器附件插件在 ElasticSearch 中为简历文档编制索引。除了索引文档外,我还存储了一些基本信息,比如它是否与申请人或雇员相关、他们的姓名以及他们在系统中分配的 ID。运行的查询在遇到 ES:
时可能看起来像这样
{
"size" : 100,
"query" : {
"query_string" : {
"query" : "software AND (developer OR engineer)",
"default_field" : "fileData"
}
},
"_source" : {
"includes" : [ "applicant.*", "employee.*" ]
}
}
得到如下结果:
"hits": [100]
0: {
"_index": "careers"
"_type": "resume"
"_id": "AVEW8FJcqKzY6y-HB4tr"
"_score": 0.4530588
"_source": {
"applicant": {
"name": "John Doe"
"id": 338338
}
}
}...
我想做的是限制结果,这样如果 John Doe 的 ID 为 338338 在系统中有三份不同的简历都匹配查询,我只得到一份匹配,最好是得分最高的一份(虽然那不是那么重要,只要我能找到那个人)。我一直在尝试使用过滤器和聚合的不同选项,但我还没有偶然发现执行此操作的方法。
在返回结果后,我可以在调用 ES 的应用程序中采用多种方法来解决这个问题,但如果我可以在 ES 端完成,那将是更可取的。由于我将查询限制为 100 个结果,我想返回 100 个个人,而不是返回 100 个结果,然后发现其中 25% 的文档与同一个人有关。
您要做的是聚合以获取前 100 条唯一记录,然后进行子聚合以获取 "top_hits"。这是我系统中的一个例子。在我的示例中,我是:
- 将结果大小设置为 0 因为我只关心聚合
- 将聚合大小设置为 100
- 对于每个聚合,获取前 1 个结果
GET index1/type1/_search
{
"size": 0,
"aggs": {
"a1": {
"terms": {
"field": "input.user.name",
"size": 100
},
"aggs": {
"topHits": {
"top_hits": {
"size": 1
}
}
}
}
}
}
使用上面的答案和 IanGabes 的 link,我能够像这样重组我的搜索:
{
"size": 0,
"query": {
"query_string": {
"query": "software AND (developer OR engineer)",
"default_field": "fileData"
}
},
"aggregations": {
"employee": {
"terms": {
"field": "employee.id",
"size": 100
},
"aggregations": {
"score": {
"max": {
"script": "scores"
}
}
}
},
"applicant": {
"terms": {
"field": "applicant.id",
"size": 100
},
"aggregations": {
"score": {
"max": {
"script": "scores"
}
}
}
}
}
}
这让我得到了两个桶,一个包含所有申请人 ID 和匹配文档中的最高分数,以及员工的相同分数。该脚本无非是包含'_score'作为内容的分片上的groovy脚本。
有一种更简单的方法可以通过使用 Elasticsearch 的折叠功能来完成@ckasek 的目标。
字段折叠,如 Elasticsearch docs 中所述:
Allows to collapse search results based on field values. The collapsing is done by selecting only the top sorted document per collapse key.
基于上面的原始查询示例,您可以这样修改它:
{
"size" : 100,
"query" : {
"query_string" : {
"query" : "software AND (developer OR engineer)",
"default_field" : "fileData"
}
},
"collapse": {
"field": "id",
},
"_source" : {
"includes" : [ "applicant.*", "employee.*" ]
}
}
我们有一个系统可以使用映射器附件插件在 ElasticSearch 中为简历文档编制索引。除了索引文档外,我还存储了一些基本信息,比如它是否与申请人或雇员相关、他们的姓名以及他们在系统中分配的 ID。运行的查询在遇到 ES:
时可能看起来像这样{
"size" : 100,
"query" : {
"query_string" : {
"query" : "software AND (developer OR engineer)",
"default_field" : "fileData"
}
},
"_source" : {
"includes" : [ "applicant.*", "employee.*" ]
}
}
得到如下结果:
"hits": [100]
0: {
"_index": "careers"
"_type": "resume"
"_id": "AVEW8FJcqKzY6y-HB4tr"
"_score": 0.4530588
"_source": {
"applicant": {
"name": "John Doe"
"id": 338338
}
}
}...
我想做的是限制结果,这样如果 John Doe 的 ID 为 338338 在系统中有三份不同的简历都匹配查询,我只得到一份匹配,最好是得分最高的一份(虽然那不是那么重要,只要我能找到那个人)。我一直在尝试使用过滤器和聚合的不同选项,但我还没有偶然发现执行此操作的方法。
在返回结果后,我可以在调用 ES 的应用程序中采用多种方法来解决这个问题,但如果我可以在 ES 端完成,那将是更可取的。由于我将查询限制为 100 个结果,我想返回 100 个个人,而不是返回 100 个结果,然后发现其中 25% 的文档与同一个人有关。
您要做的是聚合以获取前 100 条唯一记录,然后进行子聚合以获取 "top_hits"。这是我系统中的一个例子。在我的示例中,我是:
- 将结果大小设置为 0 因为我只关心聚合
- 将聚合大小设置为 100
- 对于每个聚合,获取前 1 个结果
GET index1/type1/_search
{
"size": 0,
"aggs": {
"a1": {
"terms": {
"field": "input.user.name",
"size": 100
},
"aggs": {
"topHits": {
"top_hits": {
"size": 1
}
}
}
}
}
}
使用上面的答案和 IanGabes 的 link,我能够像这样重组我的搜索:
{
"size": 0,
"query": {
"query_string": {
"query": "software AND (developer OR engineer)",
"default_field": "fileData"
}
},
"aggregations": {
"employee": {
"terms": {
"field": "employee.id",
"size": 100
},
"aggregations": {
"score": {
"max": {
"script": "scores"
}
}
}
},
"applicant": {
"terms": {
"field": "applicant.id",
"size": 100
},
"aggregations": {
"score": {
"max": {
"script": "scores"
}
}
}
}
}
}
这让我得到了两个桶,一个包含所有申请人 ID 和匹配文档中的最高分数,以及员工的相同分数。该脚本无非是包含'_score'作为内容的分片上的groovy脚本。
有一种更简单的方法可以通过使用 Elasticsearch 的折叠功能来完成@ckasek 的目标。
字段折叠,如 Elasticsearch docs 中所述:
Allows to collapse search results based on field values. The collapsing is done by selecting only the top sorted document per collapse key.
基于上面的原始查询示例,您可以这样修改它:
{
"size" : 100,
"query" : {
"query_string" : {
"query" : "software AND (developer OR engineer)",
"default_field" : "fileData"
}
},
"collapse": {
"field": "id",
},
"_source" : {
"includes" : [ "applicant.*", "employee.*" ]
}
}