Freigeben über


log_reduce_fl()

Gilt für: ✅Microsoft Fabric✅Azure Data Explorer

Die Funktion log_reduce_fl() findet gängige Muster in halbstrukturierten Textspalten, z. B. Protokollzeilen, und gruppiert die Linien entsprechend den extrahierten Mustern. Es gibt eine Zusammenfassungstabelle mit den gefundenen Mustern aus, die nach der jeweiligen Häufigkeit sortiert sind.

Voraussetzungen

  • Das Python-Plug-In muss im Cluster aktiviert sein. Dies ist für die inline Python erforderlich, die in der Funktion verwendet wird.
  • Das Python-Plug-In muss in der Datenbank aktiviert sein. Dies ist für die inline Python erforderlich, die in der Funktion verwendet wird.

Syntax

Tinvoke log_reduce_fl(| reduce_col [, use_logram [ , use_drain [, custom_regexes [ , custom_regexes_policy [, Trennzeichen [ , similarity_th [ , tree_depth [ trigram_th [ ,, bigram_th ]]]]]]]]])

Erfahren Sie mehr über Syntaxkonventionen.

Parameter

Die folgende Parameterbeschreibung ist eine Zusammenfassung. Weitere Informationen finden Sie im Abschnitt "Weitere Informationen zum Algorithmus ".

Name Type Erforderlich Beschreibung
reduce_col string ✔️ Der Name der Zeichenfolgenspalte, auf die die Funktion angewendet wird.
use_logram bool Aktivieren oder deaktivieren Sie den Logram-Algorithmus. Der Standardwert ist true.
use_drain bool Aktivieren oder deaktivieren Sie den Entwässerungsalgorithmus. Der Standardwert ist true.
custom_regexes dynamic Ein dynamisches Array, das Paare regulärer Ausdrücke und Ersetzungssymbole enthält, die in jeder Eingabezeile durchsucht und durch das entsprechende übereinstimmende Symbol ersetzt werden sollen. Der Standardwert ist dynamic([]). Die Standardmäßige regex-Tabelle ersetzt Zahlen, IP-Adressen und GUIDs.
custom_regexes_policy string Entweder 'prepend', 'append' oder 'replace'. Steuert, ob custom_regexes den Standardeinstellungen vorangestellt/angefügt/ersetzt werden. Der Standardwert ist "prepend".
delimiters dynamic Ein dynamisches Array, das Trennzeichenzeichenfolgen enthält. Der Standardwert ist dynamic([" "])das Definieren des Leerzeichens als einziges Einzelnes Zeichentrennzeichen.
similarity_th real Ähnlichkeitsschwellenwert, der vom Entwässerungsalgorithmus verwendet wird. Das Erhöhen similarity_th führt zu optimierten Datenbanken. Der Standardwert ist 0,5. Wenn "Drain" deaktiviert ist, hat dieser Parameter keine Auswirkung.
tree_depth int Das Erhöhen tree_depth verbessert die Laufzeit des Entwässerungsalgorithmus, kann jedoch die Genauigkeit verringern. Der Standardwert ist 4. Wenn "Drain" deaktiviert ist, hat dieser Parameter keine Auswirkung.
trigram_th int Das Verringern trigram_th erhöht die Wahrscheinlichkeit, dass Logram Token durch Wildcards ersetzt. Der Standardwert ist 10. Wenn Logram deaktiviert ist, hat dieser Parameter keine Auswirkung.
bigram_th int Das Verringern bigram_th erhöht die Wahrscheinlichkeit, dass Logram Token durch Wildcards ersetzt. Standardwert: 15. Wenn Logram deaktiviert ist, hat dieser Parameter keine Auswirkung.

Weitere Informationen zum Algorithmus

Die Funktion führt Mehrere Übergänge über die Zeilen aus, um auf allgemeine Muster reduziert zu werden. In der folgenden Liste werden die Durchläufe erläutert:

  • Ersetzung regulärer Ausdrücke: In diesem Durchlauf wird jede Zeile unabhängig von einer Reihe regulärer Ausdrücke abgeglichen, und jeder übereinstimmende Ausdruck wird durch ein Ersatzsymbol ersetzt. Die standardmäßigen regulären Ausdrücke ersetzen IP-Adressen, Zahlen und GUIDs durch /<IP>, <GUID> und /<NUM>. Der Benutzer kann diesen ausdrücken oder durch neue oder leere Listen ersetzen, indem er custom_regexes und custom_regexes_policy ändert. Um z. B. ganze Zahlen durch <WNUM-Set> custom_regexes=pack_array('/^\d+$/', '<WNUM>') zu ersetzen); um den Ersetzungssatz für reguläre Ausdrücke custom_regexes_policy='replace' abzubrechen. Für jede Zeile behält die Funktion die Liste der ursprünglichen Ausdrücke (vor Ersetzungen) bei, die als Parameter der generischen Ersetzungstoken ausgegeben werden sollen.

  • Tokenisierung: Ähnlich wie im vorherigen Schritt wird jede Zeile unabhängig verarbeitet und basierend auf einer Gruppe von Trennzeichen in Token unterteilt. Wenn Sie z. B. den Umbruch in Token durch Komma, Punkt oder Semikolon definieren möchten, legen Sie Trennzeichen=pack_array(',', '.', ';' fest).

  • Logram-Algorithmus anwenden: Dieser Pass ist optional, use_logram aussteht. Wir empfehlen die Verwendung von Logram, wenn große Skalierung erforderlich ist und wann Parameter in den ersten Token des Protokolleintrags angezeigt werden können. Deaktivieren Sie ihn, wenn die Protokolleinträge kurz sind, da der Algorithmus in solchen Fällen zu häufig Token durch Wildcards ersetzt. Der Logram-Algorithmus berücksichtigt 3-Tupel und 2-Tupel von Token. Wenn ein 3-Tupel von Token in den Protokollzeilen üblich ist (es wird mehr als trigram_th Mal angezeigt), ist es wahrscheinlich, dass alle drei Token Teil des Musters sind. Wenn das 3-Tupel selten ist, ist es wahrscheinlich, dass es eine Variable enthält, die durch einen Wildcard ersetzt werden soll. Bei seltenen 3-Tupeln betrachten wir die Häufigkeit, mit der 2-Tupel im 3-Tupel enthalten sind. Wenn ein 2-Tupel häufig ist (es wird mehr als bigram_th Mal angezeigt), ist das verbleibende Token wahrscheinlich ein Parameter und nicht Teil des Musters.
    Der Logram-Algorithmus ist einfach zu parallelisieren. Es erfordert zwei Übergänge am Protokollkorpus: die erste, um die Häufigkeit jedes 3-Tupels und 2-Tupels zu zählen, und der zweite, um die zuvor beschriebene Logik auf jeden Eintrag anzuwenden. Um den Algorithmus zu parallelisieren, müssen wir die Protokolleinträge nur partitionieren und die Häufigkeit der verschiedenen Mitarbeiter vereinheitlichen.

  • Anwenden des Entwässerungsalgorithmus: Dieser Pass ist optional, use_drain aussteht. "Drain" ist ein Protokollanalysealgorithmus, der auf einer abgeschnittenen Tiefenpräfixstruktur basiert. Protokollnachrichten werden entsprechend ihrer Länge geteilt, und für jede Länge werden die ersten tree_depth Token der Protokollnachricht verwendet, um eine Präfixstruktur zu erstellen. Wenn keine Übereinstimmung für die Präfixtoken gefunden wurde, wird eine neue Verzweigung erstellt. Wenn eine Übereinstimmung für das Präfix gefunden wurde, suchen wir nach dem ähnlichsten Muster unter den Mustern, die im Baumblatt enthalten sind. Die Ähnlichkeit des Musters wird durch das Verhältnis übereinstimmener Nichtwildcardtoken aus allen Token gemessen. Wenn die Ähnlichkeit des am ähnlichsten Musters über dem Ähnlichkeitsschwellenwert liegt (der Parameter similarity_th), wird der Protokolleintrag mit dem Muster abgeglichen. Für dieses Muster ersetzt die Funktion alle nicht übereinstimmenden Token durch Wildcards. Wenn die Ähnlichkeit des am ähnlichsten Musters unter dem Ähnlichkeitsschwellenwert liegt, wird ein neues Muster erstellt, das den Protokolleintrag enthält.
    Wir legen standardmäßig tree_depth auf 4 fest, basierend auf dem Testen verschiedener Protokolle. Durch die Erhöhung dieser Tiefe kann die Laufzeit verbessert werden, aber die Genauigkeit von Mustern kann beeinträchtigt werden; Das Verringern ist genauer, aber langsamer, da jeder Knoten viele weitere Ähnlichkeitstests durchführt.
    In der Regel verallgemeinert "Drain" effizient und reduziert Muster (obwohl es schwierig ist, parallelisiert zu werden). Da sie jedoch auf eine Präfixstruktur angewiesen ist, ist sie in Protokolleinträgen, die Parameter in den ersten Token enthalten, möglicherweise nicht optimal. Dies kann in den meisten Fällen gelöst werden, indem Sie Logram zuerst anwenden.

Funktionsdefinition

Sie können die Funktion definieren, indem Sie den Code entweder als abfragedefinierte Funktion einbetten oder wie folgt als gespeicherte Funktion in Ihrer Datenbank erstellen:

Definieren Sie die Funktion mithilfe der folgenden Let-Anweisung. Es sind keine Berechtigungen erforderlich.

Wichtig

Eine Let-Anweisung kann nicht alleine ausgeführt werden. Auf sie muss eine tabellarische Ausdrucksanweisung folgen. Informationen zum Ausführen eines funktionierenden Beispiels log_reduce_fl()finden Sie unter Beispiel.

let log_reduce_fl=(tbl:(*), reduce_col:string,
              use_logram:bool=True, use_drain:bool=True, custom_regexes: dynamic = dynamic([]), custom_regexes_policy: string = 'prepend',
              delimiters:dynamic = dynamic(' '), similarity_th:double=0.5, tree_depth:int = 4, trigram_th:int=10, bigram_th:int=15)
{
    let default_regex_table = pack_array('(/|)([0-9]+\\.){3}[0-9]+(:[0-9]+|)(:|)', '<IP>', 
                                         '([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})', '<GUID>', 
                                         '(?<=[^A-Za-z0-9])(\\-?\\+?\\d+)(?=[^A-Za-z0-9])|[0-9]+$', '<NUM>');
    let kwargs = bag_pack('reduced_column', reduce_col, 'delimiters', delimiters,'output_column', 'LogReduce', 'parameters_column', '', 
                          'trigram_th', trigram_th, 'bigram_th', bigram_th, 'default_regexes', default_regex_table, 
                          'custom_regexes', custom_regexes, 'custom_regexes_policy', custom_regexes_policy, 'tree_depth', tree_depth, 'similarity_th', similarity_th, 
                          'use_drain', use_drain, 'use_logram', use_logram, 'save_regex_tuples_in_output', True, 'regex_tuples_column', 'RegexesColumn', 
                          'output_type', 'summary');
    let code = ```if 1:
        from log_cluster import log_reduce
        result = log_reduce.log_reduce(df, kargs)
    ```;
    tbl
    | extend LogReduce=''
    | evaluate python(typeof(Count:int, LogReduce:string, example:string), code, kwargs)
};
// Write your query to use the function here.

Beispiel

Im folgenden Beispiel wird der Aufrufoperator verwendet, um die Funktion auszuführen. In diesem Beispiel wird Apache Hadoop verteilte Dateisystemprotokolle verwendet.

Um eine abfragedefinierte Funktion zu verwenden, rufen Sie sie nach der definition der eingebetteten Funktion auf.

let log_reduce_fl=(tbl:(*), reduce_col:string,
              use_logram:bool=True, use_drain:bool=True, custom_regexes: dynamic = dynamic([]), custom_regexes_policy: string = 'prepend',
              delimiters:dynamic = dynamic(' '), similarity_th:double=0.5, tree_depth:int = 4, trigram_th:int=10, bigram_th:int=15)
{
    let default_regex_table = pack_array('(/|)([0-9]+\\.){3}[0-9]+(:[0-9]+|)(:|)', '<IP>', 
                                         '([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})', '<GUID>', 
                                         '(?<=[^A-Za-z0-9])(\\-?\\+?\\d+)(?=[^A-Za-z0-9])|[0-9]+$', '<NUM>');
    let kwargs = bag_pack('reduced_column', reduce_col, 'delimiters', delimiters,'output_column', 'LogReduce', 'parameters_column', '', 
                          'trigram_th', trigram_th, 'bigram_th', bigram_th, 'default_regexes', default_regex_table, 
                          'custom_regexes', custom_regexes, 'custom_regexes_policy', custom_regexes_policy, 'tree_depth', tree_depth, 'similarity_th', similarity_th, 
                          'use_drain', use_drain, 'use_logram', use_logram, 'save_regex_tuples_in_output', True, 'regex_tuples_column', 'RegexesColumn', 
                          'output_type', 'summary');
    let code = ```if 1:
        from log_cluster import log_reduce
        result = log_reduce.log_reduce(df, kargs)
    ```;
    tbl
    | extend LogReduce=''
    | evaluate python(typeof(Count:int, LogReduce:string, example:string), code, kwargs)
};
//
// Finding common patterns in HDFS logs, a commonly used benchmark for log parsing
//
HDFS_log
| take 100000
| invoke log_reduce_fl(reduce_col="data")

Output

Anzahl LogReduce Beispiel
55356 081110 <NUM NUM><INFO> DFS. FSNamesystem: BLOCK* NameSystem.delete: blk_<NUM> wird zu invalidSet of <IP> 081110 220623 26 INFO dfs hinzugefügt. FSNamesystem: BLOCK* NameSystem.delete: blk_1239016582509138045 wird zu invalidSet von 10.251.123.195:50010 hinzugefügt.
10278 081110 <NUM NUM><INFO> DFS. FSNamesystem: BLOCK* NameSystem.addStoredBlock: blockMap updated: <IP> is added to blk_<NUM> size <NUM> 081110 215858 27 INFO dfs. FSNamesystem: BLOCK* NameSystem.addStoredBlock: blockMap updated: 10.250.11.85:50010 is added to blk_5080254298708411681 size 67108864
10256 081110 <NUM NUM><INFO> DFS. DataNode$PacketResponder: PacketResponder <NUM> für block blk_<NUM> endating 081110 215858 15496 INFO dfs. DataNode$PacketResponder: PacketResponder 2 für block blk_-7746692545918257727 beenden
10256 081110 <NUM NUM><INFO> DFS. DataNode$PacketResponder: Empfangener Block blk_<NUM> der Größe <NUM> von <IP> 081110 215858 15485 INFO dfs. DataNode$PacketResponder: Empfangener Block blk_5080254298708411681 größe 67108864 von /10.251.43.21
9140 081110 <NUM NUM><INFO> DFS. DataNode$DataXceiver: Empfangen von Block blk_<NUM> src: <IP dest: <IP>> 081110 215858 15494 INFO dfs. DataNode$DataXceiver: Empfangen von Block blk_-7037346755429293022 src: /10.251.43.21:45933 dest: /10.251.43.21:50010
3047 081110 <NUM NUM><INFO> DFS. FSNamesystem: BLOCK* NameSystem.allocateBlock: /user/root/rand3/temporary/task<NUM><NUM>m<NUM_<NUM>>/part-NUM><. <>081110 215858 26 INFO dfs. FSNamesystem: BLOCK NameSystem.allocateBlock: /user/root/rand3/_temporary/task_200811101024_0005_m_001805_0/part-01805. blk-7037346755429293022
1402 081110 <NUM NUM><> INFO <>: <> Block blk_<NUM><> <> 081110 215957 15556 INFO dfs. DataNode$DataTransfer: 10.250.15.198:50010:Übertragener Block blk_-3782569120714539446 bis /10.251.203.129:50010
177 081110 <NUM NUM><> INFO <>: <>> <><<*> 081110 215859 13 INFO dfs. DataBlockScanner: Überprüfung für blk_-7244926816084627474 erfolgreich
36 081110 <NUM NUM><> INFO <>: <>> <><für Block <*> 081110 215924 15636 INFO dfs. DataNode$BlockReceiver: Empfangen eines leeren Pakets für block blk_3991288654265301939
12 081110 <NUM NUM><INFO> DFS. FSNamesystem: BLOCK* <>><> <> <> <><><> <081110 215953 19 INFO dfs. FSNamesystem: BLOCK* ask 10.250.15.198:50010 to replicate blk_-3782569120714539446 to datanode(s) 10.251.203.129:50010
12 081110 <NUM NUM><> INFO <>: <>> <> <<<>>Block blk_<NUM><> <> 081110 215955 18 INFO dfs. DataNode: 10.250.15.198:50010 Startthread zum Übertragen von Block blk_-3782569120714539446 auf 10.251.203.129:50010
12 081110 <NUM NUM><INFO> DFS. DataNode$DataXceiver: Received block blk_<NUM> src: <IP dest: <IP>> of size <NUM> 081110 215957 15226 INFO dfs. DataNode$DataXceiver: Empfangener Block blk_-3782569120714539446 src: /10.250.15.198:51013 dest: /10.250.15.198:50010 der Größe 14474705
6 081110 <ANZAHL ANZAHL>DFS>><.< FSNamesystem: BLOCK NameSystem.addStoredBlock: <>> <<><> <<> <> <>>size <NUM> 081110 215924 27 WARN dfs. FSNamesystem: BLOCK* NameSystem.addStoredBlock: Redundante addStoredBlock-Anforderung empfangen für blk_2522553781740514003 am 10.251.202.134:50010 size 67108864
6 081110 <NUM NUM><INFO> DFS. DataNode$DataXceiver: <> <>>><<> <: <> <<>>> <><081110 215936 15714 INFO dfs. DataNode$DataXceiver: writeBlock blk_720939897861061328 empfangene Ausnahme java.io.IOException: Aus Stream konnte nicht gelesen werden
3 081110 <NUM NUM><INFO> DFS. FSNamesystem: BLOCK* NameSystem.addStoredBlock: <> <>> <<<>> <>><size <NUM>><> <<>><<>><> <> <. 081110 220635 28 INFO dfs. FSNamesystem: BLOCK NameSystem.addStoredBlock: addStoredBlock-Anforderung empfangen für blk_-81196479666306310 am 10.250.17.177:50010 size 53457811 Aber es gehört nicht zu einer Datei.
1 081110 <ZAHL:><> <><> <> <><<>>><><> < . . <><> <><> <> 081110 220631 19 WARN dfs. FSDataset: Unerwarteter Fehler beim Löschen von Block blk_-2012154052725261337. BlockInfo wurde in volumeMap nicht gefunden.