SOSLを使いこなす:Salesforce開発者向け徹底解説

背景と応用シーン

Salesforce 開発者として、私たちは日々、顧客の要件を満たすために、効率的でスケーラブルなソリューションを構築しています。その中で、データの「検索」機能は、ユーザーエクスペリエンスを決定づける極めて重要な要素です。ユーザーは、顧客名、会社名、電話番号といった断片的な情報から、必要なレコードを迅速に見つけ出したいと考えています。ここで強力なツールとなるのが、SOSL (Salesforce Object Search Language、Salesforceオブジェクト検索言語) です。

多くの開発者が SOQL (Salesforce Object Query Language、Salesforceオブジェクトクエリ言語) には精通していますが、SOSL は特定のシナリオにおいて SOQL よりもはるかに優れたパフォーマンスと柔軟性を提供します。SOQL が「特定のオブジェクトから、既知の条件に合致するレコードを取得する」ための言語であるのに対し、SOSL は「複数のオブジェクトを横断して、特定のテキスト文字列を検索する」ための言語です。

具体的な応用シーンとしては、以下のようなものが考えられます。

  • グローバル検索バーの実装: Lightning Web Components (LWC) や Aura Components で、Salesforce の標準グローバル検索のようなカスタム検索機能を実装する際に、単一の入力フィールドで取引先、取引先責任者、商談などを同時に検索する。
  • データの重複チェック: 新規リードが作成される際に、入力された会社名や氏名が、既存のリード、取引先、取引先責任者に存在しないかを横断的に確認する。
  • サポートコンソールの機能拡張: 顧客からの問い合わせメールの件名や本文に含まれるキーワードを基に、関連するケース、ナレッジ記事、取引先責任者を一度に検索し、オペレーターに提示する。

このように、SOSL はユーザーがどのオブジェクトに情報が存在するかを意識することなく、Google のような直感的な検索体験を提供するための鍵となります。開発者として SOSL の原理と使い方を深く理解することは、より高度で使いやすいアプリケーションを構築する上で不可欠です。


原理説明

SOSL が高速な検索を実現できる背景には、Salesforce プラットフォームが管理する強力な「検索インデックス」の存在があります。SOSL クエリが実行されると、データベースのテーブルを直接フルスキャンするのではなく、この最適化された検索インデックスに対して問い合わせが行われます。これにより、膨大なデータ量の中からでも、瞬時に関連性の高い結果を返すことが可能になっています。

SOSL クエリの基本的な構文は以下のようになります。

FIND '検索キーワード' [IN 検索グループ] RETURNING オブジェクト名(取得フィールドリスト), オブジェクト名(取得フィールドリスト), ...

主要な構成要素

1. `FIND '検索キーワード'`
検索したいテキスト文字列を指定します。このキーワードは、単一の単語でも複数の単語でも構いません。アスタリスク `(*)` やクエスチョンマーク `(?)` などのワイルドカードを使用することもできます。例えば、`'Gen*'` は 'GenePoint' や 'General' にマッチします。

2. `IN 検索グループ` (省略可能)
検索対象となるフィールドの範囲を限定します。これを指定することで、検索の精度とパフォーマンスを向上させることができます。

  • `ALL FIELDS`: (デフォルト) 検索可能な全てのテキストフィールドを対象とします。
  • `NAME FIELDS`: Name 項目のみを対象とします。
  • `EMAIL FIELDS`: Email 項目のみを対象とします。
  • `PHONE FIELDS`: Phone 項目のみを対象とします。

3. `RETURNING オブジェクト名(取得フィールドリスト)`
検索対象とするオブジェクトと、検索にヒットした場合に取得したいフィールドを指定します。カンマ区切りで複数のオブジェクトを指定することが可能です。例えば、`RETURNING Account(Id, Name), Contact(Id, Name, Email)` のように記述します。ここで重要なのは、SOSL の結果は `List<List<SObject>>` という形式で返されることです。外側のリストの各要素が `RETURNING` 句で指定したオブジェクトに対応し、内側のリストにそのオブジェクトのレコードが格納されます。

この構造を理解することが、SOSL の結果を正しく処理するための鍵となります。


示例代码

それでは、具体的な Apex コードを見ていきましょう。以下のサンプルは、Salesforce の公式ドキュメントで頻繁に引用される典型的な SOSL の使用例です。

静的 SOSL クエリ

この例では、'Wingo' というキーワードを複数のオブジェクト(Account, Contact, Lead)から検索し、それぞれのオブジェクトから指定されたフィールドを取得します。

// 'Wingo' という文字列を全てのテキスト項目から検索します。
// 検索対象オブジェクトは Account, Contact, Lead です。
List> searchList = [FIND 'Wingo' IN ALL FIELDS
                                  RETURNING Account(Name, Industry),
                                            Contact(FirstName, LastName, Email),
                                            Lead(FirstName, LastName, Company)];

// SOSL の結果は List> 型で返されます。
// RETURNING 句で指定したオブジェクトの順に結果が格納されます。
// この例では、searchList[0] が Account のリスト、searchList[1] が Contact のリスト、
// searchList[2] が Lead のリストに対応します。

// 結果をオブジェクトごとに取得します。
Account[] searchAccounts = (Account[])searchList[0];
Contact[] searchContacts = (Contact[])searchList[1];
Lead[] searchLeads = (Lead[])searchList[2];

// 取得した結果をデバッグログに出力します。
System.debug('Found ' + searchAccounts.size() + ' accounts.');
System.debug('Found ' + searchContacts.size() + ' contacts.');
System.debug('Found ' + searchLeads.size() + ' leads.');

