sphinx 源码阅读之分词,压缩索引,倒排——单词对应的文档ID列表本质和lucene无异 也是外部排序再压缩 解压的时候需要全部扫描doc_ids列表偏移量相加获得最终的文档ID
转自:http://github.tiankonguse.com/blog/2014/12/03/sphinx-token-inverted-sort.html
外部排序
现在我们的背景是有16个已经排序的数据存在磁盘上。
由于数据量很大,我们不能一次性全部读进来。
我们的目标是依次挑出最小的hit,然后交给索引引擎处理。
sphinx 使用了 CSphHitQueue 这个数据结构。
CSphHitQueue 你猜是什么? 队列? 恭喜你,猜错了。
CSphHitQueue 是一个最小堆。
且堆的最大个数是 iRawBlocks。
由于 iRawBlocks 个 hits 数组已经排序,所以我们只需要得到 已排序的hits数组的第一个元素,就可以用堆得到最小的那个元素了。
然后我们把最小的这个元素建索引压缩储存,删除最小元素,并取出最小元素所在 hits数组中下一个元素,扔到堆中。
这样就可以从小到大取出所有的元素,并逐个建立索引压缩储存了。
这段话看不懂的话,可以看下面的图。

创建索引压缩储存
其中创建索引压缩储存主要依靠这个函数
cidxHit ( tQueue.m_pData );
其中 tQueue.m_pData 的数据结构如下
/// fat hit, which is actually stored in VLN indexstruct CSphFatHit{DWORD m_iDocID; ///< document IDDWORD m_iGroupID; ///< documents group IDDWORD m_iTimestamp; ///< document timestampDWORD m_iWordID; ///< word ID in current dictionaryDWORD m_iWordPos; ///< word position in current document};
hit 是先按 m_iWordID 排序, 相等了再按 m_iDocID 排序, 最后才按 m_iWordPos 排序的。
现在我们先不考虑上面的堆,我们假设所有的 hit 已经在一个数组中了,且按上面的规则排序了。
现在我们想做的是对这个 hit 数组创建索引,并压缩储存。
主要做了这个几件事。
第一,根据 m_iWordID 将分词分为 2014 块。
并使用 cidxPagesDir 记录块的偏移量(还记得索引文件第二个写入的数据吗)。
第二,对于每一块,我们按分词分组,并在索引文件 spi 中储存每个词组的信息。
具体储存的信息如下
- 和上一个分词(wordID)的偏差
- 这个分词组在 spd 文件内的长度
- 这个分词记录的变化次数
- 这个分词的 hit 数量
第三,对于每个hit,我们存两部分信息。
- 位置(pos)偏移量信息
- 文档(docId)偏移量的信息
上面的三部分信息都储存后,我们就可以快速的解析出来。
推理 - 搜索信息
假设我们又上面的压缩的信息了。
我们要搜索一个词时,会如何工作呢?
假设我们已经得到这个词的 wordId 了,只需要二分一下,就可以再 O(log(1024)) 的时间内得到 wordId 在那个块内。
找到一个块内,出现一个问题,我们不能再次二分查找来找到对应的分词列表。 因为这个 index 储存的是和上一个分词的相对偏移量,那只好全部读入内存,扫描一遍对偏移量求和,然后才能找到对应的词。
这个过程中我们进行了两次 IO 操作。
第一次读取块列表信息 cidxPagesDir。
第二次读取选中的那一块的所有数据。
虽然储存偏移量节省了一些磁盘储存,但是却是用扫描整块数据为代价的。我们本来可以直接二分整块数据的。
不管怎样,我们在索引中找到了需要查找的那个分词的位置。
然后我们可以在数据文件内读取对应的信息,然后得到对应记录的id了。
当然,上面这个只是我的推理,下面我们来看看 sphinx 是怎么搜索的吧。
sphinx 搜索方法
看 sphinx 的搜索方法,只需要看 CSphIndex_VLN 的 QueryEx 函数即可。
首先对查询的语句进行分词,然后读取索引头 m_tHeader, 读取分块信息 cidxPagesDir。
然后就对分词进行搜索了。
为了防止相同的分词重复查找,这里采用二层循环,先来判断这个分词之前是否搜索过,搜索过就记下搜索过的那个词的位置。
没搜索过,就搜索。
xxx代码略!
看了这个代码,和我想的有点出入,但是总体思路还是一样的。
它是把所有的 cidxPagesDir 全储存起来了,这样直接定位到指定的位置了。少了一个二分搜索。
定位到某个块之后, 果然采用暴力循环来一个一个的增加偏移,然后查找对应的分词。
找到了记录对应的位置的四大元信息。
再然后由于数据量已经很小了,就把匹配的数据取出来即可。
当然,取数据的时候会进行布尔操作,而且会加上权值计算,这样就搜索满足条件的前若干条了。
sphinx 源码阅读之分词,压缩索引,倒排——单词对应的文档ID列表本质和lucene无异 也是外部排序再压缩 解压的时候需要全部扫描doc_ids列表偏移量相加获得最终的文档ID的更多相关文章
- sphinx源码分析总结
http://www.cnblogs.com/bonelee/p/6667955.html shinx索引部分源码分析——过程:连接到CSphSource对应的sql数据源,通过fetch row取其 ...
- 【转】cJSON 源码阅读笔记
前言 cjson 的代码只有 1000+ 行, 而且只是简单的几个函数的调用. 而且 cjson 还有很多不完善的地方, 推荐大家看完之后自己实现一个 封装好的功能完善的 cjson 程序. json ...
- 【原】AFNetworking源码阅读(二)
[原]AFNetworking源码阅读(二) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 上一篇中我们在iOS Example代码中提到了AFHTTPSessionMa ...
- spring-framework-4.1.x源码阅读环境搭建(导入Eclipse)
注意:搭建spring-framework-4.1.x源码 eclipse工作空间需要安装jdk8. spring-framework-4.1.x项目采用目前主流的项目管理工具gradle进行构建,至 ...
- 【原】FMDB源码阅读(二)
[原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...
- 【原】FMDB源码阅读(一)
[原]FMDB源码阅读(一) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 说实话,之前的SDWebImage和AFNetworking这两个组件我还是使用过的,但是对于 ...
- 【原】SDWebImage源码阅读(五)
[原]SDWebImage源码阅读(五) 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 前面的代码并没有特意去讲SDWebImage的缓存机制,主要是想单独开一章节专门讲 ...
- Spring源码阅读笔记
前言 作为一个Java开发者,工作了几年后,越发觉力有点不从心了,技术的世界实在是太过于辽阔了,接触的东西越多,越感到前所未有的恐慌. 每天捣鼓这个捣鼓那个,结果回过头来,才发现这个也不通,那个也不精 ...
- 【合集】TiDB 源码阅读系列文章
[合集]TiDB 源码阅读系列文章 (一)序 (二)初识 TiDB 源码 (三)SQL 的一生 (四)INSERT 语句概览 (五)TiDB SQL Parser 的实现 (六)Select 语句概览 ...
随机推荐
- ios -- 教你如何轻松学习Swift语法(一)
目前随着公司开发模式的变更,swift也显得越发重要,相对来说,swift语言更加简洁,严谨.但对于我来说,感觉swift细节的处理很繁琐,可能是还没适应的缘故吧.基本每写一句代码,都要对变量的数据类 ...
- Python 进程
安装Python的paramiko模块 步骤: 1:管理员方式打开cmd,切换到python安装路径的Scripts目录下: 2:执行命令: 1 pip3.5.exe install paramiko ...
- 0-systemctl开机启动项
防火墙:iptables Apache服务名称:httpd MySQL服务名称:mysqld VSFTP服务名称:vsftpd <!--CentOS7新指令--> 使某服务 自动启动 sy ...
- MVC 4 异步编程简化了
MVC 3 异步编程好麻烦,需要使用异步控制器,一个Action需要拆成两个,很不方便.MVC3的好处是,只需要.NET Framework 4.0就能运行 MVC 4 之后只需要使用async和aw ...
- QTP
QTP支持功能测试和回归测试的自动化. 支持录制功能,可以对脚本设置检查点,也可以进行参数化.可以在一个ACTION中调用另外一个ACTION action可以调用外部脚本.可以复制已有的ACTION ...
- 【转】 #1451 - Cannot delete or update a parent row: a foreign key constraint fails 问题的解决办法
转载地址:http://blog.csdn.net/donglynn/article/details/17056099 错误 SQL 查询: DELETE FROM `zmax_lang` WHERE ...
- noi 8787 数的划分
题目链接:http://noi.openjudge.cn/ch0206/8787/ 将整数n分成k份,且每份不能为空,任意两份不能相同(不考虑顺序). 简直跟分苹果一模一样. #include < ...
- 将B表的字段内容插入到A表字段中
update hy_b_hacker as h , ( SELECT ( @rowNO := @rowNo +1 ) AS rowno, ip FROM ( SELECT * FROM hy_b_se ...
- javascript 面向对象(转)
1.使用[]调用对象的属性和方法 function User() { this.age = 21; this.sex = "男?"; } var user = new User() ...
- 【Spring】对象后期处理,BeanPostProcessor
当我们使用Spring容器管理对象时,需要对对象进行一些后期处理时,比如数据处理.数据预加载,可以使用BeanPostProcessor接口. 简单演示它的用法. 定义扫描包,显示定义BeanPost ...