

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# AWS IoT TwinMaker 時系列データコネクタの開発
<a name="time-series-data-connectors"></a>

このセクションでは、時系列データコネクタを開発する方法を段階的に説明します。さらに、3D モデル、エンティティ、コンポーネント、アラーム、およびコネクタを含む、クッキーファクトリーサンプル全体に基づく時系列データコネクタの例を紹介します。クッキーファクトリのサンプルソースは、[AWS IoT TwinMaker サンプル GitHub リポジトリ]( https://github.com/aws-samples/aws-iot-twinmaker-samples)にあります。

**Topics**
+ [AWS IoT TwinMaker 時系列データコネクタの前提条件](#time-series-data-connectors-prereqs)
+ [時系列データコネクタの背景](#time-series-data-connectors-background)
+ [時系列データコネクタの開発](#time-series-data-connectors-develop)
+ [データコネクタの改善](#time-series-data-connectors-improve)
+ [コネクタのテスト](#time-series-data-connectors-test)
+ [セキュリティ](#time-series-data-connectors-security)
+ [AWS IoT TwinMaker リソースの作成](#time-series-data-connectors-resources)
+ [次のステップ](#time-series-data-connectors-wn)
+ [AWS IoT TwinMaker クッキー ファクトリ時系列コネクタの例](time-series-data-connectors-example.md)

## AWS IoT TwinMaker 時系列データコネクタの前提条件
<a name="time-series-data-connectors-prereqs"></a>

時系列データコネクタを開発する前に、次のタスクを完了することをお勧めします。
+ [AWS IoT TwinMaker ワークスペース](twinmaker-gs-workspace.md)を作成します。
+ [AWS IoT TwinMaker コンポーネントタイプ](https://docs.aws.amazon.com//iot-twinmaker/latest/guide/twinmaker-component-types.html)を作成します。
+ [AWS IoT TwinMaker エンティティ](https://docs.aws.amazon.com//iot-twinmaker/latest/guide/twinmaker-gs-entity.html)を作成します。
+ (オプション) 「[コンポーネントタイプの使用と作成](https://docs.aws.amazon.com//iot-twinmaker/latest/guide/twinmaker-component-types.htm)」を参照してください。
+ (オプション) 「[AWS IoT TwinMaker データコネクタインターフェイス](https://docs.aws.amazon.com//iot-twinmaker/latest/guide/data-connector-interface.html)」を読んで、 AWS IoT TwinMaker データコネクタの一般的な理解を深めてください。

**注記**  
完全に実装されたコネクタの例については、クッキーファクトリーの実装例を参照してください。

## 時系列データコネクタの背景
<a name="time-series-data-connectors-background"></a>

クッキーミキサーと水タンクを備えた工場で働いているところを想像してみてください。これらの物理エンティティの AWS IoT TwinMaker デジタルツインを構築して、さまざまな時系列メトリクスをチェックして運用状態をモニタリングできるようにしたいと考えています。

現場のセンサをセットアップし、測定データを既に Timestream データベースにストリーミングしています。オーバーヘッドを最小限に抑えながら、 AWS IoT TwinMaker で測定データを表示し、整理できるようにしたいものです。このタスクは時系列データコネクタを使用して実行できます。以下の画像は、時系列コネクタを使用して入力されるテレメトリテーブルの例を示しています。

![\[アセット ID、タイプ、メジャー、時間、値を含むテレメトリテーブルデータの例。\]](http://docs.aws.amazon.com/ja_jp/iot-twinmaker/latest/guide/images/image(1).png)


このスクリーンショットで使用されているデータセットと Timestream テーブルは、[AWS IoT TwinMaker サンプル GitHub リポジトリ](https://github.com/aws-samples/aws-iot-twinmaker-samples)にあります。前のスクリーンショットに示されている結果を生成する、実装用の[クッキーファクトリのサンプルコネクタ](time-series-data-connectors-example.md)も参照してください。

### 時系列データコネクタのデータフロー
<a name="time-series-data-connectors-dataflow"></a>

データプレーンクエリの場合、 はコンポーネントとコンポーネントタイプの定義からコンポーネントとコンポーネントタイプの両方の対応するプロパティ AWS IoT TwinMaker を取得します。 は、クエリ内の API クエリパラメータとともにプロパティを AWS Lambda 関数 AWS IoT TwinMaker に転送します。

AWS IoT TwinMaker は Lambda 関数を使用してデータソースからのクエリにアクセスして解決し、それらのクエリの結果を返します。Lambda 関数は、データプレーンのコンポーネントとコンポーネントタイプのプロパティを使用して最初のリクエストを解決します。

Lambda クエリの結果は API レスポンスにマッピングされ、ユーザーに返されます。

AWS IoT TwinMaker はデータコネクタインターフェイスを定義し、それを使用して Lambda 関数とやり取りします。データコネクタを使用すると、データ移行の手間をかけずに AWS IoT TwinMaker API からデータソースをクエリできます。次の図は、前の段落で説明した基本的なデータフローの概要を示しています。

![\[API リクエストとレスポンスは、データソースにアクセスする 3P Connector リクエストとレスポンスを使用します。\]](http://docs.aws.amazon.com/ja_jp/iot-twinmaker/latest/guide/images/data_flow.drawio.png)


## 時系列データコネクタの開発
<a name="time-series-data-connectors-develop"></a>

以下の手順は、機能的な時系列データコネクタまで段階的に構築する開発モデルの概要を示しています。基本的なステップは次のとおりです。

1. **有効な基本コンポーネントタイプの作成**

   コンポーネントタイプでは、コンポーネント間で共有される共通のプロパティを定義します。コンポーネントタイプの定義について詳しくは、「[コンポーネントタイプの使用と作成](https://docs.aws.amazon.com//iot-twinmaker/latest/guide/twinmaker-component-types.html)」を参照してください。

   AWS IoT TwinMaker は[エンティティコンポーネントモデリングパターン](https://en.wikipedia.org/wiki/Entity_component_system)を使用するため、各コンポーネントはエンティティにアタッチされます。各物理項目をエンティティとしてモデル化し、独自のコンポーネントタイプを持つ異なるデータソースをモデル化することをお勧めします。

   次の例では、1 つのプロパティを使用した Timestream テンプレートの例を示します。

   ```
   {"componentTypeId": "com.example.timestream-telemetry",
       "workspaceId": "MyWorkspace",
       "functions": {
           "dataReader": {
               "implementedBy": {
                   "lambda": {
                       "arn": "lambdaArn"
                   }
               }
           }
       },
       "propertyDefinitions": {
           "telemetryType": {
               "dataType": { "type": "STRING" },
               "isExternalId": false,
               "isStoredExternally": false,
               "isTimeSeries": false,
               "isRequiredInEntity": true
           },
           "telemetryId": {
               "dataType": { "type": "STRING" },
               "isExternalId": true,
               "isStoredExternally": false,
               "isTimeSeries": false,
               "isRequiredInEntity": true
           },
           "Temperature": {
               "dataType": { "type": "DOUBLE" },
               "isExternalId": false,
               "isTimeSeries": true,
               "isStoredExternally": true,
               "isRequiredInEntity": false
           }
       }
   }
   ```

   コンポーネントタイプの主な要素は次のとおりです。
   + `telemetryId` プロパティは、対応するデータソース内の物理項目の一意のキーを識別します。データコネクタは、このプロパティをフィルター条件として使用して、指定された項目に関連付けられた値のみをクエリします。さらに、データプレーン API レスポンスに `telemetryId` プロパティ値を含めると、クライアント側が ID を取得し、必要に応じて逆引きを行うことができます。
   + `lambdaArn` フィールドは、コンポーネントタイプが関与する Lambda 関数を識別します。
   + `isRequiredInEntity` フラグは ID の作成を強制します。このフラグは、コンポーネントの作成時に項目の ID もインスタンス化するために必要です。
   + `TelemetryId` は外部 ID としてコンポーネントタイプに追加されるため、項目は Timestream テーブルで識別できます。

1. **そのコンポーネントタイプでコンポーネントを作成**

   作成したコンポーネントタイプを使用するには、コンポーネントを作成して、データを取得したいエンティティにアタッチする必要があります。以下のステップでは、そのコンポーネントを作成するプロセスを詳しく説明します。

   1. [AWS IoT TwinMaker コンソール](https://console.aws.amazon.com/iottwinmaker/)に移動します。

   1. コンポーネントタイプを作成したのと同じワークスペースを選択して開きます。

   1. エンティティのページに移動します。

   1. 新しいエンティティを作成するか、テーブルから既存のエンティティを選択します。

   1. 使用するエンティティを選択したら、**[コンポーネントの追加]** を選択して **[コンポーネントの追加]** ページを開きます。

   1. コンポーネントに名前を付け、**[タイプ]** には **[1] でテンプレートで作成したコンポーネントタイプを選択します。有効な基本コンポーネントタイプを作成します**。

1. **コンポーネントタイプを Lambda コネクタに呼び出すようにする**

   Lambda コネクタは、データソースにアクセスし、入力に基づいてクエリステートメントを生成し、それをデータソースに転送する必要があります。次の例は、これを行う JSON リクエストテンプレートを示しています。

   ```
   {
     "workspaceId": "MyWorkspace",
     "entityId": "MyEntity",
     "componentName": "TelemetryData",
     "selectedProperties": ["Temperature"],
     "startTime": "2022-08-25T00:00:00Z",
     "endTime": "2022-08-25T00:00:05Z",
     "maxResults": 3,
     "orderByTime": "ASCENDING",
     "properties": {
         "telemetryType": {
             "definition": {
                 "dataType": { "type": "STRING" },
                 "isExternalId": false,
                 "isFinal": false,
                 "isImported": false,
                 "isInherited": false,
                 "isRequiredInEntity": false,
                 "isStoredExternally": false,
                 "isTimeSeries": false
             },
             "value": {
                 "stringValue": "Mixer"
             }
         },
         "telemetryId": {
             "definition": {
                 "dataType": { "type": "STRING" },
                 "isExternalId": true,
                 "isFinal": true,
                 "isImported": false,
                 "isInherited": false,
                 "isRequiredInEntity": true,
                 "isStoredExternally": false,
                 "isTimeSeries": false
             },
             "value": {
                 "stringValue": "item_A001"
             }
         },
         "Temperature": {
             "definition": {
                 "dataType": { "type": "DOUBLE", },
                 "isExternalId": false,
                 "isFinal": false,
                 "isImported": true,
                 "isInherited": false,
                 "isRequiredInEntity": false,
                 "isStoredExternally": false,
                 "isTimeSeries": true
             }
         }
     }
   }
   ```

   リクエストの主要な要素:
   + `selectedProperties` は、Timestream 計測の対象となるプロパティを入力するリストです。
   + `startDateTime`、`startTime`、`EndDateTime`、`endTime`の各フィールドでは、リクエストの時間範囲を指定します。これにより、返される測定値のサンプル範囲が決まります。
   + `entityId` は、データのクエリ元となるエンティティの名前です。
   + `componentName` は、データのクエリ元となるコンポーネントの名前です。
   + `orderByTime` フィールドを使用して、結果が表示される順序を整理します。

   前述のリクエスト例では、特定の項目の特定の時間枠内に、選択したプロパティの一連のサンプルが、選択した時系列で取得されることを想定しています。レスポンスステートメントは、以下のように要約できます。

   ```
   {
     "propertyValues": [
       {
         "entityPropertyReference": {
           "entityId": "MyEntity",
           "componentName": "TelemetryData",
           "propertyName": "Temperature"
         },
         "values": [
           {
             "time": "2022-08-25T00:00:00Z",
             "value": {
               "doubleValue": 588.168
             }
           },
           {
             "time": "2022-08-25T00:00:01Z",
             "value": {
               "doubleValue": 592.4224
             }
           },
           {
             "time": "2022-08-25T00:00:02Z",
             "value": {
               "doubleValue": 594.9383
             }
           }
         ]
       }
     ],
     "nextToken": "..."
   }
   ```

1. **コンポーネントタイプを 2 つのプロパティを持つように更新**

   次の JSON テンプレートは、2 つのプロパティを持つ有効なコンポーネントタイプを示しています。

   ```
   {
       "componentTypeId": "com.example.timestream-telemetry",
       "workspaceId": "MyWorkspace",
       "functions": {
           "dataReader": {
               "implementedBy": {
                   "lambda": {
                       "arn": "lambdaArn"
                   }
               }
           }
       },
       "propertyDefinitions": {
           "telemetryType": {
               "dataType": { "type": "STRING" },
               "isExternalId": false,
               "isStoredExternally": false,
               "isTimeSeries": false,
               "isRequiredInEntity": true
           },
           "telemetryId": {
               "dataType": { "type": "STRING" },
               "isExternalId": true,
               "isStoredExternally": false,
               "isTimeSeries": false,
               "isRequiredInEntity": true
           },
           "Temperature": {
               "dataType": { "type": "DOUBLE" },
               "isExternalId": false,
               "isTimeSeries": true,
               "isStoredExternally": true,
               "isRequiredInEntity": false
           },
           "RPM": {
               "dataType": { "type": "DOUBLE" },
               "isExternalId": false,
               "isTimeSeries": true,
               "isStoredExternally": true,
               "isRequiredInEntity": false
           }
       }
   }
   ```

1. **2 番目のプロパティを処理するように Lambda コネクタを更新**

    AWS IoT TwinMaker データプレーン API は、1 つのリクエストで複数のプロパティのクエリをサポートし、 のリストを指定してコネクタへの 1 つのリクエスト AWS IoT TwinMaker に従います`selectedProperties`。

   次の JSON リクエストは、2 つのプロパティのリクエストをサポートするようになった変更後のテンプレートを示しています。

   ```
   {
     "workspaceId": "MyWorkspace",
     "entityId": "MyEntity",
     "componentName": "TelemetryData",
     "selectedProperties": ["Temperature", "RPM"],
     "startTime": "2022-08-25T00:00:00Z",
     "endTime": "2022-08-25T00:00:05Z",
     "maxResults": 3,
     "orderByTime": "ASCENDING",
     "properties": {
         "telemetryType": {
             "definition": {
                 "dataType": { "type": "STRING" },
                 "isExternalId": false,
                 "isFinal": false,
                 "isImported": false,
                 "isInherited": false,
                 "isRequiredInEntity": false,
                 "isStoredExternally": false,
                 "isTimeSeries": false
             },
             "value": {
                 "stringValue": "Mixer"
             }
         },
         "telemetryId": {
             "definition": {
                 "dataType": { "type": "STRING" },
                 "isExternalId": true,
                 "isFinal": true,
                 "isImported": false,
                 "isInherited": false,
                 "isRequiredInEntity": true,
                 "isStoredExternally": false,
                 "isTimeSeries": false
             },
             "value": {
                 "stringValue": "item_A001"
             }
         },
         "Temperature": {
             "definition": {
                 "dataType": { "type": "DOUBLE" },
                 "isExternalId": false,
                 "isFinal": false,
                 "isImported": true,
                 "isInherited": false,
                 "isRequiredInEntity": false,
                 "isStoredExternally": false,
                 "isTimeSeries": true
             }
         },
         "RPM": {
             "definition": {
                 "dataType": { "type": "DOUBLE" },
                 "isExternalId": false,
                 "isFinal": false,
                 "isImported": true,
                 "isInherited": false,
                 "isRequiredInEntity": false,
                 "isStoredExternally": false,
                 "isTimeSeries": true
             }
         }
     }
   }
   ```

   同様に、次の例に示すように、対応するレスポンスも更新されます。

   ```
   {
     "propertyValues": [
       {
         "entityPropertyReference": {
           "entityId": "MyEntity",
           "componentName": "TelemetryData",
           "propertyName": "Temperature"
         },
         "values": [
           {
             "time": "2022-08-25T00:00:00Z",
             "value": {
               "doubleValue": 588.168
             }
           },
           {
             "time": "2022-08-25T00:00:01Z",
             "value": {
               "doubleValue": 592.4224
             }
           },
           {
             "time": "2022-08-25T00:00:02Z",
             "value": {
               "doubleValue": 594.9383
             }
           }
         ]
       },
       {
         "entityPropertyReference": {
           "entityId": "MyEntity",
           "componentName": "TelemetryData",
           "propertyName": "RPM"
         },
         "values": [
           {
             "time": "2022-08-25T00:00:00Z",
             "value": {
               "doubleValue": 59
             }
           },
           {
             "time": "2022-08-25T00:00:01Z",
             "value": {
               "doubleValue": 60
             }
           },
           {
             "time": "2022-08-25T00:00:02Z",
             "value": {
               "doubleValue": 60
             }
           }
         ]
       }
     ],
     "nextToken": "..."
   }
   ```
**注記**  
この場合のページ分割に関しては、リクエスト内のページサイズはすべてのプロパティに適用されます。つまり、クエリのプロパティが 5 つで、ページサイズが 100 の場合、ソースに十分なデータポイントがあれば、プロパティごとに 100 データポイント、合計 500 データポイントが表示されるはずです。

   実装例については、GitHub の「[Snowflake コネクタサンプル](https://github.com/aws-samples/aws-iot-twinmaker-samples-snowflake/blob/main/src/modules/snowflake/data-connector/lambda_connectors/data_reader_by_entity.py)」を参照してください。

## データコネクタの改善
<a name="time-series-data-connectors-improve"></a>



### 例外処理
<a name="time-series-data-connectors-handle-exceptions"></a>

Lambda コネクタが例外をスローしても安全です。データプレーン API コールでは、 AWS IoT TwinMaker サービスは Lambda 関数がレスポンスを返すのを待ちます。コネクタ実装が例外をスローする場合、 は例外タイプ AWS IoT TwinMaker を に変換し`ConnectorFailure`、API クライアントがコネクタ内で問題が発生したことを認識できるようにします。

### ページネーションの処理
<a name="time-series-data-connectors-handle-pagination"></a>

この例では、Timestream はページネーションをネイティブにサポートする[ユーティリティ関数](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/timestream-query.html#TimestreamQuery.Client.query)を提供しています。ただし、SQL などの他のクエリインターフェイスでは、効率的なページネーションアルゴリズムを実装するために余分な労力が必要になる場合があります。SQL インターフェイスでページ分割を処理する [Snowflake](https://github.com/aws-samples/aws-iot-twinmaker-samples-snowflake/blob/main/src/modules/snowflake/data-connector/lambda_connectors/data_reader_by_entity.py) コネクタの例があります。

コネクタレスポンスインターフェイス AWS IoT TwinMaker を介して新しいトークンが に返されると、トークンは API クライアントに返される前に暗号化されます。トークンが別のリクエストに含まれている場合、 は Lambda コネクタに転送する前にトークンを AWS IoT TwinMaker 復号します。トークンに機密情報を追加しないことをお勧めします。

## コネクタのテスト
<a name="time-series-data-connectors-test"></a>

コネクタをコンポーネントタイプにリンクした後でも実装を更新することはできますが、 AWS IoT TwinMakerとインテグレートする前に Lambda コネクタを検証することを強くお勧めします。

Lambda コネクタをテストするには複数の方法があります。Lambda コンソールで Lambda コネクタをテストすることも、 AWS CDKでローカルにテストすることもできます。

Lambda 関数のテストの詳細については、[「Lambda 関数のテスト](https://docs.aws.amazon.com//lambda/latest/dg/testing-functions.html)」および[「アプリケーションのローカルテスト」を参照してください AWS CDK](https://docs.aws.amazon.com//serverless-application-model/latest/developerguide/serverless-cdk-testing.html)。

## セキュリティ
<a name="time-series-data-connectors-security"></a>

Timestream のセキュリティベストプラクティスに関するドキュメントについては、「[Timestream のセキュリティ](https://docs.aws.amazon.com//timestream/latest/developerguide/security.html)」を参照してください。

SQL インジェクション防止の例については、 AWS IoT TwinMaker サンプル GitHub リポジトリの次の [Python スクリプト](https://github.com/aws-samples/aws-iot-twinmaker-samples/blob/main/src/libs/udq_helper_utils/udq_utils/sql_detector.py)を参照してください。

## AWS IoT TwinMaker リソースの作成
<a name="time-series-data-connectors-resources"></a>

Lambda 関数を実装したら、[AWS IoT TwinMaker コンソール](https://console.aws.amazon.com/iottwinmaker/)または API を使用して、コンポーネントタイプ、エンティティ、コンポーネントなどの AWS IoT TwinMaker リソースを作成できます。

**注記**  
GitHub サンプルのセットアップ手順に従うと、すべての AWS IoT TwinMaker リソースが自動的に使用可能になります。コンポーネントのタイプ定義は[AWS IoT TwinMaker GitHub サンプル](https://github.com/aws-samples/aws-iot-twinmaker-samples/tree/main/src/workspaces/cookiefactory/component_types)で確認できます。コンポーネントタイプがコンポーネントによって一度使用されると、そのコンポーネントタイプのプロパティ定義と関数は更新できません。

### インテグレーションテスト
<a name="time-series-data-connectors-resources-testing"></a>

と統合されたテスト AWS IoT TwinMaker を行い、データプレーンクエリがend-to-endで機能することを確認することをお勧めします。これは [GetPropertyValueHistory](https://docs.aws.amazon.com//iot-twinmaker/latest/apireference/API_GetPropertyValueHistory.html) を使用して実行することも、[AWS IoT TwinMaker コンソール](https://console.aws.amazon.com/iottwinmaker/)で簡単に実行することもできます。

![\[TwinMaker コンポーネント情報コンソールページには、コンポーネントの名前、タイプ、ステータスなどが表示されます。\]](http://docs.aws.amazon.com/ja_jp/iot-twinmaker/latest/guide/images/image(3).png)


 AWS IoT TwinMaker コンソールでコンポーネント**の詳細**に移動し、**テスト**の下にコンポーネント内のすべてのプロパティが一覧表示されます。コンソールの **[テスト]** エリアでは、時系列プロパティだけでなく、時系列プロパティ以外のプロパティもテストできます。時系列プロパティでは、[GetPropertyValueHistory](https://docs.aws.amazon.com//iot-twinmaker/latest/apireference/API_GetPropertyValueHistory.html) API を使用でき、non-time-seriesプロパティでは [ GetPropertyValue](https://docs.aws.amazon.com//iot-twinmaker/latest/apireference/API_GetPropertyValue.html) API を使用することもできます。Lambda コネクタが複数のプロパティクエリをサポートしている場合、複数のプロパティを選択できます。

![\[コンポーネントのテストを示す TwinMaker コンポーネント情報コンソールページの一部。\]](http://docs.aws.amazon.com/ja_jp/iot-twinmaker/latest/guide/images/image(4).png)


## 次のステップ
<a name="time-series-data-connectors-wn"></a>

[AWS IoT TwinMaker Grafana ダッシュボード](https://docs.aws.amazon.com//iot-twinmaker/latest/guide/grafana-integration.html)を設定してメトリクスを視覚化できるようになりました。また、[AWS IoT TwinMaker サンプル GitHub リポジトリ](https://github.com/aws-samples/aws-iot-twinmaker-samples/tree/main/src/modules/s3)にある他のデータコネクタサンプルを調べて、ユースケースに合っているかどうかを確認することもできます。

# AWS IoT TwinMaker クッキー ファクトリ時系列コネクタの例
<a name="time-series-data-connectors-example"></a>

[クッキーファクトリの Lambda 関数の完全なコード](https://github.com/aws-samples/aws-iot-twinmaker-samples/blob/main/src/modules/timestream_telemetry/lambda_function/udq_data_reader.py)は GitHub で公開されています。コネクタをコンポーネントタイプにリンクした後でも実装を更新することはできますが、 AWS IoT TwinMakerとインテグレートする前に Lambda コネクタを検証することを強くお勧めします。Lambda 関数のテストは、Lambda コンソールで行うか、 AWS CDKのローカルで行います。Lambda 関数のテストの詳細については、[「Lambda 関数のテスト](https://docs.aws.amazon.com//lambda/latest/dg/testing-functions.html)」および[「アプリケーションのローカルテスト」を参照してください AWS CDK](https://docs.aws.amazon.com//serverless-application-model/latest/developerguide/serverless-cdk-testing.html)。

## クッキーファクトリのコンポーネントタイプの例
<a name="time-series-data-connectors-example-ct"></a>

コンポーネントタイプでは、コンポーネント間で共有される共通のプロパティを定義します。Cookie Factory の例では、同じタイプの物理コンポーネントが同じ測定値を共有するため、コンポーネントタイプで測定値スキーマを定義できます。一例として、以下の例ではミキサータイプを定義しています。

```
{
    "componentTypeId": "com.example.cookiefactory.mixer"
    "propertyDefinitions": {
        "RPM": {
            "dataType": { "type": "DOUBLE" },
            "isTimeSeries": true,
            "isRequiredInEntity": false,
            "isExternalId": false,
            "isStoredExternally": true
        },
        "Temperature": {
            "dataType": { "type": "DOUBLE" },
            "isTimeSeries": true,
            "isRequiredInEntity": false,
            "isExternalId": false,
            "isStoredExternally": true
        }
    }
}
```

たとえば、物理コンポーネントには Timestream データベースの測定値、SQL データベースのメンテナンスレコード、アラームシステムのアラームデータが含まれる場合があります。複数のコンポーネントを作成してエンティティに関連付けると、さまざまなデータソースがエンティティにリンクされ、エンティティコンポーネントグラフにデータが入力されます。このコンテキストでは、各コンポーネントには、対応するデータソース内のコンポーネントの一意のキーを識別するための `telemetryId`プロパティが必要です。`telemetryId` プロパティを指定すると、2 つの利点があります。 プロパティをフィルター条件としてデータコネクタで使用して、特定のコンポーネントの値をクエリできます。また、データプレーン API レスポンスに `telemetryId`プロパティ値を含めると、クライアント側は ID を受け取り、必要に応じて逆引き検索を実行できます。

`TelemetryId` を外部 ID としてコンポーネントタイプに追加すると、`TimeStream`テーブル内のコンポーネントが識別されます。

```
{
    "componentTypeId": "com.example.cookiefactory.mixer"
    "propertyDefinitions": {
        "telemetryId": {
            "dataType": { "type": "STRING" },
            "isTimeSeries": false,
            "isRequiredInEntity": true,
            "isExternalId": true,
            "isStoredExternally": false
        },
        "RPM": {
            "dataType": { "type": "DOUBLE" },
            "isTimeSeries": true,
            "isRequiredInEntity": false,
            "isExternalId": false,
            "isStoredExternally": true
        },
        "Temperature": {
            "dataType": { "type": "DOUBLE" },
            "isTimeSeries": true,
            "isRequiredInEntity": false,
            "isExternalId": false,
            "isStoredExternally": true
        }
    }
}
```

同様に、以下の JSON の例に示すように、`WaterTank` のコンポーネントタイプがあります。

```
{
  "componentTypeId": "com.example.cookiefactory.watertank",
  "propertyDefinitions": {
    "flowRate1": {
      "dataType": { "type": "DOUBLE" },
      "isTimeSeries": true,
      "isRequiredInEntity": false,
      "isExternalId": false,
      "isStoredExternally": true
    },
    "flowrate2": {
      "dataType": { "type": "DOUBLE" },
      "isTimeSeries": true,
      "isRequiredInEntity": false,
      "isExternalId": false,
      "isStoredExternally": true
    },
    "tankVolume1": {
      "dataType": { "type": "DOUBLE" },
      "isTimeSeries": true,
      "isRequiredInEntity": false,
      "isExternalId": false,
      "isStoredExternally": true
    },
    "tankVolume2": {
      "dataType": { "type": "DOUBLE" },
      "isTimeSeries": true,
      "isRequiredInEntity": false,
      "isExternalId": false,
      "isStoredExternally": true
    },
    "telemetryId": {
      "dataType": { "type": "STRING" },
      "isTimeSeries": false,
      "isRequiredInEntity": true,
      "isExternalId": true,
      "isStoredExternally": false
    }
  }
}
```

エンティティスコープ内のプロパティ値のクエリを目的としている場合、`TelemetryType` はコンポーネントタイプのオプションプロパティです。例については、[AWS IoT TwinMaker サンプル GitHub リポジトリ](https://github.com/aws-samples/aws-iot-twinmaker-samples/tree/main/src/workspaces/cookiefactory/component_types)で定義されているコンポーネントタイプを参照してください。同じテーブルにはアラームタイプも埋め込まれているので、`TelemetryType` が定義され、`TelemetryId` や `TelemetryType` などの共通プロパティを親コンポーネントタイプに抽出して、他の子タイプと共有できます。

## Lambda の例
<a name="time-series-data-connectors-example-lam"></a>

Lambda コネクタは、データソースにアクセスし、入力に基づいてクエリステートメントを生成し、それをデータソースに転送する必要があります。Lambda に送信されるリクエスト例を、次の JSON 例で示すことができます。

```
{
    'workspaceId': 'CookieFactory', 
    'selectedProperties': ['Temperature'], 
    'startDateTime': 1648796400, 
    'startTime': '2022-04-01T07:00:00.000Z', 
    'endDateTime': 1650610799, 
    'endTime': '2022-04-22T06:59:59.000Z', 
    'properties': {
        'telemetryId': {
            'definition': {
                'dataType': { 'type': 'STRING' },
                'isTimeSeries': False, 
                'isRequiredInEntity': True, 
                'isExternalId': True, 
                'isStoredExternally': False, 
                'isImported': False, 
                'isFinal': False, 
                'isInherited': True, 
            }, 
            'value': {
                'stringValue': 'Mixer_22_680b5b8e-1afe-4a77-87ab-834fbe5ba01e'
            }
        }
        'Temperature': {
            'definition': {
                'dataType': { 'type': 'DOUBLE' }, 
                'isTimeSeries': True, 
                'isRequiredInEntity': False, 
                'isExternalId': False, 
                'isStoredExternally': True, 
                'isImported': False, 
                'isFinal': False, 
                'isInherited': False
            }
        }
        'RPM': {
            'definition': {
                'dataType': { 'type': 'DOUBLE' }, 
                'isTimeSeries': True, 
                'isRequiredInEntity': False, 
                'isExternalId': False, 
                'isStoredExternally': True, 
                'isImported': False, 
                'isFinal':False, 
                'isInherited': False
            }
        }, 
    'entityId': 'Mixer_22_d133c9d0-472c-48bb-8f14-54f3890bc0fe', 
    'componentName': 'MixerComponent', 
    'maxResults': 100, 
    'orderByTime': 'ASCENDING'
}
```

Lambda 関数の目的は、特定のエンティティの履歴測定データをクエリすることです。 はコンポーネントプロパティマップ AWS IoT TwinMaker を提供するため、コンポーネント ID にインスタンス化された値を指定する必要があります。たとえば、コンポーネントタイプレベルのクエリ (アラームのユースケースで一般的) を処理し、ワークスペース内のすべてのコンポーネントのアラームステータスを返すには、プロパティマップにコンポーネントタイププロパティ定義があります。

最も簡単なケースとして、前述のリクエストと同様に、特定のコンポーネントの特定の時間枠内の一連の温度サンプルを昇順で取得する必要があります。このクエリステートメントは、以下のように要約できます。

```
...
SELECT measure_name, time, measure_value::double
    FROM {database_name}.{table_name} 
    WHERE time < from_iso8601_timestamp('{request.start_time}')
    AND time >= from_iso8601_timestamp('{request.end_time}')
    AND TelemetryId = '{telemetry_id}'
    AND measure_name = '{selected_property}'
    ORDER BY time {request.orderByTime}
...
```