Kalev Leetaru 提供の小さなデータセットを使用して、Timeseries Insights API について説明します。 このデータセットは、世界のイベントとメディア カバレッジを追跡するグローバル データベース GDELT プロジェクトから派生しています。 このデータセットには、2019 年 4 月にニュースの URL で言及されているエンティティが含まれています。
目標
- Timeseries Insights API のデータ形式について学習します。
- データセットを作成、クエリ、更新、削除する方法を学習します。
料金
プレビューの費用はありません。
始める前に
スタートガイドに沿って Cloud プロジェクトを設定し、Timeseries Insights API を有効にします。
チュートリアル データセット
このデータセットには、場所、組織、人物などのエンティティのアノテーションが含まれます。
Timeseries Insights API は JSON 形式の入力を受け取ります。このデータセットのサンプル Event は次のとおりです。
{
"groupId":"-6180929807044612746",
"dimensions":[{"name":"EntityORGANIZATION","stringVal":"Medina Gazette"}],
"eventTime":"2019-04-05T08:00:00+00:00"
}
各イベントには、イベント タイムスタンプの eventTime
フィールドと、関連するイベントをマークするために長い groupId
を設定する必要があります。イベント プロパティは dimensions
として、それぞれ name
、stringVal
、boolVal
、longVal
、doubleVal
のいずれかを指定します。
注: Google Cloud APIs は、JSON フィールド名について、キャメルケース(camelCase
など)とスネークケース(snake_case
など)の両方を受け入れることができます。このドキュメントは主にキャメルケースとして記述されます。
注: JSON の長い値(数値)は実際には整数精度のみを持つ浮動小数点値であるため、JSON の場合、groupId
と longVal
の両方が事実上、53 桁のバイナリ値に制限されます。には数字を指定します。int64 データを提供するには、JSON 値を文字列として引用符で囲む必要があります。 通常、groupId
は数値 ID か、上述の制限を満たす決定論的ハッシュ関数を使用して生成されます。
注: name
フィールドと stringVal
フィールドは、'_'
を含む英数字である必要があります。スペースなどの特殊文字は使用できません。
注: 静的な Google Cloud Storage データソースから読み取る場合、各 JSON イベントは次のように 1 行に相当します。
{"groupId":"-6180929807044612746","dimensions":[{"name":"EntityORGANIZATION","stringVal":"Medina Gazette"}],"eventTime":"2019-04-05T08:00:00+00:00"}
データセットのリスト表示
projects.datasets.list は ${PROJECT_ID}
のすべてのデータセットを表示します。 gcurl
はエイリアスであり、PROJECT_ID
は両方ともスタートガイドで設定される環境変数です。
$ gcurl https://timeseriesinsights.googleapis.com/v1/projects/${PROJECT_ID}/datasets
結果は次の JSON 文字列です。
{
"datasets": [
{
"name": "example",
"state": "LOADED",
...
},
{
"name": "dataset_tutorial",
"state": "LOADING",
...
}
]
}
結果には、現在プロジェクトの下にあるデータセットが表示されます。 state
フィールドは、データセットを使用する準備ができているかどうかを示します。データセットの作成直後は、インデックス登録が完了するまで LOADING
状態になり、その後 LOADED
状態に移行します。作成およびインデックス登録中にエラーが発生した場合は、FAILED
状態になります。結果には、元の作成リクエストの完全なデータセット情報も含まれます。
データセットを作成
projects.datasets.create によって新しいデータセットがプロジェクトに追加されます。
$ gcurl -X POST -d @create.json https://timeseriesinsights.googleapis.com/v1/projects/${PROJECT}/datasets
create.json
には以下が含まれます。
{
name: "dataset_tutorial",
streaming: true,
ttl: "8640000s",
dataNames: [
"EntityCONSUMER_GOOD",
"EntityEVENT",
"EntityLOCATION",
"EntityORGANIZATION",
"EntityOTHER",
"EntityPERSON",
"EntityUNKNOWN",
"EntityWORK_OF_ART",
],
dataSources: [
{uri: "gs://data.gdeltproject.org/blog/2021-timeseries-insights-api/datasets/webnlp-201904.json"}
]
}
このリクエストは、GCS 形式のイベントデータを含む dataset_tutorial
という名前のデータセットを GCS dataSources
から作成します。dataNames
にリストされているディメンションのみがインデックスに登録され、システムによって使用されます。streaming=true
の場合、データセットは最初のインデックス登録が完了した後にストリーミング更新も受け入れます。ただし、ttl
より古いストリーミング更新は無視されます。
API サーバーで承認されると、作成リクエストによって成功が返されます。インデックスが完了するまでデータセットは LOADING
状態になり、ステータスは LOADED
になり、クエリと更新があればそれを受け入れます。
データセットのクエリ
projects.datasets.query は、異常検出クエリを実行します。
$ gcurl -X POST -d @query.json https://timeseriesinsights.googleapis.com/v1/projects/${PROJECT}/datasets/dataset_tutorial:query
query.json
には以下が含まれます。
{
dimensionNames: ["EntityLOCATION"],
testedInterval: {
startTime: "2019-04-15T00:00:00Z",
length: "86400s"
},
forecastParams: {
holdout: 10,
minDensity: 0,
forecastHistory: "1209600s",
maxPositiveRelativeChange: 1,
maxNegativeRelativeChange: 1,
forecastExtraWeight: 0,
seasonalityHint: "DAILY",
},
returnNonAnomalies: true
}
dimensionNames
で指定したディメンションに分割されたスライスの testedInterval
中に異常が起きたかどうかを検出する必要があります。スライスは、一部のディメンションで固定された値を使用して、データセット内のイベントのサブセットです。たとえば、{"name": "EntityLOCATION","stringVal": "Seine River"}
はスライスです。すべてのサブセットdataNames
として、dimensionNames
API は、説明されていないディメンションを介してイベントを集計します。これは、SQL クエリで「count(*)」を使用する「グループ別」オペレーションに似ています。
各スライスのイベントは forecastParams.aggregatedDimension
に基づいて集計されます。このフィールドが空の場合、単にスライスのすべてのイベントがカウントされます。空でない場合は、このフィールドでスライス内の有効な数値ディメンション名を想定します。数値を合計すると、時系列を形成します。
各スライスを分析して異常かどうかを判定します。
testedInterval.startTime - forecastParams.forecastHistory
からtestedInterval.startTime + testedInterval.length
までの時系列を形成する。各データポイントは長さtestedInterval.length
の時間バケットであり、そのバケット内のイベントを集計することで値が設定されます。aggregatedDimension
パラメータで指定されているとおりです。時系列で(minDensity
パラメータで指定された)データポイントが不十分な場合、分析が停止されます。- スライスの時系列を計算したら、一般的な予測手法を使用して分析します。時系列の最初の
(100 - holdout)%
を使用して予測モデルをトレーニングし、最後のholdout%
を使用してモデルの品質をテストします。エラー指標に基づいて、テストされた間隔の信頼区間を計算します。実際の値がこの範囲外の場合は、異常値としてマークします。実際の値の範囲外の境界を構成するには、maxPositiveRelativeChange
、maxNegativeRelativeChange
、forecastExtraWeight
パラメータを確認します。
クエリ結果は次のようになります。
{
"name": "projects/timeseries-staging/datasets/dataset_tutorial",
"anomalyDetectionResult": {
"anomalies": [
{
"dimensions": [
{
"name": "EntityLOCATION",
"stringVal": "Ile de la Cite"
}
],
"result": {
"holdoutErrors": {},
"trainingErrors": {
"mdape": 1,
"rmd": 1
},
"forecastStats": {
"density": "23",
"numAnomalies": 1
},
"testedIntervalActual": 440,
"testedIntervalForecastLowerBound": -1,
"testedIntervalForecastUpperBound": 1
},
"status": {}
},
{
"dimensions": [
{
"name": "EntityLOCATION",
"stringVal": "Seine"
}
],
"result": {
"holdoutErrors": {
"mdape": 0.1428571428571429,
"rmd": 0.1428571428571429
},
"trainingErrors": {
"mdape": 0.84615384615384626,
"rmd": 0.62459546925566334
},
"forecastStats": {
"density": "85",
"numAnomalies": 1
},
"testedIntervalActual": 586,
"testedIntervalForecast": 9.3333333333333339,
"testedIntervalForecastLowerBound": 8,
"testedIntervalForecastUpperBound": 10.666666666666668
},
"status": {}
},
{
"dimensions": [
{
"name": "EntityLOCATION",
"stringVal": "Notre Dame"
}
],
"result": {
"holdoutErrors": {
"mdape": 0.42857142857142855,
"rmd": 0.42857142857142855
},
"trainingErrors": {
"mdape": 0.19999999999999996,
"rmd": 0.65055762081784374
},
"forecastStats": {
"density": "100",
"numAnomalies": 1
},
"testedIntervalActual": 790,
"testedIntervalForecast": 7,
"testedIntervalForecastLowerBound": 4,
"testedIntervalForecastUpperBound": 10
},
"status": {}
},
...
],
"nonAnomalies": [
...
]
}
}
これには、同じ ForecastSlice 形式で異常に評価されたいくつかの異常と、必要に応じて評価されたスライスが含まれます。 result
には、異常値、実際の値、予測値の範囲が表示されます。trainingErrors
と holdoutErrors
は、異常検出に使用される追加の指標を示します。
ストリーミング更新
作成リクエストで streaming: true
が指定されている場合は、projects.datasets.appendEvents によって、ストリーミング レコードにイベントレコードが追加されます。
$ gcurl -X POST -d @append.json https://timeseriesinsights.googleapis.com/v1/projects/${PROJECT}/datasets/dataset_tutorial:appendEvents
append.json
には以下が含まれます。
{
events: [
{
"groupId":"-5379487492185488040",
"dimensions":[{"name":"EntityPERSON","stringVal":"Jason Marsalis"}],
"eventTime":"2021-06-01T15:45:00+00:00"
},{
"groupId":"1324354349507023708",
"dimensions":[{"name":"EntityORGANIZATION","stringVal":"WAFA"}],
"eventTime":"2021-06-02T04:00:00+00:00"
}
]
}
ストリーミングされた更新はほぼリアルタイムでインデックス登録されるため、変更はクエリ結果で迅速に返すことができます。
データセットの削除
projects.datasets.delete は削除するデータセットをマークします。
$ gcurl -X DELETE https://timeseriesinsights.googleapis.com/v1/projects/${PROJECT}/datasets/dataset_tutorial
リクエストはすぐに戻ります。データセットは追加のクエリと更新を受け入れません。データがサービスから完全に削除されるまでしばらく時間がかかる場合があります。それ以降は List データセットがこのデータセットを返しません。
次のステップ
その他の例は GDELT ウェブサイトをご覧ください。