ユーザープロファイル分析シナリオに多数の属性タグと行動タグが存在する場合、roaring bitmapアルゴリズムには大きな制限があります。Hologresは、bit-sliced index (BSI) アルゴリズムを提供することで、これらの制限を解消し、roaring bitmapアルゴリズムの利点を維持します。このトピックでは、BSIを使用してHologresでタグ計算を実装するためのベストプラクティスについて説明します。
背景情報
roaring bitmapアルゴリズムは、ユーザープロファイル分析シナリオで使用されます。このアルゴリズムは、タグテーブルのインデックスを作成し、ユーザーIDをエンコードして、エンコードされたユーザーIDをビットマップ形式で保存します。このようにして、リレーショナル操作はビットマップの積集合、和集合、差集合操作に変換されます。これにより、リアルタイムコンピューティングが高速化されます。roaring bitmapアルゴリズムには、以下のシナリオで制限があります。
複数タグの結合クエリ: roaring bitmapアルゴリズムは、属性タグベースのクエリに適しており、固定タグベースのクエリにのみ使用できます。数値タグのページビュー (PV)、注文金額、再生時間など、複数の行動タグに基づく結合クエリでroaring bitmapアルゴリズムを使用する場合は、詳細テーブルをバックトラックする必要があります。これにより、詳細データのドリルダウンコストが増加します。
カーディナリティの高いタグベースのクエリ: タグに基づいて重複排除を実行した後に大量のデータが存在する場合、roaring bitmapの格納に使用されるストレージ容量が大幅に増加し、クエリのパフォーマンスが低下します。
次のセクションでは、BSIアルゴリズムと特定の関数を使用して上記の制限を解消する方法について説明します。関数の詳細については、「BSI関数」をご参照ください。
複数タグの結合クエリでは、数値行動タグを持つデータが事前に計算され、BSIアルゴリズムを使用して圧縮されて格納されるため、精度が保証されます。詳細テーブルでの結合クエリは必要ありません。このようにして、属性タグと行動タグに基づく効率的な関連分析が実装されます。
カーディナリティの高い行動タグベースのクエリでは、BSIアルゴリズムを使用して、タグ値を最大32ビットのスライスに変換することにより、INT型のcid値が特定の範囲内にあるすべてのユーザーの行動タグ値を格納します。roaring bitmapのバイナリ変換と積集合、和集合、差集合操作を実行して、高速データコンピューティングを実行し、カーディナリティの高い行動タグ値の圧縮ストレージと低レイテンシクエリを実現します。
プロファイル分析ソリューション
この例では、2つのユーザタグテーブルが存在します。 dws_userbaseテーブルには、都道府県や性別など、ユーザーの基本的な属性タグが含まれています。 usershop_behaviorテーブルには、商品売上高 (GMV) などのユーザー行動タグが含まれています。
次の図は、生データを示しています。
次の図は、rb_tagテーブルの基本的なユーザー属性とuidのビットマップを示しています。このテーブルのtag_name列には、都道府県や性別などのタグが含まれています。
次の図は、BSIアルゴリズムを使用して、ユーザー行動タグ値とuidに基づいて生成されたビットスライスを示しています。タグ値はバイナリ値に変換され、4つのスライスのuidビットマップはbsi_gmvテーブルに記録されます。
このソリューションでは、uidと関連する行動タグ値がBSIに圧縮されます。タグベースの高速計算は、BSIアルゴリズムとroaring bitmapに対するAND、OR、NOT操作を使用して実現されます。例:
BSIアルゴリズムを使用して、特定のユーザーグループの行動タグ値に対して合計演算を実行します。合計演算は、各スライスのビットマップ積集合演算に変換されます。
BSIアルゴリズムを使用して、特定のユーザーグループの行動タグに基づいて上位K個の値を取得します。グローバルソートは、上位ビットから下位ビットへのスライスのビットマップ積集合演算に変換されます。
プロファイル分析の基本的な実践
BSIテーブル
テーブル名 | フィールド | 説明 |
dws_userbase | (uid int, province text, gender text) | ワイドテーブルソリューションのテーブルと同じ、ユーザーの元の属性タグを含むテーブル。 |
dws_uid_dict | (encode_uid serial, uid int) | roaring bitmapソリューションのテーブルと同じ、uid辞書エンコーディングテーブル。 |
usershop_behavior | (uid int, gmv int) | GMVなど、ユーザーの行動タグを含む元の行動タグテーブル。 |
rb_tag | (tag_name text, tag_val text, bitmap roaringbitmap) | roaring bitmapアルゴリズムに基づく属性タグテーブル。 |
bsi_gmv | (gmv_bsi bsi) | BSIアルゴリズムに基づく詳細GMVメトリックテーブル。 |
上記のテーブルを作成するために使用されるデータ定義言語 (DDL) ステートメント:
dws_userbaseテーブルを作成します。
CREATE TABLE dws_userbase ( uid int NOT NULL PRIMARY KEY, province text, gender text ... -- その他の属性列。 ) WITH ( distribution_key = 'uid' );
dws_uid_dictテーブルを作成します。
CREATE TABLE dws_uid_dict ( encode_uid serial, uid int PRIMARY KEY );
usershop_behaviorテーブルを作成します。
CREATE TABLE usershop_behavior ( uid int NOT NULL, gmv int ) WITH ( distribution_key = 'uid' );
rb_tagテーブルを作成します。
CREATE TABLE rb_tag ( tag_name text, tag_val text, bitmap roaringbitmap );
bsi_gmvテーブルを作成します。
CREATE TABLE bsi_gmv ( gmv_bsi bsi );
データのインポート
dws_userbaseテーブルとdws_uid_dictテーブルに基づいて属性タグ値のroaring bitmapを生成し、異なるバケットに格納します。
INSERT INTO rb_tag SELECT 'province', province, rb_build_agg (b.encode_uid) AS bitmap FROM dws_userbase a JOIN dws_uid_dict b ON a.uid = b.uid GROUP BY province; INSERT INTO rb_tag SELECT 'gender', gender, rb_build_agg (b.encode_uid) AS bitmap FROM dws_userbase a JOIN dws_uid_dict b ON a.uid = b.uid GROUP BY gender;
usershop_behaviorテーブルとdws_uid_dictテーブルに基づいて行動タグ値のBSIデータを生成し、異なるバケットにテーブルデータを格納します。
INSERT INTO bsi_gmv SELECT bsi_build(array_agg(b.encode_uid),array_agg(a.gmv)) AS bitmap FROM usershop_behavior a JOIN dws_uid_dict b ON a.uid = b.uid ;
プロファイル分析
BSIアルゴリズムを使用して、ユーザー属性タグと行動タグに基づいて関連分析を実行できます。たとえば、特定のユーザーグループの行動タグに関する洞察を得たり、行動タグでユーザーグループをフィルタリングしたりできます。
ユーザーグループの識別と行動タグ分析
広東省の男性ユーザーのGMV合計とGMV平均をクエリします。
BSIアルゴリズムとroaring bitmapアルゴリズムを使用します。
SELECT sum(kv[1]) AS total_gmv, -- GMV合計。 sum(kv[1])/sum(kv[2]) AS avg_gmv -- GMV平均。 FROM ( SELECT bsi_sum(t1.gmv_bsi,t2.crowd) AS kv FROM bsi_gmv t1, (SELECT rb_and(a.bitmap,b.bitmap) AS crowd FROM (SELECT bitmap FROM rb_tag WHERE tag_name='gender' AND tag_val='Male ') a, -- 男性ユーザー。 (SELECT bitmap FROM rb_tag WHERE tag_name='province' AND tag_val ='Guangdong') b -- 広東省のユーザー。 ) t2 ) t;
dws_userbaseテーブルとusershop_behaviorテーブルを使用します。
SELECT sum(b.gmv) AS total_gmv, avg(b.gmv) AS avg_gmv FROM dws_userbase a JOIN usershop_behavior b ON a.uid = b.uid WHERE a.province = 'Guangdong' AND a.gender = 'Male';
広東省の男性ユーザーの消費額分布をクエリします。
BSIアルゴリズムとroaring bitmapアルゴリズムを使用します: bsi_stat関数を使用して境界値配列を定義します。これにより、複数の範囲でのクエリが高速化されます。
SELECT bsi_stat('{100,300,500}', filter_bsi) FROM ( SELECT bsi_filter(t1.gmv_bsi,t2.crowd) AS filter_bsi FROM bsi_gmv t1, (SELECT rb_and(a.bitmap,b.bitmap) AS crowd FROM (SELECT bitmap FROM rb_tag WHERE tag_name='gender' AND tag_val='Male ') a, -- 男性ユーザー。 (SELECT bitmap FROM rb_tag WHERE tag_name='province' AND tag_val = 'Guangdong') b -- 広東省のユーザー。 ) t2 ) t;
dws_userbaseテーブルとusershop_behaviorテーブルを使用します: CASE WHEN構文のみを使用できます。
SELECT CASE WHEN gmv >= 0 AND gmv <= 100 THEN '0-100' WHEN gmv > 100 AND gmv <= 300 THEN '100-300' WHEN gmv > 300 AND gmv <= 500 THEN '300-500' WHEN gmv > 500 THEN '>500' END AS gmv_range, COUNT(*) AS user_count FROM dws_userbase a JOIN usershop_behavior b ON a.uid = b.uid WHERE a.province = 'Guangdong' AND a.gender = 'Male' GROUP BY gmv_range ORDER BY gmv_range;
前日の広東省の男性ユーザーの上位K個の消費額をクエリします。
BSIアルゴリズムとroaring bitmapアルゴリズムを使用します。
SELECT rb_to_array(bsi_topk(filter_bsi,10)) FROM ( SELECT bsi_filter(t1.gmv_bsi,t2.crowd) AS filter_bsi FROM bsi_gmv t1, (SELECT rb_and(a.bitmap,b.bitmap) AS crowd FROM (SELECT bitmap FROM rb_tag WHERE tag_name='gender' AND tag_val='Male ') a, -- 男性ユーザー。 (SELECT bitmap FROM rb_tag WHERE tag_name='province' AND tag_val ='Guangdong') b -- 広東省のユーザー。 ) t2 ) t;
dws_userbaseテーブルとusershop_behaviorテーブルを使用してデータをクエリします。
SELECT b.uid, b.gmv FROM dws_userbase a JOIN usershop_behavior b ON a.uid = b.uid WHERE a.province = 'Guangdong' AND a.gender = 'Male' ORDER BY gmv DESC LIMIT 10;
行動タグに基づくユーザーグループの識別
消費額が1,000を超えるユーザーを識別します。
BSIアルゴリズムとroaring bitmapアルゴリズムを使用します。
SELECT rb_to_array(bsi_gt(gmv_bsi, 1000)) AS crowd FROM bsi_gmv;
dws_userbaseテーブルとusershop_behaviorテーブルを使用します。
SELECT array_agg(uid) FROM usershop_behavior WHERE gmv > 800;
プロファイル分析の高度な実践: バケット化
前の例では、dws_userbaseテーブルはprovince列とgender列に基づいてroaring bitmapテーブルに圧縮され、usershop_behaviorテーブルはBSIテーブルに圧縮されます。圧縮されたroaring bitmapテーブルとBSIテーブルは、インスタンスの特定のノードにのみ分散されます。その結果、計算リソースとストレージリソースが均等に分散されず、インスタンスリソースが完全に使用されません。この問題を解決するには、roaring bitmapテーブルとBSIテーブルを複数のセグメントに分割し、セグメントをインスタンスに分散して実行の並行性を向上させることができます。この例では、bitmapテーブルとBSIテーブルは65,536個のセグメントに分割されます。
BSIテーブル
テーブル名 | フィールド | 説明 |
dws_userbase | (uid int, province text, gender text) | プロファイル分析の基本的な実践のテーブルと同じ、ユーザーの元の属性タグを含むテーブル。 |
dws_uid_dict | (encode_uid serial, uid int) | プロファイル分析の基本的な実践のテーブルと同じ、uid辞書エンコーディングテーブル。 |
usershop_behavior | (uid int, category text, gmv int, ds date) | 元の行動タグテーブル。 プロファイル分析の基本的な実践のテーブルと比較して、categoryフィールドとdsフィールドがこのテーブルに追加されています。 |
rb_tag | (tag_name text, tag_val text, bucket int, bitmap roaringbitmap) | roaring bitmapアルゴリズムに基づく属性タグテーブル。 プロファイル分析の基本的な実践のテーブルと比較して、bucketフィールドがこのテーブルに追加されています。 |
bsi_gmv | (ds text, category text, bucket int, gmv_bsi bsi) | BSIアルゴリズムに基づく詳細GMVメトリックテーブル。 プロファイル分析の基本的な実践のテーブルと比較して、categoryフィールド、dsフィールド、bucketフィールドがこのテーブルに追加されています。 |
上記のテーブルを作成するために使用されるDDLステートメント:
rb_tagテーブルを作成し、異なるバケットにデータを格納します。
CREATE TABLE rb_tag ( tag_name text, tag_val text, bucket int, bitmap roaringbitmap ) WITH ( distribution_key = 'bucket ' -- バケットIDを分散キーとして使用します。 );
bsi_gmvテーブルを作成し、異なるバケットにデータを格納します。
CREATE TABLE bsi_gmv ( category text, bucket int, gmv_bsi bsi, ds date ) WITH ( distribution_key = 'bucket' -- バケットIDを分散キーとして使用します。 );
データのインポート
dws_userbaseテーブルとdws_uid_dictテーブルに基づいて属性タグ値のroaring bitmapを生成し、異なるバケットに格納します。
INSERT INTO rb_tag SELECT 'province', province, encode_uid / 65536 AS "bucket", rb_build_agg (b.encode_uid) AS bitmap FROM dws_userbase a JOIN dws_uid_dict b ON a.uid = b.uid GROUP BY province, "bucket"; INSERT INTO rb_tag SELECT 'gender', gender, encode_uid / 65536 AS "bucket", rb_build_agg (b.encode_uid) AS bitmap FROM dws_userbase a JOIN dws_uid_dict b ON a.uid = b.uid GROUP BY gender, "bucket";
usershop_behaviorテーブルとdws_uid_dictテーブルに基づいて行動タグ値のBSIデータを生成し、異なるバケットにテーブルデータを格納します。
INSERT INTO bsi_gmv SELECT a.category, b.encode_uid / 65536 AS "bucket", bsi_build(array_agg(b.encode_uid),array_agg(a.gmv)) AS bitmap, a.ds FROM usershop_behavior a JOIN dws_uid_dict b ON a.uid = b.uid WHERE ds = CURRENT_DATE - interval '1 day' GROUP BY category, "bucket", ds;
プロファイル分析
BSIアルゴリズムを使用して、ユーザー属性タグと行動タグに基づいて関連分析を実行できます。たとえば、特定のユーザーグループの行動タグに関する洞察を得たり、行動タグでユーザーグループをフィルタリングしたり、ユーザーデータを異なるバケットに分散してデータ計算を高速化したりできます。
ユーザーグループの識別と行動タグ分析
前日の3Cカテゴリの広東省の男性ユーザーのGMV合計とGMV平均をクエリします。
SELECT sum(kv[1]) AS total_gmv, -- GMV合計。 sum(kv[1])/sum(kv[2]) AS avg_gmv -- GMV平均。 FROM ( SELECT bsi_sum(t1.gmv_bsi,t2.crowd) AS kv, t1.bucket FROM (SELECT gmv_bsi, bucket FROM bsi_gmv WHERE category = '3C' AND ds = CURRENT_DATE - interval '1 day') t1 JOIN (SELECT rb_and(a.bitmap,b.bitmap) AS crowd, a.bucket FROM (SELECT bitmap, bucket FROM rb_tag WHERE tag_name='gender' AND tag_val='Male ') a -- 男性ユーザー。 JOIN (SELECT bitmap, bucket FROM rb_tag WHERE tag_name = 'province' AND tag_val = 'Guangdong') b -- 広東省のユーザー。 ON a.bucket = b.bucket ) t2 ON t1.bucket = t2.bucket ) t;
前日の3Cカテゴリの広東省の男性ユーザーの消費額分布をクエリします。
SELECT bsi_stat('{100,300,500}', bsi_add_agg(filter_bsi)) FROM ( SELECT bsi_filter(t1.gmv_bsi,t2.crowd) AS filter_bsi, t1.bucket FROM (SELECT gmv_bsi, bucket FROM bsi_gmv WHERE category = '3C' AND ds = CURRENT_DATE - interval '1 day') t1 JOIN (SELECT rb_and(a.bitmap,b.bitmap) AS crowd, a.bucket FROM (SELECT bitmap, bucket FROM rb_tag WHERE tag_name='gender' AND tag_val = 'Male ') a -- 男性ユーザー。 JOIN (SELECT bitmap, bucket FROM rb_tag WHERE tag_name='province' AND tag_val = 'Guangdong') b -- 広東省のユーザー。 ON a.bucket = b.bucket ) t2 ON t1.bucket = t2.bucket ) t;
前日の広東省の男性ユーザーの上位K個の消費額をクエリします。
SELECT bsi_topk(bsi_add_agg(filter_bsi),10) FROM ( SELECT bsi_filter(t1.gmv_bsi,t2.crowd) AS filter_bsi, t1.bucket FROM (SELECT bsi_add_agg(gmv_bsi) AS gmv_bsi, bucket FROM bsi_gmv WHERE ds = CURRENT_DATE - interval '1 day' GROUP BY bucket) t1 JOIN (SELECT rb_and(a.bitmap,b.bitmap) AS crowd, a.bucket FROM (SELECT bitmap, bucket FROM rb_tag WHERE tag_name = 'gender' AND tag_val = 'Male ') a -- 男性ユーザー。 JOIN (SELECT bitmap, bucket FROM rb_tag WHERE tag_name = 'province' AND tag_val = 'Guangdong') b -- 広東省のユーザー。 ON a.bucket = b.bucket ) t2 ON t1.bucket = t2.bucket ) t;
行動タグに基づくユーザーグループの識別
前月の3Cカテゴリで消費額が1,000を超えるユーザーを識別します。
SELECT rb_to_array(bsi_gt(bsi_add_agg(gmv_bsi), 1000)) AS crowd FROM bsi_gmv WHERE category = '3C' AND ds BETWEEN CURRENT_DATE - interval '30 day' AND CURRENT_DATE - interval '1 day';