16 Die Dokumenten-APIs: Das Fundament von OpenSearch

Stellen Sie sich OpenSearch als eine riesige, hochmoderne Bibliothek vor. Die Dokumenten-APIs sind dabei wie die grundlegenden Werkzeuge eines Bibliothekars - sie ermöglichen es uns, Dokumente einzustellen, zu finden, zu aktualisieren und bei Bedarf wieder zu entfernen. Doch anders als in einer physischen Bibliothek geschieht dies in Sekundenbruchteilen, auch bei Millionen von Dokumenten.

In diesem Kapitel tauchen wir tief in diese fundamentalen APIs ein. Wir werden nicht nur lernen, wie man sie verwendet, sondern auch verstehen, warum sie auf eine bestimmte Art und Weise arbeiten. Dieses Verständnis wird Ihnen helfen, OpenSearch optimal zu nutzen und typische Fallstricke zu vermeiden.

16.1 Dokumente in OpenSearch verstehen

Bevor wir uns die einzelnen APIs im Detail ansehen, ist es wichtig zu verstehen, was ein Dokument in OpenSearch eigentlich ist. Ein Dokument ist die grundlegende Einheit der Information - vergleichbar mit einer Zeile in einer relationalen Datenbank. Aber es ist viel flexibler: Ein Dokument ist ein JSON-Objekt, das beliebig strukturierte Daten enthalten kann.

Jedes Dokument hat drei wesentliche Eigenschaften:

16.2 Die Vier Grundoperationen

16.2.1 Dokumente Erstellen: Mehr als nur Speichern

Wenn wir ein Dokument in OpenSearch erstellen, passiert wesentlich mehr als eine einfache Speicherung. OpenSearch muss:

Schauen wir uns die beiden Hauptmethoden zur Dokumentenerstellung an:

# Methode 1: Mit eigener ID (PUT)
PUT /mein-index/_doc/123
{
  "titel": "Die Kunst des Programmierens",
  "autor": "Donald E. Knuth",
  "jahr": 1968
}

# Methode 2: Mit automatischer ID (POST)
POST /mein-index/_doc
{
  "titel": "Datenbanksysteme",
  "autor": "Alfred Kemper",
  "jahr": 2010
}

Der wichtige Unterschied: Bei PUT geben wir die ID vor - praktisch wenn wir IDs aus einem bestehenden System übernehmen. Bei POST generiert OpenSearch eine eindeutige ID - ideal für neue Datensätze.

16.2.2 Dokumente Abrufen: Die Kunst des effizienten Lesens

Das Abrufen von Dokumenten erscheint zunächst einfach:

GET /mein-index/_doc/123

Aber hinter den Kulissen ist es ein komplexer Prozess:

  1. OpenSearch berechnet zuerst, auf welchem Shard das Dokument liegt
  2. Es wählt dann eine der verfügbaren Repliken (inkl. Primary)
  3. Es prüft, ob das Dokument “realtime” verfügbar ist

Der letzte Punkt ist besonders interessant. OpenSearch bietet uns hier eine wichtige Entscheidung:

# Realtime (Standard)
GET /mein-index/_doc/123

# Nach letztem Refresh
GET /mein-index/_doc/123?realtime=false

Warum ist das wichtig? Realtime-Zugriffe sind immer aktuell, aber etwas langsamer. Nicht-Realtime-Zugriffe sind schneller, zeigen aber möglicherweise nicht die allerneuste Version. Diese Wahl zwischen Konsistenz und Performance ist typisch für verteilte Systeme.

16.2.3 Dokumente Aktualisieren: Sicher und Effizient

Updates in OpenSearch sind besonders interessant, weil sie atomar und optimistisch sind. Schauen wir uns ein Beispiel an:

POST /mein-index/_update/123
{
  "doc": {
    "jahr": 1969,
    "auflage": 2
  }
}

Was passiert hier intern? 1. OpenSearch liest das aktuelle Dokument 2. Führt die Änderungen durch 3. Löscht das alte Dokument 4. Indiziert das neue Dokument

Das klingt aufwändig - ist es auch. Deshalb gibt es zwei wichtige Optimierungen:

