本文为您介绍Hologres中BSI(Bit-sliced Index)扩展函数的使用。
原理介绍
BSI本质上是对(cid::int, value::bigint)键值数据的压缩。下面以表数据为例为您介绍BSI的原理与结构。
| cid | value(十进制) | value(二进制) | 
| 1 | 3 | 0011 | 
| 2 | 6 | 0110 | 
| 3 | 4 | 0100 | 
| 4 | 10 | 1010 | 
| 5 | 7 | 0111 | 
| 6 | NULL | - | 
表中包含cid和value列。其中,value的最大值为10,即二进制最大位数为4位,因此将所有value的二进制值补充为4位。然后对二进制数据从低位向高位遍历,记录每位值为1时对应的cid数组的roaringbitmap,形成位切片索引Bit-sliced Index(BSI)。上表数据最终建立了如下切片索引:
- slice 0:roaringbitmap '{1,5}' 
- slice 1:roaringbitmap '{1,2,4,5}' 
- slice 2:roaringbitmap '{2,3,5}' 
- slice 3:roaringbitmap '{4}' 
此外,BSI中还会存储如下信息:
- Existence bitmap(ebm):存储cid数组(值非空)的roaringbitmap,本示例中为roaringbitmap '{1,2,3,4,5}'。 
- max:value的最大值,本示例为10。 
- min:value的最小值,本示例为3。 
- bitCount:value的二进制位数,本示例为4。 
基于上述原理与示例,如果已经通过RoaringBitmap进行位图计算,得到某个人群圈选结果为crowd='{1,3,5}',通过BSI即可继续针对value的高效计算,快速得到结果。比如:
- 计算圈选的人群对应的value之和: - rb_and_cardinality(crowd, slice0) * 20 + ... + rb_and_cardinality(crowd, slice3) * 23 = 14
- 计算圈选的人群对应的value的Top 2: - crowd & slice3 = NULL crowd & slice2 = {3,5} -- top2为{3,5} {3,5} & slice1 = {5} -- top1为{5}
通过BSI算法,对键值数据进行压缩存储,可以将cid的RoaringBitmap计算与value的计算完美结合,有效提升用户画像分析场景下“属性标签”与“行为标签”结合的计算效率。基于BSI函数的用户画像分析方案请参见画像分析 - BSI优化方案(Beta)。
使用限制
- 仅Hologres V2.1版本起支持BSI函数,如果您的实例版本为V2.1以下版本,请先升级实例版本,详情请参见实例升级。 
- BSI函数中的各个值仅支持正整数(1 ~ 231-1),不支持0和负数。 
- 需要Superuser执行以下语句开启两个Extension。创建Extension是DB级别,一个DB只需要开启一次即可。 - --创建extension。创建bsi需要先创建roaringbitmap CREATE EXTENSION roaringbitmap; CREATE EXTENSION bsi; --删除extension DROP EXTENSION roaringbitmap; DROP EXTENSION bsi;重要- 不推荐使用 - DROP EXTENSION <extension_name> CASCADE;命令级联卸载Extension。CASCADE(级联)删除命令不仅会删除指定扩展本身,还会一并清除扩展数据(例如PostGIS数据、RoaringBitmap数据、Proxima数据、Binlog数据、BSI数据等)以及依赖该扩展的对象(包括元数据、表、视图、Server数据等)。
函数列表
BSI构造函数
| 函数名 | 输入 | 输出 | 描述 | 示例 | 返回结果 | 
| bsi_build | integer[], bigint[] | bsi | 通过两个一维数据创建一个BSI。 |  |  | 
| bsi_add_value | bsi, integer, bigint | bsi | 为BSI增加一个键值对。 |  |  | 
BSI展开函数
| 函数名 | 输入 | 输出 | 描述 | 示例 | 返回结果 | 
| bsi_iterate | bsi | set of integer[] | 将BSI按键值展开。 |  |  | 
| bsi_show | bsi/bytea, integer | text | 将BSI按键值展开,并展示前integer个键值对。 |  |  | 
BSI查询函数
| 函数名 | 输入 | 输出 | 描述 | 示例 | 返回结果 | 
| bsi_ebm | bsi/bytea | roaringbitmap | 查询BSI的ebm数组的roaringbitmap。 |  |  | 
| bsi_eq | bsi, bigint [, bytea] | roaringbitmap | 查询BSI value等于bigint的部分,返回对应ebm数组的roaringbitmap。 如果有第三入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再进行比较查询。 |  |  | 
| bsi_filter | bsi/bytea, bytea | bsi | 查询BSI的ebm和指定bytea的交集部分,返回新的BSI。 |  |  | 
| bsi_ge | bsi, bigint [, bytea] | roaringbitmap | 查询BSI的value大于等于bigint的部分,返回对应ebm组成的roaringbitmap。 如果有第三入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再进行比较查询。 |  |  | 
| bsi_gt | bsi, bigint [, bytea] | roaringbitmap | 查询BSI的value大于bigint的部分,返回对应ebm组成的roaringbitmap。 如果有第三入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再进行比较查询。 |  |  | 
| bsi_le | bsi, bigint [, bytea] | roaringbitmap | 查询BSI的value小于等于bigint的部分,返回对应ebm组成的roaringbitmap。 如果有第三入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再进行比较查询。 |  |  | 
| bsi_lt | bsi, bigint [, bytea] | roaringbitmap | 查询BSI的value小于bigint的部分,返回对应ebm组成的roaringbitmap。 如果有第三入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再进行比较查询。 |  |  | 
| bsi_neq | bsi, bigint [, bytea] | roaringbitmap | 查询BSI的value不等于bigint的部分,返回对应ebm组成的roaringbitmap。 如果有第三入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再进行比较查询。 |  |  | 
| bsi_range | bsi, bigint, bigint [, bytea] | roaringbitmap | 查询BSI的value介于两个bigint之间(两端闭区间)的部分,返回对应ebm组成的roaringbitmap。 如果有第三入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再进行比较查询。 |  |  | 
| bsi_compare | text, bsi, [bytea,] bigint, bigint | roaringbitmap | 对BSI进行比较过滤查询。 
 |  |  | 
