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


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

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

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

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

    1. //数据源
    2. CSphSource_MySQL * pSrcMySQL = new CSphSource_MySQL ();
    3. CSphSource * pSource = pSrcMySQL;

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

    1. //分词器
    2. pTokenizer = sphCreateUTF8Tokenizer ();
    3. pSource->SetTokenizer ( pTokenizer );
    4. //字典
    5. CSphDict_CRC32 * pDict = new CSphDict_CRC32 ( iMorph );
    6. pSource->SetDict ( pDict );

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

    1. struct CSphWordHit {
    2. DWORD m_iDocID; //文档ID, 唯一代表一个记录
    3. DWORD m_iWordID; //单词ID, 对单词的hash值,可以理解为唯一标示
    4. DWORD m_iWordPos; //储存两个信息:字段位置(高8位)和分词的位置(低24位)
    5. };

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

    1. //索引
    2. CSphIndex * pIndex = sphCreateIndexPhrase ( sIndexPath );
    3. //开始创建索引
    4. pIndex->Build ( pDict, pSource, iMemLimit )

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

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

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

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

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

    1. cidxCreate()
    2. //打开索引文件,先写入 m_tHeader 信息 和 cidxPagesDir 信息。
    3. fdIndex = new CSphWriter_VLN ( ".spi" );
    4. fdIndex->PutRawBytes ( &m_tHeader, sizeof(m_tHeader) );
    5. //cidxPagesDir 数组全是 -1
    6. fdIndex->PutBytes ( cidxPagesDir, sizeof(cidxPagesDir) );
    7. //打开压缩数据文件,先写入一个开始符 bDummy
    8. fdData = new CSphWriter_VLN ( ".spd" );
    9. BYTE bDummy = 1;
    10. fdData->PutBytes ( &bDummy, 1 );
  • 相关阅读:
    apache反向代理和负载均衡
    maven学习3,如何创建一个web项目
    初识maven及其安装步骤!!
    初识Eclipse!!
    登录页面!!!
    面向对象的三大要素
    【转载】fatal error C1010: unexpected end of file while looking for precompiled header directive
    C++ 读取XML 和TXT
    python +Libsvm 配置
    C++ 引用 和 指针 心得
  • 原文地址:https://www.cnblogs.com/bonelee/p/6249343.html
Copyright © 2020-2023  润新知