当前位置: 首页 > 工具软件 > Sphinx Search > 使用案例 >

sphinx源码分析之搜索(search)

谢志用
2023-12-01

此处分析用的源码为最新版本1.0 beta版的。

//search.cpp int main ( int argc, char ** argv )

让我们从程序入口点开始进行旅程。search的入口点在文件search.cpp中,打开后定位到int main ( int argc, char ** argv )开始我们的分析:

在main中开始部分进行参数检查和配置信息的load,先进行命令行参数的检查和设置,如下:

所有的查询信息都封装在CSphQuery tQuery;中,结构CSphQuery定义可以查看原文件,此处不知道也无关系影响不大,只要清楚它只是个容器的作用,用于盛放所以查询参数就ok了。

 

继续旅程,下面进入config的加载部分:

可以看到通过类CSphConfigParser对配置文件进行解析,最终解析结果存放在结构CSphConfig中,其实CSphConfig就是一个hashtable一样的东东,config文件中的source、index、searchd等等所有节的东西都被加载进入了CSphConfig中。

 

现在所有的参数信息不管是命令行传入的还是从config文件加载进入的都已经就绪,下面就该开始真正的工作了。

首先说明一下查询的流程,查询就是一个打开索引文件,用输入的查询词在索引文件中挨个进行比较,找到满足关系的文档的过程,并读出文档,给每个文件打分,最后打分完成后进行排序,随后获取到排序后的文档列表的过程。

 

数据库中可能存在多个索引文件,而查询一次在一个索引中进行。

pIndex->Prealloc ( false, false, sWarning )预先分配知足够内存存放cache数据

!pIndex->Preread() 预先读取所有的需要cache起来的数据,存放在Prealloc 分配的空间中
获取索引关联的数据模式const CSphSchema * pSchema = &pIndex->GetMatchSchema();

查询:

pIndex->MultiQuery ( &tQuery, pResult, 1, &pTop, NULL ) )进行最终的查询过程。

函数MultiQuery的原型为virtual bool                MultiQuery ( const CSphQuery * pQuery, CSphQueryResult * pResult, int iSorters, ISphMatchSorter ** ppSorters, const CSphVector<CSphFilterSettings> * pExtraFilters, int iTag=0 ) const = 0;

在后面还将对其进行分析。

MultiQuery的查询结果由pResult和pTop返回,在pTop中存放的是docs数据,里面的数据需要进行sphFlattenQueue ( pTop, pResult, 0 )操作后才能copy到pResult中,sphFlattenQueue()的运算过程就是一个优先队列的出队操作,最后的结果就是rank从高到底的排列。pResult返回的结果是一些对全体文档都有效的数据,如字符串属性的字符串值、多值属性的值等。

 

查询得到结果后下面的代码只是进行简单的终端输出了,没什么好分析的了:

 

 

下面对文档排序器(ISphMatchSorter )的创建过程简单分析:

//sphinxsort.cpp ISphMatchSorter * sphCreateQueue ( const CSphQuery * pQuery, const CSphSchema & tSchema, CSphString & sError, bool bComputeItems )

此函数中大部分的代码段都是根据pQuery 中的配置对ISphMatchSorte人 进行定制的,源程序中的注释已经很详细,具体可以参考源代码。在进行了所有的需要定制的功能的设定后,最终如下面代码片段,进行实际的排序器构造:

 

 

还是按着查询的路线一直走下去,下面分析查询过程。

//sphinx.cpp bool CSphIndex_VLN::MultiQuery ( const CSphQuery * pQuery, CSphQueryResult * pResult, int iSorters, ISphMatchSorter ** ppSorters, const CSphVector<CSphFilterSettings> * pExtraFilters, int iTag ) const

 

//sphinx.cpp bool CSphIndex_VLN::ParsedMultiQuery ( const CSphQuery * pQuery, CSphQueryResult * pResult, int iSorters, ISphMatchSorter ** ppSorters, const XQNode_t * pRoot, CSphDict * pDict, const CSphVector<CSphFilterSettings> * pExtraFilters, CSphQueryNodeCache * pNodeCache, int iTag ) const

开头部分只是一些索引查询前的铺垫工作,为下一层接口提供需要的参数的封装:

 

 

 

最终的查找,并对找到的doc进行ranking

 

现在我们已经从index中获取到docs,此时的doc缺乏docinfo信息,下面给它们安装上docinfo:

 

//sphinx.cpp bool CSphIndex_VLN::MatchExtended ( CSphQueryContext * pCtx, const CSphQuery * pQuery, int iSorters, ISphMatchSorter ** ppSorters, ISphRanker * pRanker, int iTag ) const

 

 

***********************************************************************************************************************************************

一直到现在,都停留在index抽象层中,没有涉及到任何具体的磁盘IO,从下面开始我们将进入的外存空间,进行具体的读磁盘索引操作。

***********************************************************************************************************************************************

//sphinxsearch.cpp template < typename STATE > int ExtRanker_T<STATE>::GetMatches ( int iFields, const int * pWeights )

从磁盘中读取匹配到的docs块和hits块

 

//sphinxsearch.cpp const ExtDoc_t * ExtRanker_c::GetFilteredDocs ()

这函数没什么好说的,对查询树找到的结果进行过滤,因为有些match是不想要的

 

//sphinxsearch.cpp const ExtDoc_t * ExtAnd_c::GetDocsChunk ( SphDocID_t * pMaxID )

前面已经提到过查询是分解到一颗查询树上进行的,树叶子节点为原子词条,而分支节点为and、or等孩子节点的组合操作,从下面的函数可以看到这点,这里是一个and节点,它将两个孩子节点的查询结果进行集合运算中的and运算:

 

//sphinxsearch.cpp const ExtDoc_t * ExtTerm_c::GetDocsChunk ( SphDocID_t * pMaxID )

下面看看对于原子词条是怎么读取和它相对应的docs列表的:

 

//sphinx.cpp virtual const CSphMatch & GetNextDoc ( DWORD * pDocinfo )

 

对于从文件中读取hitslist和读docs文件差不多,这里不再给出分析过程。

 

分析了这么大半天终于接近尾声,从输入一个查询短语,一直到从index文件中读出相关的文档列表,走过了查询的主要过程,但之间还有什么忽略掉了的地方,一些细节的地方,但它们对弄懂search流程并不那么重要,要具体弄懂每一个细节的地方还得花大量的时间精力去分析它,但这里就不在深入下去了。

 

 类似资料: