Roaring Bitmap は、高性能なセットオペレーションに最適化された圧縮ビットマップフォーマットです。AnalyticDB for MySQL で使用することで、大規模なデータセット上での重複排除、タグベースのユーザーフィルタリング、時系列計算が可能になります。
Roaring Bitmap の使用
Roaring Bitmap は、ビットマップ内の各グループに含まれるエントリが 1 億以下の場合、標準的な COUNT(DISTINCT ...) クエリよりも優れたパフォーマンスを発揮します。より大きな UID 空間の場合は、それに応じてグループ数を増やしてください (例えば、100 億の UID 空間には少なくとも 100 個のグループが必要です)。
バージョン要件
| テーブルタイプ | 最小バージョン |
|---|---|
| OSS 外部テーブル | 3.1.6.4 |
| 内部テーブル | 3.2.1.0 |
V3.2.8.0 以降は、Roaring Bitmap の BIGINT データをサポートします (値の範囲が 64 ビット整数に拡張されます)。この機能を有効にするには、テクニカルサポートにお問い合わせください。有効にすると、特定の関数で BIGINT 入力を受け付けるようになり、戻り値の型が INTEGER から BIGINT に変更になります。詳細については、「Functions」をご参照ください。
クラスターバージョンを表示または更新するには、AnalyticDB for MySQL コンソールの[クラスター情報] ページにある[設定情報] セクションに移動します。
制限事項
-
ROARINGBITMAP 列に対する直接の SELECT はサポートされていません。要素を表示するには、UNNEST を使用してください。
SELECT * FROM unnest(RB_BUILD(ARRAY[1,2,3])); -
V3.2.1.0 より前のクラスターでは、ROARINGBITMAP は OSS 外部テーブルでのみサポートされています。これらのバージョンで内部テーブルに対してビットマップ操作を使用するには、ビットマップを VARBINARY として保存し、クエリ実行時に
RB_BUILD_VARBINARYを使用して変換します。-- VARBINARY を使用した内部テーブルの定義 CREATE TABLE test_rb_cstore (id INT, rb VARBINARY); -- ビットマップ関数を使用したクエリ SELECT RB_CARDINALITY(RB_BUILD_VARBINARY(rb)) FROM test_rb_cstore;
Roaring ビットマップの構築
Roaring ビットマップを構築する関数は 3 つあり、それぞれ異なる入力ソースに対応しています:
| 関数 | 入力 | 使用シナリオ |
|---|---|---|
RB_BUILD(array) |
整数配列 | リテラル配列からビットマップを構築する場合 |
RB_BUILD_AGG(integer) |
整数 (集計) | 行レベルの整数をビットマップに集計する場合 |
RB_BUILD_VARBINARY(varbinary) |
VARBINARY | 内部テーブルに VARBINARY として格納されたビットマップを読み取る場合 |
関数
スカラー関数
| 関数 | 入力タイプ | 出力タイプ | 説明 | 例 |
|---|---|---|---|---|
RB_BUILD |
ARRAY(INT) または ARRAY(BIGINT) | ROARING BITMAP | 整数配列から Roaring Bitmap を構築します。 | RB_BUILD(ARRAY[1,2,3]) |
RB_BUILD_RANGE |
INT, INT または BIGINT, BIGINT | ROARING BITMAP | start (含む) から end (含まない) までの範囲から Roaring Bitmap を構築します。 | RB_BUILD_RANGE(0, 10000) |
RB_BUILD_VARBINARY |
VARBINARY | ROARING BITMAP | VARBINARY データから Roaring Bitmap を構築します。 | RB_BUILD_VARBINARY(RB_TO_VARBINARY(RB_BUILD(ARRAY[1,2,3]))) |
RB_CARDINALITY |
ROARING BITMAP | BIGINT | ビットマップ内の要素数を返します。 | RB_CARDINALITY(RB_BUILD(ARRAY[1,2,3])) |
RB_CONTAINS |
ROARING BITMAP, INT または ROARING BITMAP, BIGINT | ブール型 | ビットマップが指定された整数を含む場合は true を返します。 |
RB_CONTAINS(RB_BUILD(ARRAY[1,2,3]), 3) |
RB_CONTAINS |
ROARING BITMAP, ROARING BITMAP | ブール型 | 最初のビットマップが2番目のビットマップのすべての要素を含む場合は true を返します。 |
RB_CONTAINS(RB_BUILD(ARRAY[1,2,3]), RB_BUILD(ARRAY[3])) |
RB_AND |
ROARING BITMAP, ROARING BITMAP | ROARING BITMAP | 2 つのビットマップの積集合 (AND) を返します。 | RB_AND(RB_BUILD(ARRAY[1,2,3]), RB_BUILD(ARRAY[2,3,4])) |
RB_OR |
ROARING BITMAP, ROARING BITMAP | ROARING BITMAP | 2 つのビットマップの和集合 (OR) を返します。 | RB_OR(RB_BUILD(ARRAY[1,2,3]), RB_BUILD(ARRAY[2,3,4])) |
RB_XOR |
ROARING BITMAP, ROARING BITMAP | ROARING BITMAP | 2 つのビットマップの排他的論理和 (XOR) を返します。 | RB_XOR(RB_BUILD(ARRAY[1,2,3]), RB_BUILD(ARRAY[2,3,4])) |
RB_AND_NULL2EMPTY |
ROARING BITMAP, ROARING BITMAP | ROARING BITMAP | NULL 安全な処理を行う AND 演算です。一方の入力が NULL の場合はもう一方の入力が返され、一方の入力が {} の場合は結果が {} になります。 |
RB_AND_NULL2EMPTY(CAST(NULL AS ROARING BITMAP), RB_BUILD(ARRAY[3,4,5])) |
RB_OR_NULL2EMPTY |
ROARING BITMAP, ROARING BITMAP | ROARING BITMAP | NULL 安全な処理を行う OR 演算です。NULL の入力は {} として扱われます。 |
RB_OR_NULL2EMPTY(CAST(NULL AS ROARING BITMAP), RB_BUILD(ARRAY[3,4,5])) |
RB_ANDNOT_NULL2EMPTY |
ROARING BITMAP, ROARING BITMAP | ROARING BITMAP | NULL 安全な処理を行う ANDNOT 演算です。NULL の入力は {} として扱われます。 |
RB_ANDNOT_NULL2EMPTY(CAST(NULL AS ROARING BITMAP), RB_BUILD(ARRAY[3,4,5])) |
RB_AND_CARDINALITY |
ROARING BITMAP, ROARING BITMAP | BIGINT | AND の結果のカーディナリティを返します。 | RB_AND_CARDINALITY(RB_BUILD(ARRAY[1,2,3]), RB_BUILD(ARRAY[3,4,5])) |
RB_AND_NULL2EMPTY_CARDINALITY |
ROARING BITMAP, ROARING BITMAP | BIGINT | AND の結果のカーディナリティを返します。NULL の入力は {} として扱われます。 |
RB_AND_NULL2EMPTY_CARDINALITY(CAST(NULL AS ROARING BITMAP), RB_BUILD(ARRAY[3,4,5])) |
RB_OR_CARDINALITY |
ROARING BITMAP, ROARING BITMAP | BIGINT | OR の結果のカーディナリティを返します。 | RB_OR_CARDINALITY(RB_BUILD(ARRAY[1,2,3]), RB_BUILD(ARRAY[3,4,5])) |
RB_OR_NULL2EMPTY_CARDINALITY |
ROARING BITMAP, ROARING BITMAP | BIGINT | OR の結果のカーディナリティを返します。NULL の入力は {} として扱われます。 |
RB_OR_NULL2EMPTY_CARDINALITY(CAST(NULL AS ROARING BITMAP), RB_BUILD(ARRAY[3,4,5])) |
RB_XOR_CARDINALITY |
ROARING BITMAP, ROARING BITMAP | BIGINT | XOR の結果のカーディナリティを返します。 | RB_XOR_CARDINALITY(RB_BUILD(ARRAY[1,2,3]), RB_BUILD(ARRAY[3,4,5])) |
RB_ANDNOT_CARDINALITY |
ROARING BITMAP, ROARING BITMAP | BIGINT | ANDNOT の結果のカーディナリティを返します。 | RB_ANDNOT_CARDINALITY(RB_BUILD(ARRAY[1,2,3]), RB_BUILD(ARRAY[3,4,5])) |
RB_ANDNOT_NULL2EMPTY_CARDINALITY |
ROARING BITMAP, ROARING BITMAP | BIGINT | ANDNOT の結果のカーディナリティを返します。NULL の入力は {} として扱われます。 |
RB_ANDNOT_NULL2EMPTY_CARDINALITY(RB_BUILD(ARRAY[1,2,3]), CAST(NULL AS ROARING BITMAP)) |
RB_IS_EMPTY |
ROARING BITMAP | ブール型 | ビットマップが空の場合は true を返します。 |
RB_IS_EMPTY(RB_BUILD(ARRAY[])) |
RB_CLEAR |
ROARING BITMAP, BIGINT, BIGINT | ROARING BITMAP | 指定された範囲 (start (含む) から end (含まない) まで) の要素を削除します。 | RB_CLEAR(RB_BUILD(ARRAY[1,2,3]), 2, 3) |
RB_FLIP |
ROARING BITMAP, INT, INT または ROARING BITMAP, BIGINT, BIGINT | ROARING BITMAP | 指定されたオフセット範囲のビットを反転させます。 | RB_FLIP(RB_BUILD(ARRAY[1,2,3,4,5]), 2, 5) |
RB_MINIMUM |
ROARING BITMAP | INT または BIGINT | 最小要素を返します。ビットマップが空の場合はエラーを返します。 | RB_MINIMUM(RB_BUILD(ARRAY[1,2,3])) |
RB_MAXIMUM |
ROARING BITMAP | INT または BIGINT | 最大要素を返します。ビットマップが空の場合はエラーを返します。 | RB_MAXIMUM(RB_BUILD(ARRAY[1,2,3])) |
RB_RANK |
ROARING BITMAP, INT または ROARING BITMAP, BIGINT | BIGINT | 指定されたオフセット以下の要素数を返します。 | RB_RANK(RB_BUILD(ARRAY[1,2,3]), 2) |
RB_TO_ARRAY |
ROARING BITMAP | ARRAY(INT) | 要素を INT 配列として返します。 | RB_TO_ARRAY(RB_BUILD(ARRAY[1,2,3])) |
RB_TO_LONG_ARRAY |
ROARING BITMAP | ARRAY(BIGINT) | 要素を BIGINT 配列として返します。 | RB_TO_LONG_ARRAY(RB_BUILD(ARRAY[4,5,6])) |
RB_TO_VARBINARY |
ROARING BITMAP | VARBINARY | ビットマップを VARBINARY にシリアル化して返します。 | RB_TO_VARBINARY(RB_BUILD(ARRAY[1,2,3])) |
RB_RANGE_CARDINALITY |
ROARING BITMAP, INT, INT または ROARING BITMAP, BIGINT, BIGINT | BIGINT | 位置 start (含む) から end (含まない) までの要素のカーディナリティを返します。位置は1から始まります。バージョン 3.1.10.0 以降が必要です。 | RB_RANGE_CARDINALITY(RB_BUILD(ARRAY[1,2,3]), 2, 3) |
RB_SELECT |
ROARING BITMAP, BIGINT, BIGINT | ROARING BITMAP | 位置 start (含む) から end (含まない) までの要素を返します。位置は1から始まります。バージョン 3.1.10.0 以降が必要です。 | RB_SELECT(RB_BUILD(ARRAY[1,3,4,5,7,9]), 2, 3) |
集計関数
| 関数 | 入力タイプ | 出力タイプ | 説明 | 例 |
|---|---|---|---|---|
RB_BUILD_AGG |
INT または BIGINT | ROARING BITMAP | 複数の行の整数値を集約してビットマップを構築します。 | RB_CARDINALITY(RB_BUILD_AGG(1)) |
RB_OR_AGG |
ROARING BITMAP | ROARING BITMAP | 複数のビットマップに対して OR 集約を実行します。 | RB_CARDINALITY(RB_OR_AGG(RB_BUILD(ARRAY[1,2,3]))) |
RB_AND_AGG |
ROARING BITMAP | ROARING BITMAP | 複数のビットマップに対して AND 集約を実行します。 | RB_CARDINALITY(RB_AND_AGG(RB_BUILD(ARRAY[1,2,3]))) |
RB_XOR_AGG |
ROARING BITMAP | ROARING BITMAP | 複数のビットマップに対して XOR 集約を実行します。 | RB_CARDINALITY(RB_XOR_AGG(RB_BUILD(ARRAY[1,2,3]))) |
RB_OR_CARDINALITY_AGG |
ROARING BITMAP | INT または BIGINT | OR 集約を実行し、カーディナリティを返します。 | RB_OR_CARDINALITY_AGG(RB_BUILD(ARRAY[1,2,3])) |
RB_AND_CARDINALITY_AGG |
ROARING BITMAP | INT または BIGINT | AND 集約を実行し、カーディナリティを返します。 | RB_AND_CARDINALITY_AGG(RB_BUILD(ARRAY[1,2,3])) |
RB_XOR_CARDINALITY_AGG |
ROARING BITMAP | INT または BIGINT | XOR 集約を実行し、カーディナリティを返します。 | RB_XOR_CARDINALITY_AGG(RB_BUILD(ARRAY[1,2,3])) |
基本的な使い方
以下の例では、テーブルの作成、ビットマップデータの挿入、およびスカラークエリと集計クエリの実行方法を示します。
内部テーブル
-
ROARINGBITMAP カラムを持つ内部テーブルを作成します。
CREATE TABLE `test_rb` ( `id` INT, `rb` ROARINGBITMAP ); -
ビットマップデータを挿入します。
INSERT INTO test_rb VALUES (1, '[1, 2, 3]'); INSERT INTO test_rb VALUES (2, '[2, 3, 4, 5, 6]'); -
各行のカーディナリティを取得します。
SELECT id, RB_CARDINALITY(rb) FROM test_rb;+------+--------------------+ | id | rb_cardinality(rb) | +------+--------------------+ | 2 | 5 | | 1 | 3 | +------+--------------------+ -
すべての行の和集合のカーディナリティを取得します。
SELECT RB_OR_CARDINALITY_AGG(rb) FROM test_rb;+---------------------------+ | rb_or_cardinality_agg(rb) | +---------------------------+ | 6 | +---------------------------+
外部テーブル
-
ROARINGBITMAP カラムを持つ OSS 外部テーブルを作成します。
CREATE TABLE `test_rb` ( `id` INT, `rb` ROARINGBITMAP ) engine = 'oss' TABLE_PROPERTIES = '{ "endpoint": "oss-cn-zhangjiakou.aliyuncs.com", "accessid": "************", "AccessKey": "************", "url": "oss://testBucketName/roaringbitmap/test_for_user/", "format": "parquet" }';外部テーブルのパラメータについては、「OSS 非パーティション化外部テーブル」をご参照ください。
-
ビットマップデータを挿入します。
重要INSERT INTO は大規模な書き込みには非効率的です。大規模なデータセットの場合は、ETL ツールを使用して Parquet ファイルを生成し、外部テーブルを作成する前に OSS パスにアップロードしてください。
INSERT INTO test_rb SELECT 1, rb_build(ARRAY[1,2,3]); INSERT INTO test_rb SELECT 2, rb_build(ARRAY[2,3,4,5]); -
各行のカーディナリティを取得します。
SELECT id, RB_CARDINALITY(rb) FROM test_rb;+------+--------------------+ | id | rb_cardinality(rb) | +------+--------------------+ | 2 | 4 | | 1 | 3 | +------+--------------------+ -
すべての行の和集合のカーディナリティを取得します。
SELECT RB_OR_CARDINALITY_AGG(rb) FROM test_rb;+---------------------------+ | rb_or_cardinality_agg(rb) | +---------------------------+ | 5 | +---------------------------+
ユーザープロファイリングチュートリアル
このチュートリアルでは、ユーザープロファイリングの完全なワークフローについて順を追って説明します。生のユーザーデータからタグテーブルを構築し、効率的な集合演算のためにビットマップフォーマットに変換し、多次元分析を実行します。
ステップ 1:ソーステーブルの準備
-
ソーステーブル
users_baseを作成します。CREATE TABLE users_base ( uid INT, tag1 STRING, -- 有効な値:x、y、z tag2 STRING, -- 有効な値:a、b tag3 INT -- 有効な値:1 ~ 10 ); -
2 つのビットマップ範囲のクロス結合 (10,000 × 10,000 = 100,000,000 行) を使用して、1 億行のランダムなテストデータを生成します。
SUBMIT JOB INSERT OVERWRITE users_base SELECT CAST(ROW_NUMBER() OVER (ORDER BY c1) AS INT) AS uid, SUBSTRING('xyz', FLOOR(RAND() * 3) + 1, 1) AS tag1, SUBSTRING('ab', FLOOR(RAND() * 2) + 1, 1) AS tag2, CAST(FLOOR(RAND() * 10) + 1 AS INT) AS tag3 FROM ( SELECT A.c1 FROM UNNEST(RB_BUILD_RANGE(0, 10000)) AS A(c1) JOIN (SELECT c1 FROM UNNEST(RB_BUILD_RANGE(0, 10000)) AS B(c1)) ); -
データを確認します。
SELECT * FROM users_base LIMIT 10;+--------+------+------+------+ | uid | tag1 | tag2 | tag3 | +--------+------+------+------+ | 74526 | y | b | 3 | | 75611 | z | b | 10 | | 80850 | x | b | 5 | | 81656 | z | b | 7 | | 163845 | x | b | 2 | | 167007 | y | b | 4 | | 170541 | y | b | 9 | | 213108 | x | a | 10 | | 66056 | y | b | 4 | | 67761 | z | a | 2 | +--------+------+------+------+
ステップ 2:グループ化フィールドの追加
分散エンジンでのビットマップ操作は、グループ間で並列に実行されます。グループ間で UID をパーティション分割するための user_group フィールドと、各グループ内の UID の位置をエンコードするための offset フィールドを追加します。
この例では、16 個のグループで式 uid = 16 × offset + user_group を使用します。
-
user_group = uid % 16— UID が所属するグループ -
offset = uid / 16— グループ内での UID の位置
グループのサイジング:各グループのビットマップには、1 億エントリ未満が含まれている必要があります。100 億の UID 空間の場合は、それぞれ 1 億のエントリを持つ 100 個のグループを使用します。クラスターの ACU と合計 UID 空間に基づいてグループ数を調整してください。
上記のグループ化の式は、説明のみを目的としています。ご自身のデータ分布に基づいて、独自のグループ化関数を設計してください。
-
グループ化フィールドを含む
usersテーブルを作成します。CREATE TABLE users ( uid INT, tag1 STRING, tag2 STRING, tag3 INT, user_group INT, -- グループ化フィールド:uid % 16 offset INT -- オフセットフィールド:uid / 16 ); -
users_baseからusersにデータを投入します。SUBMIT JOB INSERT OVERWRITE users SELECT uid, tag1, tag2, tag3, CAST(uid % 16 AS INT), CAST(FLOOR(uid / 16) AS INT) FROM users_base; -
データを確認します。
SELECT * FROM users LIMIT 10;+---------+------+------+------+------------+--------+ | uid | tag1 | tag2 | tag3 | user_group | offset | +---------+------+------+------+------------+--------+ | 377194 | z | b | 10 | 10 | 23574 | | 309440 | x | a | 1 | 0 | 19340 | | 601745 | z | a | 7 | 1 | 37609 | | 753751 | z | b | 3 | 7 | 47109 | | 988186 | y | a | 10 | 10 | 61761 | | 883822 | x | a | 9 | 14 | 55238 | | 325065 | x | b | 6 | 9 | 20316 | | 1042875 | z | a | 10 | 11 | 65179 | | 928606 | y | b | 5 | 14 | 58037 | | 990858 | z | a | 8 | 10 | 61928 | +---------+------+------+------+------------+--------+
ステップ 3:ビットマップタグテーブルの構築
タグディメンションごとに、各行が (tag_value, user_group) ペアごとに 1 つのビットマップを格納するビットマップタグテーブルを作成します。このビットマップは、そのグループ内の一致するすべてのユーザーのオフセットをエンコードします。
内部テーブル
-
tag1のビットマップタグテーブルを作成して、データを入力します。CREATE TABLE `tag_tbl_1` ( `tag1` STRING, `rb` ROARINGBITMAP, `user_group` INT ); INSERT OVERWRITE tag_tbl_1 SELECT tag1, RB_BUILD_AGG(offset), user_group FROM users GROUP BY tag1, user_group; -
タグテーブルを確認します。
SELECT tag1, user_group, RB_CARDINALITY(rb) FROM tag_tbl_1;+------+------------+--------------------+ | tag1 | user_group | rb_cardinality(rb) | +------+------------+--------------------+ | y | 13 | 563654 | | x | 11 | 565013 | | z | 2 | 564428 | | x | 4 | 564377 | ... | z | 5 | 564333 | | x | 8 | 564808 | | x | 0 | 564228 | | y | 3 | 563325 | +------+------------+--------------------+ -
tag2のビットマップタグテーブルを作成して移入します。CREATE TABLE `tag_tbl_2` ( `tag2` STRING, `rb` ROARINGBITMAP, `user_group` INT ); INSERT OVERWRITE tag_tbl_2 SELECT tag2, RB_BUILD_AGG(offset), user_group FROM users GROUP BY tag2, user_group; -
タグテーブルを確認します。
SELECT tag2, user_group, RB_CARDINALITY(rb) FROM tag_tbl_2;+------+------------+--------------------+ | tag2 | user_group | rb_cardinality(rb) | +------+------------+--------------------+ | a | 9 | 3123039 | | a | 5 | 3123973 | | a | 12 | 3122414 | | a | 7 | 3127218 | | a | 15 | 3125403 | ... | a | 10 | 3122698 | | b | 4 | 3126091 | | b | 3 | 3124626 | | b | 9 | 3126961 | | b | 14 | 3125351 | +------+------------+--------------------+
外部テーブル
-
OSS で
tag1用のビットマップタグテーブルを作成し、データを入力します。CREATE TABLE `tag_tbl_1` ( `tag1` STRING, `rb` ROARINGBITMAP, `user_group` INT ) engine = 'oss' TABLE_PROPERTIES = '{ "endpoint": "oss-cn-zhangjiakou.aliyuncs.com", "accessid": "************", "accesskey": "************", "url": "oss://testBucketName/roaringbitmap/tag_tbl_1/", "format": "parquet" }'; INSERT OVERWRITE tag_tbl_1 SELECT tag1, RB_BUILD_AGG(offset), user_group FROM users GROUP BY tag1, user_group; -
タグテーブルを確認します。
SELECT tag1, user_group, RB_CARDINALITY(rb) FROM tag_tbl_1;+------+------------+--------------------+ | tag1 | user_group | rb_cardinality(rb) | +------+------------+--------------------+ | z | 7 | 2082608 | | x | 10 | 2082953 | | y | 7 | 2084730 | | x | 14 | 2084856 | ... | z | 15 | 2084535 | | z | 5 | 2083204 | | x | 11 | 2085239 | | z | 1 | 2084879 | +------+------------+--------------------+ -
OSS で
tag2のビットマップタグテーブルを作成および設定します。CREATE TABLE `tag_tbl_2` ( `tag2` STRING, `rb` ROARINGBITMAP, `user_group` INT ) engine = 'oss' TABLE_PROPERTIES = '{ "endpoint": "oss-cn-zhangjiakou.aliyuncs.com", "accessid": "************", "accesskey": "************", "url": "oss://testBucketName/roaringbitmap/tag_tbl_2/", "format": "parquet" }'; INSERT OVERWRITE tag_tbl_2 SELECT tag2, RB_BUILD_AGG(offset), user_group FROM users GROUP BY tag2, user_group; -
タグテーブルを確認します。
SELECT tag2, user_group, RB_CARDINALITY(rb) FROM tag_tbl_2;+------+------------+--------------------+ | tag2 | user_group | rb_cardinality(rb) | +------+------------+--------------------+ | b | 11 | 3121361 | | a | 6 | 3124750 | | a | 1 | 3125433 | ... | b | 2 | 3126523 | | b | 12 | 3123452 | | a | 4 | 3126111 | | a | 13 | 3123316 | | a | 2 | 3123477 | +------+------------+--------------------+
ステップ 4:ビットマップタグテーブルを使用した分析
以下のシナリオは、ステップ 3 で構築したビットマップタグテーブルを使用した一般的な分析パターンを示しています。
シナリオ 1:フィルターとグループ化
tag1 IN ('x', 'y') の条件に一致するユーザーを tag2 でグループ化してカウントします。
すべてのクエリは user_group でビットマップタグテーブルを結合し、グループごとにセット操作を適用してから、グループ全体で集計するという同じパターンに従います。
-
グループごとの中間結果を確認します。
SELECT t2.tag2, t2.user_group, RB_CARDINALITY(RB_AND(t2.rb, t1.rb1)) AS rb FROM tag_tbl_2 AS t2 JOIN ( SELECT user_group, RB_OR_AGG(rb) AS rb1 FROM tag_tbl_1 WHERE tag1 IN ('x', 'y') GROUP BY user_group ) AS t1 ON t1.user_group = t2.user_group;+------+------------+---------+ | tag2 | user_group | rb | +------+------------+---------+ | b | 3 | 1041828 | | a | 15 | 1039859 | | a | 9 | 1039140 | | b | 1 | 1041524 | | a | 4 | 1041599 | | b | 1 | 1041381 | | b | 10 | 1041026 | | b | 6 | 1042289 | +------+------------+---------+ -
グループごとのカウントを合計して、最終的な合計を取得します。
SELECT t2.tag2, SUM(RB_CARDINALITY(RB_AND(t2.rb, t1.rb1))) AS cnt FROM tag_tbl_2 AS t2 JOIN ( SELECT user_group, RB_OR_AGG(rb) AS rb1 FROM tag_tbl_1 WHERE tag1 IN ('x', 'y') GROUP BY user_group ) AS t1 ON t1.user_group = t2.user_group GROUP BY t2.tag2;+------+----------+ | tag2 | sum(cnt) | +------+----------+ | a | 33327868 | | b | 33335220 | +------+----------+
シナリオ 2:2つのビットマップタグテーブル間の積集合
(tag1 = 'x' OR tag1 = 'y') かつ tag2 = 'b' であるユーザーを検索します。
両方の入力はビットマップタグテーブルから取得します。まず各タグテーブル内で OR 集計を行い、次に 2 つの結果を AND 演算します。
SELECT user_group, RB_CARDINALITY(rb) FROM (
SELECT
t1.user_group AS user_group,
RB_AND(rb1, rb2) AS rb
FROM (
SELECT user_group, RB_OR_AGG(rb) AS rb1
FROM tag_tbl_1
WHERE tag1 = 'x' OR tag1 = 'y'
GROUP BY user_group
) AS t1
JOIN (
SELECT user_group, RB_OR_AGG(rb) AS rb2
FROM tag_tbl_2
WHERE tag2 = 'b'
GROUP BY user_group
) AS t2 ON t1.user_group = t2.user_group
GROUP BY user_group
);+------------+--------------------+
| user_group | rb_cardinality(rb) |
+------------+--------------------+
| 10 | 2083679 |
| 3 | 2082370 |
| 9 | 2082847 |
| 2 | 2086511 |
...
| 1 | 2082291 |
| 4 | 2083290 |
| 14 | 2083581 |
| 15 | 2084110 |
+------------+--------------------+
シナリオ 3:ビットマップタグテーブルとソーステーブル間の積集合
(tag1 = 'x' OR tag1 = 'y') かつ tag2 = 'b' の条件でユーザーを検索します。ただし、2 番目の条件は、事前に構築されたビットマップタグテーブルではなく、生の users テーブルからフィルタリングされます。
RB_BUILD_AGG を使用して users テーブルからビットマップを動的に構築し、tag_tbl_1 の事前に構築されたビットマップと AND 演算を実行します。
SELECT user_group, RB_CARDINALITY(rb) FROM (
SELECT
t1.user_group AS user_group,
RB_AND(rb1, rb2) AS rb
FROM (
SELECT user_group, RB_OR_AGG(rb) AS rb1
FROM tag_tbl_1
WHERE tag1 = 'x' OR tag1 = 'y'
GROUP BY user_group
) AS t1
JOIN (
SELECT user_group, RB_BUILD_AGG(offset) AS rb2
FROM users
WHERE tag2 = 'b'
GROUP BY user_group
) AS t2 ON t1.user_group = t2.user_group
GROUP BY user_group
);+------------+--------------------+
| user_group | rb_cardinality(rb) |
+------------+--------------------+
| 3 | 2082370 |
| 1 | 2082291 |
| 0 | 2082383 |
| 4 | 2083290 |
| 11 | 2081662 |
| 13 | 2085280 |
...
| 14 | 2083581 |
| 15 | 2084110 |
| 9 | 2082847 |
| 8 | 2084860 |
| 5 | 2083056 |
| 7 | 2083275 |
+------------+--------------------+
シナリオ 4:ビットマップ結果のOSSへのエクスポート
シナリオ 2 のビットマップ結果を、後続の処理で利用するために OSS 外部テーブルに保存します。
-
出力テーブルを作成します。
CREATE TABLE `tag_tbl_3` ( `user_group` INT, `rb` ROARINGBITMAP ) engine = 'oss' TABLE_PROPERTIES = '{ "endpoint": "oss-cn-zhangjiakou.aliyuncs.com", "accessid": "************", "accesskey": "************", "url": "oss://testBucketName/roaringbitmap/tag_tbl_3/", "format": "parquet" }'; -
シナリオ 2 の結果を
tag_tbl_3に書き込みます。INSERT OVERWRITE tag_tbl_3 SELECT t1.user_group AS user_group, RB_AND(rb1, rb2) AS rb FROM ( SELECT user_group, RB_OR_AGG(rb) AS rb1 FROM tag_tbl_1 WHERE tag1 = 'x' OR tag1 = 'y' GROUP BY user_group ) AS t1 JOIN ( SELECT user_group, RB_OR_AGG(rb) AS rb2 FROM tag_tbl_2 WHERE tag2 = 'b' GROUP BY user_group ) AS t2 ON t1.user_group = t2.user_group;クエリが完了すると、結果は Parquet 形式で
oss://testBucketName/roaringbitmap/tag_tbl_3/に保存されます。
シナリオ 5:内部キャッシュテーブルによるクエリの高速化 (外部テーブル向け)
繰り返し実行されるクエリを高速化するために、OSS 外部テーブルから内部テーブルにビットマップデータをインポートします。V3.2.1.0 より前の内部テーブルは ROARINGBITMAP 型をネイティブにサポートしていないため、ビットマップを VARBINARY として保存し、クエリ実行時に変換します。
-
ビットマップを格納するための VARBINARY カラムを持つ内部キャッシュテーブルを作成します。
CREATE TABLE `tag_tbl_1_cstore` ( `tag1` VARCHAR, `rb` VARBINARY, `user_group` INT ); -
OSS テーブルからインポートし、各ビットマップを
VARBINARYにシリアライズします。INSERT INTO tag_tbl_1_cstore SELECT tag1, RB_TO_VARBINARY(rb), user_group FROM tag_tbl_1; -
キャッシュテーブルにクエリを実行し、クエリ実行時に
VARBINARYをビットマップにデシリアライズします。SELECT tag1, user_group, RB_CARDINALITY(RB_OR_AGG(RB_BUILD_VARBINARY(rb))) FROM tag_tbl_1_cstore GROUP BY tag1, user_group;+------+------------+---------------------------------------------------+ | tag1 | user_group | rb_cardinality(rb_or_agg(rb_build_varbinary(rb))) | +------+------------+---------------------------------------------------+ | y | 3 | 2082919 | | x | 9 | 2083085 | | x | 3 | 2082140 | | y | 11 | 2082268 | | z | 4 | 2082451 | ... | z | 2 | 2081560 | | y | 6 | 2082194 | | z | 7 | 2082608 | +------+------------+---------------------------------------------------+