(翻訳): Data Cloud セグメンテーション ベスト プラクティス
「 Data Cloud で セグメントを 作成する 正しい 方法 はありますか 」、 「 私 が持っている データの 品質は かなり 良い と思いますし、 扱っている データ 量も そこそこ 多いのにも関わらず ( Data Cloud が 扱える データ量 とは 比べ物になりませんが )。セグメンテーション できない のはなぜでしょう ? 」 「 Resource Exhausted エラー を 頻繁 に見かけます。 どうすれば、 この エラーが 頻繁に 起こらないように できますか? 」「 Data Cloud で 最適化された セグメント を作成するための ガイドラインはありますか? 」 などなど 。 もし あなたが Data Cloud でセグメント を作成することに慣れてはいるが、 このような 疑問を いまだに 持っているなら、 この 記事が 役に 立つでしょう。
訳:AI and Analytics Specialist, Salesforce 小見 一平
数ヶ月前、私は Data Cloud のセグメンテーション チームにプロダクト マネージャーとして加わりました。私は上記疑問への答えを探し始めました。ヘルプ ドキュメントはかなり良いとは思いますが、それでもなおかつ、今日お客様が遭遇する一般的な問題のいくつかを回避するために従うことができるベスト プラクティスを書き留める必要があることにすぐに気づきました。そこで、この投稿を皆さんにお届けすることにしました。
Note: このブログでは、今日、セグメントのパフォーマンスを向上させる方法について、私や私の同僚の見解をお伝えします。Data Cloud は進化する製品であり、これらのテクニックは後々機能しなくなるかもしれません。しかし、この投稿をできるだけ最新に保つよう努力します。
それでは早速ベストプラクティスをご紹介します
1. 適切な「セグメント基準」エンティティを選びましょう
Salesforce Data Cloudでセグメントを作成する場合、「セグメント基準」データモデルオブジェクト(DMO)を選択します。簡単に言うと、このエンティティをさらに絞り込むことで、ターゲットとなる顧客層が形成されます。例えば、あなたは自動車保険会社を経営しており、保険スコアが良い既存顧客に対して、いくつかの特典を追加して契約を更新するキャンペーンを実施したいとします。この場合、セグメントオンのエンティティは潜在的に「統合個人」DMOになり得ます。しかし、「個人」DMOもあります。では、どちらを使うべきか?多くの場合、統一オブジェクトとその構成オブジェクトのどちらかを選択する必要があります。
“個人” DMO vs “統合された個人” DMO:
データがさまざまなソースから得られている場合は、「セグメント基準」エンティティは、ID解決ルール(Data Cloudで定義およびカスタマイズ)が「類似した」個々のレコードを1つに統合するため、統合された個別DMOを使用することをお勧めします。 これは、「統合個人」DMOのレコード総数が「個人」DMOのレコード総数より少ない可能性が高いことを意味します。これはまた、セグメントオーディエンスにおいて、重複した個人が存在しないことを意味します。
一般的なルールとして、データが異なるシステムから入ってくる場合は、代わりに統一オブジェクトを使用します。これにより、より高いパフォーマンスが保証され、より正確な結果が得られます。
2. 正しいDMOタイプを使用する
Data Cloudには3つのデータカテゴリーがあります: プロファイル、エンゲージメント、その他です。それぞれの詳細については、こちらをご覧ください。このセクションでは、DMOの「エンゲージメント」タイプに焦点を当てます。エンゲージメントDMOは通常、大量のデータを保存しており、他と比較すると流入量も多くなります。そのため、このデータを「イベント時間フィールド」で分割して、読み取り操作を高速化します。今までは「エンゲージメント タイプ」DMO にマッピングできなかったエンゲージメント データをData Cloudに取り込むことができるようになりました。たとえば、以前は電子メールのインタラクション データをインジェストすると、それらは「その他」タイプの DMO にマッピングされました。この操作はエラーにはなりませんが、このデータのパーティショニングは行われません。その結果、読み取り操作が最適化されません。そのため、セグメントで使用しているDMO、特にエンゲージメントデータを操作しているときに使用しているDMOが、正しいタイプのDMOにマッピングされていることを常に確認してください。
3. コンテナと属性のパス – 最短パスを選択し、循環パスを避ける
キャンペーンの実施など、特定のビジネス目的のためにターゲット オーディエンスを特定するには、「直接」と「関連」の属性にフィルタを適用することができます。これらの違いは何でしょうか?詳しくはこちらをご覧ください。簡単にまとめると:
- 直接属性-「セグメント基準」エンティティまたはデータモデル オブジェクト(DMO)の属性で、「セグメント基準」オブジェクトと(あるパス上で)1:1またはN:1の関係を持つ。
- 関連属性-「セグメント基準」オブジェクトと(あるパス上で)1対Nの関係を持つDMO。
「セグメント基準」エンティティと 「属性」DMOの間に複数のパスが存在する場合、セグメント ビルダーは必要なパスを手動で選択するオプションを提供します。ここは注意が必要です。「直接」属性または「関連」属性を選択するたびに、セグメンテーション エンジンはデータモデル レベルで定義された「DMOリレーションシップ」を使用して、「セグメント基準」エンティティから選択した属性への到達方法を決定します。簡単に言えば、DMO同士を結合する仕組みです。各リレーションシップ(結合)により、関連するDMO間を移動することができます。この結合の文字列が、セグメンテーションにおける「パス」を形成します。セグメンテーション エンジンは、同じパスを使用して、「セグメント基準」エンティティから直接属性および関連属性(これも DMO である)に移動する。デフォルトでは、エンジンは 2 つの DMO 間で利用可能な唯一のパスを選択します。ただし、2 つの DMO 間に複数のパスが存在する場合もあり、その場合、エンジンはデフォルトで最短パスを選択します。下の画像では、”Case” と “Unified Account main” DMO 間に存在するさまざまなパスに注目してください。
ベストプラクティスとして、可能な限り、常に2つのDMO間の最短パスを選択しましょう。パスが長くなると、結合パスも長くなり、それによりセグメンテーション エンジンの作業が増えてしまいます。
循環パス:
また、可能な限り循環パスの使用は避けましょう。循環パスでは、あるDMOからスタートし、結合関係に沿って最終的に同じDMOに到達します。基本的には、a→b→c→a、またはa→b→c→bになるような場合です。今のところ、循環パスが避けられないシナリオには遭遇していません。循環パスが見つかったら、同じ結果になるように代替案をチェックします。例えばa→b→c→aの場合、DMOの中で直接属性を探します。a → b → c → bのケースでは、cから取得するのではなく、bから属性を探します。sales_order_key → line_item_order_key → sales_order_keyのようなケースがあります。これは循環パスの典型的な例ですが、簡単に避けることができます。
循環パスは処理時間の増加につながり、クエリの失敗の原因となり得ます。
4. 処理するデータ量を制限する
セグメンテーション エンジンが処理しなければならないデータ量を減らすことができれば、セグメントの全体的なパフォーマンスは向上します。どのようにすればよいでしょうか?
データ量を制限するためには、データスペースを使うこともできるし、セグメントで明示的なフィルターを定義することもできます。それぞれの方法について詳しく説明します。
4.1 データスペースを使う
データスペースは、データの論理的なパーティショニングです。データスペースが組織で有効になっている場合、権限セットを通じてDMO、計算されたインサイト、セグメント、およびアクティベーションへのアクセスを制御できます。概要については、図を参照してください:
DMOはデータ スペース固有のものである。つまり、データスペースを使用することは、セグメントとそのアウトプットのアクセスを管理するだけでなく、(もしあれば)データ スペース固有のフィルターがセグメント レベルでも適用されることを保証します。データ スペースフィルターは、セグメンテーションエンジンが処理するデータ量を減らし、処理時間を 短縮する、プッシュダウン述語のようなものだと考えてください。
4.2 エンゲージメント・データに明示的なフィルターを使用する
エンゲージメント・データの行動日時列に明示的なフィルタを使用します
はい、エンゲージメント・データの行動日時列には、標準セグメントには2年間、高速セグメントには7日間のデフォルトフィルターが適用されます。このフィルターは「ルックバック期間」とも呼ばれます。しかし、可能な限り、行動日時列にフィルターを作成することで、処理するデータをさらに減らすことができます。
5. 可能な限りコンテナをマージする
同じコンテナパスを持つ2つのコンテナが “Or “ロジックで結合されている場合、それらをマージします
可能であれば、関連属性で作業している間にコンテナをマージします。まったく同じパスを使用し、”Or “の関係を持つすべてのコンテナは、ほとんどの場合、マージすることができます。この説明を理解したなら、次のセクションに進んでください。そうでない場合は、このまま読み進めてください。次の段落では、コンテナがどのように機能するのか、そして可能な限りコンテナをマージすることを推奨する理由を説明します。
少なくとも1件のクローズ・ステータスのケース、または優先順位の低いケースが1件あるアカウントをすべて特定したいとします。このために2つのシナリオを作成しましょう。
- 2つの別々のコンテナを作成し、ORで結合する:
セグメント ルールはこんな感じになるでしょう:
セグメンテーション エンジンは、「クローズド ステータス」のケースを持つすべてのアカウントを識別し、次に「低」優先度のケースを持つすべてのアカウントを識別する。この後、結合が実行されます。結果のサンプル SQL はこのようになります:
select distinct count(*)
from (
(
select distinct "ssot__Account__dlm__0"."ssot__Id__c", "ssot__Account__dlm__0"."KQ_Id__c"
from "ssot__Account__dlm" as "ssot__Account__dlm__0"
where exists (
select *
from "ssot__Case__dlm" as "ssot__Case__dlm__0"
where (
"ssot__Account__dlm__0"."ssot__Id__c" = "ssot__Case__dlm__0"."ssot__AccountId__c"
and trim(cast("ssot__Account__dlm__0"."ssot__Id__c" as varchar)) <> ''
and "ssot__Account__dlm__0"."KQ_Id__c" is not distinct from "ssot__Case__dlm__0"."KQ_AccountId__c"
and lower("ssot__Case__dlm__0"."ssot__CaseStatusId__c") = lower('Closed')
and "ssot__Case__dlm__0"."ssot__CreatedDate__c" >= timestamp '2021-09-21 06:56:13.320 -07:00'
and "ssot__Case__dlm__0"."ssot__CreatedDate__c" >= timestamp '2021-09-21 06:56:13.320 -07:00'
and "ssot__Case__dlm__0"."ssot__Id__c" is not null
)
)
)
union (
select distinct "ssot__Account__dlm__0"."ssot__Id__c", "ssot__Account__dlm__0"."KQ_Id__c"
from "ssot__Account__dlm" as "ssot__Account__dlm__0"
where exists (
select *
from "ssot__Case__dlm" as "ssot__Case__dlm__1"
where (
"ssot__Account__dlm__0"."ssot__Id__c" = "ssot__Case__dlm__1"."ssot__AccountId__c"
and trim(cast("ssot__Account__dlm__0"."ssot__Id__c" as varchar)) <> ''
and "ssot__Account__dlm__0"."KQ_Id__c" is not distinct from "ssot__Case__dlm__1"."KQ_AccountId__c"
and lower("ssot__Case__dlm__1"."ssot__CasePriorityId__c") = lower('Low')
and "ssot__Case__dlm__1"."ssot__CreatedDate__c" >= timestamp '2021-09-21 06:56:13.320 -07:00'
and "ssot__Case__dlm__1"."ssot__CreatedDate__c" >= timestamp '2021-09-21 06:56:13.320 -07:00'
and "ssot__Case__dlm__1"."ssot__Id__c" is not null
)
)
)
) as "alias_108427578"
ご覧のように、クエリ エンジンは、優先順位の低いケースを持つアカウントを識別するために、追加のサブクエリを実行します。私が何を言っているのかをよりよく理解するために、2番目のアプローチを見てみましょう。
2. コンテナを1つ作成し、フィルター条件をORで結合する:
セグメント ルールはこんな感じになるでしょう:
セグメンテーション エンジンは、「低」優先度または「クローズ」ステータスのケースが少なくとも1つあるすべてのアカウントを識別します。
最終的なクエリはこんな感じになるでしょう:
select distinct count(*)
from (
select distinct "ssot__Account__dlm__0"."ssot__Id__c", "ssot__Account__dlm__0"."KQ_Id__c"
from "ssot__Account__dlm" as "ssot__Account__dlm__0"
where exists (
select *
from "ssot__Case__dlm" as "ssot__Case__dlm__0"
where (
"ssot__Account__dlm__0"."ssot__Id__c" = "ssot__Case__dlm__0"."ssot__AccountId__c"
and trim(cast("ssot__Account__dlm__0"."ssot__Id__c" as varchar)) <> ''
and "ssot__Account__dlm__0"."KQ_Id__c" is not distinct from "ssot__Case__dlm__0"."KQ_AccountId__c"
and (
lower("ssot__Case__dlm__0"."ssot__CaseStatusId__c") = lower('Closed')
or lower("ssot__Case__dlm__0"."ssot__CasePriorityId__c") = lower('Low')
)
and "ssot__Case__dlm__0"."ssot__CreatedDate__c" >= timestamp '2021-09-21 07:07:54.591 -07:00'
and "ssot__Case__dlm__0"."ssot__CreatedDate__c" >= timestamp '2021-09-21 07:07:54.591 -07:00'
and "ssot__Case__dlm__0"."ssot__CreatedDate__c" >= timestamp '2021-09-21 07:07:54.591 -07:00'
and "ssot__Case__dlm__0"."ssot__Id__c" is not null
)
)
) as "alias_725833"
ご覧のように、セグメンテーション クエリー エンジンは、必要なアカウントを特定するために追加のサブクエリーを実行する必要はありません。故に、可能な限り、コンテナをマージすることをお勧めします。
Note: “AND “条件で結合されたコンテナをマージすることを選択することもできます。ただし、注意してください。コンテナ間のAND動作の仕組みを理解するには、このこのヘルプ文書 を参照してください。
6. ネスト演算子を使う
ネストされた演算子を使用して、1つのコンテナで複雑なセグメンテーション要件に対応
前のセクションでは、コンテナの追加がセグメント クエリに与える影響について説明しました。コンテナの数を減らすことで、セグメントのパフォーマンスを向上させることができます。ネストされた演算子を使用すると、演算子を混在させたい (A AND (B OR C) など) 複雑なシナリオにも対応できます。
前の例に戻りましょう。優先順位の低いケースが少なくとも1つ、またはクローズド ステータスのケースが少なくとも1つあるすべてのアカウントを特定したいと思います。ここで、今月作成された優先度の低いケースだけを調べたいとします。
やりたいことは以下のような感じでしょうか:
(Case Status = ‘Closed’ OR (Case Priotiy = ‘Low’ AND CreatedDate Is This Month))
このようなシナリオに対処するには、2つの別々のコンテナを使用する代わりに、ネストされた演算子を使用すれば同じ結果を得ることができます。ネストされた演算子をどのように作成したかは、以下の動画をご覧ください。
オペレーターのネスティングは、最大5階層まで対応しています。そのため、1つのコンテナでセグメント内のさらに複雑なシナリオに対応することができます。
SQLをご覧になりたい方は、こちらをご覧ください:
select distinct count(*)
from (
select distinct "ssot__Account__dlm__0"."ssot__Id__c", "ssot__Account__dlm__0"."KQ_Id__c"
from "ssot__Account__dlm" as "ssot__Account__dlm__0"
where exists (
select *
from "ssot__Case__dlm" as "ssot__Case__dlm__0"
where (
"ssot__Account__dlm__0"."ssot__Id__c" = "ssot__Case__dlm__0"."ssot__AccountId__c"
and trim(cast("ssot__Account__dlm__0"."ssot__Id__c" as varchar)) <> ''
and "ssot__Account__dlm__0"."KQ_Id__c" is not distinct from "ssot__Case__dlm__0"."KQ_AccountId__c"
and (
lower("ssot__Case__dlm__0"."ssot__CaseStatusId__c") = lower('Closed')
or (
lower("ssot__Case__dlm__0"."ssot__CasePriorityId__c") = lower('Low')
and "ssot__Case__dlm__0"."ssot__CreatedDate__c" between timestamp '2023-08-19 15:20:53.212 -07:00' and timestamp '2023-10-23 15:20:53.212 -07:00'
and try(cast(date_diff(
'month',
date_trunc(
'month',
at_timezone(
cast(current_timestamp as timestamp),
'America/Los_Angeles'
)
),
date_trunc(
'month',
at_timezone(
cast("ssot__Case__dlm__0"."ssot__CreatedDate__c" as timestamp),
'America/Los_Angeles'
)
)
) as decimal(38, 18))) between cast('0' as decimal(38, 18)) and cast('0' as decimal(38, 18))
)
)
and "ssot__Case__dlm__0"."ssot__CreatedDate__c" >= timestamp '2021-09-21 08:20:53.212 -07:00'
and "ssot__Case__dlm__0"."ssot__CreatedDate__c" >= timestamp '2021-09-21 08:20:53.212 -07:00'
and "ssot__Case__dlm__0"."ssot__CreatedDate__c" >= timestamp '2021-09-21 08:20:53.212 -07:00'
and "ssot__Case__dlm__0"."ssot__CreatedDate__c" >= timestamp '2021-09-21 08:20:53.212 -07:00'
and "ssot__Case__dlm__0"."ssot__Id__c" is not null
)
)
) as "alias_56795836"
7. ネストされたセグメントを使う
セグメントの中に別のセグメントを入れ子にすることで、あるセグメントを別のセグメン トに含めたり、別のセグメントから除外したりすることができます。可能であれば、定義モードではなく、セグメント メンバーシップ モードを使用します。セグメント メンバーシップ モードでは、セグメントの最後の実行の出力が使用されます。一方、 セグメント定義モードでは、セグメントで定義されたフィルター基準が使用されます。メンバーシップ モードでセグメントをネストすると、セグメンテーション エンジンはネストされたセグ メントのフィルター基準を再実行する必要がなくなるので、セグメントのパフォーマンスが向上します。
Note: ネストされたセグメントについては、こちらをご覧ください。
8. 複雑な業務に計算済みインサイトやデータ変換を使用する
計算済みインサイトとデータ変換は、セグメンテーションの計算の負担を軽減する強力なツールです。先ほどの例に戻りましょう。今月作成された「低」優先度ケースまたはクローズド ステータスのケースが少なくとも1つあるアカウントをすべて特定したいとしましょう。ここでは、収益が 50 万ドル以上で、従業員数が 5000 人以上のアカウントに絞り込みます。
セグメントでこれら2つのフィルターを追加する代わりに、これらのアカウントを識別する計算済みインサイト(CI)を作成して使用することができます。これは簡単な例ですが、実際のシナリオで、セグメントで計算済みインサイト(CI)を多用している顧客もいます。
計算済みインサイト(CI)を使えば、上記の条件を満たすアカウントにフラグを立てることができます。そして、その計算済みインサイト(CI)をセグメントで代わりに使うことができます。これにより、セグメンテーションエンジンの全体的な負荷が軽減されます。
Note: セグメント内での計算済みインサイトの使用については、こちらをご覧ください。また、セグメントと計算済みインサイト(CI) のスケジュールにも注意してください。
9. 偏ったエンゲージメント・データの使用を避ける
データ量が多い場合、セグメントのパフォーマンスに影響するため、セグメントで偏ったエンゲージメントデータを使用することは避けてください。最初のポイントでは、”行動日時”列を使用してエンゲージメントデータをパーティショニングする方法について説明しました。データが偏っていると、1つのパーティションに多くのデータが含まれる可能性があり、操作時間が長くなります。
謝辞: このブログ記事を投稿できたのは以下の人たちのおかげです
Nishant, Piyush, Priyank, Sameer, Samyak, SD, Vartik, Vivek, Naheeda.
このブログがお役に立てば幸いです。私たちの製品は常に進化していますので、このブログでも最新のおすすめ情報をお伝えしていきたいと思います。ご質問がありましたら、コメント欄までお寄せください。