Elasticsearch Nest Top Hits 聚合
Elastic search Nest TopHits aggregation
我已经为一个问题苦苦挣扎了一段时间,所以我想我会通过 Whosebug 解决这个问题。
我的文档类型有一个标题、一个语言字段(用于过滤)和一个分组 ID 字段(我省略了所有其他字段以保持这一点)
当我搜索文档时,我想找到所有包含标题文本的文档。我只希望每个唯一分组 ID 对应一个文档。
我一直在看tophits聚合,据我所知应该可以解决我的问题。
当 运行 此查询针对我的索引时:
{
"query": {
"match": {
"title": "dingo"
}
},
"aggs": {
"top-tags": {
"terms": {
"field": "groupId",
"size": 1000000
},
"aggs": {
"top_tag_hits": {
"top_hits": {
"_source": {
"include": [
"*"
]
},
"size": 1
}
}
}
}
}
}
我得到以下响应(所有结果都使用相同的语言):
{
"took": 9,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"top-tags": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [{
"key": "3044BC9E7C29450AAB2E4B6C9B35AAE2",
"doc_count": 2,
"top_tag_hits": {
"hits": {
"total": 2,
"max_score": 1.4983996,
"hits": [{
"_index": "elasticsearch",
"_type": "productdocument",
"_id": "FB15279FB18E4B34AD66ACAF69B96E9E",
"_score": 1.4983996,
"_source": {
"groupId": "3044BC9E7C29450AAB2E4B6C9B35AAE2",
"title": "wombat, dingo and zetapunga actionfigures",
}
}]
}
}
},
{
"key": "F11799ABD0C14B98ADF2554C84FF0DA0",
"doc_count": 1,
"top_tag_hits": {
"hits": {
"total": 1,
"max_score": 1.30684,
"hits": [{
"_index": "elasticsearch",
"_type": "productdocument",
"_id": "42562A25E4434A0091DE0C79A3E7F3F4",
"_score": 1.30684,
"_source": {
"groupId": "F11799ABD0C14B98ADF2554C84FF0DA0",
"title": "awesome dingo raptor"
}
}]
}
}
}]
}
}
}
这正是我所期望的(一个桶中有两次命中,但该桶只检索到一个文档)。但是,当我在 NEST 中尝试此操作时,我似乎无法检索所有文档。
我的查询如下所示:
result = _elasticClient.Search<T>(s => s
.From(skip)
.Filter(fd => fd.Term(f => f.Language, language))
.Size(pageSize)
.SearchType(SearchType.Count)
.Query(
q => q.Wildcard(f => f.Title, query, 2.0)
|| q.Wildcard(f => f.Description, query)
)
.Aggregations(agd =>
agd.Terms("groupId", tagd => tagd
.Field("groupId")
.Size(100000) //We sadly need all products
)
.TopHits("top_tag_hits", thagd => thagd
.Size(1)
.Source(ssd => ssd.Include("*")))
));
var topHits = result.Aggs.TopHits("top_tag_hits");
var documents = topHits.Documents<ProductDocument>(); //contains only one document (I would expect it to contain two, one for each bucket)
检查调试器中的聚合显示有一个 "groupId" 聚合和 2 个桶(并且匹配我在 "raw" 查询中看到的索引。只是没有任何明显的方法来检索文档)
所以我的问题是。我如何检索每个桶的最高命中率?还是我这样做完全错了?有没有其他方法可以实现我想要做的事情?
编辑
在收到帮助后,我能够通过以下方式检索我的结果:
result = _elasticClient.Search<T>(s => s
.From(skip)
.Filter(fd => fd.Term(f => f.Language, language))
.Size(pageSize)
.SearchType(SearchType.Count)
.Query(
q => q.Wildcard(f => f.Title, query, 2.0)
|| q.Wildcard(f => f.Description, query)
)
.Aggregations(agd =>
agd.Terms("groupId", tagd => tagd
.Field("groupId")
.Size(0)
.Aggregations(tagdaggs =>
tagdaggs.TopHits("top_tag_hits", thagd => thagd
.Size(1)))
)
)
);
var groupIdAggregation = result.Aggs.Terms("groupId");
var topHits =
groupIdAggregation.Items.Select(key => key.TopHits("top_tag_hits"))
.SelectMany(topHitMetric => topHitMetric.Documents<ProductDocument>()).ToList();
您的 NEST 查询尝试 运行 Terms 聚合和 TopHits 并排,而您的原始查询首先 运行s Terms 然后为每个桶调用 TopHits。
您只需将 TopHits 聚合移动到 NEST 查询中的 Terms 中即可使其正常工作。
这应该可以解决问题:
.Aggregations(agd =>
agd.Terms("groupId", tagd => tagd
.Field("groupId")
.Size(0)
.Aggregations(tagdaggs =>
tagdaggs.TopHits("top_tag_hits", thagd => thagd
.Size(1)))
)
)
顺便说一下,您不必使用 Include("*")
来包含所有字段。只需删除此选项,同时指定 .Size(0)
应该会为您返回所有可能的条款。
我已经为一个问题苦苦挣扎了一段时间,所以我想我会通过 Whosebug 解决这个问题。
我的文档类型有一个标题、一个语言字段(用于过滤)和一个分组 ID 字段(我省略了所有其他字段以保持这一点)
当我搜索文档时,我想找到所有包含标题文本的文档。我只希望每个唯一分组 ID 对应一个文档。
我一直在看tophits聚合,据我所知应该可以解决我的问题。
当 运行 此查询针对我的索引时:
{
"query": {
"match": {
"title": "dingo"
}
},
"aggs": {
"top-tags": {
"terms": {
"field": "groupId",
"size": 1000000
},
"aggs": {
"top_tag_hits": {
"top_hits": {
"_source": {
"include": [
"*"
]
},
"size": 1
}
}
}
}
}
}
我得到以下响应(所有结果都使用相同的语言):
{
"took": 9,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 0,
"hits": []
},
"aggregations": {
"top-tags": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [{
"key": "3044BC9E7C29450AAB2E4B6C9B35AAE2",
"doc_count": 2,
"top_tag_hits": {
"hits": {
"total": 2,
"max_score": 1.4983996,
"hits": [{
"_index": "elasticsearch",
"_type": "productdocument",
"_id": "FB15279FB18E4B34AD66ACAF69B96E9E",
"_score": 1.4983996,
"_source": {
"groupId": "3044BC9E7C29450AAB2E4B6C9B35AAE2",
"title": "wombat, dingo and zetapunga actionfigures",
}
}]
}
}
},
{
"key": "F11799ABD0C14B98ADF2554C84FF0DA0",
"doc_count": 1,
"top_tag_hits": {
"hits": {
"total": 1,
"max_score": 1.30684,
"hits": [{
"_index": "elasticsearch",
"_type": "productdocument",
"_id": "42562A25E4434A0091DE0C79A3E7F3F4",
"_score": 1.30684,
"_source": {
"groupId": "F11799ABD0C14B98ADF2554C84FF0DA0",
"title": "awesome dingo raptor"
}
}]
}
}
}]
}
}
}
这正是我所期望的(一个桶中有两次命中,但该桶只检索到一个文档)。但是,当我在 NEST 中尝试此操作时,我似乎无法检索所有文档。
我的查询如下所示:
result = _elasticClient.Search<T>(s => s
.From(skip)
.Filter(fd => fd.Term(f => f.Language, language))
.Size(pageSize)
.SearchType(SearchType.Count)
.Query(
q => q.Wildcard(f => f.Title, query, 2.0)
|| q.Wildcard(f => f.Description, query)
)
.Aggregations(agd =>
agd.Terms("groupId", tagd => tagd
.Field("groupId")
.Size(100000) //We sadly need all products
)
.TopHits("top_tag_hits", thagd => thagd
.Size(1)
.Source(ssd => ssd.Include("*")))
));
var topHits = result.Aggs.TopHits("top_tag_hits");
var documents = topHits.Documents<ProductDocument>(); //contains only one document (I would expect it to contain two, one for each bucket)
检查调试器中的聚合显示有一个 "groupId" 聚合和 2 个桶(并且匹配我在 "raw" 查询中看到的索引。只是没有任何明显的方法来检索文档)
所以我的问题是。我如何检索每个桶的最高命中率?还是我这样做完全错了?有没有其他方法可以实现我想要做的事情?
编辑
在收到帮助后,我能够通过以下方式检索我的结果:
result = _elasticClient.Search<T>(s => s
.From(skip)
.Filter(fd => fd.Term(f => f.Language, language))
.Size(pageSize)
.SearchType(SearchType.Count)
.Query(
q => q.Wildcard(f => f.Title, query, 2.0)
|| q.Wildcard(f => f.Description, query)
)
.Aggregations(agd =>
agd.Terms("groupId", tagd => tagd
.Field("groupId")
.Size(0)
.Aggregations(tagdaggs =>
tagdaggs.TopHits("top_tag_hits", thagd => thagd
.Size(1)))
)
)
);
var groupIdAggregation = result.Aggs.Terms("groupId");
var topHits =
groupIdAggregation.Items.Select(key => key.TopHits("top_tag_hits"))
.SelectMany(topHitMetric => topHitMetric.Documents<ProductDocument>()).ToList();
您的 NEST 查询尝试 运行 Terms 聚合和 TopHits 并排,而您的原始查询首先 运行s Terms 然后为每个桶调用 TopHits。
您只需将 TopHits 聚合移动到 NEST 查询中的 Terms 中即可使其正常工作。
这应该可以解决问题:
.Aggregations(agd =>
agd.Terms("groupId", tagd => tagd
.Field("groupId")
.Size(0)
.Aggregations(tagdaggs =>
tagdaggs.TopHits("top_tag_hits", thagd => thagd
.Size(1)))
)
)
顺便说一下,您不必使用 Include("*")
来包含所有字段。只需删除此选项,同时指定 .Size(0)
应该会为您返回所有可能的条款。