Anleitung

Wir verwenden ein kleines Dataset von Kalev Leetaru, um die TimeSeries Insights API zu veranschaulichen. Das Dataset wird aus dem GDELT-Projekt abgeleitet, einem globalen Datenbanksystem zum Erfassen globaler Ereignisse und Medienabdeckung. Dieses Dataset enthält Entitätserwähnungen in Nachrichten-URLs im April 2019.

Ziele

  • Weitere Informationen zum Datenformat für TimeSeries Insights API.
  • Hier erfahren Sie, wie Sie Datasets erstellen, abfragen, aktualisieren und löschen.

Kosten

Für die Vorschau fallen keine Kosten an.

Hinweis

Richten Sie ein Cloud-Projekt ein und aktivieren Sie die Timeseries Insights API nach Erste Schritte.

Anleitungs-Dataset

Das Dataset enthält Entitätsanmerkungen von Standorten, Organisationen, Personen usw.

Die Timeseries Insights API akzeptiert Eingaben im JSON-Format. Ein Beispiel-Ereignis für dieses Dataset:

{
  "groupId":"-6180929807044612746",
  "dimensions":[{"name":"EntityORGANIZATION","stringVal":"Medina Gazette"}],
  "eventTime":"2019-04-05T08:00:00+00:00"
}

Jedes Ereignis muss ein eventTime-Feld für den Ereigniszeitstempel und ein Long-groupId-Wert haben, um zugehörige Ereignisse zu kennzeichnen. Ereigniseigenschaften sind im dimensions enthalten, von denen jedes eine name und einer der folgenden Werte hat: stringVal, boolVal, longVal oder doubleVal.

HINWEIS: Google Cloud APIs akzeptieren für JSON-Feldnamen sowohl den Kamelfall (z. B. camelCase) als auch die Schleuse (z. B. snake_case). Die Dokumentation wird hauptsächlich als Kamel geschrieben.

HINWEIS: Da lange JSON-Werte (Zahlen) Gleitkommawerte mit nur genauen Genauigkeiten sind,groupId undlongVal sind maximal 53 Ziffern, wenn JSON Zahlen verwendet. Zur Bereitstellung von Int64-Daten muss der JSON-Wert als String in Anführungszeichen gesetzt werden. Eine groupId ist in der Regel eine numerische ID oder wird mit einer deterministischen Hash-Funktion generiert und erfüllt die obige Einschränkung.

HINWEIS:Die Felder name und stringVal sollten alphanumerische Werte sein, einschließlich '_'. Sonderzeichen wie das Leerzeichen werden nicht unterstützt.

HINWEIS:Beim Lesen aus einer statischen Google Cloud Storage-Datenquelle sollte jedes JSON-Ereignis wie folgt eine Zeile darstellen:

{"groupId":"-6180929807044612746","dimensions":[{"name":"EntityORGANIZATION","stringVal":"Medina Gazette"}],"eventTime":"2019-04-05T08:00:00+00:00"}

Datasets auflisten

projects.datasets.list zeigt alle Datasets unter ${PROJECT_ID} an. gcurl ist ein Alias und PROJECT_ID eine Umgebungsvariable, die beide unter Erste Schritte eingerichtet werden.

$ gcurl https://timeseriesinsights.googleapis.com/v1/projects/${PROJECT_ID}/datasets

Das Ergebnis ist ein JSON-String wie

{
  "datasets": [
    {
      "name": "example",
      "state": "LOADED",
      ...
    },
    {
      "name": "dataset_tutorial",
      "state": "LOADING",
      ...
    }
  ]
}

Die Ergebnisse zeigen die Datasets, die sich derzeit unter dem Projekt befinden. Das Feld state gibt an, ob das Dataset verwendet werden kann. Wenn ein Dataset gerade erstellt wird, befindet es sich im Status LOADING, bis die Indexierung abgeschlossen ist und dann in den Status LOADED wechselt. Wenn während der Erstellung und Indexierung Fehler auftreten, erhält sie den Status FAILED. Das Ergebnis enthält auch die vollständigen Dataset-Informationen aus der ursprünglichen Erstellungsanfrage.

Dataset erstellen

projects.datasets.create fügt dem Projekt ein neues Dataset hinzu.

$ gcurl -X POST -d @create.json https://timeseriesinsights.googleapis.com/v1/projects/${PROJECT}/datasets

Dabei enthält create.json Folgendes:

{
  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"}
  ]
}

Diese Anfrage erstellt ein Dataset mit dem Namen dataset_tutorial aus GCS dataSources, das Ereignisdaten im JSON-Format enthält. Nur in dataNames aufgeführte Dimensionen werden indexiert und vom System verwendet. Mit der Einstellung streaming=true akzeptiert das Dataset auch Streaming-Updates, nachdem die erste Indexierung abgeschlossen ist. Streaming-Updates, die älter als ttl sind, werden ignoriert.

