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

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

最終更新日:Oct 23, 2026

Roaring Bitmap は、高性能な集合演算に最適化された圧縮ビットマップ形式です。AnalyticDB for MySQL で使用することで、大規模データセットに対する重複排除、タグベースのユーザーフィルタリング、時系列計算を効率的に実行できます。

Roaring Bitmap を使用する場合

Roaring Bitmap は、ビットマップ内の各グループに含まれるエントリが 1 億未満の場合、標準的な COUNT(DISTINCT ...) クエリよりも優れたパフォーマンスを発揮します。より大きい UID 空間に対しては、それに応じてグループ数を増やしてください (例:UID 空間が 100 億の場合、少なくとも 100 グループが必要です)。

バージョン要件

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 開始位置 (含む) から終了位置 (含まない) までの要素のカーディナリティを返します。位置は 1 ベースです。バージョン 3.1.10.0 以降が必要です。 RB_RANGE_CARDINALITY(RB_BUILD(ARRAY[1,2,3]), 2, 3)
RB_SELECT ROARING BITMAP, BIGINT, BIGINT ROARING BITMAP 開始位置 (含む) から終了位置 (含まない) までの要素を返します。位置は 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 つのビットマップ範囲のクロス結合を使用して、1 億行のランダムテストデータを生成します (10,000 × 10,000 = 100,000,000 行)。

    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 億未満のエントリが含まれている必要があります。UID 空間が 100 億の場合、それぞれ 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,
      t1.user_group,
      RB_CARDINALITY(RB_AND(t1.rb1, t2.rb)) 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 tag2, SUM(cnt) FROM (
      SELECT
        t2.tag2,
        RB_CARDINALITY(RB_AND(t1.rb1, t2.rb)) 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 tag2;
    +------+----------+
    | tag2 | sum(cnt) |
    +------+----------+
    | a    | 33327868 |
    | b    | 33335220 |
    +------+----------+

シナリオ 2:2 つのビットマップタグテーブル間の積集合

(tag1 = 'x' OR tag1 = 'y') AND 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') AND 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;

    クエリが完了すると、結果は oss://testBucketName/roaringbitmap/tag_tbl_3/ に Parquet 形式で保存されます。

シナリオ 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 |
    +------+------------+---------------------------------------------------+