Elasticsearch 订单项按分数聚合
Elasticsearch order terms aggregate by score
我是 ElasticSearch 的新手。以前我只在 Django-Haystack 中以非常有限的方式使用它,并且从未直接与 ES 交谈过。
目前,我有一个包含一些文档的 ElasticSearch(5.x 索引)。我正在使用 Python + elasticsearch-dsl + django-elasticsearch-dsl 所以我正在索引数据库模型,但这并不重要。我会尽量让这个问题与库无关。
从概念上讲,我将用户和他们的帖子都存储在同一个索引中。用户文档和帖子文档有一个共同点 - 字段 user_id
.
用户看起来像这样:
{
"_id": 1,
"_type": "user_document",
"username": "jdoe",
"user_id": 1,
"title": "Test user"
}
帖子是这样的:
{
"_id": 1,
"_doc": "post_document",
"user_id": 1,
"title": "Hello world!",
"text": "Lorem ipsum test test test..."
}
我希望我的应用程序实现的是一个单输入搜索字段,它对用户及其帖子进行全文搜索(在现实世界中有更多文档 "types" - 我正在简化事情在这里,仅用于示例目的)。我想按 user_id
聚合以仅显示匹配的不同用户的列表。
目前,我正在做这样的查询:
{
"query": {
"multi_match": {
"query": "test",
"fields": ["username^3", "title^2", "text"]
}
},
"aggs": {
"user_ids": {"terms": {"field": "user_id"}}
}
}
然后使用响应的 aggregations.user_ids.buckets.key
获取匹配用户列表。
然而,该列表似乎只是按文档计数排序(因此,如果用户有一对包含单词 "test" 的帖子,他们似乎会赢得名为 "test" 的用户),并且我想尝试订购。我目前的想法是使用平均(或中值)文档匹配 _score
.
注意:在实际情况中,不止有两种文档类型,因此走捷径并仅在特定 _type
上查询是行不通的。
我该怎么做?我正在阅读 "Sorting by a Metric" 一章,但我有点迷失了那里的想法。我做了几次尝试,但基本上都是无稽之谈。任何人都可以展示一个具体的查询示例(最好是解释它是如何构建的),以便我从中学习?
这是 Gist with an example dataset,上面显示的搜索查询,以及我得到的确切结果。我想要的(在 test_query_01_results.json
中)是让 user_id
1 优先于 2,其逻辑是 2.0794415 > (0.78306973 + 0.45315093) / 2.
我觉得我做错的另一件事是我根本不使用 hits
- 我只是不需要它们 - 只有聚合的 user_id
值。如果这没问题 - 有没有办法 "disable" 它们并且只有 return 聚合?
我想我找到了对聚合进行排序的解决方案。我必须创建一个子聚合,然后一切正常。我错了,在没有任何 _score
的情况下试图使用 "order": {"_score: "desc"}
和类似的废话(那是文档的集合,而不是文档,所以那里没有分数)。
{
"query": {
"multi_match": {
"query": "test",
"fields": ["username^3", "title^2", "text"]
}
},
"aggs": {
"user_ids": {
"terms": {
"field": "user_id",
"order": {"avg_score": "desc"}
},
"aggs": {
"avg_score": {
"avg": {"script": "_score"}
}
}
}
}
}
有了这个,我的 aggregations
看起来就像我想要的那样:
...
"aggregations": {
"user_ids": {
"buckets": [
{
"avg_score": {"value": 2.079441547393799},
"doc_count": 1,
"key": 1
},
{
"avg_score": {"value": 0.618110328912735},
"doc_count": 2,
"key": 2
}
],
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0
}
},
...
但是,关于 hits
(我不使用)的问题仍然存在。
使用以下查询
{
"size": 0 , ==> to return no hits
"query": { ==> query similar to yours
"multi_match": {
"query": "test",
"fields": ["username^3", "title^2", "text"]
}
},
"aggs": {
"user_ids": {
"terms": {
"field": "user_id",
"order": {"avg_score": "desc"}
},
"aggs": {
"avg_score": {
"avg": {"script": "_score"}
}
}
}
}
}
我是 ElasticSearch 的新手。以前我只在 Django-Haystack 中以非常有限的方式使用它,并且从未直接与 ES 交谈过。
目前,我有一个包含一些文档的 ElasticSearch(5.x 索引)。我正在使用 Python + elasticsearch-dsl + django-elasticsearch-dsl 所以我正在索引数据库模型,但这并不重要。我会尽量让这个问题与库无关。
从概念上讲,我将用户和他们的帖子都存储在同一个索引中。用户文档和帖子文档有一个共同点 - 字段 user_id
.
用户看起来像这样:
{
"_id": 1,
"_type": "user_document",
"username": "jdoe",
"user_id": 1,
"title": "Test user"
}
帖子是这样的:
{
"_id": 1,
"_doc": "post_document",
"user_id": 1,
"title": "Hello world!",
"text": "Lorem ipsum test test test..."
}
我希望我的应用程序实现的是一个单输入搜索字段,它对用户及其帖子进行全文搜索(在现实世界中有更多文档 "types" - 我正在简化事情在这里,仅用于示例目的)。我想按 user_id
聚合以仅显示匹配的不同用户的列表。
目前,我正在做这样的查询:
{
"query": {
"multi_match": {
"query": "test",
"fields": ["username^3", "title^2", "text"]
}
},
"aggs": {
"user_ids": {"terms": {"field": "user_id"}}
}
}
然后使用响应的 aggregations.user_ids.buckets.key
获取匹配用户列表。
然而,该列表似乎只是按文档计数排序(因此,如果用户有一对包含单词 "test" 的帖子,他们似乎会赢得名为 "test" 的用户),并且我想尝试订购。我目前的想法是使用平均(或中值)文档匹配 _score
.
注意:在实际情况中,不止有两种文档类型,因此走捷径并仅在特定 _type
上查询是行不通的。
我该怎么做?我正在阅读 "Sorting by a Metric" 一章,但我有点迷失了那里的想法。我做了几次尝试,但基本上都是无稽之谈。任何人都可以展示一个具体的查询示例(最好是解释它是如何构建的),以便我从中学习?
这是 Gist with an example dataset,上面显示的搜索查询,以及我得到的确切结果。我想要的(在 test_query_01_results.json
中)是让 user_id
1 优先于 2,其逻辑是 2.0794415 > (0.78306973 + 0.45315093) / 2.
我觉得我做错的另一件事是我根本不使用 hits
- 我只是不需要它们 - 只有聚合的 user_id
值。如果这没问题 - 有没有办法 "disable" 它们并且只有 return 聚合?
我想我找到了对聚合进行排序的解决方案。我必须创建一个子聚合,然后一切正常。我错了,在没有任何 _score
的情况下试图使用 "order": {"_score: "desc"}
和类似的废话(那是文档的集合,而不是文档,所以那里没有分数)。
{
"query": {
"multi_match": {
"query": "test",
"fields": ["username^3", "title^2", "text"]
}
},
"aggs": {
"user_ids": {
"terms": {
"field": "user_id",
"order": {"avg_score": "desc"}
},
"aggs": {
"avg_score": {
"avg": {"script": "_score"}
}
}
}
}
}
有了这个,我的 aggregations
看起来就像我想要的那样:
...
"aggregations": {
"user_ids": {
"buckets": [
{
"avg_score": {"value": 2.079441547393799},
"doc_count": 1,
"key": 1
},
{
"avg_score": {"value": 0.618110328912735},
"doc_count": 2,
"key": 2
}
],
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0
}
},
...
但是,关于 hits
(我不使用)的问题仍然存在。
使用以下查询
{
"size": 0 , ==> to return no hits
"query": { ==> query similar to yours
"multi_match": {
"query": "test",
"fields": ["username^3", "title^2", "text"]
}
},
"aggs": {
"user_ids": {
"terms": {
"field": "user_id",
"order": {"avg_score": "desc"}
},
"aggs": {
"avg_score": {
"avg": {"script": "_score"}
}
}
}
}
}