すべてのプロダクト
Search
ドキュメントセンター

AnalyticDB:ユーザーセグメンテーション関数 (Roaring Bitmap)

最終更新日:May 14, 2026

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]))

基本的な使い方

以下の例では、テーブルの作成、ビットマップデータの挿入、およびスカラークエリと集計クエリの実行方法を示します。

内部テーブル

  1. ROARINGBITMAP カラムを持つ内部テーブルを作成します。

    CREATE TABLE `test_rb` (
      `id` INT,
      `rb` ROARINGBITMAP
    );
  2. ビットマップデータを挿入します。

    INSERT INTO test_rb VALUES (1, '[1, 2, 3]');
    INSERT INTO test_rb VALUES (2, '[2, 3, 4, 5, 6]');
  3. 各行のカーディナリティを取得します。

    SELECT id, RB_CARDINALITY(rb) FROM test_rb;
    +------+--------------------+
    | id   | rb_cardinality(rb) |
    +------+--------------------+
    |    2 |                  5 |
    |    1 |                  3 |
    +------+--------------------+
  4. すべての行の和集合のカーディナリティを取得します。

    SELECT RB_OR_CARDINALITY_AGG(rb) FROM test_rb;
    +---------------------------+
    | rb_or_cardinality_agg(rb) |
    +---------------------------+
    |                         6 |
    +---------------------------+

外部テーブル

  1. 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 非パーティション化外部テーブル」をご参照ください。

  2. ビットマップデータを挿入します。

    重要

    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]);
  3. 各行のカーディナリティを取得します。

    SELECT id, RB_CARDINALITY(rb) FROM test_rb;
    +------+--------------------+
    | id   | rb_cardinality(rb) |
    +------+--------------------+
    |    2 |                  4 |
    |    1 |                  3 |
    +------+--------------------+
  4. すべての行の和集合のカーディナリティを取得します。

    SELECT RB_OR_CARDINALITY_AGG(rb) FROM test_rb;
    +---------------------------+
    | rb_or_cardinality_agg(rb) |
    +---------------------------+
    |                         5 |
    +---------------------------+

ユーザープロファイリングチュートリアル

このチュートリアルでは、ユーザープロファイリングの完全なワークフローについて順を追って説明します。生のユーザーデータからタグテーブルを構築し、効率的な集合演算のためにビットマップフォーマットに変換し、多次元分析を実行します。

Workflow overview: original label table converted to Roaring Bitmap label table for computations

ステップ 1:ソーステーブルの準備

  1. ソーステーブル users_base を作成します。

    CREATE TABLE users_base (
      uid  INT,
      tag1 STRING,  -- 有効な値:x、y、z
      tag2 STRING,  -- 有効な値:a、b
      tag3 INT      -- 有効な値:1 ~ 10
    );
  2. 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))
    );
  3. データを確認します。

    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 空間に基づいてグループ数を調整してください。

説明

上記のグループ化の式は、説明のみを目的としています。ご自身のデータ分布に基づいて、独自のグループ化関数を設計してください。

  1. グループ化フィールドを含む users テーブルを作成します。

    CREATE TABLE users (
      uid        INT,
      tag1       STRING,
      tag2       STRING,
      tag3       INT,
      user_group INT,  -- グループ化フィールド:uid % 16
      offset     INT   -- オフセットフィールド:uid / 16
    );
  2. 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;
  3. データを確認します。

    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 つのビットマップを格納するビットマップタグテーブルを作成します。このビットマップは、そのグループ内の一致するすべてのユーザーのオフセットをエンコードします。

内部テーブル

  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;
  2. タグテーブルを確認します。

    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 |
    +------+------------+--------------------+
  3. 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;
  4. タグテーブルを確認します。

    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 |
    +------+------------+--------------------+

外部テーブル

  1. 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;
  2. タグテーブルを確認します。

    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 |
    +------+------------+--------------------+
  3. 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;
  4. タグテーブルを確認します。

    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 でビットマップタグテーブルを結合し、グループごとにセット操作を適用してから、グループ全体で集計するという同じパターンに従います。

  1. グループごとの中間結果を確認します。

    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 |
    +------+------------+---------+
  2. グループごとのカウントを合計して、最終的な合計を取得します。

    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 外部テーブルに保存します。

  1. 出力テーブルを作成します。

    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. シナリオ 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 として保存し、クエリ実行時に変換します。

  1. ビットマップを格納するための VARBINARY カラムを持つ内部キャッシュテーブルを作成します。

    CREATE TABLE `tag_tbl_1_cstore` (
      `tag1`       VARCHAR,
      `rb`         VARBINARY,
      `user_group` INT
    );
  2. OSS テーブルからインポートし、各ビットマップを VARBINARY にシリアライズします。

    INSERT INTO tag_tbl_1_cstore
    SELECT tag1, RB_TO_VARBINARY(rb), user_group
    FROM tag_tbl_1;
  3. キャッシュテーブルにクエリを実行し、クエリ実行時に 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 |
    +------+------------+---------------------------------------------------+