16.2.3.1 Scripted Updates

Für komplexe Änderungen, die vom aktuellen Zustand abhängen:

POST /mein-index/_update/123
{
  "script": {
    "source": "ctx._source.counter += params.increment",
    "lang": "painless",
    "params": {
      "increment": 1
    }
  }
}

16.2.3.2 Upserts

Eine elegante Kombination aus Update und Insert:

POST /mein-index/_update/123
{
  "doc": {
    "jahr": 1969
  },
  "upsert": {
    "titel": "Die Kunst des Programmierens",
    "autor": "Donald E. Knuth",
    "jahr": 1969
  }
}

Dies ist besonders nützlich in verteilten Systemen, wo wir nicht immer wissen, ob ein Dokument schon existiert.

16.2.4 Dokumente Löschen: Die versteckte Komplexität

Das Löschen erscheint zunächst trivial:

DELETE /mein-index/_doc/123

Aber auch hier gibt es wichtige Details zu beachten. OpenSearch markiert das Dokument zunächst nur als gelöscht - ein “soft delete”. Das eigentliche Entfernen geschieht später während der Segment-Zusammenführung. Dies erklärt auch, warum der Speicherplatz nicht sofort freigegeben wird.

16.3 Bulk-Operationen: Der Schlüssel zur Performance

Wenn wir viele Dokumente verarbeiten müssen, sind Einzeloperationen ineffizient. Hier kommen Bulk-Operationen ins Spiel:

POST _bulk
{"index":{"_index":"bücher","_id":"1"}}
{"titel":"Buch 1","autor":"Autor 1"}
{"index":{"_index":"bücher","_id":"2"}}
{"titel":"Buch 2","autor":"Autor 2"}

Wichtig zu verstehen:

Die optimale Batch-Größe liegt bei 5-15 MB. Größere Batches bringen meist keine weitere Verbesserung.

16.4 Fortgeschrittene Konzepte

16.4.1 Versionierung und Konkurrenzkontrolle

OpenSearch verwendet optimistische Konkurrenzkontrolle. Jedes Dokument hat eine Versionsnummer, die bei jeder Änderung erhöht wird:

# Version prüfen
PUT /mein-index/_doc/123?if_seq_no=10&if_primary_term=2
{
  "titel": "Neuer Titel"
}

Dies verhindert das “Lost Update Problem”, wenn mehrere Prozesse gleichzeitig ein Dokument aktualisieren wollen.

16.4.2 Routing: Der Schlüssel zur Skalierung

Standardmäßig berechnet OpenSearch den Shard für ein Dokument aus seiner ID. Wir können dies aber anpassen:

# Dokument mit Custom Routing erstellen
PUT /mein-index/_doc/123?routing=user123
{
  "titel": "Benutzerspezifisches Dokument"
}

# Gleiches Routing beim Abruf verwenden
GET /mein-index/_doc/123?routing=user123

Dies ist besonders nützlich, wenn zusammengehörige Dokumente auf dem gleichen Shard landen sollen.

16.5 Best Practices und häufige Fallstricke

16.5.1 Refresh-Strategien optimieren

Der refresh-Parameter ist mächtig, aber gefährlich:

# NICHT in Produktionsumgebungen
POST /mein-index/_doc?refresh=true

# Bessere Alternative
POST /mein-index/_doc?refresh=wait_for

16.5.2 Batch-Verarbeitung richtig einsetzen

16.5.3 Versionierung gezielt einsetzen

16.6 Die Kunst der Dokumentenverarbeitung

Die Dokumenten-APIs sind das Herzstück von OpenSearch. Sie richtig zu verstehen und einzusetzen ist entscheidend für:

Beachten Sie besonders:

  1. Wählen Sie die richtigen Operationen für Ihren Anwendungsfall
  2. Nutzen Sie Bulk-Operationen wo möglich
  3. Implementieren Sie robuste Fehlerbehandlung
  4. Optimieren Sie Refresh- und Routing-Strategien

Mit diesem Wissen sind Sie gut gerüstet, um OpenSearch effektiv in Ihren Anwendungen einzusetzen.