🗿

ABテストをSalesforce Data 360で実現する方法~詳細編

に公開

TL;DR

Salesforce Data 360(旧称 Salesforce Data Cloud、以下 Data 360)を用いてセグメントを任意の割合でランダム分割して配信したい場合、4つのステップにて実現が可能。本記事では具体的なステップを解説

コントロールグループ(以下CG)とターゲットグループ(以下TG)

前回の記事はこちら
https://zenn.dev/datacloud/articles/6786c61249bf58

直近1か月で購入があったお客様のうち、ランダムな10%の顧客をTG、残り90%をCGとして設定したい

このような要件にData 360で対応したい場合、前回記載の通り
4つのステップを実行する必要があります。

1.セグメント作成:
母集団となるセグメントを作成する(例:「直近1か月で購入があったお客様」)
2.データ変換作成:
1で公開したセグメントを参照する形で母集団データを退避。
あわせて一意な文字列を付与
3.計算済みインサイト作成:
2で作成したDMOを参照する形で、顧客にランダムIDを割り振る
4.セグメント作成:
3で割り振ったランダム値を元に、セグメントを作成する

今回の記事では、1,2のステップを具体的な実装方法と合わせて解説していきます。

制約事項

本処理においては下記の制約、注意事項があります。

  • セグメント対象DMOにおいてIDごとにレコードが一意であること
    • 最終的にIDごとに割り当てたランダム値の集計を行うため、一意でない場合%の指定に誤差が出ます。
  • 厳密なランダムではないこと
    • 本処理ではレコードごとに一意なUUIDと、指定した項目によるソートを行った結果を元に0-99の値を割り当てます

1.セグメント作成

まずはTG/CG全体の母集団となるセグメントを作成していきます。
今回の例ですと「直近1か月で購入があった場合の顧客」というセグメントを作成します。

条件指定の方法はお持ちのデータ構造によりさまざまですので、画像は一例です。

Data 360ではGUIを用いる他、AI利用、TableauCloudからの作成、と複数の方法で顧客セグメントが作成可能です。
Tableauからのセグメント作成についてはこちらの記事で詳しくまとめていますので、ご興味がありましたらご覧ください。
https://zenn.dev/datacloud/articles/84cfcd247564a1


作成したセグメントを「いますぐ公開」することでセグメントの情報が
「セグメントメンバーシップDMO」に書き込まれます。
このデータを次のステップで利用していきます。

セグメントを公開してからセグメントメンバーシップDMOにデータが書き込まれるまで
数分程度かかる場合がありますので、公開後少し待って次の作業へ移っていきます。

その前に:セグメントメンバーシップDMOとは?

詳しいテーブル構造についてはhelpに記載があります。
https://help.salesforce.com/s/articleView?id=data.c360_a_segment_membership_dmo_schema.htm&type=5

主には
・セグメントに誰が含まれているのか(Id)
・いつ更新されたのか(TimeStamp)
・同じセグメントが前回更新されたときと比較して「新規に追加されたか」「前回もいたか」「前回はいたが今回は削除されたか」(delta type)
が確認できるようになっています。

セグメントメンバーシップDMOは、セグメントを作成するときに指定する「セグメント対象」毎に作成されますので、この後の作業ではセグメント対象と対応するセグメントメンバーシップDMOを参照する必要があります。

なお、セグメントメンバーシップには、各セグメントの
・最終更新時点のデータのみを保持する「Latest」と
・過去更新実行分も含めて保持する「History」
があります。

以降のステップでは、
過去のある時点のセグメントを対象にTG/CGを作成したい
というシーンも想定して「History」を利用する形で説明させて頂きます。

