zoukankan      html  css  js  c++  java
  • Xapian索引-文档检索过程分析之匹配百分比

        本文属于文档检索过程分析的一部分,重点分析文档匹配百分比(percent)的计算过程。

    1 percent是什么?

        我们之前分析的检索demo:

    Xapian::Query term_one = Xapian::Query("T世界");
    Xapian::Query term_two = Xapian::Query("T比赛");
    Xapian::Query query = Xapian::Query(Xapian::Query::OP_OR, term_one, term_two); // query组装
    
    std::cout << "query=" << query.get_description() << std::endl;
    
    Xapian::Enquire enquire(db);
    enquire.set_query(query);
    Xapian::MSet result = enquire.get_mset(0, 10); // 执行检索,获取结果
    std::cout << "find results count=" << result.get_matches_estimated() << std::endl;
    
    for (auto it = result.begin(); it != result.end(); ++it) {
        Xapian::Document doc = it.get_document();
        std::string data = doc.get_data();
        double doc_score_weight = it.get_weight();
        /// 匹配百分比
        int doc_score_percent = it.get_percent();
        std::cout << "doc=" << data << ",weight=" << doc_score_weight << ",percent=" << doc_score_percent << std::endl;
    }
    percent就是 int doc_score_percent = it.get_percent(); 这里获取的文档匹配百分比。

    2 为什么需要percent?

        先说一下背景,做过搜索的人应该都知道BM25算法,这也是xapian内部默认的相关性打分算法,它是一个针对term做打分的公式。这个公式可以分为三个部分,第一部分跟term的idf有关,第二部分跟term在doc的权重有关,第三部分跟term在query中的权重有关(可以参考这里理论分析部分的介绍)。公式第一部分的idf是以索引库中的文档来统计的,第二部分中用到的文档平均长度,也是以索引库中的文档来计算的,当我们的数据含有多个业务,并且每个业务有独立的索引库时,相同term的idf在不同索引库中差别可能很大,而idf又是BM25公式中一个很重要的因子,这就可能导致同一个query在A库中搜索出来的doc BM25打分永远比在B库中搜索出来的要高,并且,xapian的打分支持term-boost的(打分系数),乘上系数之后,BM25打分值差距可能就更大了。所以,我们不能也不应该直接拿BM25打分来比较哪个doc更相关,我们需要一个归一化后的数值,这就是percent。

    3 percent是怎么算出来的?

        percent是某个doc跟query的相关性归一化分值,是为做相关性打分排序而存在的,它的基本原则是:归一化。

        分成两个层面,首先是term命中个数:所有命中文档中BM25分值最高的doc的term命中个数为分子,请求term个数为分母;然后是某个doc的BM25打分为分子,最大的doc BM25打分为分母。公式如下: [(最大BM25打分doc的命中词个数) / (请求词个数)] * [(本doc的BM25打分) / (最大BM25打分)]

        相关代码:

    void MultiMatch::get_mset(Xapian::doccount first, Xapian::doccount maxitems,
                 Xapian::doccount check_at_least,
                 Xapian::MSet & mset,
                 Xapian::Weight::Internal & stats,
                 const Xapian::MatchDecider *mdecider,
                 const Xapian::KeyMaker *sorter) {
    ......
        {
            // greatest_wt_subqs_matched 表示最大的匹配term数
            // total_subqs 表示总term数
    // percent_scale是计算percent的一个因子,后面会看到怎么用
    // greatest_wt 最大BM25分值
    percent_scale = greatest_wt_subqs_matched / double(total_subqs); percent_scale /= greatest_wt; } ...... }
    int MSet::Internal::convert_to_percent_internal(double wt) const {
        LOGCALL(MATCH, int, "Xapian::MSet::Internal::convert_to_percent_internal", wt);
        if (percent_factor == 0) {
            RETURN(100);
        }
        /// wt是文档的打分,percent_factor是之前计算的 percent_scale * 100
        // Excess precision on x86 can result in a difference here.
        double v = wt * percent_factor + 100.0 * DBL_EPSILON;
        int pcent = static_cast<int>(v);
        LOGLINE(MATCH, "wt = " << wt << ", max_possible = " << max_possible << " =>  pcent = " << pcent);
        if (pcent > 100) pcent = 100;
        if (pcent < 0) pcent = 0;
        if (pcent == 0 && wt > 0) pcent = 1;
    
        RETURN(pcent);
    }

         以上就是xapian源码中percent的计算过程。

    4 percent值不等于匹配词个数

        percent是归一化后的BM25相关性分值,从上面的分析,我们知道它的计算方式非常依赖匹配词个数,但它不等于匹配词个数。因为这个匹配词个数来自于最大BM25打分文档的匹配词个数。譬如:有检索语句:A or B or C,其中,A term的重要性极高,只要它匹配了就认为相关性高达90%,而B、C term不重要,加起来只有10%的权重。BM25的分值最高的文档,可能只命中了A词,而另一个打分比较低的文档命中了B、C词,这时候每一个文档的最高可能percent都是在1/3以下,这时候即便命中了B、C词的文档,其percent值也是小于1/3的。当然,大多数情况下,percent值会跟匹配词个数相当,因为如果A term极其重要,在设计检索策略时,我们便会将A term设计为必出词,不含有A term的文档就不会进入percent计算环节。而如果我们没有设计为必出词,又想用percent来做阈值过滤,譬如:要求percent值必须大于66(大约2/3个词),且想让只命中了A term(权重极高)的文档留下来怎么办呢?那就要参考BM25分值了,把BM25分值极高的留下来。

        percent设计的初衷其实很简单:1、0~1之间的值,值的顺序跟BM25值的顺序一致;2、能体现出来只匹配了部分term;注意:这里的匹配term个数要使用最大BM25打分doc的term个数。 这给我们做阈值截断的时候带来一些不方便,譬如上面的case,虽然只命中了A term,但其实已经是非常相关了,一种调整思路是在计算percent的时候,乘上其权重,公式这样子:
    percent = [(累加(最大BM25打分doc的命中词 * 权重)) / (累加(请求词 * 权重))] * [(本docBM25打分) / (最大BM25打分)]。
    这样子,percent就不再代表匹配词个数,而是代表term加权之后的匹配比例。

        

  • 相关阅读:
    RFID亮灯电子标签在仓储管理中的应用
    漫画:寻找股票买入卖出的最佳时机(动态规划)
    JAVA深入解析-36个话题-Two
    一行代码让训练速度提升2倍,飞桨自动混合精度技术详解
    追源码的平凡之路
    看完这篇,你也是字符编码大神!
    微服务的熔断原理与实现
    经典论文复现 | PyraNet:基于特征金字塔网络的人体姿态估计
    一文看懂人机对话
    「Spring Boot 2.4 新特性」一键构建Docker镜像
  • 原文地址:https://www.cnblogs.com/cswuyg/p/10552564.html
Copyright © 2011-2022 走看看