用Golang写一个搜索引擎(0x02)--- 倒排索引技术

这一篇,我们来说说搜索引擎最核心的技术,倒排索引技术,倒排索引可能需要分成几篇文章才说得完,我们先会说说倒排索引的技术原理,然后会讲讲怎么用一些数据结构和算法来实现一个倒排索引,然后会说一个索引器怎么通过文档来生成一个倒排索引。

倒排索引

什么是倒排索引呢?索引我们都知道,就是为了能更快的找到文档的数据结构,比如给文档编个号,那么通过这个号就可以很快的找到某一篇文档,而倒排索引不是根据文档编号,而是通过文档中的某些个词而找到文档的索引结构。

倒排索引技术简单,高效,简直是为搜索引擎这种东西量身定做的,就是靠这个技术,实现一个搜索引擎才成为可能,我们也才能在海量的文章中通过一个关键词找到我们想要的内容。

我们看个例子,有下面的几个文档:

文档编号 文档内容
1 这是一个Go语言实现的搜索引擎
2 PHP是世界上最好的语言
3 Linux是C语言和汇编语言实现的
4 谷歌是一个世界上最好的搜索引擎公司

直观的看,我们通过编号1,2,3,4可以很快的找到文档,但是我们需要通过关键词找文档,那么把上面那个表格稍微变化一下,就是倒排索引了

倒排索引【只列出了部分关键词】

关键词 文档编号
Go 1
语言 1,2,3
实现 1,3
搜索引擎 1,4
PHP 2
世界 2,4
最好 2,4
汇编 3
公司 4

这样就非常好理解了吧,实际上倒排索引就是把文档的内容切词以后重新生成了一个表格,通过这个表格,我们可以很快的找到每个关键词对应的文档,好了,没有了,到这里,就是倒排索引的核心原理,也是搜索引擎最基础的基石,不管是谷歌还是某度,最核心的东西就是这两个表格了,呵呵,没这两表格,啥都干不了。

看上去很简单吧,好吧,我们现在来模拟搜索引擎进行一次搜索,比如,我们键入关键词搜索引擎
1.我们在表格2中查到搜索引擎这个词出现在第4行
2.找到第4行的第2列,把文档编号找出来,是1和4
3.去第一个表格通过文档编号把每个文档的实际内容找出来
4.将1和4的结果显示出来
5.搜索完成

上面就是搜索引擎的最基础的技术了,如果来设计一个数据结构和算法来实现表2就成了搜索引擎技术的关键。

在实现数据结构和算法之前,我们需要知道搜索引擎搜索的是海量的数据,一般的中型电商的数据都是几十上百G的数据了,所以这个数据结构应该是存储在本地磁盘的而不是在内存中的,基于以上的考虑,为了快速搜索,要么自己实现cache来缓存热数据,要么考虑使用操作系统的底层技术MMAP,鉴于我自己实现的cache不见得(基本上是不太可能)比操作系统做得好,所以我使用的是MMAP

MMAP系统调用

mmap是将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。

mmap最大的一个好处是操作系统会自己将磁盘上的文件映射到内存,当内存足够的时候,操作文件就像操作内存一样快,而当内存不足的时候,操作系统又会自己将一些页从内存中去掉,实现了一个类似缓存的东西。特别适合于对于巨大文件的读操作,而我们的倒排索引文件就是这种巨大的文件,而且基本上写入一次以后就不太修改了,每次查询都读操作,所以使用mmap是一个比较好的选择。

mmap是一个系统调用,不同的操作系统实现有所不同,Linux下对应的C的调用方法是下面这个,具体的参数含义大家可以man一下:

头文件 <sys/mman.h>
函数原型
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);

一个巨大的文件mmap之后,文件读写操作的性能由系统内存决定,系统可用内存越大,那么读写文件的性能越好,因为操作系统的内存足够,系统会将更多的文件载入到内存,提高系统吞吐量。

在Go语言中,对应的MMAP调用是:(需要引入Syscall包)

func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error)

参数分别是:文件描述符,偏移量,需要映射的长度,期望的内存保护标志【是只读还是只写还是读写】,映射方式【是否同步到文件,还是只是副本修改等】。

因为mmap是基础实现,很多地方都需要使用,所以单独实现了一个mmap的类,在utils.mmap中,提供一些基础的方法:

func NewMmap(file_name string, mode int) (*Mmap, error) 新建一个mmap
func (this *Mmap) ReadInt64(start int64) int64 //从指定位置读取一个int64的值
func (this *Mmap) WriteInt64(start, value int64) error //在指定位置写入一个int64的值
func (this *Mmap) ReadDocIdsArry(start, len uint64) []DocIdNode //从指定位置读取一个docid的链
......

巨大文件的读写技术方案解决了,实际上主要就是解决了表2的第二列的问题,在一个拥有巨大文档数的数据中,表2的第二列占用了绝大多数磁盘空间,我们会将表2分成两个数据结构来存储,第二列就是一个连续的存储文件,叫倒排文件,在上述例子中,我们会将第二列存成:

1 1,2,3 1,3 1,4 2 2,4 2,4 3 4

而第一列我们将保存关键字和偏移量。这样,表2就被我们拆分成两个数据结构了,现在的关键是第一列使用什么数据结构可以保证在查询的时候迅速找到对应的关键字,从而找到偏移量得到第二列的具体数据。

好了,现在有几位选手要上场,他们都可以实现第一列的结构,他们分别是:顺序表哈希表查找树前缀树,下一篇我们分别看看他们的能力。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容