注意点
「Segment Membership」は過去30日以内に公開されたセグメントデータのみ保持(https://help.salesforce.com/s/articleView?id=data.c360_a_segment_membership_data.htm&type=5)され、それ以上昔のデータについては自動的に削除されていきます。
そのため、31日以上前に公開したセグメントデータを元にTG/CGを作成したい場合は、あらかじめセグメントメンバーシップのデータを他のオブジェクトに退避しておく必要があります。

2.データ変換作成

1の作業で作成したセグメント=TG/CGの母集団についてランダムな値を付与する前処理として
データ変換を作成します。

データ変換を作成する理由は下記の2点です。
a.セグメントメンバーシップから、対象となるセグメントのデータだけを抽出する
b.ランダムな文字列値UUIDを付与する

まずはaから。
セグメントメンバーシップには
・異なる複数のセグメント情報
・同一セグメントの更新時点別の情報
が保存されているので、
「9/18 17時に更新したAセグメントの情報」のように、どのセグメント情報を使いたいか
指定してデータを取得してくる必要があります。

続いてb。
最終的に0-99などランダムな数値を顧客ごとに割り当てたいのですが、DataCloudにはランダム数値を割り当てる関数がありません。そこで前段階として顧客ごとに一意となるランダムな文字列を割り振って置き、次のステップでこの文字列を元にランダム数値を割り当てます。

では具体的な手順を画面写真を交えてご紹介します。

データ変換作成


まずデータ変換を新規に作成します。
バッチデータ変換、ストリーミングデータ変換どちらでも問題ありませんが
前者の方が利用コストが低く、またセグメントメンバーシップ自体がストリーミングでデータが入ってくるものではないため、通常は前者を選択します。


セグメントメンバーシップはDMOなので、参照オブジェクトはDLOではなくDMOを選択します。


オブジェクト一覧を"history"で検索します。
セグメントの作成状況によっては複数のオブジェクトが表示されますので、その場合は
1で作成したセグメントの「セグメント対象」に対応するものを選びます。

今回はセグメント対象「Individual」としていますので、対応するIndividual_Historyを選択します。

データ絞り込み

続いて、セグメントメンバーシップヒストリーDMOには複数セグメント,複数回公開履歴のデータが保存されているので、今回TG/CGの母集団にしたいデータだけに絞り込みを行います。


絞り込みを行うには、「Individual History」のノート右側にある+ボタンを押下して「検索条件」を選択します。

ここで、絞り込みは「SegmentID」、「Timestamp」、「delta_type」で行います。

SegmentID、TimeStampにどんな値を指定するかはプレビュー画面で判断がつくこともありますが、プレビューからではわからない場合、事前に「クエリエディター」機能を使いSegmentIDとTimeStampの値を確認しておく必要があります。

「クエリエディター」タブから新規を選択すると、SQLを記載することのできるワークスペースが表示されますので、下記のようなSQLを実行することでSegmentID,TimeStampの一覧確認が可能です。

SELECT distinct "Segment_Id__c","Timestamp__c" FROM
"Individual_SMH_1731571620364__dlm"
order by "Timestamp__c" desc
LIMIT 100

SQLの実行結果から、取得したいセグメントを公開した時間を元にSegmentIDを特定していきます。

今回の実行結果では、SegmentID=1sgIT000000KynDについて、9/17,18の2回公開がされていますので、最新である9/18のセグメント公開情報を元にTG/CGを作成していきます。

もう一点「delta_type」での絞り込みも行っておきましょう。
delta_typeには「new」「existing」「removed」のいずれかの値がセットされますが、このうち「removed」は
前回同じセグメントを公開したときは含まれていたが、今回公開時には含まれなくなった顧客
を意味します。

たとえば「直近1週間で購入があった顧客」というセグメントを作成した際、前回のセグメント公開時から1週間以内には購入があったが、今回セグメント更新から1週間以内には購入がなかったような顧客です。

このような顧客はTG/CGの母集団には含めないのが正しいため、あらかじめ
delta_type≠removed として除外しておきます。

以上をまとめると検索条件の設定例は下記のようになります。

UUID付与

続いてUUIDを付与します。
まずは+ボタンを押して「ノードを追加」より「変換」を選択します。

次にfxと書かれたボタンを押して「カスタム数式」を選択します。

関数一覧からその他の関数>UUIDを選択します。

この文字列は行ごとに一意な文字列を付与することが出来、他のフィールドの値に依存しないため
次のステップで行うランダム値を算出するための項目として利用します。

出力種別は「テキスト」、表示名/API参照名は任意ですがわかりやすい名前にしておきましょう。

出力

最後に、加工したデータを別のDMOとして出力します。

まずは+ボタンを押して「ノードを追加」より「出力」を選択します

更新モードは「更新/挿入」、オブジェクトカテゴリは「プロファイル」を選択します。
オブジェクト名、オブジェクトAPI参照名は任意ですがわかりやすい名前にしておきましょう。

KeyQualifierは「Key Qualifier ID」を選択、
Primary Keyは「UUID」を選択します。

なお、ここでは簡単のためPrimary KeyをUUIDとしていますが
UUIDはデータ変換実行のたびに異なる値が割り振られるので、同じ内容のデータ変換を複数実行した場合に同じ顧客が複数回登録されてしまいます。
そのため、複数回データ変更を実行する場合は、あらかじめSegmentID+ID+Timestampのような項目をあらかじめ用意しておき、PrimaryKeyとして指定しましょう。

以上でデータ変換の作成は終了です。

3.計算済みインサイト作成

続いて、作成したデータ変換の出力結果を参照する形で計算済みインサイトを作成します。

作成方法として「SQL」を選択します。

任意の名前を付け、SQLクエリ欄に下記を貼り付けます。

SELECT
	RESULT.I_ID__c as ID__c
	,MAX(RESULT.RAND__c) as RANDNUM__c
FROM
	(SELECT
		ssot__Individual__dlm.ssot__Id__c AS I_ID__c
		,MOD(ROW_NUMBER() OVER(ORDER BY ssot__Individual__dlm.ssot__LastModifiedDate__c asc),100) AS RAND__c
	FROM ssot__Individual__dlm
	INNER JOIN indiv_segment_for_rand__dlm ON
		ssot__Individual__dlm.ssot__Id__c = indiv_segment_for_rand__dlm.Id__c
) RESULT
GROUP BY ID__c

ご自身の作成内容に合わせてコードをカスタマイズする場合は下記をご参考に編集ください

  • ssot__Individual__dlm.ssot__Id__cは「セグメントを作成したいDMOのID項目」を指定
  • ROW_NUMBER関数におけるssot__LastModifiedDate__cは項目のソート順を指定します。レコードの並び順により値の割り振りが固定化することを極力避けるために、規則性がない項目を指定するのがベターです
  • MOD関数における引数100は除数を意味します。0-99で値を割り振りたい場合は100を指定します。10を指定した場合は0-9で値が割り振られます
  • MAX関数は計算済インサイトの仕様上集計関数が必要であるため付与しています。ssot__Individual__dlm.ssot__Id__cが一意である場合はMAX、MINであっても結果は変わりません
    • 冒頭の制約事項の通り、上記IDが一意でない場合は値が均等に割り振られず%指定に誤差が出ます
  • クエリ上でつける列別名は最後が「__c」で終わる必要があります

完成イメージは画像のような形になります。

「有効化」を選択し保存した後、右上のドロップダウンより「いますぐ公開」を実行します。
これで計算済みインサイトが実行され、計算結果がCIOとして保存されます。

実行結果を確認してみましょう。
データエクスプローラーで計算済みインサイトを指定すると、先ほど作成した計算済みインサイトの実行結果が確認できます。

IDの並び順とは別に、それぞれのIDに1,2,3...と数字がセットされていることが分かります。
今回は元となるレコード数が少ないため確認できませんが、この値は0-99までの値が同じ出現頻度で割り振られています。

4.セグメント作成

計算済みインサイトで顧客ごとに割り当てたランダム値を元にセグメントを作成します。

まずは母集団となるセグメントをinclude条件に含めます。

続いて、3のステップで付与したランダム値をInclude条件に指定します。

TGとして母集団のうち10%だけを取得したい場合は
ランダム値が「次の範囲内にある」「下限値1」「上限値10」のように指定します。
下限値、上限値については「11~20」のように値のレンジが10であれば構いません。

なお上記についてはデータが100件以上あるときの指定方法で、今回のように母集団が19件しかないようなケースですと上記の指定では正しく10%の抽出にならないので注意ください。
(このような小さな母集団に対してTG/CGの割り振りをすることはあまりないと思いますが、たとえば19件の10%=1.9件という事で、1~2と指定すれば対応は可能です)

母集団からTGを除外したCGについても作成していきます。
TGと同様に、まずは母集団となるセグメントをinclude条件に含めます。

続いて、TGセグメントの際と同様の条件をExclude条件に指定します。

TGセグメントでは「次の範囲内にある」「下限値1」「上限値10」をInclude条件に指定したので、
CGセグメントでは「次の範囲内にある」「下限値1」「上限値10」をExclude条件に指定しています。

補足として、母集団セグメントをInclude条件に指定したように
セグメントに対するInclude/Exclude条件にセグメントを利用することが可能ですが、
「セグメントを条件に使用して作成されたセグメント」を更に別のセグメント条件に使用することはできません。
そのため、CGセグメントを作成する際に作成済みのTGセグメントを条件として利用することは出来ず、上記のような処理を行う必要があります。

以上で、TG/CGの作成は終了です。
厳密なランダムではない、件数が少ない場合はパラメータの指定に注意が必要といった部分はありますがおおまかにTG/CGを分けて運用したい場合の工夫としてご活用を検討ください。

※本記事は、私が所属する会社とは一切関係のない事柄です。

Discussion