高性能搜索引擎sphinx源码解析之搜索过程和评分公式
来源:互联网 发布:mac显示路径命令 编辑:程序博客网 时间:2024/05/16 19:08
sphinx搜索(select)逻辑
用输入的查询词在索引文件中挨个进行比较,找到满足关系的文档的过程,并读出文档,给每个文件打分,最后打分完成后进行排序,随后获取到排序后的文档列表的过程。
sphinx搜索过程包括以下步骤
1) 搜收用户输入,并存储,存储格式CsphString,字符串形式,例如select id,weight() ,list_namefrom LISTING wherematch('金');
2) 解析用户输入,解析完成后每条语句以SqlStmt_t格式存储
下面对SqlStmt_t作出简要分析
3) SqlStmt_t结构成员CsphQuery,此类存储着查询所需的所有信息
示意图如下,全部成员见类图,下图只给出主成员
4) 根据SqlStmt_t结构中命令动词,来匹配不同的程序分支,这里只分析select流程
5) pLocalSorter =sphCreateQueue( tQueueSettings );创建优先级队列,用于对结果排序,默认以weight排序,weight越大在队列中的优先级越高,按照优先级依次出队就完成了排序
6) 得到ram chunk 和disk chunk的指针,创建分词器
7) 对搜索字符串进行分词,分词结束后语法树逻辑结构如下
8) 创建ranker
9) 通过查找hash表,获得分词和DocID关系结构图
分词和DocId的结构图
获得每个分词DocID所占连续内存入口结构图
在hash表ExtQwordsHash_t中ExtQword_t是Key与入口地址是一对一的关系
获得DocID过程
a) 由分词搜索ram chunk中的hash表,得结构ExtQword_t
b) 结构中存储着每个分词DocID的数目
c) 通ExtQword_t可获得每个分词DocID内存所对应的入口地址
d) 分词的DocID在内存中占着连续的内存空间,这样就可以从内存中直接读出所有的DocID 即可
e) 过滤掉KILLlist中的DocID
f) search RAM chunk,给每个DocID安装DocInfo信息,给每条DocID打分
下面是如何查找属性信息,这里只是找到这条文档的属性在RtSegment_t中的指针,用于属性过滤,以下是docinfo的内存存储结构
struct RtSegment_t : ISphNoncopyable{ CSphTightVector<CSphRowitem> m_dRows; ///<row data CSphTightVector<BYTE> m_dStrings; ///< strings storage CSphTightVector<DWORD> m_dMvas; ///<MVAs storage}
通过二分查找,找到这条文档在m_dRows的位置,就可获得这条文件档属性在m_dStrings和m_dMvas的指针和位移,然后进行属性过滤
10) 把结果存储在ISphMatchSorter中,在multiQuery函中完成对Ram chunk 、Disk chunk的搜索
11) 把结果存储到SearchHandler_c的成员,m_dResults中,同时释放ISphMatchSorter结构内存,在RunLocalSearches中完成结果集的转存
搜索Diskchunk的过程
搜索Disk chunk过程与内存大致相同,多了一步读文件,关于索引文件(spa,spd,…)的处理方法在第三部分讲解
权重算法详解
权重因子
1)Hits
举例说明
insert into LISTING(id,rtf_list_name) values(-99, '金龙鱼金龙鱼特香纯正花生油5L'');
insert into LISTING(id,rtf_list_name, rtf_channel) values(-98, '金龙鱼金龙鱼特香纯正花生油5L',’金龙鱼大小龙鱼');
用如下 selecl id,weight from LISTING where (‘龙鱼’);show meta;
此时,
龙鱼,hits:6
-99,uMatchHits:2
-98,uMatchHits:4
Fields, 代表每个分词所对应的field的字段,索引建立时确定,举例说明,假设索引字段编码如下,sphinx用一个32无符号整数对每个索引字段编码
insert into LISTING(id,rtf_list_name, rtf_standard_channel) values(-98, ‘金龙鱼特香纯正花生油5L’, ‘金龙鱼特香纯正花生油5L’)
这条文档的m_uDocFields为6,对应分词,龙鱼
pDoc->m_uDocFields
tDoc.m_uDocFields =m_pQword->m_dQwordFields.GetMask32() & m_dQueriedFields.GetMask32();
m_iWeight = m_iWeight + uRank*SPH_BM25_SCALE其中,m_iWeight是BM25算法得到,uRank相似度
1、用户可以为每个field指定weight,格式optionfield_weights=(rtf_list_name=10),默认为1,这样可以加大或减小每个field所占的权重比例
2、每个分词的IDF计算方法, IDF是指在整个文档集中的反向文档频率。常见词(如“the” or “to”等)的IDF值小,罕见词的IDF值大,当一个关键词只在一个文档中出现时,达到峰值IDF=1,
而当关键词在每个索引文档都出现时,IDF=-1
float fLogTotal = logf (float ( 1+iTotalClamped ) );
fIDF = logf (float (iTotalClamped-iTermDocs+1 ) / float ( iTermDocs ) ) /( 2*fLogTotal );
fIDF /= iQwords;
参数说明:
1) iTotalClamped索引中总的DOcID数目,就是select count(*) 的输出结果
2) iTermDocs每个分词对应的DocID数目,对金,为docs[0],对 龙鱼,为docs[1]
3) iQwords,一个查询语句中,分词的个数,对下面的例子是2
举例:
select id,weight() ,list_name from LISTING where match('金龙鱼') limit 44;show meta;
输出如下:
每条文档的uRank,,相似度计算方法:
struct ExtDoc_t{ SphDocID_t m_uDocid; CSphRowitem * m_pDocinfo; ///< for inline storage only SphOffset_t m_uHitlistOffset; DWORD m_uDocFields; float m_fTFIDF;}; for ( inti=0; i<iWeights; i++ ) if( pDoc->m_uDocFields & (1<<i) ) { uRank += m_pWeights[i];}
参数说明:
1) iWeights总的field数目
2) m_pWeights[i]用户给每个field指定的权重值,默认是1
3) pDoc->m_uDocFields
tDoc.m_uDocFields =m_pQword->m_dQwordFields.GetMask32() & m_dQueriedFields.GetMask32();
dQueriedFields,查询时指定的字段,例如match(‘@rtf_list_name 金龙鱼’),值是4,如果没有指定field字段32位全是1
BM25参数,tDoc.m_fTFIDF每个分词对应多个文档,每个文档对应一个此参数
tDoc.m_fTFIDF= float(m_pQword->m_uMatchHits)/ float(m_pQword->m_uMatchHits+SPH_BM25_K1) * m_fIDF;
参数说明:
m_pQword->m_uMatchHits每个文档对应hit数目
SPH_BM25_K1=1.2f
m_fIDF为上面计算出的值
m_iWeight,为临时变量,m_iWeight = (int)((m_fTFIDF+0.5f)*SPH_BM25_SCALE )
参数说明:SPH_BM25_SCALE=1000
最终权重
m_iWeight = m_iWeight + uRank*SPH_BM25_SCALE
uRank最小为1,由此可能权重一定大于1000
多关键词处理方法
AND:将两个孩子节点获取到的doc合并起来,过滤掉docId不相同的,权重相加,代码如下
tDoc.m_uDocFields = pCur0->m_uDocFields| pCur1->m_uDocFields;
tDoc.m_fTFIDF = pCur0->m_fTFIDF + pCur1->m_fTFIDF;
OR:依次取前两个结点,如果DocID相同,权重相加,代码如下
m_dDocs[iDoc].m_uDocFields =pCur0->m_uDocFields | pCur1->m_uDocFields;m_dDocs[iDoc].m_fTFIDF = pCur0->m_fTFIDF+ pCur1->m_fTFIDF;
- 高性能搜索引擎sphinx源码解析之搜索过程和评分公式
- 高性能搜索引擎sphinx源码解析之中文分词和mmseg
- Sphinx高性能的搜索引擎(简单、强大、实用)
- sphinx源码分析之搜索(search)
- sphinx源码分析之搜索(search)
- ElasticSearch源码解析(五):排序(评分公式)
- Sphinx 搜索性能优化
- 高性能队列Disruptpor核心源码解析
- lucene-搜索过程源码解析-Weight树
- lucene-搜索过程源码解析-Score树
- 全文检索之sphinx源码分析--配置文件和轮转操作
- sphinx搜索引擎的安装和使用
- Sphinx高性能实时索引的解决方案
- sphinx 与搜索的安装配置过程
- 深入解析php之sphinx
- Sphinx 搜索性能优化 —— 多线程搜索
- Windows下安装sphinx和sphinx搜索标红
- 高性能Java解析器实现过程详解
- Maven学习(三)使用Maven部署发布Web项目
- 树莓派 b+ 第0天
- java类集---属性类:Properties
- Benchmarks of DFJSPs 01-10
- java JVM 堆新生代与老年代及回收方式
- 高性能搜索引擎sphinx源码解析之搜索过程和评分公式
- makefile(六):makefile的命令行参数
- Android中原型模式
- 微信小程序删除项目报 已存在touristappid
- [ Java学习 ] 破除思维定势之 C++ 和 Java 的差异 003
- 简易多线程服务器
- ElasticSearch 集群安装(5.5.2)
- JavaScript中的正则表达式
- 让instance使用hugepage