執筆者:Salesforce データエンジニア
背景と利用シーン
Salesforceは世界No.1のCRMプラットフォームとして、顧客データを中心とした様々な情報を管理する能力に長けています。しかし、ビジネスがデジタル化し、IoTデバイスの普及や顧客エンゲージメントの追跡が高度化するにつれて、企業が扱うデータ量は爆発的に増加しています。日々のログデータ、センサーからの時系列データ、Webサイトのクリックストリームなど、その規模は数億、数十億レコードに達することも珍しくありません。
従来のSalesforce標準オブジェクトやカスタムオブジェクトは、トランザクションデータを扱うことに最適化されており、このような大規模データを格納すると、パフォーマンスの低下、ガバナ制限への抵触、そして高額なストレージコストといった課題に直面します。
この課題を解決するために登場したのが Big Objects (ビッグオブジェクト) です。Big Objectsは、Salesforceプラットフォーム上で数十億レコード規模のデータをネイティブに格納・管理するために設計された特別なオブジェクトです。データエンジニアの観点から見ると、これは単なるストレージソリューションではなく、大規模データ活用のための強力な基盤となります。
主な利用シーン
- イベントモニタリングと監査ログ: ユーザーのログイン履歴、APIコール、ページの閲覧履歴など、詳細なアクティビティログを長期間保存し、セキュリティ分析や利用状況の把握に活用します。
- IoTデータ収集: 製造業における機械のセンサーデータ、スマートデバイスからのヘルスケアデータなど、膨大な時系列データを収集・蓄積します。
- 顧客エンゲージメントの追跡(360度ビュー): Webサイトのクリック履歴、メールの開封・クリック、モバイルアプリの操作履歴など、顧客とのあらゆる接点のデータを記録し、顧客理解を深めます。
- データアーカイブ: 取引が完了した古い商談やクローズしたケースなど、頻繁にアクセスする必要はないが、コンプライアンスや将来の分析のために保持が必要なデータを、標準オブジェクトからBig Objectsに移動させることで、本番環境のパフォーマンスを維持します。
原理説明
Big Objectsがなぜ大規模データを効率的に扱えるのかを理解するためには、その技術的な基盤と、標準オブジェクトとの違いを把握することが重要です。
Big Objectsは、Apache HBaseのような実績のあるビッグデータ技術を基盤として構築されています。これにより、標準データベースとは異なるスケーラビリティとパフォーマンスを実現しています。その核心となるのが、index (インデックス) の概念です。
インデックス (複合主キー)
Big Objectsを定義する際、最も重要なのがインデックスの設計です。これは複数の項目(最大5つ)を組み合わせた複合主キー (composite primary key) であり、Big Objects内のすべてのレコードを一意に識別し、ソート順を決定します。
このインデックスは、Big Objectsからデータを効率的に取得するための唯一の手段です。標準オブジェクトのように、任意の項目にインデックスを追加してクエリを高速化することはできません。データはインデックスの順序で物理的に格納されており、クエリを実行する際は、このインデックスを前方一致で指定する必要があります。したがって、どのような条件でデータを検索・フィルタリングするかを事前に設計し、それに基づいてインデックスを定義することが極めて重要です。一度定義したインデックスは後から変更できません。
クエリとデータ操作
Big Objectsに対するデータ操作は、標準オブジェクトとは大きく異なります。
- データ投入: データは主にAPI(Bulk APIなど)やApexの
Database.insertImmediate()メソッドを使用して一括で投入されます。UIからの手動作成はサポートされていません。 - データの更新・削除: Big Objectsのレコードは、原則として更新(Update)や削除(Delete)ができません。これは、イベントログのように「一度書き込んだら変更しない」という性質のデータ(イミュータブルデータ)を扱うのに適しています。
- クエリ: データのクエリには、主に2つの方法があります。
- 標準SOQL: インデックスを構成するすべての項目をWHERE句で完全に指定する場合にのみ、同期的に少数のレコードを高速に取得できます。特定の1レコードを取得するようなユースケースで利用します。
- Async SOQL (非同期 SOQL): Big Objectsに格納された大規模データセット全体をスキャンし、集計やフィルタリングを行うための主要なツールです。クエリは非同期で実行され、結果は別のSalesforceオブジェクト(カスタムオブジェクトなど)や外部ストレージに出力されます。データエンジニアがバッチ処理や分析を行う際には、このAsync SOQLが中心的な役割を果たします。
示例コード
ここでは、Big Objectsの定義からデータ投入、そしてAsync SOQLによるデータ集計までの一連の流れをコードで示します。
1. Big Objectの定義 (メタデータ)
Big Objectは、メタデータAPIやAnt移行ツールなどを使用して、XMLファイルで定義します。以下は、顧客のWebサイト閲覧履歴を格納する Customer_Interaction_History__b というBig Objectの定義例です。
<?xml version="1.0" encoding="UTF-8"?>
<CustomObject xmlns="http://soap.sforce.com/2006/04/metadata">
<deploymentStatus>Deployed</deploymentStatus>
<fields>
<fullName>Account_Id__c</fullName>
<label>Account Id</label>
<length>18</length>
<required>true</required>
<type>Text</type>
<unique>false</unique>
</fields>
<fields>
<fullName>Interaction_DateTime__c</fullName>
<label>Interaction DateTime</label>
<required>true</required>
<type>DateTime</type>
</fields>
<fields>
<fullName>Page_URL__c</fullName>
<label>Page URL</label>
<length>255</length>
<required>false</required>
<type>Text</type>
<unique>false</unique>
</fields>
<indexes>
<fullName>CustomerInteractionIndex</fullName>
<label>Customer Interaction Index</label>
<fields>
<name>Account_Id__c</name>
<sortDirection>ASC</sortDirection>
</fields>
<fields>
<name>Interaction_DateTime__c</name>
<sortDirection>DESC</sortDirection>
</fields>
</indexes>
<label>Customer Interaction History</label>
<pluralLabel>Customer Interaction Histories</pluralLabel>
</CustomObject>
解説:
__bというサフィックスがBig Objectを示します。<indexes>タグで複合主キーを定義しています。この例では、「取引先ID (昇順)」と「インタラクション日時 (降順)」でインデックスを構成しています。これにより、特定の取引先の最新の閲覧履歴から順に高速にアクセスできます。
2. Apexによるデータ投入
ApexからBig Objectsにデータを挿入するには、Database.insertImmediate() を使用します。通常のDML insert とは異なる点に注意が必要です。
// 挿入するBig Objectレコードのリストを作成
List<Customer_Interaction_History__b> newInteractions = new List<Customer_Interaction_History__b>();
// 1件目のレコード
Customer_Interaction_History__b interaction1 = new Customer_Interaction_History__b();
interaction1.Account_Id__c = '001xx000003DHPxAAO'; // 実際の取引先ID
interaction1.Interaction_DateTime__c = System.now();
interaction1.Page_URL__c = '/products/awesome-product';
newInteractions.add(interaction1);
// 2件目のレコード
Customer_Interaction_History__b interaction2 = new Customer_Interaction_History__b();
interaction2.Account_Id__c = '001xx000003DHPxAAO'; // 同じ取引先ID
interaction2.Interaction_DateTime__c = System.now().addSeconds(10);
interaction2.Page_URL__c = '/pricing';
newInteractions.add(interaction2);
// Database.insertImmediateを使用して同期的にレコードを挿入
// このメソッドはトランザクションの制御外で実行される
Database.SaveResult[] results = Database.insertImmediate(newInteractions);
// 結果の確認
for (Database.SaveResult res : results) {
if (res.isSuccess()) {
System.debug('Successfully inserted Big Object record. ID: ' + res.getId());
} else {
for (Database.Error err : res.getErrors()) {
System.debug('Error inserting record: ' + err.getStatusCode() + ': ' + err.getMessage());
}
}
}
3. Async SOQLによるデータ集計
Big Objectに蓄積されたデータからインサイトを得るには、Async SOQLが不可欠です。以下は、各取引先が過去30日間に何回Webサイトを閲覧したかを集計し、その結果を Monthly_Interaction_Summary__c というカスタムオブジェクトに保存する例です。
// 集計結果を格納するカスタムオブジェクト
// Fields: Account__c (Lookup(Account)), Interaction_Count__c (Number), Target_Date__c (Date)
// Async SOQLクエリを定義
String query = 'SELECT Account_Id__c, COUNT(Id) ' +
'FROM Customer_Interaction_History__b ' +
'WHERE Interaction_DateTime__c = LAST_N_DAYS:30 ' +
'GROUP BY Account_Id__c';
// Async SOQLジョブのターゲットオブジェクトと操作を指定
AsyncApiJob job = new AsyncApiJob();
job.targetObject = 'Monthly_Interaction_Summary__c';
job.operation = 'insert';
// 項目マッピングを定義
// 左辺がターゲットオブジェクトの項目、右辺がSOQLの結果
job.columnMapping = '{' +
'"Account__c": "Account_Id__c",' +
'"Interaction_Count__c": "expr0",' + // COUNT(Id)はexpr0として参照される
'"Target_Date__c": "' + Date.today().format() + '"' + // 静的な値を設定
'}';
// ジョブを実行
job.query = query;
AsyncApiJob resultJob = System.AsyncApi.submitJob(job);
System.debug('Job ID: ' + resultJob.Id); // このIDでジョブのステータスを追跡
解説:
- Async SOQLは、
FROM句にBig Objectを指定し、GROUP BYや集計関数(COUNT()など)を使用して大規模なデータセットを処理できます。 - クエリの結果は直接返されるのではなく、
AsyncApiJobを通じて指定したターゲットオブジェクトに挿入されます。 columnMappingで、クエリ結果のどの部分をターゲットオブジェクトのどの項目にマッピングするかを定義します。
注意事項
Big Objectsを効果的に活用するためには、以下の制約と注意点を十分に理解する必要があります。
- インデックス設計の重要性: 前述の通り、インデックスは後から変更できません。データアクセスパターンを慎重に分析し、最適なインデックスを設計することが成功の鍵です。インデックスに含まれない項目でのフィルタリングは、フルスキャンとなり非常に非効率です。 - UIの非サポート: Big Objectsのレコードは、標準のレコード詳細ページ、リストビュー、レポート、ダッシュボードでは直接表示できません。データを可視化するには、Async SOQLで集計結果を標準/カスタムオブジェクトに格納し、そちらを利用する必要があります。
- リレーションの制限: Big Objectsは、標準/カスタムオブジェクトへの参照関係 (Lookup Relationship) を持つことができますが、主従関係 (Master-Detail Relationship) は作成できません。また、Big Objectsが親となるリレーションは作成できません。
- トリガとプロセスの非サポート: Big Objectsに対して、Apexトリガ、プロセスビルダー、フローなどを実行することはできません。データ処理は、外部からのバッチ投入やAsync SOQLによる後処理が基本となります。
- ガバナ制限: Big Objects自体はデータストレージ制限の対象外ですが、Async SOQLの実行には日次のジョブ数制限など、独自ガバナ制限が存在します。大量のジョブを定期的に実行する場合は、これらの制限を考慮する必要があります。
- 権限設定: 標準オブジェクトと同様に、プロファイルや権限セットを通じてオブジェクト権限や項目レベルセキュリティ (Field-Level Security) を設定できます。
まとめとベストプラクティス
Big Objectsは、Salesforceプラットフォーム上で大規模データを扱うための、非常に強力でスケーラブルなソリューションです。しかし、それは標準オブジェクトの完全な代替品ではなく、特定のユースケースに特化したツールです。データエンジニアとしてBig Objectsを成功裏に導入・運用するためには、以下のベストプラクティスを推奨します。
- 適切なユースケースの選択: 「書き込みが多く、読み取りは特定パターン、更新・削除は稀」なデータ(ログ、履歴、アーカイブなど)にBig Objectsを適用します。トランザクショナルな操作が必要なデータには、引き続き標準/カスタムオブジェクトを使用します。
- インデックス第一の設計思想: どのようなクエリが最も重要かをビジネス部門と協力して特定し、それを満たすインデックスを設計します。これがプロジェクトの成否を分けます。
- データ可視化戦略の立案: Big Objectsにデータを格納するだけでなく、そこからどのようにインサイトを引き出し、ビジネスユーザーに提供するかを計画します。Async SOQLとサマリーオブジェクトを組み合わせたアーキテクチャは一般的なパターンです。
- データライフサイクル管理: Big Objectsのデータは永続的に増加する傾向があるため、どのデータを、どのくらいの期間保持するか、というデータ保持ポリシーを定義することが重要です。
- テストの徹底: 本番環境にデプロイする前に、サンドボックスで想定されるデータ量とクエリパターンを用いてパフォーマンステストを実施し、インデックス設計の妥当性を検証します。
これらの特性とベストプラクティスを理解し、適切に活用することで、Big ObjectsはSalesforceを単なるCRMから、エンタープライズ規模のデータプラットフォームへと昇華させるための重要な要素となるでしょう。
コメント
コメントを投稿