Lucene中的部分算法浅析

Lucene作为一个索引和存储引擎,其实现中包含了很多数据存储和检索方面的算法。这里对其中一部分算法做些简单的分析,希望能够对我们在其他领域处理类似问题时提供参考。

批量顺序写入索引数据

和传统的数据库比较,Lucene由于对检索的要求更高:全文检索、高亮、相似度等,其索引处理和存储发的负担要远多于一般的数据库。再加上,Lcuene追求更大的文档处理吞吐量,所以Lcuene没有使用大多数传统的关系数据库的索引结构:B+树,而是使用map这种更利于I/O的结果存储索引。

map的新增操作只需要在map文件的末尾添加记录即可,而在普通的B+树增加记录却可能需要执行seek+update操作。对磁盘来说,由于需要移动磁头/寻道的概率较低,顺序写的效率要高于随机写,所以map的写效率是优于B+树的。

为了保持磁盘的IO效率,lucene避免对索引文件的直接修改,所有的索引文件一旦生成,就是只读,不能被改变的。其操作过程如下:

  1. 在内存中保存新增的索引;
  2. 内存中的索引数量达到一定阈值时,触发写操作,将这部分数据批量写入新文件,我们称为segment;
  3. 新增的segment生成后,不能被修改;
  4. update操作和delete操作不会立即导致原有的数据被修改或者删除。

上面的过程执行一段时间后,最终我们会得到大量的segment。为了减少资源占用,也为了提高检索效率,lcuene会自动定期将这些小的segment合并成大的segment,合并过程中,由于map中的数据都是排好序的,所以也不会有随机写操作。通过merge,我们还可以把update和delete操作真正生效,删除多余的数据,节省空间。

Lucene使用的索引结构和管理办法,其出发点是为了保证写入性能,同时又能支持较高效率的检索,这种方法在很多NoSQL数据库中被使用,和B+树对应,这类索引方法我们称为LSM树(log structured merge tree)。LSM在不同的数据中有多种具体实现,差异主要表现在segment的内容组织,segment的合并时机和算法等方面。详细的资料可以参考:log-structured-merge-trees

联合检索

在很多数据库中,如果检索涉及到多个字段,通常检索过程中只会利用其中一个字段的索引。但Lucene能够保证使用所用相关字段的索引,其检索过程如下:

  1. 通过各个字段的索引检索出多组文档;

  2. 这些文档使用排好序的跳表(skip list)保存;

  3. 遍历这些跳表,找出它们之间的交集。

这里举个具体的例子(来自:algorithms-and-data-structures-power-lucene-and-elasticsearch)

假定我们根据三个不同字段检索得到三组文档,表示成下面三个列表:

A:[2, 13, 17]
B:[1, 13, 22]
C: [1, 3, 13]

每个列表提供两个操作:nextadvance:

next表示得到将列表指针指向一个位置;

advance(m)表示将指针指向下一个值不小于m的位置;

开始遍历时,每个列表的指针指向第一个元素,

A.next -> 2
B.next -> 1

由于B的当前值1小于A的当前值2,所以执行:B.advance(2),将B的指针跳向第一个不小于2的位置,这个值就是13。

而A的当前值为2,小于13,所以这次轮到A需要执行跳跃:A.advance(13),结果指针也来到13。

A和B的指针都指向13,我们可以对A和C也执行上述操作,导致C的指针也指向13,所以13就是符合条件的文档。

这个过程中,我们利用到了跳表的快速遍历特性,提供了检索效率。

行存储和列存储

Lucene在存储文档原始数据时,使用行存储格式,每行大小固定(16k), 在行内可存储多个文档。这么设计的用意在于考虑到Lucene面向的文档大部分较小,可以多个文档共存于一行,这样便于减少行数,相应的行索引数量也减少,提高读写效率。

Lucene为了支持数据的排序和聚合需求,还另外提供了列存储(DocValue),它用于存储所有文档的特定字段,当需要按照该字段进行排序、聚合时,和行存储比较,列式的存储更利于批量获取多个文档的字段值。

关于Lucene的文件存储格式,请参考lucene的相关文档

压缩

为了节省空间,lucene在行存储和列存储中存放的都是压缩数据。对于行存储,lucene提供了两种压缩选项:BEST_SPEEDBEST_COMPRESSION,对应速度优先和空间优先的不同策略。

而在列存储中,lucene主要通过对数据的编解码实现压缩,这里有些例子:

  • Delta Encoding
  1. 取出字段的最小值;
  2. 其他字段的值表示成和最小值的差异;
  • Table Encoding
  1. 如果字段的取值不超过256个;将所有的值保存在一个独立的table中;
  2. 各个字段表示成table的索引
  3. 在字段值的cardinality不多的情况下适用

Cardinality

Cardinality是指集合中不同值的个数。按照一般的做法,我们需要遍历集合,将不同的值保存到一个Map中,完成遍历后,map的size就是cardinality。可是这种处理方法不适合大集合,会消耗太多内存。

Lucene采用了另外的方法来统计cardinality,该方法不能够得到精确计算结果,但是能够得到一个近似值。方法的名称为:HyperLogLog++,计算过程如下:

  1. 计算字段的hash值;
  2. 统计hash值末尾开始的连续0的个数,记为m;
  3. 记录m的最大值;
  4. Cardinality = 2m
原始值 hash值 末尾连续0的个数
12345 11001011111101011010 1
3456 10001101001100111000 3
948 01000111110100110100 2

我们来看个例子:

原始值 hash值 末尾连续0的个数
12345 11001011111101011010 1
3456 10001101001100111000 3
948 01000111110100110100 2

在上面的3个值中,我们观察到末尾连续0的个数最大为3,根据公式,cadinality等于23=8

这个计算过程不需要我们去遍历和记住所有的不同值,只需要一个变量(末尾连续0的个数)就可以了,所以对内存资源占用很少。当然,我们上面的描述是对HyperLogLog的简化,为了减少结果偏差,HyperLogLog的实现要比上面的过程稍微复杂一些,但是其本质不变,都是对结果的近似估算。

其实有很多类似的的近似估算方法,它们一般被归类到data sketch算法,适用于大数据环境中对数据的近似统计。更详细的记录可以参考:skectching-sclaing

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

推荐阅读更多精彩内容