作者:唐刘

最近看了一篇论文 SuRF: Practical Range Query Filtering with Fast Succinct Tries,里面提到使用一种新的数据结构 Succinct Range Filter(SuRF) 替换掉了 RocksDB 默认的 Bloom filter, 在一些性能测试上面,尤其是 seek 上面,性能提升了不少,并且也降低了很多 I/O 开销,这一下子就引起了我的兴趣。

大家都知道,RocksDB 里面,为了加速 key 查询的速度,使用了 Bloom filter,但 Bloom filter 只适用于 point get,对于 seek 就无能为力了。虽然 RocksDB 后面引入了 prefix seek,但对于 key 的格式有要求,使用比较受限。为了提高 RocksDB range query 的速度,论文的作者引入了一种省空间的数据结构,也就是 SuRF。

在了解 SuRF 之前,首先要了解掌握的就是 Succinct data structure 相关的知识,这篇文章主要是讲 Succinct data structure 相关的东西,后面再讨论 SuRF 如何实现的。

Rank 和 Select

Succinct data structure 第一次提出,应该是 Guy Jacobson 的论文 “Succinct static data structures”,但实话,我在网上找了半天,都没找到这篇 paper,只是找到了作者另一篇 Space-efficient static trees and graphs。它的主要思想就是使用非常少量的空间(接近信息编码的下界)来存储数据。你可以认为就是使用了一种非常高效的压缩算法,但不同于压缩,它同时来提供非常高效的查询。

对于 Succinct data structure 来说,我们会将数据按 0 和 1 来编码,所以可以用 bits,而不是 bytes。操作 succinct 数据,通常的就是几个操作函数:

  • rank1(x) - 返回在 range [0, x] 里面 1 的个数
  • select1(y) - 返回第 y 个 1 所在的位置

上面我们只是列举了 rank1 和 select1,对应的也有 rank0 和 select0,这里就不需要解释了。这么说有点过于抽象,这里举一个简单的例子。假设我们有一个 bits 序列 11000001,那么 rank1 和 select1 可以映射如下:

另外,大家可以注意到,rank 和 select 其实是相反的,上面的例子,select1(3) = 7,然后我们也会发现,rank1(7) = 3

Level Order Unary Degree Sequence

上面简单介绍了下 Succinct data structure 的 rank 和 select。 在 SuRF 里面,它参考的基础编码方式,是 Level order unary degree sequence(LOUDS),在 LOUDS 里面,我们会将一颗树,分层依次进行编码。而规则也是非常的简单,如果这个树的节点有 N 个子节点,那么就用 N 个 1 来编码,然后最后加上 0。

假设我们有如下的 tree:

为了计算简单,LOUDS 会加入一个 pseudo root 节点,这里我们变成如下的 tree:

然后我们对这个 tree 进行编码,得到:

那么生成的 bits 序列为:

那么我们拿到了这一个序列到底有什么用呢?在 LOUDS 里面,我们可以非常方便的进行很多操作,假设我们的 node 就是按照上面的,0,1,2,这样的 number 来标记的,position 对应的就是 bits 里面的 position。我们通常会用两个计算公式来得到 node number 和 position 的对应关系:

  • node-num = rank1(i):在 position i 得到对应的 node number,譬如 rank1(2) = 2
  • i = select1(node-num),根据 node number,知道对应的 position,譬如 select1(2) = 2

有了上面的公式,我们就能对这个 tree 进行操作了:

  • first_child(i) = select0(rank1(i)) + 1 - 得到第 i 个位置所在节点的第一个子节点所在的 position
  • last_child(i) = select0(rank1(i) + 1) - 1 - 得到第 i 个位置所在节点的最后一个子节点所在的 position
  • parent(i) = select1(rank0(i)) - 得到第 i 个位置所在节点的父节点所在的 position
  • children(i) = last_child(i) - first_child(i) + 1 - 得到第 i 个位置所在节点的子节点的个数
  • child(i, num) = first_child(i) + num 得到第 i 个位置所在节点的第 num 个子节点所在的 position,num >= 0

上面这些公式感觉好绕,那么我们来一个简单的例子,以节点 4 为例。从上面的 tree 可以知道,4 的 parent node 是 1,它的第一个子节点是 7,最后一个是 8,总共有两个子节点。

首先我们需要计算节点 4 的位置,根据上面的公式 select1(4) 我们得到 position 是 4。那么第一个子节点位置就是 first_child(4) = select0(rank1(4)) + 1 = select0(4) + 1 = 9 + 1 = 10,那么第一个子节点就是 rank1(10) = 7

我们再来计算最后一个子节点,根据公式,最后一个就是 last_child(4) = select0(rank1(4) + 1) - 1 = select0(4 + 1) - 1 = 12 - 1 = 11,那么最后一个子节点就是 rank1(11) = 8

再来看看父节点,就是 parent(4) = select1(rank0(4)) = select1(1) = 0,那么父节点就是 rank1(0) = 1

Epilogue

使用 LODUS,我们可以用 bits 方便的编码一棵树,然后用 rank 和 select 操作,就能方便的对 tree 进行遍历,业内已经有很多 paper,能将 rank 和 select 做到 O(1) 的开销,所以速度还是很快的。

