DataPrime betreiber

Dieser Leitfaden enthält ein Glossar der Operatoren von IBM® Cloud Logs DataPrime.

block

Die Negation von filter. Filtert alle Ereignisse aus, bei denen die Bedingung erfüllt ist. Der gleiche Effekt kann durch die Verwendung von filter mit !(condition) erzielt werden.

block $d.status_code >= 200 && $d.status_code <= 299         # Leave all events which don't have a status code of 2xx

Die Daten werden in den folgenden Feldern angezeigt:

  • $m - Ereignis-Metadaten

    • timestamp
    • severity- Mögliche Werte sind Verbose, Debug, Info, Warning, Error, Critical
    • priorityclass- Mögliche Werte sind high, medium, low
    • logid
  • $l - Ereignisbezeichnungen

    • applicationname
    • subsystemname
    • category
    • classname
    • computername
    • methodname
    • threadid
    • ipaddress
  • $d -Die Daten des Benutzers

bottom

Keine Gruppierungsvariante: Begrenzt die zurückgegebenen Zeilen auf eine bestimmte Anzahl und ordnet das Ergebnis nach einer Reihe von Ausdrücken.

order_direction := "descending"/"ascending" according to top/bottom
bottom <limit> <result_expression1> [as <alias>] [, <result_expression2> [as <alias2>], ...] by <orderby_expression> [as alias>]

Beispielsweise sollte die Abfrage

bottom 5 $m.severity as $d.log_severity by $d.duration

Führt zu Protokollen der folgenden Form:

[
   { "log_severity": "Debug", "duration":  1000 }
   { "log_severity": "Warning", "duration": 2000 },
   ...
]

Gruppierungsvariation: Begrenzt die zurückgegebenen Zeilen auf eine bestimmte Anzahl und gruppiert sie nach einer Reihe von Aggregationsausdrücken und ordnet sie nach einer Reihe von Ausdrücken.

order_direction := "descending"/"ascending" according to top/bottom

bottom <limit> <(groupby_expression1|aggregate_function1)> [as <alias>] [, <(groupby_expression2|aggregate_function2)> [as <alias2>], ...] by <(groupby_expression1|aggregate_function1)> [as <alias>]

Beispielsweise sollte die Abfrage

bottom 10 $m.severity, count() as $d.number_of_severities by avg($d.duration) as $d.avg_duration

Führt zu Protokollen der folgenden Form:

[
   { "severity": "Warning", "number_of_severities": 50, avg_duration: 1000 },
   { "severity": "Debug", "number_of_severities":  10, avg_duration: 2000 }
   ...
]

Die unterstützten Aggregationsfunktionen sind im Abschnitt "Aggregationsfunktionen" aufgeführt.

choose

Lassen Sie nur die vorgesehenen Tastenwege stehen und verwerfen Sie alle anderen Tasten. Vollständige Unterstützung verschachtelter Schlüsselpfade in der Ausgabe.

(choose|select) <keypath1> [as <new_keypath>],<keypath2> [as <new_keypath>],...

Beispiele:

choose $d.mysuperkey.myfield
choose $d.my_superkey.mykey as $d.important_value, 10 as $d.the_value_ten

convert

Konvertieren Sie die Datentypen der Schlüssel.

Das Schlüsselwort datatypes ist optional und kann zur besseren Lesbarkeit verwendet werden.

(conv|convert) [datatypes] <keypath1>:<datatype1>,<keypath2>:<datatype2>,...

Beispiele:

convert $d.level:number
conv datatypes $d.long:number,$d.lat:number
convert $d.data.color:number,$d.item:string

count

Gibt eine einzelne Zeile zurück, die die Anzahl der von den vorangegangenen Operatoren erzeugten Zeilen enthält.

count [into <keypath>]

Ein Alias kann angegeben werden, um den Tastaturpfad zu überschreiben, in den das Ergebnis geschrieben werden soll.

Zum Beispiel der folgende Teil einer Abfrage:

count into $d.num_rows

Das Ergebnis ist eine einzelne Zeile der folgenden Form:

{ "num_rows": 7532 }

countby

Gibt eine Zeile zurück, die alle durch den Ausdruck gruppierten Zeilen zählt.

countby <expression> [as <alias>] [into <keypath>]

Ein Alias kann angegeben werden, um den Tastaturpfad, in den das Ergebnis geschrieben wird, zu überschreiben.

Zum Beispiel der folgende Teil einer Abfrage

countby $d.verb into $d.verb_count

Das Ergebnis ist eine Zeile für jede Gruppe.

Sie ist funktionell identisch mit

groupby $data.verb calculate count() as $d.verb_count

create

