Engineering

Verwendung von Painless in geskripteten Kibana-Feldern

Kibana bietet leistungsstarke Möglichkeiten zum Durchsuchen und Visualisieren von Daten, die in Elasticsearch gespeichert sind. Für die Visualisierung sucht Kibana nach Feldern, die in Elasticsearch-Mappings definiert sind, und zeigt sie den Nutzer:innen als Optionen bei der Diagrammerstellung an. Aber was ist, wenn Sie vergessen, einen wichtigen Wert in Ihrem Schema als separates Feld zu definieren? Oder wenn Sie zwei Felder kombinieren und als eines bearbeiten wollen? Da kommen die geskripteten Felder in Kibana ins Spiel.

Eigentlich gibt es die geskripteten Felder schon seit den Anfängen von Kibana 4. Zum Zeitpunkt ihrer Einführung konnten sie aber nur mit Lucene Expressions definiert werden, einer Skripting-Sprache in Elasticsearch, die ausschließlich mit numerischen Werten arbeitet. Daher war der Einsatz geskripteter Felder auf bestimmte Anwendungsfälle begrenzt. In 5.0 führte Elasticsearch Painless ein, eine sichere und leistungsstarke Skripting-Sprache, die es ermöglicht, mit einer Vielzahl von Datentypen zu arbeiten. Daher sind geskriptete Felder in Kibana 5.0 deutlich leistungsfähiger.

In diesem Blogpost zeigen wir, wie Sie geskriptete Felder für gängige Anwendungsfälle erstellen können. Dazu verwenden wir ein Dataset aus dem Erste-Schritte-Tutorial für Kibana und eine Instanz von Elasticsearch und Kibana, die in Elastic Cloud ausgeführt wird und kostenlos eingerichtet werden kann.

Im folgenden Video erfahren Sie, wie Sie Ihre eigene Instanz mit Elasticsearch und Kibana in der Elastic Cloud starten und einen Beispiel-Dataset laden. 

So funktionieren geskriptete Felder

In Elasticsearch können Sie bei jeder Anfrage geskriptete Felder verwenden. Kibana verbessert diese Funktion noch, indem es Ihnen erlaubt, ein geskriptetes Feld einmalig im Abschnitt „Management“ zu definieren. Dieses Feld kann ab da an mehreren Stellen in der Benutzeroberfläche genutzt werden. Beachten Sie aber, dass geskriptete Felder in Kibana zusammen mit der übrigen Konfiguration im Index .kibana speichert werden und diese Konfiguration ausschließlich für Kibana ist. Das heißt, die geskripteten Kibana-Felder stehen den API-Nutzer:innen von Elasticsearch nicht zur Verfügung.

Wenn Sie ein geskriptetes Feld in Kibana definieren, können Sie eine Skripting-Sprache aus allen auf den Elasticsearch-Nodes installierten Sprachen auswählen, die dynamische Skripterstellung unterstützen. Standardmäßig sind das in 5.0 „Expression“ und „Painless“ und in 2.x nur „Expression“. Sie können andere Skripting-Sprachen installieren und dynamische Skripterstellung für sie aktivieren. Das wird jedoch nicht empfohlen, da sie nicht vollständig auf ihre Sandbox beschränkt werden können und als „deprecated“ markiert sind.

Geskriptete Felder laufen nur für ein Elasticsearch-Dokument gleichzeitig, können aber auf mehrere Felder in diesem Dokument verweisen. Damit können Sie geskriptete Felder benutzen, um Felder in einem Dokument zu kombinieren oder umzuwandeln, aber keine Berechnungen aufgrund mehrerer Dokumente anstellen (z. B. Zeitreihenanalyse). Sowohl Painless als auch Lucene Expressions berücksichtigen Felder, die in doc_values gespeichert sind. Für String-Daten müssen Sie also den String im Datentyp „keywords“ speichern. Mit Painless geskriptete Felder funktionieren außerdem nicht direkt mit _source.

Sobald die geskripteten Felder unter „Management“ gespeichert sind, können Nutzer:innen mit ihnen im Rest von Kibana auf dieselbe Weise interagieren wie mit anderen Feldern. Geskriptete Felder werden automatisch in der Feldliste „Discover“ angezeigt und stehen in „Visualize“ für die Erstellung von Visualisierungen zur Verfügung. Kibana reicht die Definitionen der geskripteten Felder einfach zum Abfragezeitpunkt zur Evaluierung an Elasticsearch weiter. Der daraus resultierende Dataset wird mit anderen Ergebnissen aus Elasticsearch kombiniert und den Nutzer:innen in einer Tabelle oder einem Diagramm angezeigt.

Zum Zeitpunkt des Schreibens dieses Blogposts gibt es einige bekannte Beschränkungen bei der Arbeit mit geskripteten Feldern. Sie können die meisten im Kibana Visual Builder verfügbaren Elasticsearch-Aggregationen auf geskriptete Felder anwenden. Es gelten aber einige Ausnahmen, von denen die wichtigste die Aggregation „significant terms“ ist. Sie können geskriptete Felder auch über die Filterleiste in Discover, Visualize und im Dashboard filtern. Dafür müssen Sie jedoch ordentliche Skripte schreiben, die gut definierte Werte ausgeben. Wie das geht, zeigen wir weiter unten. Außerdem sollten Sie sich im Folgenden den Abschnitt „Best Practices“ ansehen, damit Sie die Stabilität Ihrer Umgebung nicht mit geskripteten Feldern gefährden.

Im folgenden Video sehen Sie, wie Sie in Kibana geskriptete Felder erstellen.

Beispiele für geskriptete Felder

In diesem Abschnitt zeigen wir Ihnen ein paar mit Lucene Expressions und Painless geskriptete Felder in Kibana in gängigen Szenarien. Wie oben erwähnt wurden diese Beispiele auf Grundlage eines Dataset aus dem „Erste Schritte mit Kibana“-Tutorial erarbeitet. Wir gehen auch davon aus, dass Sie Elasticsearch und Kibana 5.1.1 benutzen, da es in früheren Versionen einige bekannte Probleme mit dem Filtern und Sortieren bestimmter geskripteter Felder gibt.

Zum Großteil sollten geskriptete Felder ohne Zusatzarbeit funktionieren, da Lucene Expressions und Painless in Elasticsearch 5.0 standardmäßig aktiviert sind. Die einzige Ausnahme bilden Skripte, für die ein Regex-basiertes Parsing der Felder erforderlich ist. Dafür müssen Sie in elasticsearch.yml für Regex-Matching in Painless die folgende Einstellung setzen: „script.painless.regex.enabled: true“

Durchführen einer Berechnung für ein einzelnes Feld

  • Beispiel: Kilobytes aus Bytes berechnen
  • Sprache: expressions
  • Rückgabetyp: number
 doc['bytes'].value / 1024

Hinweis: Beachten Sie, dass geskriptete Felder in Kibana immer nur mit einem Dokument gleichzeitig funktionieren. Sie können also mit geskripteten Feldern keine Zeitreihenanalysen durchführen.

Datumsberechnung mit Ausgabe einer Zahl

  • Beispiel: Datum in Stunde des Tages umrechnen
  • Sprache: expressions
  • Rückgabetyp: number

Lucene Expressions bieten out of the box eine ganze Menge von Funktionen zur Datumsbearbeitung. Allerdings geben Lucene Expressions nur Zahlenwerte aus, weshalb wir Painless verwenden müssen, um einen String-basierten Wochentag ausgeben zu können (unten).

 doc['@timestamp'].date.hourOfDay

Hinweis: Das obige Skript gibt 1–24 aus.

doc['@timestamp'].date.dayOfWeek

Hinweis: Das obige Skript gibt 1–7 aus.

Zwei String-Werte kombinieren

  • Beispiel: Quelle und Ziel oder Vor- und Nachname kombinieren
  • Sprache: painless
  • Rückgabetyp: string
 doc['geo.dest.keyword'].value + ':' + doc['geo.src.keyword'].value

Hinweis: Da geskriptete Felder nur Felder in doc_values verarbeiten können, verwenden wir .keyword-Versionen der obigen Strings.

Logik hinzufügen

  • Beispiel: Dokumente mit mehr als 10.000 Bytes als „großer Download“ kennzeichnen
  • Sprache: painless
  • Rückgabetyp: string
 if (doc['bytes'].value > 10000) { 
return "big download";
}
return "";

Hinweis: Bei der Einführung von Logik müssen Sie darauf achten, dass jeder Ausführungspfad über ein ordnungsgemäß definiertes Ausgabe-Statement und einen ordnungsgemäß definierten Ausgabewert (nicht null) verfügt. So schlägt z. B. das obige geskriptete Feld mit einem Compile-Fehler fehl, wenn es in den Kibana-Filtern ohne das Return-Statement am Ende benutzt wird oder das Statement null ausgibt. Beachten Sie auch, dass Sie bei geskripteten Kibana-Feldern die Logik nicht in mehrere Funktionen aufspalten können. 

Teilstring ausgeben lassen

  • Beispiel: URL-Teil nach dem letzten Schrägstrich ausgeben
  • Sprache: painless
  • Rückgabetyp: string
 def path = doc['url.keyword'].value;
if (path != null) {
int lastSlashIndex = path.lastIndexOf('/');
if (lastSlashIndex > 0) {
return path.substring(lastSlashIndex+1);
}
}
return "";

Hinweis: Vermeiden Sie beim Extrahieren von Teilstrings soweit als möglich Regex-Ausdrücke, da indexOf()-Operationen ressourcenschonender und weniger fehleranfällig sind. 

Einen String mit Regex abgleichen und den Treffer weiterverarbeiten

  • Beispiel: Einen String „error“ ausgeben, wenn der Substring „error“ im Feld „referer“ gefunden wird, ansonsten einen String „no error“ ausgeben
  • Sprache: painless
  • Rückgabetyp: string
if (doc['referer.keyword'].value =~ /de/error/) { 
return "error"
} else {
return "no error"
}

Hinweis: Die vereinfachte Regex-Syntax eignet sich für Bedingungen auf Grundlage eines Regex-Treffers. 

Einen String abgleichen und den Treffer ausgeben

  • Beispiel: Domain ausgeben, also den String nach dem letzten Punkt im Feld „host“
  • Sprache: painless
  • Rückgabetyp: string
def m = /^.*\.([a-z]+)$/.matcher(doc['host.keyword'].value);
if ( m.matches() ) {
return m.group(1)
} else {
return "no match"
}

Hinweis: Wenn Sie ein Objekt über die Regex-matcher()-Funktionen definieren, können Sie Zeichengruppen extrahieren und ausgeben, die mit dem regulären Ausdruck übereinstimmen. 

Eine Zahl abgleichen und den Treffer ausgeben

  • Beispiel: Das erste Oktett einer IP-Adresse (als String gespeichert) ausgeben und als Zahl bearbeiten
  • Sprache: painless
  • Rückgabetyp: number
 def m = /^([0-9]+)\..*$/.matcher(doc['clientip.keyword'].value);
if ( m.matches() ) {
return Integer.parseInt(m.group(1))
} else {
return 0
}

Hinweis: Es muss unbedingt der richtige Datentyp in einem Skript ausgegeben werden. Ein Regex-Treffer gibt einen String aus, auch wenn der Treffer eine Zahl ist. Sie sollten ihn daher explizit bei der Ausgabe in eine Ganzzahl umwandeln. 

Datumsberechnung mit String als Ergebnis

  • Beispiel: Datum in Wochentag als String umwandeln
  • Sprache: painless
  • Rückgabetyp: string
LocalDateTime.ofInstant(Instant.ofEpochMilli(doc['@timestamp'].value), ZoneId.of('Z')).getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.getDefault())

Hinweis: Da Painless alle nativen Typen von Java unterstützt, bietet es auch Zugang zu nativen Funktionen für diese Typen, zum Beispiel LocalDateTime(), was für die erweiterte Datumsberechnung hilfreich ist.

Best Practices

Wie Sie sehen, bietet die Skripting-Sprache Painless vielfältige Möglichkeiten für die Extraktion nützlicher Informationen mithilfe von geskripteten Kibana-Feldern aus Elasticsearch. Allerdings bringt große Macht auch große Verantwortung mit sich. 

Im Folgenden führen wir einige Best Practices zur Benutzung der geskripteten Kibana-Felder an.

  • Benutzen Sie für das Experimentieren mit geskripteten Feldern immer eine Entwicklungsumgebung, denn geskriptete Felder sind sofort nach dem Speichern im Abschnitt „Management“ von Kibana aktiv. So werden sie allen Nutzer:innen in der Discover-Ansicht für dieses Indexmuster angezeigt. Deshalb sollten Sie sie nicht direkt in Ihrer Produktionsumgebung erstellen. Wir empfehlen, Ihre Syntax zuerst in einer Entwicklungsumgebung zu testen, die Auswirkungen auf praxisnahe Datensätze und ‑volumina im Staging auszuloten und sie erst dann in die Produktion zu übernehmen. 
  • Sobald Sie sicher sind, dass das geskriptete Feld Ihren Nutzer:innen einen Mehrwert bietet, können Sie Ihre Datenspeicherung so bearbeiten, dass das Feld zur Indexzeit extrahiert wird. So spart Elasticsearch zum Abfragezeitpunkt Ressourcen und liefert schneller Ergebnisse für Kibana-Nutzer:innen. Außerdem können Sie mit der _reindex-API in Elasticsearch vorhandene Daten neu indizieren.