但在实际中,如果光用 LODUS,性能还是没法保证的,所以这也是为啥会有 SuRF 的原因,关于 SuRF,后面会在说明。

在数据库领域,Succinct 是一个比较有趣的研究方向,也有很多数据库采用了 succinct 来保存数据,毕竟如果能用更少的空间存放数据,memory 能装的更多,cache 更友好,性能就更好。但现在 succinct 还没有大规模的落地,可以看看后续的发展。如果你对构建新的存储引擎有兴趣,欢迎联系我 tl@pingcap.com。

原文链接

Succinct Data Structure相关推荐

  1. 用于数据库的新兴数据结构Succinct Data Structure

    这篇文章简单介绍了Succinct Data Structure 摘要: Succinct是一种数据编码方式, 能够以保证信息不丢失情况下, 使用最少的存储空间. https://mp.weixin. ...

  2. LeetCode Two Sum III - Data structure design

    原题链接在这里:https://leetcode.com/problems/two-sum-iii-data-structure-design/ 题目: Design and implement a ...

  3. leetcode 211. Add and Search Word - Data structure design Trie树

    题目链接 写一个数据结构, 支持两种操作. 加入一个字符串, 查找一个字符串是否存在.查找的时候, '.'可以代表任意一个字符. 显然是Trie树, 添加就是正常的添加, 查找的时候只要dfs查找就可 ...

  4. leetcode Add and Search Word - Data structure design

    我要在这里装个逼啦 class WordDictionary(object):def __init__(self):"""initialize your data str ...

  5. TRIE - Data Structure

    Introduction 介绍 Trie,又称单词查找树,是一种树形结构,用于保存大量的字符串.它的优点是:利用字符串的公共前缀来节约存储空间. Trie is an ordered tree dat ...

  6. 牛客小白月赛11:Rinne Loves Data Structure

    Rinne Loves Data Structure 思路 我们插入的位置大概分了四种: 第一种 显然我们找到比当前插入的值的pre,也就是比当前节点大的最小值. 第二种 我们只要找到当前节点的suc ...

  7. HDU - 7072 Boring data structure problem 双端队列 + 思维

    传送门 文章目录 题意: 思路: 题意: 你需要实现如下四个操作 q≤1e7q\le1e7q≤1e7 思路: 做的时候想了个链表的思路让队友写了,懒. 看了题解感觉题解还是很妙的. 你需要快速插入一个 ...

  8. HDU - 6967 G I love data structure 线段树维护矩阵 + 细节

    传送门 文章目录 题意: 思路: 题意: 给你两个长度为nnn的数组a,ba,ba,b,你需要完成如下四种操作: 思路: 思路还是比较简单的,首先建一颗线段树,线段树中维护a,b,a2,b2,aba, ...

  9. 170. Two Sum III - Data structure design【easy】

    170. Two Sum III - Data structure design[easy] Design and implement a TwoSum class. It should suppor ...

最新文章

  1. centos7 中搭建gitlab
  2. 【143】360云盘资源
  3. PAT甲级1009 Product of Polynomials:[C++题解]多项式乘法、高精度乘法
  4. 迷你HTM在线L编辑器—xhEditor
  5. SAP UI5 未来发展的趋势之一:拥抱 TypeScript
  6. java 数组地图绘画_Java将地图转换为数组[Snippet]
  7. 第一个将Palette Mode引入VVC(H.266),阿里云在JVET会议上引起关注
  8. MySQL 的 IFNULL()、ISNULL() 、 NULLIF()、IF() 函数
  9. 构建直接路由模式(DR)的LVS
  10. 系统学习机器学习之正则化(一)
  11. React Native 0.21 发布 (翻译Changelog)
  12. 用Binary Viewer查看H264文件中的每一帧
  13. python 爬取google总结
  14. 截取字符串时,截取完整的表情符
  15. 099node-MongoDB数据库添加账户
  16. MFC edit control动态设置密码
  17. RTKLIB中的各种AR mode 详解
  18. 2021-03-26:给定一个正整数N,表示有N份青草统一堆放在仓库里。有一只牛和一只羊,牛先吃,羊后吃,它俩轮流吃草。 不管是牛还是羊,每一轮能吃的草量必须是:1,4,16,64…(4的某次方)。谁
  19. 500万补贴!武汉市企业牵头承担国家科技项目配套补贴对象标准及申报流程
  20. feign.codec.DecodeException异常解决方案

热门文章

  1. 小little白white单片机教程01环境配置
  2. OnlyOffice验证(一)DocumentServer编译验证
  3. 谷歌浏览器插件的下载与安装
  4. 【迅为iMX6Q】开发板 Linux 5.15.71 RTL8211E 以太网驱动适配
  5. 纯干货分享:高项论文怎么写?这些写保证能及格!!!
  6. 使用AI写作工具,进阶文案写手:WordHero AI
  7. 吐血整理——python常用的第三方库——库名称简介
  8. MySQL中的几个“L”,你还记得否?
  9. Linux中函数库文件依赖关系查找网站 www.rpmfind.net
  10. 天津城建大学计算机教室图片,天津城建大学携手浩辰CAD共建建筑电气实训室