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(, ); // 执行检索,获取结果
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 == ) {
RETURN();
}
/// 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 > ) pcent = ;
if (pcent < ) pcent = ;
if (pcent == && wt > ) pcent = ;
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加权之后的匹配比例。
Xapian索引-文档检索过程分析之匹配百分比的更多相关文章
- Xapian索引-文档检索过程分析
本文是Xapian检索过程的分析,本文内容中源码比较多.检索过程,总的来说就是拉取倒排链,取得合法doc,然后做打分排序的过程. 1 理论分析 1.1 检索语法 面对不同的检索业务,我们会有多种检索 ...
- [No0000100]正则表达式匹配解析过程分析(正则表达式匹配原理)&regexbuddy使用&正则优化
常见正则表达式引擎引擎决定了正则表达式匹配方法及内部搜索过程,了解它至关重要的.目前主要流行引擎有:DFA,NFA两种引擎. 引擎 区别点 DFA Deterministic finite autom ...
- mysql的最左索引匹配原则
最近复习数据库,主要看的是mysql.很多东西忘得一干二净.看到某乎上有个答案非常给力,就记录一下,以后方便查看. 链接:https://www.zhihu.com/question/36996520 ...
- SQL语句-创建索引
语法:CREATE [索引类型] INDEX 索引名称ON 表名(列名)WITH FILLFACTOR = 填充因子值0~100 GO USE 库名GO IF EXISTS (SELECT * FRO ...
- Mysql 索引优化分析
MySQL索引优化分析 为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain命令的使用,以及explain输出字 ...
- Mysql数据库建立索引的优缺点有哪些?
索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息. 什么是索引 数据库索引好比是一本书前面的目录,能加快数据库的查询速度. 例如这样一个查询:select * ...
- mysql存储引擎和索引
正确的创建合适的索引,是提升数据库查询性能的基础. 第一章 mysql之索引 索引的定义:索引是为了加速对表中数据行的检索而创建的一种分散存储的数据结构. 我们为什么要使用索引: a.极大的减少存储引 ...
- mySql索引优化分析
MySQL索引优化分析 为什么你写的sql查询慢?为什么你建的索引常失效?通过本章内容,你将学会MySQL性能下降的原因,索引的简介,索引创建的原则,explain命令的使用,以及explain输出字 ...
- MySQL索引优化入门
索引简介 官方定义:索引(Index) 是帮助MySQL高效获取数据的数据结构.大家一定很好奇,索引为什么是一种数据结构,它又是怎么提高查询的速度?我们拿最常用的二叉树来分析索引的工作原理.看下面的图 ...
随机推荐
- Android 打造编译时注解解析框架 这只是一个开始
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/43452969 ,本文出自:[张鸿洋的博客] 1.概述 记得很久以前,写过几篇博客 ...
- 查看centos系统位数和强制关闭yum
一个小命令查看centos 是什么多少位系统 getconf LONG_BIT 方法二: [root@linuxzgf ~]#uname -m 如果有x86_64就是64位的,没有就是32位的后面是X ...
- 一步一步理解 python web 框架,才不会从入门到放弃 -- 开始使用 Django
背景知识 要使用 Django,首先必须先安装 Django. 下图是 Django 官网的版本支持,我们可以看到上面有一个 LTS 存在.什么是 LTS 呢?LTS ,long-term suppo ...
- BZOJ_3261_最大异或和_可持久化trie
BZOJ_3261_最大异或和_可持久化trie Description 给定一个非负整数序列{a},初始长度为N. 有M个操作,有以下两种操作类型: 1.Ax:添加操作,表示在序列末尾添加一个数x, ...
- RocketMQ源码 — 十一、 RocketMQ事务消息
分布式事务是一个复杂的问题,rmq实现了事务的最终一致性,rmq保证本地事务成功消息一定会发送成功并被成功消费,如果本地事务失败了,消息不会被发送. rmq事务消息的实现过程为: producer发送 ...
- dubbo+zookeeper的使用
我们讨论过Nginx+tomcat组成的集群,这已经是非常灵活的集群技术,但是当我们的系统遇到更大的瓶颈,全部应用的单点服务器已经不能满足我们的需求,这时,我们要考虑另外一种,我们熟悉的内容,就是分布 ...
- a标签跳转之前加点击事件
①在html标签中出现提示 <a href="http://www.baidu.com" onclick="if(confirm('确认百度吗?')==false) ...
- surging 微服务引擎 1.0 正式发布
surging 是一个分布式微服务引擎,提供高性能RPC远程服务调用,服务引擎支持http.TCP.WS.Mqtt协议,采用Zookeeper.Consul作为surging服务的注册中心,集成了哈希 ...
- Docker 发布 Abp net core web 服务
Docker 发布 Abp net core web 服务 准备工作:Abp 项目,这个是模板下载地址 https://aspnetboilerplate.com/Templates (本例使用的是S ...
- 性能超前,详解腾讯云新一代Redis缓存数据库
背景 当前内存数据库发展迅速,用户对于存储系统的要求也越来越高,为了满足各类业务场景的需要,腾讯云设计了新一代的内存数据库,不但保留了原来系统的高性能,高可用等特性,同时还兼容了当前流行的Redis原 ...