動的 SOSL クエリ

実際のアプリケーションでは、検索キーワードはユーザーの入力によって動的に変わります。その場合は、`Search.query()` メソッドを使用して動的に SOSL クエリを構築します。この際、SOSL インジェクションを防ぐために、ユーザーからの入力値を必ずエスケープ処理する必要があります。

public class DynamicSoslExample {
    public static List> searchForTerm(String searchTerm) {
        // ユーザー入力をサニタイズして、SOSLインジェクションを防ぎます。
        // これはセキュリティ上、非常に重要です。
        String sanitizedSearchTerm = String.escapeSingleQuotes(searchTerm);

        // 動的な検索クエリ文字列を構築します。
        // ここでは、検索キーワードの前後にワイルドカード '*' を追加して部分一致検索を可能にしています。
        String soslQuery = 'FIND \'' + sanitizedSearchTerm + '*\' IN NAME FIELDS ' +
                           'RETURNING Account(Id, Name), Contact(Id, Name, Phone)';

        // Search.query() メソッドを実行して、動的 SOSL を実行します。
        List> searchResult = Search.query(soslQuery);

        return searchResult;
    }
}

// 呼び出し例
// List> results = DynamicSoslExample.searchForTerm('Gene');
// Account[] accounts = (Account[])results[0];
// Contact[] contacts = (Contact[])results[1];
// System.debug('Found Accounts: ' + accounts);
// System.debug('Found Contacts: ' + contacts);

注意事項

SOSL を使用する際には、Salesforce のマルチテナント環境における制約とベストプラクティスを理解しておく必要があります。

ガバナ制限 (Governor Limits)

Salesforce プラットフォームでは、リソースの公平な利用を保証するためにガバナ制限が設けられています。SOSL も例外ではありません。

  • 1トランザクションあたりの SOSL クエリ発行回数: 同期 Apex では 20 回、非同期 Apex (Batch, Futureなど) では 100 回です。ループ内で SOSL クエリを発行するコードは絶対に避けるべきです。
  • SOSL クエリが返す最大レコード数: SOSL クエリは最大で 2,000 件のレコードを返すことができます。この上限は、SOQL の 50,000 件に比べて少ないため、大量のデータを取得する目的には向いていません。あくまで「検索」のためのツールと割り切る必要があります。

権限と共有ルール

SOSL は、実行ユーザーの権限と共有ルールを完全に尊重します。つまり、ユーザーがアクセス権を持たないレコードは、検索結果に含まれることはありません。これはセキュリティを担保する上で非常に重要な仕様です。開発者は、ユーザーのプロファイルや権限セットを意識してテストを行う必要があります。

SOSL インジェクション (SOSL Injection)

動的 SOSL を使用する際は、セキュリティリスクに最大限の注意を払う必要があります。ユーザーからの入力をそのままクエリ文字列に連結すると、悪意のあるユーザーがクエリの意図を改変し、本来アクセスできないはずの情報を窃取する可能性があります。これを防ぐために、必ず `String.escapeSingleQuotes()` メソッドを使用してユーザー入力をサニタイズしてください。

検索インデックスの遅延

レコードが作成または更新されてから、その内容が検索インデックスに反映されるまでには、わずかなタイムラグが存在する場合があります。通常は数秒以内ですが、大規模なデータロード時などには遅延が大きくなる可能性も考慮に入れておくべきです。リアルタイム性が厳密に求められる要件では、この特性が問題にならないか検討が必要です。


まとめとベストプラクティス

SOSL は、Salesforce アプリケーションに強力で直感的な検索機能を提供する上で欠かせないツールです。SOQL との違いを正しく理解し、適材適所で使い分けることが、パフォーマンスとユーザーエクスペリエンスを両立させる鍵となります。

ベストプラクティス

  1. SOQL との使い分けを徹底する:
    • SOSL: ユーザーが入力したキーワードで、複数のオブジェクトを横断して検索する場合。どのオブジェクトにデータがあるか不明な場合。
    • SOQL: 単一のオブジェクトから、特定の条件(ID、作成日、ステータスなど)に基づいてレコードを取得する場合。関連オブジェクトのデータを取得する場合。
  2. 検索範囲を限定する:
    可能な限り `IN NAME FIELDS` などを指定して検索対象を絞り込みましょう。`IN ALL FIELDS` は便利ですが、意図しないフィールドがヒットし、パフォーマンスが低下する可能性があります。同様に `RETURNING` 句でも、本当に必要なオブジェクトとフィールドのみを指定してください。
  3. 動的クエリのセキュリティを確保する:
    `Search.query()` を使用する際は、`String.escapeSingleQuotes()` によるサニタイズを常に忘れないでください。これは開発者としての責務です。
  4. ガバナ制限を意識した設計:
    特にトリガーや一括処理の中で SOSL を使用する場合は、発行回数が上限を超えないように、処理をバルク化(一括処理)する設計を心がけてください。
  5. 結果セットの構造を理解する:
    `List<List<SObject>>` の扱いに慣れましょう。`RETURNING` 句のオブジェクトの順序と、結果リストのインデックスが対応していることを常に意識してコードを記述することが、バグを防ぐことにつながります。

SOSL をマスターすることで、私たちは単なるデータ格納庫ではない、ユーザーが積極的に情報を探し、活用できるインテリジェントな Salesforce アプリケーションを構築することができます。ぜひ、次のプロジェクトで SOSL を活用してみてください。

コメント