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.
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:
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.
Das Abrufen von Dokumenten erscheint zunächst einfach:
GET /mein-index/_doc/123
Aber hinter den Kulissen ist es ein komplexer Prozess:
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.
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:
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
}
}
}
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.
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.
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.
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.
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.
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
Die Dokumenten-APIs sind das Herzstück von OpenSearch. Sie richtig zu verstehen und einzusetzen ist entscheidend für:
Beachten Sie besonders:
Mit diesem Wissen sind Sie gut gerüstet, um OpenSearch effektiv in Ihren Anwendungen einzusetzen.