BSI聚合分析函数
| 函数名 | 输入 | 输出 | 描述 | 示例 | 返回结果 | 
| bsi_add | bsi, bsi | bsi | 将两个BSI相同ebm对应的value相加,返回新的BSI。 |  |  | 
| bsi_add_agg | bsi | bsi | 求和聚合计算。 |  |  | 
| bsi_merge | bsi, bsi | bsi | 将两个BSI合并,要求两个BSI的ebm没有交集。 |  |  | 
| bsi_merge_agg | bsi | bsi | 合并聚合计算,要求BSI的ebm没有交集。 |  |  | 
| bsi_stat | bigint[], bsi/bytea [, bytea] | text | BSI value的分布统计。分布区间根据输入的边界值数组切分。 如果有第三入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再进行分布统计。 |  |  | 
| bsi_sum | bsi/bytea [, bytea] | bigint[] | 返回BSI value之和sum以及ebm基数cardinality组成的数组。 如果有第二入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再计算sum与基数。 |  |  | 
| bsi_topk | bsi/bytea, [bytea, ] integer | roaringbitmap | 返回BSI top k个最大value对应的ebm组成的roaringbitmap。 如果有第二入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再计算top K。 |  |  | 
| bsi_transpose | bsi/bytea [, bytea] | roaringbitmap | 返回BSI的value转置结果,即去重后组成的roaringbitmap。 如果有第二入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再计算转置。 |  |  | 
| bsi_transpose_with_count | bsi/bytea [, bytea] | bsi | 将BSI的value转置并统计次数,返回新的BSI。 如果有第二入参roaringbitmap类型序列化的bytea,则先查询BSI的ebm和bytea的交集部分,再计算转置并统计。 |  |  |