ElasticSearch顺序术语按得分聚合

irtuqstp  于 2023-02-07  发布在  ElasticSearch
关注(0)|答案(3)|浏览(168)

我是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..."
}

我希望我的应用程序实现的是一个单输入搜索字段,它可以对用户及其帖子进行全文搜索(在真实的世界中,文档“类型”更多--我在这里只是为了举例而简化了一些),并且我希望按user_id进行聚合,以显示匹配的不同用户的列表。
目前,我正在执行如下查询:

{
    "query": {
        "multi_match": {
            "query": "test",
            "fields": ["username^3", "title^2", "text"]
        }
    },
    "aggs": {
        "user_ids": {"terms": {"field": "user_id"}}
    }
}

然后使用response的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值。如果这样可以的话-有没有办法“禁用”它们并只返回聚合?

mv1qrgav

mv1qrgav1#

使用以下查询

{
"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"}
              }
          }
      }
    }
  }
m1m5dgzv

m1m5dgzv2#

我想我找到了一个对聚合进行排序的解决方案。我必须创建一个子聚合,然后它就工作了。我错了,试图使用"order": {"_score: "desc"}和类似的废话,而那里没有任何_score(那是文档的集合,而不是文档,所以那里没有得分)。

{
    "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(我不使用它)的问题仍然存在。

e5nszbig

e5nszbig3#

帖子的答案很棒,只是有一件小事要提一下。
我觉得我做错的另一件事是我根本不使用hits--我只是不需要它们--只使用聚合的user_id值。如果这没问题--有没有办法“禁用”它们,只返回聚合?
要实现这一点,只需使用“size”:“查询”字段中的0。

{
    "query": {
        "multi_match": {
            "query": "test",
            "fields": ["username^3", "title^2", "text"]
        }
    },
    "size": 0,
    "aggs": {
        "user_ids": {
            "terms": {
                "field": "user_id",
                "order": {"avg_score": "desc"}
            },
            "aggs": {
                "avg_score": {
                    "avg": {"script": "_score"}
                }
            }
        }
    }
}

相关问题