如何获取 Elasticsearch 评分结果详细信息?

Posted

技术标签:

【中文标题】如何获取 Elasticsearch 评分结果详细信息?【英文标题】:How to get Elasticsearch score result detail? 【发布时间】:2020-08-28 16:37:44 【问题描述】:

我有一个弹性索引来保存一些项目。结构如下。

public class items

    public string item_no  get; set; 
    public string category  get; set; 
    public int campaign  get; set; 
    public int in_stock  get; set; 
    // Next properties only include [a-z0-9]. Not any other characters
    public string score_item_no  get; set;    
    public string score_group_one  get; set; 
    public string score_group_two  get; set; 
    public string score_description  get; set; 
    public string score_all_fields  get; set;  /* score_item_no + score_group_one + score_group_two + score_description and something else */


public class ClassForScore

        public int id  get; set; 
        public string item_no  get; set; 

我必须从结果中过滤掉无用的记录。我决定使用 score 选项并创建一个函数来计算平均分数。所以首先我调用 elasticsearch 来获取分数,然后使用 minscore 参数调用。我找不到任何过滤无用结果的解决方案对此有什么建议吗?这是第一个问题。

第二个: 第一个 score 调用返回 7 条记录。每条记录都有不同的分数。例如,第一条记录有 1100 分。 但是我想知道这个1100是从哪里来的? 1000 来自 score_item_no 和 100 来自 score_group_one,或 500 来自 score_group_one 匹配 5 个部分,其中 500 个 score_group_two 匹配 5 个部分,100 个来自 score_description 匹配 2 个部分。 有没有办法找到分数详情?

    QueryContainer queryContainsAnd = new WildcardQuery()  Field = "score_all_fields", Value = "*" + mykeyword + "*" ;
    QueryContainer queryEqualsOr =  new TermQuery()  Field = "category", Value = *something1* ;
    queryEqualsOr |=  new TermQuery()  Field = "category", Value = *something2* ;
    QueryContainer queryEqualsAnd = new TermQuery()  Field = "campaign", Value = 1 ;
    queryEqualsAnd &= new TermQuery()  Field = "in_stock", Value = 1 ;
            
            
    QueryContainer mainQuery = queryContainsAnd & queryEqualsAnd & queryEqualsOr;
    
    Func<QueryContainerDescriptor<ClassForScore>, QueryContainer> fo = funcScoreParam(new ClassForScore(), filterItemNo, filterGroupOne, filterGroupTwo, filterDescription, mainQuery);
    ISearchResponse<ClassForScore> srcSkor = elasticClient.Search<ClassForScore>(s => s
        .RequestConfiguration(r => r.DisableDirectStreaming())
        .Query(fo)
        .Size(100)
    );
    IReadOnlyCollection<IHit<ClassForScore>> lstSkor = srcSkor.Hits;
    double? dblSkorAvg = 0;
    // Some calculation..
    //.....
    Func<QueryContainerDescriptor<items>, QueryContainer> fo2 = funcScoreParam(new ClassForScore(), filterItemNo, filterGroupOne, filterGroupTwo, filterDescription, mainQuery);
    ISearchResponse<items> srcResult = elasticClient.Search<items>(s => s
        .RequestConfiguration(r => r.DisableDirectStreaming())
        .From(0)
        .Size(100)
        .Sort(S => S.Descending(SortSpecialField.Score).Ascending(r => r.item_no))
        .MinScore(dblSkorAvg)
        .Query(fo2)
    );
    
    
    private Func<QueryContainerDescriptor<T>, QueryContainer> funcScoreParam<T>(T nesne, QueryContainer filterItemNo, QueryContainer filterGroupOne, QueryContainer filterGroupTwo, QueryContainer filterDescription, QueryContainer mainQuery) where T : class
    
        return new Func<QueryContainerDescriptor<T>, QueryContainer>(q => q
            .FunctionScore(fsc => fsc
                .BoostMode(FunctionBoostMode.Sum)
                .ScoreMode(FunctionScoreMode.Sum)
                .Functions(fu => fu
                        .Weight(w => w
                            .Weight(1000)
                            .Filter(wf => wf
                            .Bool(bb => bb
                            .Must(filterItemNo))
                            ))
                        .Weight(w => w
                            .Weight(100)
                            .Filter(wf => wf
                            .Bool(bb => bb
                            .Must(filterGroupOne))
                            ))
                        .Weight(w => w
                            .Weight(100)
                            .Filter(wf => wf
                            .Bool(bb => bb
                            .Must(filterGroupTwo)) 
                            ))
                        .Weight(w => w
                            .Weight(50)
                            .Filter(wf => wf
                            .Bool(bb => bb
                            .Must(filterDescription))
                            ))
                    )
                    .Query(q2 => q2
                        .Bool(b => b
                        .Should(mainQuery))
                    )
        ));
    

【问题讨论】:

【参考方案1】:

您可以使用搜索 API 上的 explain 参数返回有关每次点击的分数计算的详细信息

ISearchResponse<items> srcResult = elasticClient.Search<items>(s => s
    .RequestConfiguration(r => r.DisableDirectStreaming())
    .From(0)
    .Size(100)
    .Sort(S => S.Descending(SortSpecialField.Score).Ascending(r => r.item_no))
    .MinScore(dblSkorAvg)
    .Query(fo2)
    .Explain() // <-- explain score computation for each hit
);

还有一个专门的explain API to understand how a specific document's score is calculated.

【讨论】:

非常感谢@RussCam。而且我发现,如果您将 null QueryContainer 作为参数发送给函数,则总分包括它的权重。顺便说一句,两次弹性搜索是计算分数和过滤或任何建议的正确方法? > BTW 两次去弹性搜索是计算分数和过滤的正确方法或任何建议?我不确定您为什么要这样做,但 Elasticsearch 会为给定查询的每个文档计算分数。评分是使用BM25 计算的,因此评分与文档中查询输入中术语的频率和跨文档的反频率有关。查看您的查询,您可能想要在 bool 查询中对查询使用提升,而不是对函数中的查询使用权重。 Elasticsearch如何在没有字段权重的情况下计算分数?也许,我的结构有问题。我有 5 个评分字段和一个用于搜索的字段,包括每个文档的所有关键字。我正在根据哪个评分字段包含关键字来计算分数。我不确定我是否能用我的英语正确解释。在这种情况下,您有什么建议? 我已将其作为一个新问题提出:***.com/questions/63670605/…【参考方案2】:

在 Python elasticsearch_dsl 库中,此语法为

 my_search.extra(explain=True).execute()

【讨论】:

以上是关于如何获取 Elasticsearch 评分结果详细信息?的主要内容,如果未能解决你的问题,请参考以下文章

Elasticsearch——评分机制详解

Elasticsearch搜索之explain评分分析

基于发生率的 Elasticsearch 衰减分数

当结果具有相同分数时在 Elasticsearch 中分页

ElasticSearch 默认评分机制

ElasticsearchElasticsearch自定义评分的N种方法