您的位置:首页 > 其它

sphinx 源码阅读之分词,压缩索引,倒排——单词对应的文档ID列表本质和lucene无异 也是外部排序再压缩 解压的时候需要全部扫描doc_ids列表偏移量相加获得最终的文档ID

2017-01-04 16:58 417 查看

转自:http://github.tiankonguse.com/blog/2014/12/03/sphinx-token-inverted-sort.html

前言

sphinx 在创建索引前需要做下面几件事:有数据源(pSource),有分词器(pTokenizer),有停止词Stopword 和 字典(pDict),索引引擎。

我们假设 数据源是 mysql, 分词器是 utf8 分词器。

索引前背景介绍

第一步是准备数据源。
这里采用 mysql 数据源。
mysql 数据的特点是一行一个记录。
每个记录有相同的字段。
每个字段可能代表数字,字符串,时间,二进制等信息,我们都可以按字符串处理即可。

//数据源


CSphSource_MySQL * pSrcMySQL = new CSphSource_MySQL ();


CSphSource * pSource = pSrcMySQL;


第二步准备分词器和字典。
这里不多说分词器,以后会专门写一篇记录来讲解分词器。
分词器依靠字典,可以把一个字符串分割为一些词语(word)。
然后根据这些词语,我们可以把mysql的每条记录每个字段都分割为若干词语,这里成为分词。
分割后这个分词需要保留几个信息:什么分词,属于哪个记录,属于哪个字段,在字段中的位置。
分词我们会hash (crc32) 成一个数字,冲突了就当做一个词了。
记录标示就是用自增整数ID.
字段一般不会很多,我们假设最多255个,使用8位可以表示。 字段的位置不确定,但是一个字段的内容也不会很多,我们用24位表示足够了。
所以哪个字段和字段的哪个位置就可以用一个32位整数代替了。
这样一个分词就可以用三个整数<wordId, docId, pos>来表示了。

//分词器


pTokenizer = sphCreateUTF8Tokenizer ();


pSource->SetTokenizer ( pTokenizer );




//字典


CSphDict_CRC32 * pDict = new CSphDict_CRC32 ( iMorph );


pSource->SetDict ( pDict );


一个分词称为一个hit, 数据结构如下

struct CSphWordHit {


DWORD m_iDocID;		//文档ID, 唯一代表一个记录


DWORD m_iWordID;	//单词ID, 对单词的hash值,可以理解为唯一标示


DWORD m_iWordPos;	//储存两个信息:字段位置(高8位)和分词的位置(低24位)


};


我们一条记录一条记录的把所有的记录都分词了,就得到一个分词列表了。
由于这个列表很大,我们需要分成多块储存,这里假设最多16块吧。
对于每块,储存前先排序一下,这样我们就得到 16 个 有序的数组了。
然后我们就可以创建索引了。

//索引


CSphIndex * pIndex = sphCreateIndexPhrase ( sIndexPath );




//开始创建索引


pIndex->Build ( pDict, pSource, iMemLimit )


其中 一切准备完毕后进入 Build 函数。

build 函数创建搜索

进入 build 函数后先准备内容。

在执行 build 函数时 ,先逐条读取记录,然后对每条记录的每个字段会进行分词(Next函数),存在 hit 数据结构中。
而且会把 hit 数据按指定块大小排序后压缩储存在 *.spr 文件中

块信息储存在 bins 数组中,块数最多16块, 块数用 iRawBlocks 表示。

接下来就是关键的创建压缩索引了。
首先创建索引对象。

cidxCreate()




//打开索引文件,先写入 m_tHeader 信息 和 cidxPagesDir 信息。


fdIndex = new CSphWriter_VLN ( ".spi" );


fdIndex->PutRawBytes ( &m_tHeader, sizeof(m_tHeader) );


//cidxPagesDir 数组全是 -1


fdIndex->PutBytes ( cidxPagesDir, sizeof(cidxPagesDir) );




//打开压缩数据文件,先写入一个开始符 bDummy


fdData = new CSphWriter_VLN ( ".spd" );


BYTE bDummy = 1;


fdData->PutBytes ( &bDummy, 1 );
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: