Index Templates in OpenSearch

Wenn man mehrere Indexe erstellen will, möchte man gerne wiederkehrende Einstellungen global haben und immer nutzen. Dafür gibt es Index Templates

Einleitung

Man verwendet in OpenSearch häufig mehr als einen Index. Das wird für sehr viele verschiedene Dinge benötigt und wird einem bei größeren Projekten ständig begleiten. Wichtig ist zu wissen, dass OpenSearch keine Relationen zwischen Dokumenten in verschiedenen Indexen erlaubt (es gibt hat nur Hilfsmittel, um Denormalisierungen zu unterstützen, aber das hat mit echten Relationen aus RDBMS nichts zu tun). Trotzdem braucht man viele verschiedene Dokumentmodelle (die dann in jeweils eigenen Index kommen) oder gar immer die gleichen Dokument-Schemas in vielen Indexen (Archivierung, unterschiedliche Kategorisierung, usw. usw).

Ein Beispiel aus Mastodon, wo man Follower und Following unterscheidet. Der Dokument-Typ (Schema-Object) ist in beiden Fällen Account, aber die Handhabung ist eine komplett andere. Man könnte das mit einem “Type” Attribute unterscheidbar machen und dann alle Accounts in einem Index speichern. Aber dann geht es schon las: Man braucht zwei Attribute (weil ja beides möglich ist: folgen, gefolgt werden, sogar gar nichts von beidem). Das kann Abfragen und Abgrenzungen schwierig machen. Deswegen einfach getrennt ablegen. OpenSearch kann übrigens in jeder Suche grundsätzlich beliebig viele Indexe nutzen. D.h. brauche ich eine Liste von Accounts, denen ich folge und die mir folgen, dann suche ich zugleich über beide Indexe:

http://localhost:9200/followers,following/_search

Ok, die beiden Indexe gibt es noch nicht (das kommt in einem späteren Artikel). Die Indexe dürfen dabei völlig unterschiedliche Dokumentstrukturen enthalten. Der Consumer muss halt sehen, wie er das verarbeitet. Wichtig ist zu wissen, dass Dokumente mit derselben _id nicht aggregiert werden. Die _id ist nur in jeweiligen Index eindeutig.

Index Templates

Ok, es geht aber hier um eine andere Thematik. Es gibt immer wieder Einstellungen für Indexe, die man in jedem Index wieder braucht. Zum Beispiel die Einstellungen der Shards, Analyse-Funktionen in den Mappings usw.

Diese Vorgaben kann man in Index-Templates ablegen. Wird ein neuer Index erzeugt, übernimmt OpenSearch die Angaben aus dem Template. Templates werden mit Namen angelegt und haben Pattern, das zur Auswahl genutzt wird, wenn ein Index angelegt wird.

Template erstellen

In Python ist das wieder simpel (ich lasse mal das Login in OpenSearch weg):

standard_settings={
    "index_patterns" : ["*"],
    "priority" : 1,
    "template": {
        "settings" : {
            "number_of_shards" : 2,
            "analysis": {
                "filter": {
                    "english_stop": {
                        "type":       "stop",
                        "stopwords":  "_english_"
                    },
                    "german_stop": {
                        "type":       "stop",
                        "stopwords":  "_german_"
                    },
                },
                "analyzer": {
                    "my_html_analyzer": {
                        "type": "custom",
                        "tokenizer": "standard",
                        "filter": [
                            "lowercase",
                            "english_stop",
                            "german_stop"
                        ],
                        "char_filter": [
                            "html_strip"
                        ]
                    },
                }
            }
        }
    }
}

client.indices.put_index_template("standard", body=standard_settings)

Mit index_patterns und dem * geben wir an, dass das Template immer zu Zuge kommt. Denn der Stern passt auf alle Namen. Da man mehrere Templates angeben kann und sich die Patterns überschneiden können, braucht es eine Priorität. Können zwei Templates identifiziert werden, deren Pattern zum neuen Index passen, gewinnt das Template mit höherer Priorität.

Die Eigenschaften des Templates werden bei der Erstellung eines Index einfach als Vorlage genutzt. Ändert man das Template nachträglich, ändern sich die bereits angelegten Indexe nicht.

Templates lesen

Hier mal eine Abfrage der existierenden Templates ohne die OpenSearch Python API:

import requests

response = requests.request("GET",
    "http://localhost:9201/_index_template/?pretty=true")

print(response.text)

Abschließend das komplette Script osIndexTemplate.py mit ein paar Anpassungen:

import json
from opensearchpy import OpenSearch


def login (host, port):
    # Client zu dem Dev Cluster (ohne SSL, ohne Anmeldung)
    return OpenSearch(
        hosts = [{'host': host, 'port': port}],
        http_compress = True, # enables gzip compression for request bodies
        use_ssl = False
    )


client = login("localhost", 9200)

standard_settings={
    "index_patterns" : ["*"],
    "priority" : 1,
    "template": {
        "settings" : {
            "number_of_shards" : 2,
            'number_of_replicas': 0,
            "analysis": {
                "filter": {
                    "english_stop": {
                        "type":       "stop",
                        "stopwords":  "_english_"
                    },
                    "german_stop": {
                        "type":       "stop",
                        "stopwords":  "_german_"
                    },
                },
                "analyzer": {
                    "my_html_analyzer": {
                        "type": "custom",
                        "tokenizer": "standard",
                        "filter": [
                            "lowercase",
                            "english_stop",
                            "german_stop"
                        ],
                        "char_filter": [
                            "html_strip"
                        ]
                    },
                }
            }
        }
    }
}

template_name="standard"
print (f"Create or update index template {template_name}")
res = client.indices.put_index_template(template_name, body=standard_settings)
print (json.dumps(res, indent=4, default=str))

Zu beachten ist, dass die Anzahl der Shards und das Abschalten der Replikations-Nodes nur auf einem Dev-System sinnvoll sind.


Mit solchen Templates reduzieren sich die Settings für neue Indexe enorm. Man muss sich dann aber auch mehr strukturieren. Es mag sinnvoll sein, Namenspräfixe für Indexe zu verwenden, damit das Matching der Templates präziser funktioniert. Es bleibt anzumerken, dass Index Templates selbst wieder aus Bausteinen, den sogenannten Component Templates zusammengesetzt werden können. Das geht hier jetzt aber zu weit ;-)

In dem nächsten Artikel werden tatsächlich mehrere Indexe angelegt, die alle den Analyzer benötigen. Stay tuned.