Die Erstellungsanfrage gibt Erfolg zurück, wenn sie vom API-Server akzeptiert wird. Das Dataset befindet sich im Status LOADING, bis die Indexierung abgeschlossen ist. Der Status wird zu LOADED und akzeptiert Anfragen und Aktualisierungen, sofern vorhanden.

Abfrage-Dataset

projects.datasets.query führt eine Anomalieerkennung durch.

$ gcurl -X POST -d @query.json https://timeseriesinsights.googleapis.com/v1/projects/${PROJECT}/datasets/dataset_tutorial:query

Dabei enthält query.json Folgendes:

{
  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
}

Wir möchten herausfinden, ob Anomalien in den testedInterval für Segmente aufgetreten sind, die auf die von dimensionNames angegebenen Dimensionen aufgeteilt sind. Ein Slice ist eine Untermenge der Ereignisse im Dataset, bei denen einige ihrer Dimensionen feste Werte haben. Beispielsweise ist {"name": "EntityLOCATION","stringVal": "Seine River"} ein Segment. Jede Teilmenge von dataNames aus der Dataset-Definition kann als dimensionNames verwendet werden. Die API aggregiert das Ereignis also über die nicht erwähnten Dimensionen. Dies ähnelt einem "Gruppieren nach"-Vorgang mit "count(*)" in SQL-Abfragen.

Ereignisse in den einzelnen Segmenten werden anhand von forecastParams.aggregatedDimension aggregiert. Ist dieses Feld leer, werden alle Ereignisse im Segment gezählt. Wenn das Feld nicht leer ist, erwarten wir, dass dieses Feld einen gültigen numerischen Dimensionsnamen in den Ereignissen dieses Segments enthält. Die numerischen Werte werden addiert, um die Zeitachse zu bilden.

Wir analysieren jedes Segment, um zu überprüfen, ob es sich um eine Anomalie handelt:

  1. Erstellen einer Zeitachse aus testedInterval.startTime - forecastParams.forecastHistory bis testedInterval.startTime + testedInterval.length, wobei jeder Datenpunkt ein Zeit-Bucket der Länge testedInterval.length ist und durch die Angabe von Ereignissen in diesem Bucket seinen Wert angibt. angegeben, wie durch den Parameter aggregatedDimension angegeben. Wenn die Zeitachsen nicht genügend Datenpunkte haben (wie im Parameter minDensity angegeben), wird sie nicht mehr analysiert.
  2. Nachdem wir die Zeitachse für das Segment berechnet haben, analysieren wir sie mithilfe gängiger Prognosetechniken. Mit dem ersten (100 - holdout)% der Zeitachse wird ein Vorhersagemodell trainiert und mit dem letzten holdout% die Modellqualität getestet. Anhand der Fehlermesswerte berechnen wir Konfidenzgrenzen für das getestete Intervall. Wenn der tatsächliche Wert außerhalb dieser Grenzwerte liegt, wird er als Anomalie gekennzeichnet. Mit den Parametern maxPositiveRelativeChange, maxNegativeRelativeChange und forecastExtraWeight können Sie festlegen, wie viel der tatsächliche Wert außerhalb der Grenzen liegen darf.

Das Abfrageergebnis sieht so aus:

{
  "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": [
      ...
    ]
  }
}

Sie enthält Anomalien und optional bewertete Slices, die nicht als Anomalien markiert wurden, im selben PrognosePrognose-Format. result gibt den Zeitpunkt der Anomalie, den tatsächlichen Wert und den Bereich der Prognosewerte an. trainingErrors und holdoutErrors zeigen zusätzliche Messwerte an, die zur Anomalieerkennung verwendet werden.

Streaming update

projects.datasets.appendEvents fügt Ereignisdatensätze im Streaming-Format hinzu, wenn die Anfrage zur Erstellung streaming: true enthält.

$ gcurl -X POST -d @append.json https://timeseriesinsights.googleapis.com/v1/projects/${PROJECT}/datasets/dataset_tutorial:appendEvents

Dabei enthält append.json Folgendes:

{
  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"
    }
  ]
}

Gestreamte Updates werden nahezu in Echtzeit indexiert, sodass Änderungen schnell in Abfrageergebnissen angezeigt werden können.

Dataset löschen

projects.datasets.delete markiert das Dataset zum Löschen.

$ gcurl -X DELETE https://timeseriesinsights.googleapis.com/v1/projects/${PROJECT}/datasets/dataset_tutorial

Die Anfrage wird sofort zurückgegeben und das Dataset akzeptiert keine weiteren Abfragen oder Updates. Es kann einige Zeit dauern, bis die Daten vollständig aus dem Dienst entfernt wurden. Danach wird für diese Datasets das Dataset nicht zurückgegeben.

Nächste Schritte

Weitere Beispiele finden Sie auf der GDELT-Website.