# リアルタイムパーソナライゼーション2.0サーバーサイドユースケースガイド

## はじめにと概要

リアルタイムパーソナライゼーション2.0は、顧客プロファイルの属性・行動・セグメントに関する即時かつコンテキストに沿った情報を提供するデータエンジンです。Webやモバイルインターフェイスのリアルタイムなパーソナライゼーションを実現するために設計されています。[リアルタイムパーソナライゼーションの詳細はこちら](/ja/products/customer-data-platform/real-time/about-real-time-personalization)をご覧ください。

リアルタイムパーソナライゼーション2.0は、クライアントサイド構成・サーバーサイド構成のどちらでも実装できます。このガイドはサーバーサイド実装に焦点を当てています。

このステップバイステップガイドでは、シンプルなWebアプリケーションを題材に、リアルタイムパーソナライゼーション2.0のサーバーサイドユースケースを構築・実装する方法を紹介します。データの取り込みと属性設定から、オーディエンスセグメンテーション、下流の統合まで、全体のプロセスを順を追って説明します。

## リアルタイムパーソナライゼーション2.0について

リアルタイムパーソナライゼーション2.0（RT 2.0）は、モダンなサーバー間のプッシュ/プルAPIアーキテクチャを提供します。行動データの迅速な取り込みと、Treasure DataのAudience Studioで定義したパーソナライゼーションルールやセグメントに対するリアルタイム評価の両方を実現します。ユーザーは、サインアップやログイン、商品閲覧などのイベントに即座に反応し、パーソナライゼーション向けのペイロードを返す体験を設計できます。

*RT 2.0パーソナライゼーションAPIとRT 1.0（Profiles API）の比較*

| Feature | RT 1.0 | RT 2.0 |
|  --- | --- | --- |
| Method | ルックアップキーを送るGET | データを取り込むPOST |
| Endpoint | cdp.in.treasuredata.com | us01.p13n.in.treasuredata.com |
| Access | SDK（クライアントサイド） | サーバー間通信 |
| Response & String-build | セグメント、バッチ属性 | バッチ+リアルタイム属性とセグメント |
| SLA | 保証なし | 100ms |
| Token | UIで作成 | UI＋手動設定 |
| Latency: Batch Update | トークンWF実行＋PSワークフロー | ワークフロー実行＋RT同期実行 |


リアルタイムパーソナライゼーション1.0と比べると、2.0（サーバーサイド）はより包括的で低レイテンシーなレスポンスを提供します。サーバーサイドのユースケースと準リアルタイムアクティベーションに最適化されています。

以下のセクションでは、Webアプリケーション向けにリアルタイムパーソナライゼーション2.0を設定する方法を紹介します。

## ステップ1: データ取り込みとAPIオプション

このステップでは、WebアプリからTreasure Data CDPへのデータフローを設定する方法を説明します。主要な取り込みAPIとテーブル/セグメント設計のベストプラクティスに焦点を当てます。

既にCDPテーブルにデータを送信している場合も、新たなパーソナライゼーションユースケースに合わせてテーブルを準備する場合も、行動イベントを個別のテーブルにマッピングし、下流で「ペアレントセグメント」として活用するようにしてください。これらのセグメントがRT 2.0構成の基盤になります。

RT 2.0をセットアップした後は、テーブルやセグメントを継続的に更新しても、構成を再申請する必要はありません。

### Ingestion APIとSDK 4.1の比較

* SDK 4.1: ブラウザ/クライアントサイドからデータを送信します。実装は容易ですが、機密性の高いPIIやビジネスロジックを扱う場合はセキュリティリスクが高くなる可能性があります。
* Ingest API: サーバーやサーバーレス（例: AWS Lambda）からイベントデータを送信します。セキュリティと制御の観点から推奨される方法です。


### Lambda（サーバーサイド）を使った取り込み例

