前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Clickhouse添加bitmap分页函数

Clickhouse添加bitmap分页函数

作者头像
DH镔
发布2023-10-21 11:50:58
3360
发布2023-10-21 11:50:58
举报
文章被收录于专栏:编程从踩坑到跳坑

# Clickhouse添加bitmap分页函数

# 起因

在做标签引擎的时候,我们在采用了bitmap存储对象id,基础的结构如下

标签类型

标签值

对象id bitmap

性别

[1,2,3]

性别

[8,9,10]

表如下:

代码语言:javascript
复制
create table if not exists label_string_local on cluster clickhouse_cluster
(
    label_type  String comment '标签id',
    label_value String comment '标签值',
    object_bitmap AggregateFunction(groupBitmap, UInt32) comment '标签值'
)
    engine = AggregatingMergeTree PARTITION BY label_type
        ORDER BY (label_type, label_value)
        SETTINGS index_granularity = 8192;

到后面需求要求对对象id分页返回,问题就来了,clickhouse的官方没有bitmap的分页函数,最原始的解决方案就是把bitmap整个返回,在应用层对bitmap进行切割,这样导致接口的性能急剧下降。开始萌生了个大胆的想法,给clickhouse添加bitmap分页函数

# 开干

通过阅读Clickhouse的源码,步骤如下:

  1. 实现分页

在Clickhouse中bitmap指向的class是RoaringBitmapWithSmallSet ,bitmap底层使用的是RoaringBitmap,github地址:https://github.com/RoaringBitmap/CRoaring.gitopen in new windowRoaringBitmapWithSmallSet对rb进行了包装,在这个类下添加分页函数

代码语言:javascript
复制
   UInt64 rb_offset_limit(UInt64 offset, UInt64 limit, RoaringBitmapWithSmallSet & r1) const
    {
        if (limit == 0 || offset >= size())
            return 0;

        if (isSmall())
        {
            UInt64 count = 0;
            UInt64 offset_count = 0;
            auto it = small.begin();
            for (;it != small.end() && offset_count < offset; ++it)
                ++offset_count;

            for (;it != small.end() && count < limit; ++it, ++count)
                r1.add(it->getValue());
            return count;
        }
        else
        {
            UInt64 count = 0;
            UInt64 offset_count = 0;
            auto it = rb->begin();
            for (;it != rb->end() && offset_count < offset; ++it)
                ++offset_count;

            for (;it != rb->end() && count < limit; ++it, ++count)
                r1.add(*it);
            return count;
        }
    }
  1. Clickhouse函数定义

FunctionsBitmap.h定义Clickhouse函数

代码语言:javascript
复制
struct BitmapSubsetOffsetLimitImpl
{
public:
    static constexpr auto name = "subBitmap";
    template <typename T>
    static void apply(
        const AggregateFunctionGroupBitmapData<T> & bitmap_data_0,
        UInt64 range_start,
        UInt64 range_end,
        AggregateFunctionGroupBitmapData<T> & bitmap_data_2)
        {
        bitmap_data_0.rbs.rb_offset_limit(range_start, range_end, bitmap_data_2.rbs);
        }
};

using FunctionBitmapSubsetOffsetLimit = FunctionBitmapSubset<BitmapSubsetOffsetLimitImpl>;
  1. Clickhouse函数注册

FunctionsBitmap.cpp注册函数

代码语言:javascript
复制
#include <Functions/FunctionFactory.h>

// TODO include this last because of a broken roaring header. See the comment inside.
#include <Functions/FunctionsBitmap.h>


namespace DB
{

void registerFunctionsBitmap(FunctionFactory & factory)
{
    ...
    factory.registerFunction<FunctionBitmapSubsetOffsetLimit>();
    ...
}
}

这样就完事了,最终这部分的代码提交到了Clickhosue仓库,最终得到了合并,https://github.com/ClickHouse/ClickHouse/pull/27234open in new window

# 后续

后面又来了个需求,要求标签能够修改,这又炸了,Clickhosue是不支持修改的,bitmap采用的数据结构是AggregateFunction(groupBitmap, UInt32),groupBitmap的合并逻辑是或运算,内部Clickhosue开发了一种新的数据结构xor_groupBitmap,支持合并逻辑异或运算,变相支持删除操作,考虑这部分并不通用,所以没有开源出来

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # Clickhouse添加bitmap分页函数
    • # 起因
      • # 开干
        • # 后续
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档