Erstellen Sie einen neuen Schlüssel und setzen Sie seinen Wert auf das Ergebnis des Ausdrucks. Die Schlüsselerstellung ist granular, d. h. übergeordnete Schlüssel im Pfad werden nicht überschrieben.

  (a|add|c|create) <keypath> from <expression> [on keypath exists (fail|skip|overwrite)] [on keypath missing (fail|create|skip)] [on datatype change (skip|fail|overwrite)

Die Erstellung kann durch Hinzufügen der folgenden Klauseln kontrolliert werden:

  • Durch Hinzufügen von keypath exists können Sie festlegen, was geschehen soll, wenn der Tastaturpfad bereits existiert.

    • overwrite- Überschreibt den alten Wert. Dies ist der Standardwert.

    • fail- Die Abfrage schlägt fehl

    • skip- Überspringt die Erstellung des Schlüssels

  • Das Hinzufügen von keypath missing entscheidet, was zu tun ist, wenn der neue Tastaturpfad nicht existiert.

    • create- Erzeugt den Schlüssel. Dies ist der Standardwert.

    • fail- Die Abfrage schlägt fehl

    • skip- Überspringt die Erstellung des neuen Schlüssels

  • Das Hinzufügen auf datatype changed entscheidet, was zu tun ist, wenn der Schlüssel bereits existiert und die neuen Daten den Datentyp des Wertes ändern.

    • overwrite- Überschreibt den Wert. Dies ist der Standardwert.

    • fail- Die Abfrage schlägt fehl

    • skip- Belässt den Schlüssel mit dem ursprünglichen Wert (und Typ)

Beispiele:

create $d.radius from 100+23
c $d.log_data.truncated_message from $d.message.substring(1,50)
c $data.trimmed_name from $data.username.trim()

create $d.temperature from 100*23 on datatype changed skip

distinct

Gibt eine Zeile für jede eindeutige Kombination der angegebenen Ausdrücke zurück.

distinct <expression> [as <alias>] [, <expression_2> [as <alias_2>], ...]

Dieser Operator ist funktional identisch mit groupby ohne Aggregatfunktionen.

enrich

Reichern Sie Ihre Protokolle mit zusätzlichem Kontext aus einer Nachschlagetabelle an.

Laden Sie Ihre Lookup-Tabelle mit Datenfluss Datenfluss-Symbol > Data Enrichment > Custom Enrichment hoch.

enrich <value_to_lookup> into <enriched_key> using <lookup_table>
  • value_to_lookup- Ein String-Ausdruck, der in der Lookup-Tabelle nachgeschlagen wird.

  • enriched_key- Zielschlüssel zur Speicherung des Anreicherungsergebnisses.

  • lookup_table- Der Name der zu verwendenden Tabelle für die benutzerdefinierte Anreicherung.

Die Spalten der Tabelle werden als Unterschlüssel zum Zielschlüssel hinzugefügt. Wenn value_to_lookup nicht gefunden wird, ist der Zielschlüssel Null. Sie können dann die Ergebnisse mit den Funktionen von DataPrime filtern, z. B. die Protokolle nach einem bestimmten Wert im angereicherten Feld.

Beispiel:

Das Originalprotokoll:

{
    "userid": "111",
    ...
}

Die Nachschlagetabelle für benutzerdefinierte Anreicherungen heißt my_users:

Beispiel einer Nachschlagetabelle
ID Name Abteilung
111 John Finanzen
222 Emily optimieren

Ausführen der folgenden Abfrage:

enrich $d.userid into $d.user_enriched using my_users

Das Ergebnis ist das folgende angereicherte Protokoll:

{
    "userid": "111",
    "user_enriched": {
        "ID": "111",
        "Name": "John",
        "Department": "Finance"
    },
    ...
}

Beachten Sie bei der Verwendung von enrich die folgenden Punkte:

  • Führen Sie die DataPrime Abfragequelle lookup_table aus, um die Anreicherungstabelle anzuzeigen.

  • Wenn das ursprüngliche Protokoll bereits den angereicherten Schlüssel enthält:

    • Wenn value_to_lookup in lookup_table vorhanden ist, werden die Unterschlüssel mit dem neuen Wert aktualisiert. Wenn die value_to_lookup nicht existiert, bleibt ihr aktueller Wert erhalten.

    • Alle anderen Unterschlüssel, die keine Spalten in der lookup_table sind, bleiben mit ihren bestehenden Werten erhalten.

  • Alle Werte auf der Website lookup_table werden als Zeichenketten betrachtet. Dies bedeutet Folgendes:

    • Die Adresse value_to_lookup muss in einem String-Format vorliegen.

    • Alle Werte werden in einem String-Format angereichert. Sie können sie dann mit den entsprechenden Funktionen in Ihr bevorzugtes Format (z. B. JSON, Zeitstempel) umwandeln.

extract

Extrahieren von Daten aus einem String-Wert in ein neues Objekt. Es werden mehrere Extraktionsmethoden unterstützt.

(e|extract) <expression> into <keypath> using <extraction-type>(<extraction-params>) [datatypes keypath:datatype,keypath:datatype,...]

Im Folgenden werden die unterstützten Extraktionsmethoden und ihre Parameter aufgeführt:

  • regexp- Ein neues Objekt auf der Grundlage von regexp capture-groups erstellen

  • e- Ein regulärer Ausdruck mit Namen capture-groups.

Beispiel:

extract $d.my_text into $d.my_data using regexp(e=/user (?<user>.*) has logged in/)
  • kv- Extrahieren eines neuen Objekts aus einer Zeichenkette, die Schlüssel=Wert-Schlüssel=Wert-Paare enthält

  • pair_delimiter- Das Trennzeichen, das zwischen Paaren erwartet wird. Standard ist (ein Leerzeichen)

  • key_delimiter- Das zu erwartende Trennzeichen zwischen einem Schlüssel und einem Wert. Die Voreinstellung ist =.

Beispiele:

extract $d.text into $d.my_kvs using kv()
e $d.text into $d.my_kvs using kv(pair_delimiter=' ',key_delimiter='=')
  • jsonobject- Extrahieren eines neuen Objekts aus einem String, der ein kodiertes json-Objekt enthält, wobei möglicherweise versucht wird, den String zu entschlüsseln, bevor er in ein json-Objekt dekodiert wird

  • max_unescape_count- Maximale Anzahl der Escape-Ebenen, die vor dem Parsen des json unescape sind. Der Standardwert ist '1'. Bei einem Wert von 1 oder mehr erkennt die Engine, ob der Wert eine escapte JSON-Zeichenfolge enthält, und entschlüsselt sie, bis die Anzahl der parsbaren oder maximalen Entschlüsselungen überschritten wird.

Beispiel:

e $d.json_message_as_str into $d.json_message using jsonobject(max_unescape_count=1)

Es ist möglich, Datentypinformationen als Teil der Extraktion bereitzustellen, indem die Datentypen-Klausel verwendet wird. Das Hinzufügen von Datentypen my_field:number zu einer Extraktion würde zum Beispiel dazu führen, dass der Extrakt my_field keypath eine Zahl statt einer Zeichenkette ist. Zum Beispiel:

extract $d.my_msg into $d.data using kv() datatypes my_field:number

Die extrahierten Daten werden immer als Objekt in einen neuen Keypath eingefügt, so dass die neuen Schlüssel innerhalb dieses neuen Objekts weiterverarbeitet werden können. Zum Beispiel:

# Assuming a dataset which look like that:
{ "msg": "query_type=fetch query_id=100 query_results_duration_ms=232" }
{ "msg": "query_type=fetch query_id=200 query_results_duration_ms=1001" }

# And the following DataPrime query:
source logs
  | extract $d.msg into $d.query_data using kv() datatypes
query_results_duration_ms:number
  | filter $d.query_data.query_results_duration_ms > 500

# The results will contain only the second message, in which the duration is greater than 500 ms

filter

Ereignisse filtern, so dass nur Ereignisse übrig bleiben, für die die Bedingung als wahr ausgewertet wird.

(f|filter|where) <condition-expression>

Beispiele:

f $d.radius > 10
filter $m.severity.toUpperCase() == 'INFO'
filter $l.applicationname == 'myapp'
filter $l.applicationname == 'myapp' && $d.msg.contains('failure')

Der Vergleich mit null funktioniert nur für skalare Werte und gibt bei JSON-Teilbäumen immer null zurück.

Wenn Sie eine Bedingung verwenden, um einen Keypath mit Null zu vergleichen, funktioniert dies nur bei skalaren Werten (String, Zahl, Zeitstempel usw.). Bei JSON-Objekten innerhalb eines bestimmten Dokuments gibt der Vergleich mit null immer null zurück.

Verwenden Sie Filter mit Funktionen, um komplexe Suchen durchzuführen.

Beispiele:

filter in($l.applicationname, 'ibm-audit-event', 'ibm-platform-logs') #
filter ipInSubnet(ip_address, '155.64.5.20/24')

e - Filter für IP-Adressen in einem bestimmten Bereich. filter kann mit Funktionen gekoppelt werden, um komplexe Suchen mit sehr wenig Syntax durchzuführen, zum Beispiel mit der Funktion ipInSubnet:

filter ipInSubnet(ip_address, ' 154.67.8.20/24 ')

groupby

Gruppiert die Ergebnisse der vorangegangenen Operatoren nach den angegebenen Gruppierungsausdrücken und berechnet Aggregatfunktionen für jede erstellte Gruppe.

groupby <grouping_expression> [as <alias>] [, <grouping_expression_2> [as <alias_2>], ...] [calculate]
  <aggregate_function> [as <result_keypath>]
  [, <aggregate_function_2> [as <result_keypath_2], ...]

Beispielsweise sollte die Abfrage

groupby $m.severity calculate sum($d.duration)

Führt zu Protokollen der folgenden Form:

{ "severity": "Warning", "_sum": 17045 }

Die Tastaturpfade für die Gruppierungsausdrücke werden immer unter $d zu finden sein. Mit dem Schlüsselwort as können wir den Tastaturpfad für die Gruppierungsausdrücke und Aggregationsfunktionen umbenennen. Zum Beispiel:

groupby $l.applicationname as $d.app calculate sum($d.duration) as $d.sum_duration

Führt zu Protokollen der folgenden Form:

{ "app": "web-api", "sum_duration": 17045 }

Bei der Abfrage mit dem Operator groupby können Sie eine Aggregationsfunktion (z. B. avg, max, sum) auf den Bereich der Ergebnisse anwenden. Diese Funktion gibt Ihnen die Möglichkeit, einen Aggregationsausdruck innerhalb des Ausdrucks selbst zu manipulieren, so dass Sie Ihre Daten gleichzeitig berechnen und manipulieren können.

join

Join führt die Ergebnisse der aktuellen (linken) Abfrage mit einer zweiten (rechten) Abfrage auf der Grundlage einer angegebenen Bedingung zusammen. Sie bietet mehrere Formulare, um zu steuern, wie die Daten kombiniert werden, und unterstützt Verschachtelungen, so dass die richtige Abfrage ihren eigenen Befehl join enthalten kann.

Join unterstützt drei Varianten:

join left|join
Für jedes Ereignis in der linken Abfrage wählt der Befehl ein passendes Ereignis aus der rechten Abfrage auf der Grundlage der angegebenen Bedingung aus. Wenn keine Übereinstimmung gefunden wird, werden Zeilen für alle Ereignisse in der linken Abfrage aufgenommen. Nicht übereinstimmende Zeilen aus der rechten Abfrage werden auf null gesetzt.
join full
Gibt eine Zeile für jedes Ereignis zurück, einschließlich derer, für die es in beiden Abfragen (links oder rechts) keine Übereinstimmung gibt, wobei fehlende Werte mit null aufgefüllt werden.
join inner
Gibt nur Zeilen zurück, in denen die Ergebnisse beider Abfragen nicht null sind.
join cross
Paart jede Zeile aus der linken Abfrage mit jeder Zeile aus der rechten Abfrage und erzeugt so das vollständige kartesische Produkt. Im Gegensatz zu anderen join Typen unterstützt join cross nicht on oder using conditions. Sie funktioniert ähnlich wie join inner, allerdings ohne Filterung, und liefert alle möglichen Zeilenkombinationen.

Für left (Standard), inner und full können Sie entweder eine Bedingung join mit dem Schlüsselwort on oder einen Schlüsselpfad mit dem Schlüsselwort keyword angeben. Das kartesische Produkt wird gefiltert, um nur Zeilen zu erhalten, bei denen die Bedingung zutrifft oder bei denen die Werte des Schlüsselpfads auf beiden Seiten übereinstimmen.

Da alle Verknüpfungen, unabhängig vom Modifikator, auf dem kartesischen Produkt basieren, kann es zu doppelten Ergebnissen kommen, wenn die Bedingung join mehrfach zutrifft. Um unbeabsichtigte Duplikationen zu vermeiden, sollten Sie Unterabfragen vorverarbeiten, z. B. durch Verwendung von distinct.

Syntax:

<left_side_query> | join [left/inner/full] (<right_side_query>) on <condition> into <right_side_target>
<left_side_query> | join [left/inner/full] (<right_side_query>) using <join_keypath_1> [, <join_keypath_2>, ...] into <right_side_target>
<left_side_query> | join cross (<right_side_query>) into <right_side_target>

Dabei gilt:

  • <right_side_query>- Die <right_side_query> bezeichnet die neue Abfrage, mit der sie verbunden werden soll.

  • <left_side_query>- Das <left_side_query> bezeichnet die ursprüngliche Abfrage, z.B. in der Abfrage source logs | filter x != null | join ... ist die linke Seite der Abfrage source logs | filter x != null.

  • <condition>- Die Bedingung, ob Ergebnisse aus beiden Abfragen zusammengeführt werden sollen.

    In der Bedingung können Sie die Präfixe left=> und right=> verwenden, um auf die Ereignisse der linken bzw. rechten Abfrage zu verweisen. Sie ist jedoch nicht erforderlich, wenn ein Schlüsselpfad nur in einer der Abfragen vorhanden ist.

    Wenn Sie den == (Gleichheits-)Operator in Ihrer Bedingung verwenden, muss er einen Schlüsselpfad aus der linken Abfrage mit einem Schlüsselpfad aus der rechten Abfrage vergleichen. Da die Schlüsselpfade jedoch eindeutig sein müssen oder mit left=> oder right=> vorangestellt werden, ist die Reihenfolge der Operanden nicht wichtig.

  • <join_keypath_n>- <join_keypath_n> als Verknüpfungsschlüssel bedeutet, dass Ergebnisse verknüpft werden, bei denen ein bestimmter Schlüsselpfad sowohl in den Ergebnissen der linken als auch in denen der rechten Abfrage gleich ist.

  • <right_side_target>- Der Schlüsselpfad, unter dem die verbundenen Daten zur aktuellen Abfrage hinzugefügt werden.

join Beispiel

Sie haben diese benutzerdefinierte Anreicherungstabelle mit dem Namen users, die Informationen über IDs in Verbindung mit Namen enthält:

{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }

Und diese Daten liefern Anmeldeereignisse und Benutzerkennungen, aber nicht die mit den Benutzerkennungen verbundenen Benutzernamen.

{ "userid": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "userid": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z" }

Mit join können Sie eine Abfrage verwenden, um Daten einschließlich der gewünschten Daten zurückzugeben.

source users | join (source logs | countby userid) on id == userid into logins

Diese Abfrage wird wie folgt bearbeitet:

  • Die source ist die benutzerdefinierte Anreicherungstabelle (users).

  • Im join wird eine Zählung über das Feld userid vorgenommen. Daraus ergibt sich unsere Statistik count.

  • Das Feld id in der benutzerdefinierten Anreicherungstabelle wird mit dem Feld userid in den Protokollen verglichen.

  • Das Ergebnis wird auf die Taste logins übertragen. Wenn der Schlüssel logins bereits in der linken Abfrage vorhanden ist, wird er überschrieben.

Zum Beispiel:

{ "id": "111", "name": "John", "logins": { "userid": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "userid": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }

Das Ergebnis der Abfrage auf der rechten Seite befindet sich nun im Feld logins. Beachten Sie, dass es keine Anmeldungen für die Benutzer-ID 333 (Alice) gab, so dass das Feld Anmeldungen null lautet, weil es kein Ergebnis gab, das mit der Bedingung join übereinstimmte.

join beispiel mit dem Schlüsselwort using

Nehmen wir an, unser Login-Datensatz ist:

{ "id": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }

In diesem Fall enthalten die Daten auf beiden Seiten der Verknüpfung das Feld id. In diesem Fall kann das Schlüsselwort using verwendet werden, um die gemeinsamen Daten zu nutzen:

source users | join (source logins | countby id) using id into logins

Das Ergebnis ist ähnlich, aber anstelle von userid wird das Feld id zurückgegeben.

{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }

Wenn Sie zwei Felder haben, die unterschiedlich benannt sind, aber Ihre join Abfrage vereinfachen würden, können Sie mit move verwenden, um eines der Felder zu verschieben, damit die Schlüsselpfade auf beiden Seiten übereinstimmen.

join beispiel mit den Schlüsselwörtern left=> und right=>

Sie können die Präfixe left=> und right=> verwenden, um auf die Ereignisse der linken und rechten Abfrage zu verweisen. Sie ist jedoch nicht erforderlich, wenn ein Schlüsselpfad nur in einer der Abfragen vorhanden ist.

Betrachten Sie die Daten aus dem vorangegangenen Beispiel und stellen Sie sich folgende Frage:

source users | join (source logins | countby id) on left=>id == right=>id into logins

Dies ist erforderlich, weil beide Datensätze ein Feld mit demselben Namen enthalten (id). Damit DataPrime ein Feld eindeutig identifizieren kann, muss es wissen, auf welche Seite der Abfrage wir uns beziehen. Diese Abfrage ergibt die gleiche Ausgabe wie die vorherige, bei der das Schlüsselwort using verwendet wurde.

Wenn Sie den == (Gleichheits-)Operator in Ihrer Bedingung verwenden, muss er einen Schlüsselpfad aus der linken Abfrage mit einem Schlüsselpfad aus der rechten Abfrage vergleichen. Da die Schlüsselpfade jedoch eindeutig sein müssen oder mit left=> oder right=> vorangestellt werden, ist die Reihenfolge der Operanden nicht wichtig.

join full Beispiel

Sie haben diese benutzerdefinierte Anreicherungstabelle mit dem Namen users, die Informationen über IDs in Verbindung mit Namen enthält:

{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }

Und betrachten Sie diesen Datensatz:

{ "id": "001", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }

Die zweite Gruppe von Dokumenten (rechte Abfrage) enthält einen Protokolleintrag mit "id": "001", der in der ersten Gruppe von Dokumenten (linke Abfrage) nicht vorhanden ist. Wenn Sie einen Standard-Join verwenden, wird dieser Eintrag aus der rechten Abfrage ignoriert und erscheint nicht im Ergebnis. Um sicherzustellen, dass jedes id Feld in der Ausgabe enthalten ist, unabhängig davon, ob es in der linken oder rechten Abfrage erscheint, können Sie join full verwenden:

source users | join full (source logins | countby id) using id into logins

Diese Abfrage führt zu folgenden Ergebnissen:

{ "id": "001", "name": "null", "logins": { "id": "001", "_count": 1 } }
{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }

Durch die Verwendung von join full bleiben alle id Felder aus beiden Datensätzen erhalten, und alle fehlenden Werte werden auf null gesetzt.

join full ist besonders nützlich, wenn die Ergebnisse beider Abfragen Zeitspannen enthalten. Wenn beispielsweise in den Ergebnissen der linken Abfrage ein Zeitbereich für eine bestimmte Stunde fehlt (z. B. XX:XX:XX), wird dieser Datenpunkt mit join full aufgenommen. Dies ist besonders nützlich für den Vergleich zweier Zeitreihen in einem Diagramm.

join inner Beispiel

Wenn Sie alle Zeilen entfernen möchten, wenn Spaltenergebnisse für die linken oder rechten Abfragen einen Nullwert ergeben, verwenden Sie join inner.

Anhand der vorherigen Daten werden bei dieser Abfrage Zeilen mit nicht übereinstimmenden Daten auf beiden Seiten entfernt:

source users | join inner (source logins | countby id) using id into logins
  • Die linke Abfrage source users ruft den Benutzerdatensatz ab, der die Felder id und name enthält.

  • Die rechte Abfrage (source logins | countby id) ruft den Logins-Datensatz ab, gruppiert nach id und zählt die Vorkommen für jedes id.

  • join inner gleicht Zeilen ab, in denen id in beiden Datensätzen vorhanden ist, und führt die Daten zu einem einzigen Datensatz zusammen.

  • Zeilen, die in keinem der beiden Datensätze übereinstimmen, werden von den endgültigen Ergebnissen ausgeschlossen.

In diesem Fall ergeben sich für die beiden oben genannten Dokumentensätze die folgenden Ergebnisse:

{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }

join cross Beispiel

join cross kombiniert jede Zeile aus der linken Abfrage mit jeder Zeile aus der rechten Abfrage und erzeugt ein kartesisches Produkt der beiden Mengen.

Angenommen, wir haben die folgenden Dokumente aus einer benutzerdefinierten Anreicherungstabelle namens users.

{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }

Betrachten Sie nun diese Menge von Dokumenten mit dem Namen logs.

{ "id": "111", "timestamp": "2022-01-01T12:00:00Z" }
{ "id": "111", "timestamp": "2022-01-01T12:30:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }
{ "id": "222", "timestamp": "2022-01-01T13:00:00Z" }

Die folgende Abfrage erzeugt ein kartesisches Produkt aus den Datensätzen users und logs, da join cross jede Zeile aus der linken Abfrage mit jeder Zeile aus der rechten Abfrage paart, unabhängig von übereinstimmenden Bedingungen.

source users | join cross (source logs) into logins
{ "id": "111", "name": "John", "logins": { "id": "111", "timestamp": "2022-01-01T12:00:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "111", "timestamp": "2022-01-01T12:30:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "111", "name": "John", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "111", "timestamp": "2022-01-01T12:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "111", "timestamp": "2022-01-01T12:30:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "111", "timestamp": "2022-01-01T12:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "111", "timestamp": "2022-01-01T12:30:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }
{ "id": "333", "name": "Alice", "logins": { "id": "222", "timestamp": "2022-01-01T13:00:00Z" } }

Die Abfrage führt dazu, dass jeder Benutzer mit jedem Protokolleintrag gepaart wird: 3 Zeilen aus users multipliziert mit 5 Zeilen aus logs, was 15 Zeilen ergibt. Jeder Benutzer (John, Emily, Alice) ist mit jedem Protokolleintrag gepaart.

Die Verwendung von join cross ist vor allem dann sinnvoll, wenn Sie sich ein vollständiges Bild von Ihren Daten machen möchten und dann zu diesen Ergebnissen eine left oder right join hinzufügen möchten.

Beschränkungen und Überlegungen

Es gibt Einschränkungen und Überlegungen bei der Einbeziehung von join in eine Abfrage:

  • Die Bedingung join unterstützt nur die Gleichheit von Schlüsselpfaden (==). Wenn mehrere Gleichheitsbedingungen benötigt werden, können sie mit && (logisch und) kombiniert werden.

  • Eine Seite der Verknüpfung (entweder aktuelle Abfrage oder Verknüpfungsabfrage) muss klein sein (< 200MB ). Sie können verwenden filter und remove verwenden, um die Größe der Abfrage zu verringern.

  • Bei Left Outer Joins müssen alle Spalten in der Bedingung ungleich Null sein. Alle Nullspalten werden nicht verbunden. Um Nullspalten der rechten Abfrage einzuschließen, verwenden Sie join full. Um alle Nullspalten auszuschließen, die von den linken und rechten Joins erzeugt werden, verwenden Sie join inner.

limit

Begrenzt die Ausgabe auf die ersten event-count Ereignisse.

limit <event-count>

Beispiel:

limit 100

move

Verschieben eines Schlüssels (einschließlich seiner Unterschlüssel, falls vorhanden) an eine neue Position.

(m|move) <source-keypath> to <target-keypath>

Beispiele:

move $d.my_data.hostname to $d.my_new_data.host
m $d.kubernetes.labels to $d.my_labels

multigroupby

multigroupby fasst die Ergebnisse von zwei oder mehr Abfragen unter Einbeziehung von groupby zu einem einzigen Datensatz zusammen.

Verwenden Sie multigroupby für:

  • Effizient: Die Daten werden bei Mehrfachabfragen nur einmal gescannt.

  • Synchronisierung: Die Ergebnisse bleiben kohärent, so dass Diskrepanzen vermieden werden, die bei der Ausführung getrennter Abfragen entstehen können.

multigroupby  (<grouping_expression_1> as <alias> [, <grouping_expression_2> as <alias_2>, ...])  [, (<grouping_expression_1> as <alias> [, <grouping_expression_2> as <alias_2>, ...]), ...][calculate]  <aggregation_expression> [as <result_keypath>] [, <aggregation_expression_2> [as <result_keypath_2], ...]

Durch die Verwendung desselben Alias app für beide Gruppierungen wird die gleiche semantische Bedeutung als ein einheitliches Feld dargestellt. Im nächsten Beispiel werden verschiedene Aliasnamen verwendet und die Daten kombiniert, aber nicht zusammengeführt.

Beispiel - Multigroupby mit demselben Alias

In diesem Beispiel wollen wir unsere Protokolle wie folgt gruppieren:

  • Zunächst nach applicationname (app) und dann weiter nach subsystemname (ss), mit detaillierten Zählungen für jede Kombination.

  • Dann unabhängig von applicationname, was die Gesamtzahl der Protokolle für jede Anwendung unabhängig von subsystems ergibt.

source logs
| multigroupby ($l.applicationname as app, $l.subsystemname as ss),($l.applicationname as app) calculate count() | orderby app,ss

Das Ergebnis wird ähnlich sein:

[
    {
        "_count0": 241,
        "app": "monitoring24",
        "ss": "NO_SUBSYSTEM_NAME"
    },
    {
        "_count0": 231,
        "app": "monitoring24",
        "ss": "logs-opentelemetry-agent"
    },
    {
        "_count0": 15,
        "app": "monitoring24",
        "ss": "logs-opentelemetry-collector"
    },
    {
        "_count0": 487,
        "app": "monitoring24",
        "ss": null
    }
]

Die ersten drei Zeilen stellen die Zählungen für jede eindeutige Kombination von app und ss dar. Zum Beispiel gibt es 241 Protokolle, bei denen die Anwendung (app) monitoring24 und das Subsystem (ss) NO_SUBSYSTEM_NAME ist. In ähnlicher Weise gibt es 231 Protokolle für dieselbe Anwendung, aber mit dem Subsystem logs-opentelemetry-agent und so weiter.

In der letzten Zeile wird die Gesamtzahl der Protokolle für die Anwendung monitoring24 angegeben, wobei alle Teilsysteme zusammengefasst werden. Hier beträgt _count0 487, die Summe aller oben genannten detaillierten Zählungen. Das Feld ss ist null, um anzugeben, dass es sich um die Gesamtsumme für den gesamten Antrag handelt.

Durch die Verwendung desselben Alias app für beide Gruppierungen wird die gleiche semantische Bedeutung als ein einheitliches Feld dargestellt. Im nächsten Beispiel werden verschiedene Aliasnamen verwendet und die Daten kombiniert, aber nicht zusammengeführt.

Beispiel - Multigroupby mit verschiedenen Aliasnamen

Betrachten wir nun die Auswirkungen der Einführung von 2 verschiedenen Aliasen für die Abfragen. In diesem Fall wird die erste Gruppierung als app1 für applicationname kombiniert mit ss bezeichnet, während die zweite Gruppierung als app2 für applicationname alone bezeichnet wird.

source logs | multigroupby ($l.applicationname as app1, $l.subsystemname as ss),($l.applicationname as app2) calculate count()

Das Ergebnis wird ähnlich sein:

[
    {
        "_count0": 241,
        "app1": "monitoring24",
        "app2": null,
        "ss": "logs-opentelemetry-agent"
    },
    {
        "_count0": 231,
        "app1": "monitoring24",
        "app2": null,
        "ss": "logs-opentelemetry-collector"
    },
    {
        "_count0": 15,
        "app1": "monitoring24",
        "app2": null,
        "ss": "no_subsystem_name"
    },
    {
        "_count0": 487,
        "app1": null,
        "app2": "monitoring24",
        "ss": null
    }
]

Durch die Einführung separater Aliasnamen (app1 und app2) behält die Abfrage die Unterscheidung zwischen den beiden Gruppierungen bei, anstatt die Daten zusammenzuführen. Zeilen, in denen app1 ausgefüllt ist und app2 null ist, entsprechen der detaillierten Gruppierung nach applicationname und subsystemname. Zum Beispiel sind 241 Protokolle mit app1 = "monitoring24" und ss = "logs-opentelemetry-agent" verbunden. Dies entspricht der ersten Gruppierungslogik.

Die Zeile, in der app2 aufgefüllt wird und app1 null ist, spiegelt die Gesamtzahl für die zweite Gruppierung wider, bei der die Protokolle ausschließlich nach applicationname aggregiert werden. Für app2 = "monitoring24" beträgt die Anzahl 487, und sowohl app1 als auch ss sind null, um diese übergeordnete Aggregation anzuzeigen.

Durch die Verwendung separater Aliasnamen (app1 und app2) führt die Abfrage die Daten nicht zusammen, sondern macht deutlich, zu welcher Gruppe die einzelnen Ergebnisse gehören. Die allgemeine Logik bleibt dieselbe: detaillierte Zählungen für spezifische Kombinationen und aggregierte Zählungen für die Gesamtzahl.

Multigroupby - Einschränkungen

multigroupby gibt keine doppelten Zeilen für doppelte Gruppensätze zurück.

Wenn Sie multigroupby mit app und ss ausführen, könnte das erwartete Ergebnis (wenn Duplikate zulässig wären) wie folgt aussehen:

[
  {"app": "monitoring24", "ss": "logs-opentelemetry-agent", "_count0": 2},
  {"app": "monitoring24", "ss": "logs-opentelemetry-collector", "_count0": 2}
]

Aufgrund dieser Einschränkung führt multigroupby diese Duplikate zusammen und gibt nur eine Zeile für jede eindeutige Kombination zurück, auch wenn diese Kombination mehrfach in den Daten vorkommt:

[
  {"app": "monitoring24", "ss": "logs-opentelemetry-agent", "_count0": 2}
]

orderby / sortby / order by / sort by

Sortieren Sie die Daten in aufsteigender/absteigender Reihenfolge nach dem Wert des Ausdrucks. Das Ordnen nach mehreren Ausdrücken wird unterstützt.

(orderby|sortby|order by|sort by) <expression> [(asc|desc)] , ...

Beispiele:

orderby $d.myfield.myfield
orderby $d.myfield.myfield:number desc
sortby $d.myfield desc

Die Sortierung numerischer Werte kann durch Casting des Ausdrucks auf den Typ: erfolgen, z. B. <expression>: number. In einigen Fällen wird dies von der Maschine automatisch abgeleitet.

redact

Ersetzt alle Teilzeichenketten, die mit einem Regexp-Muster übereinstimmen, aus einem Keypath-Wert und verbirgt so den ursprünglichen Inhalt.

Das passende Schlüsselwort ist optional und kann zur Verbesserung der Lesbarkeit verwendet werden.

redact <keypath> [matching] /<regular-expression>/ to '<redacted_str>'
redact <keypath> [matching] <string> to '<redacted_str>'

Beispiele:

redact $d.mykey /[0-9]+/ to 'SOME_INTEGER'
redact $d.mysuperkey.user_id 'root' to 'UNKNOWN_USER'
redact $d.mysuperkey.user_id matching 'root' to 'UNKNOWN_USER'

remove

Entfernt einen Tastaturpfad aus dem Objekt.

r|remove <keypath1> [ "," <keypath2> ]...

Beispiele:

r $d.mydata.unneeded_key
remove $d.mysuperkey.service_name, $d.mysuperkey.unneeded_key

replace

Ersetzen Sie den Wert eines Schlüssels durch einen neuen Wert.

Wenn der Ersetzungswert den Datentyp des Keypaths ändert, stehen die folgenden Optionen zur Verfügung:

  • skip- Die Ersetzung wird ignoriert

  • fail- Die Abfrage wird fehlschlagen

  • overwrite- Der neue Wert überschreibt den vorherigen Wert und ändert den Datentyp des Keypaths

replace <keypath> with <expression> [on datatype changed skip/fail/overwrite]

Beispiele:

replace $d.message with null
replace $d.some_superkey.log_length_plus_10 with $d.original_log.length()+10 on datatype changed overwrite

roundtime

Rundet die Zeit des Ereignisses in ein bestimmtes Zeitintervall und erstellt möglicherweise einen neuen Schlüssel für das Ergebnis.

  • Wenn source-timestamp nicht angegeben wird, wird $m.timestamp als Quellzeitstempel verwendet.

  • Wenn source-timestamp angegeben wird, sollte es vom Typ timestamp sein (oder in diesen umgewandelt werden).

Standardmäßig wird das gerundete Ergebnis in den Quell-Keypath source-timestamp zurückgeschrieben. Wenn in target-keypath angegeben wird, wird source-timestamp nicht geändert und das Ergebnis wird in ein neues target-keypath geschrieben.

Unterstützte Zeitintervalle sind:

  • Xns - X Nanosekunden (Achten Sie auf die Auflösung des Zeitstempels der Quelle)
  • Xms - X Millisekunden
  • Xs - X Sekunden
  • Xm - X Minuten
  • Xh - X Stunden
  • Xd - X Tage

Und jede Kombination von größeren zu kleineren Zeiteinheiten, zum Beispiel 1h30m15s.

roundtime [source-timestamp] to <time-interval> [into <target-keypath>]

Beispiele:

roundtime to 1h into $d.tm
roundtime $d.timestamp to 1h
roundtime $d.my_timestamp: timestamp to 60m
roundtime to 60s into $d.rounded_ts_to_the_minute

source

Legen Sie die Datenquelle fest, auf der Ihre DataPrime-Abfrage basiert.

(source|from) <data_store>

Wobei data_store entweder sein kann:

  • logs

  • Der Name der benutzerdefinierten Anreicherung. In diesem Fall wird der Befehl die benutzerdefinierte Anreicherungstabelle anzeigen.

Beispiele:

source logs

stitch

Der Befehl stitch führt eine horizontale Vereinigung von zwei Datensätzen durch, indem er sie Seite an Seite kombiniert. Es gleicht Zeilen aus einem Datensatz mit Zeilen aus einem anderen ab und verkettet ihre Spalten, wodurch ein einziger, einheitlicher Datensatz entsteht.

Bei Verwendung des Befehls stitch:

  • Die Datensätze müssen geordnet sein, da die Zeilen der Reihe nach kombiniert werden (d. h. Zeile 1 von Datensatz A wird mit Zeile 1 von Datensatz B zusammengefügt).

  • Wenn ein Datensatz mehr Zeilen als der andere hat, haben nicht übereinstimmende Zeilen Nullwerte in den zusammengefügten Spalten.

  • Das resultierende Dataset enthält alle Spalten aus beiden Datasets.

stitch unterscheidet sich von union. stitch kombiniert Datensätze horizontal, indem es Spalten zeilenweise anhängt. union hängt Zeilen vertikal an, indem es Datensätze übereinander stapelt.

... | stitch (<subquery>) into <target-keypath>

Beispiel:

Sie haben diese benutzerdefinierten Anreicherungstabellen:

sales datensatz:

{ "product": "Widget", "sales": 100 }
{ "product": "Gadget", "sales": 200 }
{ "product": "Dashboard", "sales": 150 }

revenue datensatz:

{ "product": "Widget", "revenue": 5000 }
{ "product": "Gadget", "revenue": 8000 }
{ "product": "Dashboard", "revenue": 6000 }

In dieser Abfrage kombinieren Sie diese Datensätze nebeneinander und stellen sicher, dass jede Zeile des einen Datensatzes mit der entsprechenden Zeile des anderen Datensatzes übereinstimmt:

source sales | orderby product
| stitch (source revenue | orderby product) into combined_data
  • source sales holt alle Zeilen aus dem Datensatz sales, der Produkte und die entsprechenden Verkaufszahlen enthält.

  • orderby product sortiert den Datensatz sales nach dem Feld product, um eine einheitliche Reihenfolge für die Ausrichtung der Zeilen zu schaffen.

  • stitch (source revenue | orderby product) holt Zeilen aus dem Datensatz revenue und sortiert sie nach dem Feld product. Die Datensätze sales und revenue werden horizontal kombiniert, wobei die Zeilen nach der Sortierung in ihrer Reihenfolge ausgerichtet werden.

  • into combined_data speichert den kombinierten Datensatz in einer Variablen namens combined_data.

Das Ergebnis der Abfrage ist:

{ "product": "Widget", "sales": 100, "combined_data": { "product": "Widget", "revenue": 5000 } }
{ "product": "Gadget", "sales": 200, "combined_data": { "product": "Gadget", "revenue": 8000 } }
{ "product": "Dashboard", "sales": 150, "combined_data": { "product": "Dashboard", "revenue": 6000 } }

Wenn die Datensätze ungleiche Zeilen haben, füllt der Befehl stitch die fehlenden Werte mit null auf.

Nehmen wir zum Beispiel die folgenden Datensätze:

sales datensatz (3 Zeilen):

{ "product": "Widget", "sales": 100 }
{ "product": "Gadget", "sales": 200 }
{ "product": "Dashboard", "sales": 150 }

revenue datensatz (2 Zeilen):

{ "product": "Widget", "revenue": 5000 }
{ "product": "Gadget", "revenue": 8000 }

Diese Abfrage wird ausgeführt:

source sales | orderby product
| stitch (source revenue | orderby product) into combined_data

Ergebnisse in:

{ "product": "Widget", "sales": 100, "combined_data": { "product": "Widget", "revenue": 5000 } }
{ "product": "Gadget", "sales": 200, "combined_data": { "product": "Gadget", "revenue": 8000 } }
{ "product": "Dashboard", "sales": 150, "combined_data": { "product": "Dashboard", "revenue": null } }

stitch Hinweise zur Verwendung

  • Die Zeilen müssen logisch zusammenhängen, damit das Heften sinnvolle Ergebnisse liefert. Vergewissern Sie sich, dass die Zeilen aus beiden Datensätzen dieselben Entitäten darstellen und in derselben Reihenfolge angeordnet sind. Wenn z. B. das Feld product im Datensatz sales nicht mit dem Feld product im Datensatz revenue für die entsprechenden Zeilen übereinstimmt, funktioniert die Verknüpfung nicht wie erwartet.

  • Wenn sich die Datensätze in der Zeilenzahl unterscheiden, enthält das Ergebnis null Werte für fehlende Daten in dem kürzeren Datensatz.

top

Keine Gruppierungsvariante: Begrenzt die zurückgegebenen Zeilen auf eine bestimmte Anzahl und ordnet das Ergebnis nach einer Reihe von Ausdrücken.

order_direction := "descending"/"ascending" according to top/bottom

top <limit> <result_expression1> [as <alias>] [, <result_expression2> [as <alias2>], ...] by <orderby_expression> [as alias>]

Beispielsweise sollte die Abfrage

top 5 $m.severity as $d.log_severity by $d.duration

Führt zu Protokollen der folgenden Form:

[
   { "log_severity": "Warning", "duration": 2000 },
   { "log_severity": "Debug", "duration":  1000 }
   ...
]

Gruppierungsvariation: Begrenzt die zurückgegebenen Zeilen auf eine bestimmte Anzahl und gruppiert sie nach einer Reihe von Aggregationsausdrücken und ordnet sie nach einer Reihe von Ausdrücken.

order_direction := "descending"/"ascending" according to top/bottom

top <limit> <(groupby_expression1|aggregate_function1)> [as <alias>] [, <(groupby_expression2|aggregate_function2)> [as <alias2>], ...] by <(groupby_expression1|aggregate_function1)> [as <alias>]

Beispielsweise sollte die Abfrage

top 10 $m.severity, count() as $d.number_of_severities by avg($d.duration) as $d.avg_duration

Führt zu Protokollen der folgenden Form:

[
   { "severity": "Debug", "number_of_severities":  10, avg_duration: 2000 }
   { "severity": "Warning", "number_of_severities": 50, avg_duration: 1000 },
   ...
]

Sie können eine Aggregationsfunktion anwenden..

union

Der Befehl union fasst die Ergebnisse von zwei oder mehr Datensätzen zu einem Datensatz zusammen. Dies ermöglicht es den Nutzern, die Ergebnisse mehrerer Abfragen in einem einzigen nahtlosen Datensatz zu kombinieren. Ein Datensatz kann eine Ergebnismenge sein, die über die Pipeline in den Befehl union geleitet und dann mit einem anderen Datensatz verkettet wird.

Verwenden Sie union, wenn Sie Zeilen aus einem Datensatz an einen anderen anhängen müssen.

Um die Leistung bei der Verarbeitung großer Datensätze zu optimieren, sollten Sie die Verwendung von filter in Betracht ziehen, um Zeilen aus jedem Datensatz zu begrenzen, bevor Sie union verwenden.

Die Benutzer können maximal 10 union Befehle pro Abfrage für Prioritätserkenntnisse Daten verwenden. Für andere Daten gibt es keine Beschränkungen.

Wie unterscheidet sich union von join

  • union kombiniert Ergebnismengen durch Anhängen von Zeilen aus einem Datensatz an einen anderen. Es werden keine Spalten aus mehreren Dokumenten zusammengeführt oder verglichen.

  • join gleicht Spalten aus zwei Tabellen auf der Grundlage einer Bedingung ab und kombiniert sie, wodurch Zeilen entstehen, die Daten aus beiden Tabellen enthalten.

<query> | union <query>

Beispiel für die Kombination von 2 Datensätzen

Sie haben diese 2 Datensätze:

Protokolle für Team 58942

{ "id": "111", "name": "John" , "team.id": "58942" }
{ "id": "222", "name": "Emily", "team.id": "58942" }
{ "id": "333", "name": "Alice", "team.id": "58942" }

Protokolle für Team 98361

{ "userid": "111", "timestamp": "2022-01-01T12:00:00Z", "team.id": "98361" }
{ "userid": "111", "timestamp": "2022-01-01T12:30:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }

Und Sie wollen sie zu einem Datensatz zusammenfassen. Sie können dies mit union tun.

source logs(teamId=58942) | union logs(teamId=98361)

Die Abfrage verarbeitet die beiden Datensätze:

  • source logs(teamId=58942): Ruft alle Dokumente ab für Team 58942
  • union logs (teamID=98361): Hängt den Datensatz Team 98361 an den Datensatz Team 58942 an

Das Ergebnis ist der folgende Datensatz:

{ "id": "111", "name": "John" , "team.id": "58942" }
{ "id": "222", "name": "Emily", "team.id": "58942" }
{ "id": "333", "name": "Alice", "team.id": "58942" }
{ "userid": "111", "timestamp": "2022-01-01T12:00:00Z", "team.id": "98361" }
{ "userid": "111", "timestamp": "2022-01-01T12:30:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }
{ "userid": "222", "timestamp": "2022-01-01T13:00:00Z", "team.id": "98361" }