* Ingest APIエンドポイント:
  * [https://us01.records.in.treasuredata.com](https://us01.records.in.treasuredata.com)
  * [https://eu01.records.in.treasuredata.com](https://eu01.records.in.treasuredata.com)
  * [https://ap02.records.in.treasuredata.com](https://ap02.records.in.treasuredata.com)
  * [https://ap01.records.in.treasuredata.com](https://ap01.records.in.treasuredata.com)


リージョンごとのbaseURLについては[Treasure Dataドキュメント](/apis/endpoints/endpoints)をご確認ください。

Ingest APIとPersonalization APIの違いは何ですか？

* Ingest API: イベントデータをCDPに送信し、保存および後でのセグメンテーションに利用します。レスポンスでパーソナライゼーションペイロードは返しません。
* Personalization API: イベントデータを取り込み、直ちにパーソナライゼーションロジックを評価して、Audience Studioで定義したルールに基づくリアルタイムペイロードを返します。


ニュースレター登録イベントを送信する例:

* Ingest APIの場合: イベントデータをPOSTして将来のセグメント更新に利用し、別途API呼び出し（または下流処理）でセグメントや属性情報を取得します。
* Personalization APIの場合: 1回のAPI呼び出しでイベントを取り込み、`user_status: subscribed` や `segment_membership: batch_subscribed_users` のようなリアルタイムフラグをレスポンスで受け取ります。


Personalization APIエンドポイント:

* [https://us01.p13n.in.treasuredata.com](https://us01.p13n.in.treasuredata.com)
* [https://eu01.p13n.in.treasuredata.com](https://eu01.p13n.in.treasuredata.com)
* [https://ap01.p13n.in.treasuredata.com](https://ap01.p13n.in.treasuredata.com)


Personalization APIは、取り込みとリアルタイム評価を1つのAPI呼び出しで実現し、統合の簡素化・レイテンシ削減・即時の体験提供を可能にします。

Personalization APIリクエスト例:


```json
{
  "td_client_id":"1986b2a4-3957-4863-be2c-7ef36a14afee",
  "td_url":"https://treasuredemos.com/retail",
  "td_path":"/retail"
  // additional properties...
}
```

Personalization APIレスポンス例:


```json
{
  "offers": {
    "First-Time-Visitor": {
      "attributes": {
        "newsletter_section": "show"
      },
      "batch_segments": null
    }
  }
}
```

## ステップ2: UIでのリアルタイムパーソナライゼーション設定

このステップでは、リアルタイムパーソナライゼーション2.0の有効化を依頼する方法、Treasure DataのUIで主要機能を設定する手順、APIアクセス用のパーソナライゼーショントークンを管理する方法を紹介します。

### RT Personalization 2.0の有効化

アカウントでRT Personalization 2.0を有効化するには、次の手順に従います。

* まずAudience Studioでペアレントセグメントを作成します。
* 次に、カスタマーサクセスマネージャー（CSM）にリアルタイムパーソナライゼーション2.0機能の有効化を依頼します。
* CSMには以下の情報を提供してください。
  * AWSインスタンス名
  * 環境（本番、ステージングなど）
  * ペアレントセグメントID


アカウントで機能が有効化されると、次の情報が提供されます。

* 有効化前/後のスクリーンショットによる確認
* パーソナライゼーション2.0トークンを作成する際に使用する Reactor Instance Configuration（例: a11874n4）


### リアルタイムパーソナライゼーション2.0の構成

Treasure コンソールでリアルタイムパーソナライゼーション2.0を設定するには、次の手順を実行します。

* 対象のペアレントセグメントを選択します。
* Configuration Options画面の「Personalization Configuration」セクションで「Configure settings」ボタンをクリックします。
* パーソナライゼーションサービスの一覧が表示されたデータグリッドに移動します。
* 「Create new personalized service」ボタンをクリックします。
* パーソナライゼーションサービスの名前を入力し、必要に応じて説明を追加します。
* SSO/ID検証に関するメッセージが表示される場合があります。アカウントがユーザー名＋パスワードの場合でも、SSO用のメッセージが表示されることがあります。サインアウト・サインインで解決するケースがあります。
* 右側のパネルで「+ Add token」ボタンをクリックします。


パーソナライゼーショントークンの作成と管理:

* 各パーソナライゼーショントークンに名前を付けます。
* サービスタイプとしてPublicまたはPrivateを選択します。
  * IP WhitelistはPrivateサービスでのみ設定できます。指定したIPアドレスの範囲からのみアクセスが可能になります。IPアドレスを指定しない場合は、Treasure アカウントのIPホワイトリスト設定が適用されます。
* 必要に応じてトークンを特定のIPアドレス範囲に制限できます（任意）。空欄の場合は、アカウントのIPホワイトリストが適用されます。
* 各APIトークンの形式は `[YOUR_ACCOUNT_INSTANCE_ID]/[REACTOR_INSTANCE_ID]/[RT_PERSONALIZATION_TOKEN]` です。
  * 例: `11874/3/YOUR_TOKEN`
* Postmanやサーバーコードで利用する場合は、ヘッダーに `"WP13n-Token": "11874/3/YOUR_TOKEN"` の形式で設定します。


1つのパーソナライゼーションインスタンスにつき複数のトークンを作成できます。ステージングと本番でアクセス権を分けたり、将来的にサーバー用とクライアント用でトークンを分離したりする際に便利です。Treasure Dataでは、パーソナライゼーションサービスごとに最大50個、ペアレントセグメント全体で最大200個のトークンを利用できます。

検証時の注意点:

* トークンを後から閲覧する際、再ログインを求められることがあります（セキュリティのため正常な動作です）。
* V4 UIとV5 UIで挙動が異なる場合があります。V4はパスワード検証、V5はSSOプロンプトが表示されることがあります。


## ステップ3: イベントと属性の定義

パーソナライゼーションサービスの設定後は、イベントテーブル、イベントフィルタ、関連属性を定義します。

### イベントテーブルとイベント定義

* Real-Time Configurationセクションで、利用するストリーミングイベントテーブルをすべて追加します。
* イベントを新規作成する手順:
  * 「Create new event」をクリック
  * イベントに名前を付ける
  * ソーステーブルを選択する
  * 必要に応じて特定アクションをフィルタリング（例: `td_path` の正規表現で商品ページ閲覧を抽出）


商品ページ閲覧のイベントフィルタ例:

* `td_path` 正規表現: `^/retail/.*/product/.*`


属性の定義（Attributesタブ）:

* 属性タイプごとに感度を設定しながら追加します。
  * Single: ユーザーの最新値（文字列/数値）を保持。機密/非機密のいずれかに設定可能。
  * List: 最大100件の配列（例: 閲覧した商品）を保持し、各要素は60日で期限切れ。機密/非機密のいずれかに設定可能。
  * Counter: イベントの回数や数値合計を追跡。スライディング（ローリングウィンドウ）と累積モードをサポート。非機密のみ設定可能。
  * Imported Batch: バッチセグメントから値を参照。リアルタイムイベントでは更新されず、ペアレントセグメントの再実行でのみ更新。機密/非機密のいずれかに設定可能。


注意: 属性の感度は機密または非機密に分類できます。APIレスポンスで公開されるのは非機密属性のみです。

Single属性のポイント:

* 最新イベント値（例: 最後に閲覧した商品）を保持します。
* 各属性にはシステムIDがあり、名称変更で新しいシステムIDが発行されます。
* 履歴データを取り込む場合はBatch Backfill（タイムスタンプ整合を伴うバッチインポート）を使用します。
* リアルタイム属性とバッチ属性の名前/エイリアスが衝突しないように設計してください。


List属性のポイント:

* セッションや直近ユースケース向け（例: 「過去X時間に閲覧した商品」）で、文字列/数値の配列を保持します。
* バッチのバックフィルはできません。必要に応じてバッチ用とリアルタイム用で属性を分けます。
* 集計オプション: First、Last、Sum、Min、Max、Distinct List。Sum/Min/Maxは数値型のみ利用可能など、戻り値の制約があります。
* ユースケースとして、最新アクション、ユニークアイテム、直近リストなどがあり、マッピングや取り込み形式を慎重に設計する必要があります。


既知のList属性の挙動:

* メインの `value_field_name` が文字列の場合、集計用にリストが「フラット化」されます。
* 価格やURLなどのプロパティを配列としてマッピングすると、最後の要素だけでなくJSONリスト全体が保持されます。
* ワークアラウンドとして、イベントを粒度の細かい単位で送信する、またはすべての項目プロパティをバッファ属性としてマッピングする方法があります。


Counter属性のポイント:

* 定義した期間内でイベント発生数や合計値をカウントします。
* スライディングカウンター: 指定した期間（分・時間・日）のローリングウィンドウ。サブ期間（例: 日次内の時間単位）を最大20個まで定義可能。
* 累積カウンター: 固定の破棄ウィンドウ（最大60日）内で累積します。
* 粒度とシステム制約のバランスを考慮して期間を設定してください。


Imported Batch属性のポイント:

* ペアレントセグメントで定義されている場合、リアルタイムペイロードに含められます。
* RT構成で追加・削除できますが、リアルタイム取り込みで更新されることはなく、ペアレントセグメントの再実行でのみ値が更新されます。
* ペアレントセグメントからバッチ属性を削除し、RT構成を更新しないままだとエラーになります。必要に応じてペアレントセグメントに再追加して実行するか、ダミーテーブル/属性を作成してください。


属性設計のベストプラクティス:

* 属性/システム名の計画を行い、衝突を避けます。
* バッチ経路とリアルタイム経路の両方で属性更新をテストし、一貫性を確認します。
* 集計ロジックとウィンドウ期間を事前に定義します。


## ステップ4: プロファイル統合とIDステッチ

IDステッチは、バッチデータとリアルタイムデータをプロファイルレベルで統合し、複数の識別子（メール、クライアントIDなど）を単一の顧客ビューにまとめます。

IDステッチの設定方法:

* 「stitching keys」を定義します（例: `td_client_id`、`email`、`canonical_id`）。正規表現でのフィルタや、バッチ専用として「workflow only」を設定することも可能です。
* 構成を保存したら、利用可能なキーからプライマリキーを選択します。プライマリキーはペアレントセグメント内の全プロファイルで一意かつ安定している必要があります。
* プライマリキーを設定後、ワークフローを再起動しない限りステッチ処理は有効になりません。
* システムは最も古いIDをプライマリとして選択し、プロファイルを統合します。
* ステッチキーは最大200個まで定義できます。


ベストプラクティスと注意事項:

* イベントデータが提供するIDを計画し、バッチ経路とリアルタイム経路で整合させます。
* プライマリキーの設定は慎重に行ってください。稼働後に変更する場合は、システムの再実行が必要になります。


例:

* 新しいイベントにメールが含まれ、既存プロファイルが `td_client_id` で存在する場合、最も古いIDがプライマリとして統合されます。
* 除外値やフィルタを設定することで、テスト用・誤った識別子を無視できます。


## ステップ5: Audience Studioでのパーソナライゼーション構築と管理

イベントと属性を設定したら、Audience Studioでパーソナライゼーションロジックを構築・管理します。

新しいパーソナライゼーションの作成:

* 左側のサイドバーで親/マスターセグメントにアクセスします。
* 「Create」をクリックし、「Personalization」を選択して名前を付けます。
* パーソナライゼーションを開き、Personalization Canvasに進みます。


セクションを追加して条件とペイロードを設定:

* 各セクションには以下が含まれます。
  * Criteria: パーソナライゼーションを発火させる条件（例: 未知ユーザーの場合は「email is null」、既知ユーザーの場合は「email is not null」）。
  * Payload: 条件に一致した際に返すデータ。バッチ属性とリアルタイム属性を追加し、必要に応じてエイリアスやバッチセグメントを設定します。
  * ペイロードに機密扱いのリアルタイム属性またはインポート属性が含まれると、セクション名の横に感度アイコンが表示されます。


考慮事項:

* パーソナライゼーションで使用するイベントが、想定するトリガーと合致している必要があります。
* ステッチキーが正しく構成されていないと、属性伝播に問題が生じます。
* 下流のマッピング用に、各ペイロードフィールドにエイリアスを設定してください。
* SLA 100msを満たすため、ペイロードサイズは10KB未満、属性数は20個以下に抑えてください。
* バッチセグメントや属性を変更した場合は、親/マスターセグメントのワークフローを再実行し、最新の結果を反映させてください。


UIワークフローのヒント:

* 「Save payload」をクリックするとボタンが無効化されます。完了するには「Cancel」を2回押してから「Save & Launch」をクリックします。
* UIの読み込みに時間がかかる場合があります。必要に応じてリフレッシュしてください。


## ステップ6: API統合と実装例

このセクションでは、アプリケーションコードやデプロイ環境でRT 2.0パーソナライゼーションAPIを統合するための実装ガイドを紹介します。

APIエンドポイント形式:

* 米国リージョン: `https://us01.p13n.in.treasuredata.com/{YOUR_DB_NAME}/{tableName}`
  * `YOUR_DB_NAME`: ストリーミングイベントデータベース
  * `tableName`: 対象イベントを保持するテーブル


必要なヘッダー:

* `"Content-Type": "application/vnd.treasuredata.v1+json"`
* `"Authorization": "TD1 [TD_API_KEY]"`
* `"WP13n-Token": "[YOUR_ACCOUNT_INSTANCE_ID]/[REACTOR_INSTANCE_ID]/[RT_PERSONALIZATION_TOKEN]"`


リクエストボディ例（JSON）:


```json
{
  "td_client_id": "42a508e2-d9b1-4baa-9eb2-6c3fb8bd5e16",
  "td_url": "https://treasuredemos.com/retail/shop/women",
  "td_path": "/retail/shop/women",
  "product_name": "women’s-tank-top",
  "product_category": "women",
  "product_list": ["women’s-running-shoes", "kids’-hoodie", "women’s-tank-top"],
  "category_list": ["women", "kids"]
}
```

Node.js Lambda（サーバーサイド）でのAPIリクエスト例:


```javascript
jsconst fetch = require("node-fetch");
exports.lambdaHandler = async (event) => {
    try {
        const tableName = event.pathParameters?.tableName || null;
        const requestBody = event.body ? JSON.parse(event.body) : {};
        if (!tableName) {
            return { statusCode: 400, body: JSON.stringify({ error: "Missing tableName parameter" }) };
        }
        if (!requestBody.td_client_id) {
            return { statusCode: 400, body: JSON.stringify({ error: "Missing td_client_id" }) };
        }
        const response = await fetch(`https://us01.p13n.in.treasuredata.com/{YOUR_DB_NAME}/${tableName}`, {
            method: "POST",
            headers: {
                "Content-Type": "application/vnd.treasuredata.v1+json",
                "Authorization": `TD1 ${process.env.TD_API_KEY}`,
                "WP13n-Token": process.env.PERSONALIZATION_TOKEN
            },
            body: JSON.stringify(requestBody)
        });
        if (!response.ok) {
            throw new Error(`Treasure Data API returned status: ${response.status}`);
        }
        const data = await response.json();
        return { statusCode: 200, body: JSON.stringify(data) };
    } catch (error) {
        return { statusCode: 500, body: JSON.stringify({ error: error.message }) };
    }
};
```

Personalization APIレスポンスの例（非機密属性を含む場合）:


```json
{
  "offers": {
    "Welcome to our website!": {
      "attributes": {
        "welcome_message": "Welcome to our website! Enjoy your shopping!"
      }
    },
    "Silver rewards just for you!": {
      "attributes": {
        "real-time_single_attribute_first_name": "John",
        "real-time_counter_attribute_total_purchase": 28700,
        "real-time_list_attribute_items_purchased": [],
        "order_summary": "Here is your order summary!",
        "thank_you_message": "Thanks you for shopping with us!",
        "promotions_message": "Enjoy your 15% discount for your next purchase!"
      }
    },
    "Golden membership offer!": {
      "attributes": {
        "customer_name": "John",
        "order_total": 28700,
        "list_reactor_offers_ak_1 - aggr1_path_list_reactor_offers_ak_1": [
          "/06130004",
          "/promotion",
          "/silver"
        ],
        "rewards_message": "You have spent $300 on eligible purchases. Your Rewards Certificate(s) are ready for you!"
      }
    }
  }
}
```

Personalization APIレスポンスの例（機密属性が除外される場合）:


```json
{
  "offers": {}
}
```

デプロイ手順:

* ローカルで依存パッケージをインストールします（`npm install node-fetch`）。
* パッケージ化してLambdaにアップロードします。
* APIキーとパーソナライゼーショントークンをLambdaの環境変数として設定します。
* API GatewayでPOSTエンドポイントを作成し、Lambdaをトリガーします。


クライアントサイドからのFetch例:


```javascript
jsconst apiUrl = "https://{your-api-id}.execute-api.{region}.amazonaws.com/dev/fetch-treasure-data/user_data";
fetch(apiUrl, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        td_client_id: "12345",
        email: "user@example.com",
        td_url: "https://example.com/",
        td_path: "/"
    })
})
.then(response => response.json())
.then(data => console.log("Personalization Response:", data));
```

以上で、シンプルなWebアプリケーションを対象にリアルタイムパーソナライゼーション2.0（サーバーサイド）を構成する方法の紹介は終了です。