DataPrime operatori
Questa guida fornisce un glossario degli operatori di IBM® Cloud Logs DataPrime.
block
La negazione di filter. Filtra tutti gli eventi in cui la condizione è vera. Lo stesso effetto può essere ottenuto utilizzando filter con !(condition).
block $d.status_code >= 200 && $d.status_code <= 299 # Leave all events which don't have a status code of 2xx
I dati sono esposti utilizzando i seguenti campi:
-
$m - Metadati dell'evento
timestampseverity- I valori possibili sonoVerbose,Debug,Info,Warning,Error,Criticalpriorityclass- I valori possibili sonohigh,medium,lowlogid
-
$l - Etichette degli eventi
applicationnamesubsystemnamecategoryclassnamecomputernamemethodnamethreadidipaddress
-
$d -I dati dell'utente
bottom
Nessuna variazione di raggruppamento: Limita le righe restituite a un numero specificato e ordina il risultato in base a un insieme di espressioni.
order_direction := "descending"/"ascending" according to top/bottom
bottom <limit> <result_expression1> [as <alias>] [, <result_expression2> [as <alias2>], ...] by <orderby_expression> [as alias>]
Ad esempio la seguente query:
bottom 5 $m.severity as $d.log_severity by $d.duration
Il risultato sarà un registro della forma seguente:
[
{ "log_severity": "Debug", "duration": 1000 }
{ "log_severity": "Warning", "duration": 2000 },
...
]
Variazione di raggruppamento: Limita le righe restituite a un numero specifico e le raggruppa in base a un insieme di espressioni di aggregazione e le ordina in base a un insieme di espressioni.
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>]
Ad esempio la seguente query:
bottom 10 $m.severity, count() as $d.number_of_severities by avg($d.duration) as $d.avg_duration
Il risultato sarà un registro della forma seguente:
[
{ "severity": "Warning", "number_of_severities": 50, avg_duration: 1000 },
{ "severity": "Debug", "number_of_severities": 10, avg_duration: 2000 }
...
]
Le funzioni di aggregazione supportate sono elencate nella sezione "Funzioni di aggregazione".
choose
Lasciare solo i percorsi chiave forniti, scartando tutte le altre chiavi. Supporta completamente i percorsi chiave annidati nell'output.
(choose|select) <keypath1> [as <new_keypath>],<keypath2> [as <new_keypath>],...
Esempi:
choose $d.mysuperkey.myfield
choose $d.my_superkey.mykey as $d.important_value, 10 as $d.the_value_ten
convert
Convertire i tipi di dati delle chiavi.
La parola chiave datatypes è facoltativa e può essere usata per la leggibilità.
(conv|convert) [datatypes] <keypath1>:<datatype1>,<keypath2>:<datatype2>,...
Esempi:
convert $d.level:number
conv datatypes $d.long:number,$d.lat:number
convert $d.data.color:number,$d.item:string
count
Restituisce una singola riga contenente il numero di righe prodotte dagli operatori precedenti.
count [into <keypath>]
È possibile fornire un alias per sovrascrivere il percorso chiave in cui verrà scritto il risultato.
Ad esempio, la seguente parte di una query:
count into $d.num_rows
Il risultato sarà una singola riga della forma seguente:
{ "num_rows": 7532 }
countby
Restituisce una riga che conta tutte le righe raggruppate dall'espressione.
countby <expression> [as <alias>] [into <keypath>]
È possibile fornire un alias per sovrascrivere il percorso chiave in cui verrà scritto il risultato.
Ad esempio, la seguente parte di una query
countby $d.verb into $d.verb_count
Si otterrà una riga per ogni gruppo.
È funzionalmente identico a
groupby $data.verb calculate count() as $d.verb_count
create
Creare una nuova chiave e impostare il suo valore sul risultato dell'espressione. La creazione delle chiavi è granulare, il che significa che le chiavi parentali nel percorso non vengono sovrascritte.
(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)
La creazione può essere controllata aggiungendo le seguenti clausole:
-
L'aggiunta di
keypath existsconsente di scegliere cosa fare quando il percorso chiave esiste già.-
overwrite- Sovrascrive il vecchio valore. Questo è il valore predefinito -
fail- Non riesce a eseguire l'interrogazione -
skip- Salta la creazione della chiave
-
-
L'aggiunta di
keypath missingsceglie cosa fare quando il nuovo percorso chiave non esiste.-
create- Crea la chiave. Questo è il valore predefinito -
fail- Non riesce a eseguire l'interrogazione -
skip- Salta la creazione della nuova chiave
-
-
Adding on
datatype changedsceglie cosa fare se la chiave esiste già e i nuovi dati cambiano il tipo di dato del valore.-
overwrite- Sovrascrive il valore. Questo è il valore predefinito. -
fail- Non riesce a eseguire l'interrogazione -
skip- Lascia la chiave con il valore (e il tipo) originale
-
Esempi:
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
Restituisce una riga per ogni combinazione distinta delle espressioni fornite.
distinct <expression> [as <alias>] [, <expression_2> [as <alias_2>], ...]
Questo operatore è funzionalmente identico a groupby senza funzioni aggregate.
enrich
Arricchite i vostri log utilizzando un contesto aggiuntivo da una tabella di ricerca.
Caricare la tabella di ricerca utilizzando Flusso di dati > Arricchimento dati > Arricchimento personalizzato.
enrich <value_to_lookup> into <enriched_key> using <lookup_table>
-
value_to_lookup- Un'espressione stringa che verrà cercata nella tabella di ricerca. -
enriched_key- Chiave di destinazione per memorizzare il risultato dell'arricchimento. -
lookup_table- Il nome della tabella Arricchimento personalizzato da utilizzare.
Le colonne della tabella saranno aggiunte come sottochiavi alla chiave di destinazione. Se value_to_lookup non viene trovato, la chiave di destinazione sarà nulla. È quindi possibile filtrare i risultati utilizzando le funzionalità
di DataPrime, ad esempio filtrando i registri in base al valore specifico del campo arricchito.
Esempio:
Il registro originale:
{
"userid": "111",
...
}
La tabella di arricchimento personalizzata chiamata my_users:
| ID | Nome | Dipartimento |
|---|---|---|
| 111 | John | Finanza |
| 222 | Emily | l'IT |
Eseguire la seguente query:
enrich $d.userid into $d.user_enriched using my_users
Il risultato sarà il seguente registro arricchito:
{
"userid": "111",
"user_enriched": {
"ID": "111",
"Name": "John",
"Department": "Finance"
},
...
}
Considerate quanto segue quando utilizzate enrich:
-
Eseguire l'origine della query DataPrime
lookup_tableper visualizzare la tabella di arricchimento. -
Se il registro originale contiene già la chiave arricchita:
-
Se
value_to_lookupesiste inlookup_table, le sottochiavi verranno aggiornate con il nuovo valore. Se il sitovalue_to_lookupnon esiste, il suo valore attuale rimane. -
Tutte le altre sottochiavi che non sono colonne di
lookup_tablerimarranno con i loro valori esistenti.
-
-
Tutti i valori di
lookup_tablesono considerati stringhe. Ciò significa che:-
L'indirizzo
value_to_lookupdeve essere in formato stringa. -
Tutti i valori sono arricchiti in un formato stringa. È quindi possibile convertirli nel formato preferito (ad esempio, JSON, timestamp) utilizzando le funzioni appropriate.
-
extract
Estrarre i dati da un valore stringa in un nuovo oggetto. Sono supportati diversi metodi di estrazione.
(e|extract) <expression> into <keypath> using <extraction-type>(<extraction-params>) [datatypes keypath:datatype,keypath:datatype,...]
Di seguito sono riportati i metodi di estrazione supportati e i relativi parametri:
-
regexp- Creare un nuovo oggetto basato sulla regexp gruppi di cattura -
e- Un'espressione regolare con nomi di gruppi di cattura.
Esempio:
extract $d.my_text into $d.my_data using regexp(e=/user (?<user>.*) has logged in/)
-
kv- Estrarre un nuovo oggetto da una stringa contenente coppie chiave=valore. -
pair_delimiter- Il delimitatore da prevedere tra le coppie. Il valore predefinito è (uno spazio) -
key_delimiter- Il delimitatore da prevedere per la separazione tra una chiave e un valore. L'impostazione predefinita è =.
Esempi:
extract $d.text into $d.my_kvs using kv()
e $d.text into $d.my_kvs using kv(pair_delimiter=' ',key_delimiter='=')
-
jsonobject- Estrarre un nuovo oggetto da una stringa contenente un oggetto json codificato, tentando potenzialmente di decodificare la stringa prima di decodificarla in un json -
max_unescape_count- Numero massimo di livelli di escape da decomprimere prima di analizzare il json. Il valore predefinito è 1. Se impostato a 1 o più, il motore rileverà se il valore contiene una stringa JSON sottoposta a escape e la disincapsulerà fino a quando non verrà superato il conteggio di parsable o max unescape.
Esempio:
e $d.json_message_as_str into $d.json_message using jsonobject(max_unescape_count=1)
È possibile fornire informazioni sul tipo di dati come parte dell'estrazione, utilizzando la clausola datatypes. Ad esempio, aggiungendo i tipi di dati my_field:number a un'estrazione, il percorso chiave dell'estratto my_field sarà un numero anziché una stringa. Ad esempio:
extract $d.my_msg into $d.data using kv() datatypes my_field:number
I dati estratti vengono sempre inseriti in un nuovo percorso chiave come oggetto, consentendo l'ulteriore elaborazione delle nuove chiavi all'interno di questo nuovo oggetto. Ad esempio:
# 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
Filtra gli eventi, lasciando solo quelli per i quali la condizione è vera.
(f|filter|where) <condition-expression>
Esempi:
f $d.radius > 10
filter $m.severity.toUpperCase() == 'INFO'
filter $l.applicationname == 'myapp'
filter $l.applicationname == 'myapp' && $d.msg.contains('failure')
Il confronto con null funziona solo per i valori scalari e restituisce sempre null sui sottoalberi JSON.
Quando si usa una condizione per confrontare un percorso chiave con null, questa funziona solo su valori scalari (stringa, numero, timestamp e così via). Per gli oggetti JSON all'interno di un dato documento, il confronto con null restituirà sempre null.
Utilizzate i filtri con le funzioni per eseguire ricerche complesse.
Esempi:
filter in($l.applicationname, 'ibm-audit-event', 'ibm-platform-logs') #
filter ipInSubnet(ip_address, '155.64.5.20/24')
e - Filtra gli indirizzi IP in un determinato intervallo. il filtro può essere abbinato a funzioni per eseguire ricerche complesse con pochissima sintassi, ad esempio utilizzando la funzione ipInSubnet:
filtro ipInSubnet(ip_address, ' 154.67.8.20/24 ')
groupby
Raggruppa i risultati degli operatori precedenti in base alle espressioni di raggruppamento specificate e calcola le funzioni aggregate per ogni gruppo creato.
groupby <grouping_expression> [as <alias>] [, <grouping_expression_2> [as <alias_2>], ...] [calculate]
<aggregate_function> [as <result_keypath>]
[, <aggregate_function_2> [as <result_keypath_2], ...]
Ad esempio la seguente query:
groupby $m.severity calculate sum($d.duration)
Il risultato sarà un registro della forma seguente:
{ "severity": "Warning", "_sum": 17045 }
I percorsi chiave per le espressioni di raggruppamento saranno sempre sotto $d. Utilizzando la parola chiave as, è possibile rinominare il percorso chiave per le espressioni di raggruppamento e le funzioni di aggregazione.
Ad esempio:
groupby $l.applicationname as $d.app calculate sum($d.duration) as $d.sum_duration
Il risultato sarà un registro della forma seguente:
{ "app": "web-api", "sum_duration": 17045 }
Quando si esegue una query con l'operatore groupby, è possibile applicare una funzione di aggregazione (come avg, max, sum)
al bucket dei risultati. Questa funzione consente di manipolare un'espressione di aggregazione all'interno dell'espressione stessa, permettendo di calcolare e manipolare i dati contemporaneamente.
join
Join unisce i risultati della query corrente (sinistra) con una seconda query (destra) basata su una condizione specificata. Offre diverse forme per controllare il modo in cui i dati vengono combinati e supporta il nesting, consentendo
alla query giusta di includere il proprio comando join.
Join supporta tre varianti:
join left|join- Per ogni evento della query di sinistra, il comando seleziona un evento corrispondente dalla query di destra in base alla condizione specificata. Se non viene trovata alcuna corrispondenza, vengono incluse le righe per tutti gli eventi della
query di sinistra. Le righe non corrispondenti della query giusta sono impostate su
null. join full- Restituisce una riga per ogni evento, compresi quelli che potrebbero non avere una corrispondenza in nessuna delle due query (sinistra o destra), riempiendo i valori mancanti con
null. join inner- Restituisce solo le righe in cui sono presenti risultati non nulli da entrambe le query.
join cross- Accoppia ogni riga della query di sinistra con ogni riga della query di destra, generando il prodotto cartesiano completo. A differenza degli altri tipi di
join,join crossnon supportaonousing conditions. Funziona in modo simile ajoin innerma senza alcun filtro, restituendo tutte le possibili combinazioni di righe.
Per left (default), inner, e full, è possibile specificare una condizione join utilizzando la parola on o un percorso chiave utilizzando la parola keyword. Il prodotto
cartesiano viene filtrato per conservare solo le righe in cui la condizione è vera o in cui i valori del percorso chiave corrispondono su entrambi i lati.
Poiché tutte le giunzioni, indipendentemente dal modificatore, si basano sul prodotto cartesiano, è possibile che si verifichino risultati duplicati se la condizione join corrisponde più volte. Per evitare duplicazioni indesiderate,
si può considerare la possibilità di preelaborare le sottoquery, ad esempio utilizzando distinct.
Sintassi:
<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>
Dove:
-
<right_side_query>-<right_side_query>indica la nuova query a cui unirsi. -
<left_side_query>-<left_side_query>indica la query iniziale, ad esempio, nella querysource logs | filter x != null | join ..., la query di sinistra èsource logs | filter x != null. -
<condition>- La condizione se i risultati di entrambe le query devono essere uniti.Nella condizione, è possibile utilizzare i prefissi
left=>eright=>per riferirsi agli eventi delle query di sinistra e di destra, rispettivamente. Tuttavia, non è necessario se un percorso chiave esiste solo in una delle query.Quando si usa l'operatore
==(uguaglianza) nella condizione, questo deve confrontare un percorso chiave della query di sinistra con un percorso chiave della query di destra. Tuttavia, dato che i percorsi chiave devono essere unici o preceduti daleft=>oright=>, l'ordine degli operandi non è importante. -
<join_keypath_n>-<join_keypath_n>come chiave di join significa unire i risultati in cui un determinato percorso chiave è uguale nei risultati della query di sinistra e di quella di destra. -
<right_side_target>- Il percorso chiave in cui i dati uniti saranno aggiunti alla query corrente.
join esempio
Si dispone di una tabella di arricchimento personalizzata denominata users che fornisce informazioni sugli ID relativi ai nomi:
{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }
Questi dati forniscono eventi di login e ID utente, ma non il nome utente associato agli ID utente.
{ "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" }
Utilizzando join è possibile utilizzare una query per restituire i dati che includono i dati desiderati.
source users | join (source logs | countby userid) on id == userid into logins
Questa richiesta viene elaborata come segue:
-
sourceè la tabella di arricchimento personalizzata (users). -
In
joinviene generato un conteggio dal campouserid. Questo ci dà le statistiche dicount. -
Il campo
idnella tabella di arricchimento personalizzata viene confrontato con il campouseridnei registri. -
Il risultato viene inserito nel tasto
logins. Se la chiaveloginsesiste già nella query di sinistra, verrà sovrascritta.
Ad esempio:
{ "id": "111", "name": "John", "logins": { "userid": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "userid": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }
Il risultato della query di destra si trova ora nel campo logins. Si noti che non ci sono stati accessi per l'ID utente 333 (Alice), quindi il campo accessi è null perché non c'è stato alcun risultato
corrispondente alla condizione join.
join esempio con la parola chiave using
Consideriamo se il nostro set di dati di login è:
{ "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 questo caso i dati su entrambi i lati della join includono il campo id. In questo caso è possibile utilizzare la parola chiave using per sfruttare i dati comuni:
source users | join (source logins | countby id) using id into logins
Il risultato sarà simile, ma al posto di userid verrà restituito il campo id.
{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }
Se si hanno due campi con nomi diversi, ma si vuole semplificare la query di join, si può usare il metodo move per spostare uno dei campi
in modo che i percorsi chiave corrispondano su entrambi i lati.
join esempio utilizzando le parole chiave left=> e right=>
È possibile utilizzare i prefissi left=> e right=> per riferirsi agli eventi delle query di sinistra e di destra. Tuttavia, non è necessario se un percorso chiave esiste solo in una delle query.
Utilizzando i dati dell'esempio precedente, si consideri la query:
source users | join (source logins | countby id) on left=>id == right=>id into logins
Questo è necessario perché entrambi i set di dati contengono un campo con lo stesso nome (id). Per identificare in modo univoco un campo, DataPrime deve sapere a quale parte della query ci si riferisce. Questa query produrrà lo
stesso risultato della precedente che utilizzava la parola chiave using.
Quando si usa l'operatore == (uguaglianza) nella condizione, questo deve confrontare un percorso chiave della query di sinistra con un percorso chiave della query di destra. Tuttavia, dato che i percorsi chiave devono essere unici
o preceduti da left=> o right=>, l'ordine degli operandi non è importante.
join full esempio
Si dispone di una tabella di arricchimento personalizzata denominata users che fornisce informazioni sugli ID relativi ai nomi:
{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }
E considerate questo set di dati:
{ "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" }
Il secondo insieme di documenti (query di destra) include una voce di registro con "id": "001" che non esiste nel primo insieme di documenti (query di sinistra). Se si utilizza un join standard, questa voce
della query di destra verrà ignorata e non apparirà nel risultato. Per assicurarsi che ogni campo di id sia incluso nell'output, indipendentemente dal fatto che appaia o meno nella query di sinistra o di destra, si può usare
join full:
source users | join full (source logins | countby id) using id into logins
Questa ricerca ha come risultato:
{ "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 }
Utilizzando join full, tutti i campi id di entrambi i set di dati vengono conservati e i valori mancanti vengono impostati su null.
join full è particolarmente utile quando i risultati di entrambe le query includono bucket temporali. Ad esempio, se nei risultati della query di sinistra manca un bucket temporale per un'ora specifica (ad esempio, XX:XX:XX),
con join full questo punto di dati viene incluso. È particolarmente utile per confrontare due serie temporali su un grafico.
join inner esempio
Se si desidera rimuovere tutte le righe se i risultati delle colonne per le query di sinistra o di destra producono un valore nullo, utilizzare join inner.
Utilizzando i dati precedenti, questa query rimuove le righe con dati non corrispondenti da entrambi i lati:
source users | join inner (source logins | countby id) using id into logins
-
La query di sinistra
source usersrecupera il dataset degli utenti contenente i campiidename. -
La query di destra (
source logins | countby id) recupera il dataset dei login, raggruppando peride contando le occorrenze per ogniid. -
join innercorrisponde alle righe in cuiidesiste in entrambi i set di dati e unisce i dati in un unico record. -
Le righe senza corrispondenza in entrambi i set di dati sono escluse dai risultati finali.
In questo caso, per i due set di documenti di cui sopra, i risultati saranno i seguenti:
{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
join cross esempio
join cross combina ogni riga della query di sinistra con ogni riga della query di destra, producendo un prodotto cartesiano dei due insiemi.
Si supponga di avere i seguenti documenti da una tabella di arricchimento personalizzata denominata users.
{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }
Consideriamo ora questo insieme di documenti denominato 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" }
La seguente query produrrà un prodotto cartesiano dei dataset users e logs perché join cross accoppia ogni riga della query di sinistra con ogni riga della query di destra, indipendentemente dalle condizioni
di corrispondenza.
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" } }
La query risulta nell'abbinamento di ogni utente con ogni voce di registro: 3 righe di users moltiplicate per 5 righe di logs, ottenendo 15 righe. Ogni utente (John, Emily, Alice)
è abbinato a ogni voce di registro.
L'uso di join cross è particolarmente utile quando si è interessati a vedere un quadro completo dei dati, aggiungendo poi un left o un right join a questi risultati.
Limitazioni e considerazioni
Ci sono limitazioni e considerazioni da fare quando si include join in una query:
-
La condizione
joinsupporta solo l'uguaglianza dei percorsi chiave (==). Se sono necessarie più condizioni di uguaglianza, possono essere combinate con&&(logico e). -
Un lato della join (sia la query corrente che la query di join) deve essere piccolo (< 200MB ). È possibile utilizzare
filtereremoveper ridurre le dimensioni della query. -
Le giunzioni esterne a sinistra richiedono che tutte le colonne della condizione siano non nulle. Le colonne nulle non vengono unite. Per includere le colonne nulle della query di destra, utilizzare
join full. Per escludere tutte le colonne nulle prodotte dalle giunzioni a sinistra e a destra, utilizzarejoin inner.
limit
Limita l'output ai primi eventi di event-count.
limit <event-count>
Esempio:
limit 100
move
Sposta una chiave (comprese le eventuali chiavi figlie) in una nuova posizione.
(m|move) <source-keypath> to <target-keypath>
Esempi:
move $d.my_data.hostname to $d.my_new_data.host
m $d.kubernetes.labels to $d.my_labels
multigroupby
multigroupby concatena i risultati di due o più query che incorporano groupby in un unico set di dati.
Utilizzare multigroupby per:
-
Efficienza: I dati vengono analizzati una sola volta per più interrogazioni.
-
Sincronizzazione: I risultati rimangono coerenti, evitando le discrepanze che possono verificarsi quando si eseguono query separate.
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], ...]
Utilizzando lo stesso alias app per entrambi i raggruppamenti, lo stesso significato semantico viene presentato come un campo unificato. Nell'esempio successivo, vengono utilizzati alias diversi e i dati vengono combinati, ma non
uniti.
Esempio - Multigroupby con lo stesso alias
In questo esempio vogliamo raggruppare i log come segue:
-
Prima per
applicationname(app) e poi persubsystemname(ss), fornendo conteggi dettagliati per ogni combinazione. -
Poi indipendentemente da
applicationname, ottenendo il conteggio totale dei log per ogni applicazione indipendentemente dasubsystems.
source logs
| multigroupby ($l.applicationname as app, $l.subsystemname as ss),($l.applicationname as app) calculate count() | orderby app,ss
Il risultato sarà simile a:
[
{
"_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
}
]
Le prime tre righe rappresentano i conteggi per ogni combinazione unica di app e ss. Ad esempio, ci sono 241 registri in cui l'applicazione (app) è monitoring24 e il sottosistema (ss)
è NO_SUBSYSTEM_NAME. Allo stesso modo, ci sono 231 registri per la stessa applicazione ma con il sottosistema logs-opentelemetry-agent, e così via.
L'ultima riga fornisce il conteggio totale dei registri per l'applicazione monitoring24, aggregando tutti i sottosistemi. Qui, _count0 è 487, la somma di tutti i conteggi dettagliati di cui sopra. Il campo ss è null per indicare che si tratta del totale dell'intera applicazione.
Utilizzando lo stesso alias app per entrambi i raggruppamenti, lo stesso significato semantico viene presentato come un campo unificato. Nell'esempio successivo, vengono utilizzati alias diversi e i dati vengono combinati, ma
non uniti.
Esempio - Multigroupby con alias diversi
Si considerino ora gli effetti dell'introduzione di due alias diversi per le query. In questo caso, il primo raggruppamento è etichettato come app1 per applicationname combinato con ss, mentre il secondo
raggruppamento è etichettato come app2 per applicationname alone.
source logs | multigroupby ($l.applicationname as app1, $l.subsystemname as ss),($l.applicationname as app2) calculate count()
Il risultato sarà simile a:
[
{
"_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
}
]
Introducendo alias separati (app1 e app2), la query mantiene la distinzione tra i due raggruppamenti anziché unire i dati. Le righe in cui app1 è popolato e app2 è null corrispondono
al raggruppamento dettagliato per applicationname e subsystemname. Ad esempio, 241 registri sono associati a app1 = "monitoring24" e ss = "logs-opentelemetry-agent".
Questo segue la prima logica di raggruppamento.
La riga in cui app2 è popolato e app1 è null riflette il conteggio totale per il secondo raggruppamento, in cui i registri sono aggregati esclusivamente per applicationname. Per app2 = "monitoring24",
il conteggio è 487, e sia app1 che ss sono null per indicare questa aggregazione di livello superiore.
Utilizzando alias separati (app1 e app2), la query non unisce i dati, ma rende chiaro a quale gruppo appartiene ciascun risultato. La logica generale rimane la stessa: conteggi dettagliati per combinazioni specifiche
e conteggi aggregati per il totale.
Multigroupby limitazioni
multigroupby non restituisce righe duplicate per gli insiemi di gruppi duplicati.
Se si esegue multigroupby con app e ss, il risultato atteso (se sono consentiti i duplicati) potrebbe essere il seguente:
[
{"app": "monitoring24", "ss": "logs-opentelemetry-agent", "_count0": 2},
{"app": "monitoring24", "ss": "logs-opentelemetry-collector", "_count0": 2}
]
A causa della limitazione, multigroupby unirà questi duplicati e restituirà solo una riga per ogni combinazione unica, anche se tale combinazione ricorre più volte nei dati:
[
{"app": "monitoring24", "ss": "logs-opentelemetry-agent", "_count0": 2}
]
orderby / sortby / order by / sort by
Ordina i dati in base all'ordine crescente/decrescente del valore dell'espressione. È supportato l'ordinamento per espressioni multiple.
(orderby|sortby|order by|sort by) <expression> [(asc|desc)] , ...
Esempi:
orderby $d.myfield.myfield
orderby $d.myfield.myfield:number desc
sortby $d.myfield desc
L'ordinamento dei valori numerici può essere fatto lanciando l'espressione nel tipo:, ad esempio, <expression>: number. In alcuni casi, questo viene dedotto automaticamente dal motore.
redact
Sostituisce tutte le sottostringhe che corrispondono a uno schema regexp da un valore keypath, nascondendo di fatto il contenuto originale.
La parola chiave di corrispondenza è facoltativa e può essere usata per aumentare la leggibilità.
redact <keypath> [matching] /<regular-expression>/ to '<redacted_str>'
redact <keypath> [matching] <string> to '<redacted_str>'
Esempi:
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
Rimuove un percorso chiave dall'oggetto.
r|remove <keypath1> [ "," <keypath2> ]...
Esempi:
r $d.mydata.unneeded_key
remove $d.mysuperkey.service_name, $d.mysuperkey.unneeded_key
replace
Sostituisce il valore di una chiave con un nuovo valore.
Se il valore sostitutivo modifica il tipo di dati del percorso chiave, sono disponibili le seguenti opzioni:
-
skip- La sostituzione verrà ignorata -
fail- La query fallirà -
overwrite- Il nuovo valore sovrascriverà il precedente, cambiando il tipo di dati del percorso chiave
replace <keypath> with <expression> [on datatype changed skip/fail/overwrite]
Esempi:
replace $d.message with null
replace $d.some_superkey.log_length_plus_10 with $d.original_log.length()+10 on datatype changed overwrite
roundtime
Arrotonda l'ora dell'evento in un intervallo di tempo, eventualmente creando una nuova chiave per il risultato.
-
Se
source-timestampnon viene fornito, viene utilizzato$m.timestampcome timestamp di origine. -
Se viene fornito
source-timestamp, deve essere di tipo (o castato a)timestamp.
Per impostazione predefinita, il risultato arrotondato viene scritto nel percorso chiave di origine source-timestamp. Se viene fornito target-keypath, source-timestamp non viene modificato e il risultato
viene scritto in un nuovo target-keypath.
Gli intervalli di tempo supportati sono:
- Xns - X nanosecondi (prestare attenzione alla risoluzione del timestamp sorgente)
- Xms - X millisecondi
- Xs - X secondi
- Xm - X minuti
- Xh - X ore
- Xd - X giorni
E qualsiasi combinazione da unità di tempo maggiori a minori, ad esempio 1h30m15s.
roundtime [source-timestamp] to <time-interval> [into <target-keypath>]
Esempi:
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
Impostare l'origine dei dati su cui si basa la query DataPrime.
(source|from) <data_store>
Dove data_store può essere uno dei due:
-
logs -
Il nome dell'arricchimento personalizzato. In questo caso, il comando visualizzerà la tabella di arricchimento personalizzata.
Esempi:
source logs
stitch
Il comando stitch esegue un'unione orizzontale di due set di dati, combinandoli fianco a fianco. Allinea le righe di un set di dati con quelle di un altro e concatena le loro colonne, creando un unico set di dati unificato.
Quando si usa il comando stitch:
-
I set di dati devono essere ordinati, poiché le righe vengono combinate in sequenza (cioè, la riga 1 del set di dati A viene cucita con la riga 1 del set di dati B).
-
Se un set di dati ha più righe dell'altro, le righe non corrispondenti avranno valori nulli nelle colonne cucite.
-
Il set di dati risultante conterrà tutte le colonne di entrambi i set di dati.
stitch differisce da union. stitch combina i set di dati orizzontalmente aggiungendo le colonne riga per riga. union aggiunge le righe verticalmente, impilando i set di dati l'uno sull'altro.
... | stitch (<subquery>) into <target-keypath>
Esempio:
Avete queste tabelle di arricchimento personalizzate:
sales set di dati:
{ "product": "Widget", "sales": 100 }
{ "product": "Gadget", "sales": 200 }
{ "product": "Dashboard", "sales": 150 }
revenue set di dati:
{ "product": "Widget", "revenue": 5000 }
{ "product": "Gadget", "revenue": 8000 }
{ "product": "Dashboard", "revenue": 6000 }
In questa query si combinano questi set di dati fianco a fianco, assicurandosi che ogni riga di un set di dati sia allineata con la riga corrispondente dell'altro:
source sales | orderby product
| stitch (source revenue | orderby product) into combined_data
-
source salesrecupera tutte le righe del datasetsales, che contiene i prodotti e le relative cifre di vendita. -
orderby productordina il datasetsalesin base al campoproductper creare un ordine coerente per l'allineamento delle righe. -
stitch (source revenue | orderby product)recupera le righe dal datasetrevenuee le ordina in base al campoproduct. I datasetsaleserevenuevengono combinati orizzontalmente, allineando le righe in base al loro ordine dopo l'ordinamento. -
into combined_datamemorizza il set di dati combinato in una variabile chiamatacombined_data.
Il risultato della query è:
{ "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 } }
Se i dataset hanno righe disuguali, il comando stitch riempie i valori mancanti con null.
Ad esempio, si considerino i seguenti set di dati:
sales (3 righe):
{ "product": "Widget", "sales": 100 }
{ "product": "Gadget", "sales": 200 }
{ "product": "Dashboard", "sales": 150 }
revenue (2 righe):
{ "product": "Widget", "revenue": 5000 }
{ "product": "Gadget", "revenue": 8000 }
Eseguire questa query:
source sales | orderby product
| stitch (source revenue | orderby product) into combined_data
Risultati 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 Note di utilizzo
-
Le righe devono essere correlate logicamente affinché la cucitura produca risultati significativi. Assicurarsi che le righe di entrambi i set di dati rappresentino le stesse entità e siano nello stesso ordine. Ad esempio, se il campo
productdel datasetsalesnon corrisponde al campoproductdel datasetrevenueper le righe corrispondenti, la cucitura non funzionerà come previsto. -
Se i set di dati differiscono per numero di righe, il risultato includerà i valori
nullper i dati mancanti nel set di dati più corto.
top
Nessuna variazione di raggruppamento: Limita le righe restituite a un numero specificato e ordina il risultato in base a un insieme di espressioni.
order_direction := "descending"/"ascending" according to top/bottom
top <limit> <result_expression1> [as <alias>] [, <result_expression2> [as <alias2>], ...] by <orderby_expression> [as alias>]
Ad esempio la seguente query:
top 5 $m.severity as $d.log_severity by $d.duration
Il risultato sarà un registro della forma seguente:
[
{ "log_severity": "Warning", "duration": 2000 },
{ "log_severity": "Debug", "duration": 1000 }
...
]
Variazione di raggruppamento: Limita le righe restituite a un numero specifico e le raggruppa in base a un insieme di espressioni di aggregazione e le ordina in base a un insieme di espressioni.
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>]
Ad esempio la seguente query:
top 10 $m.severity, count() as $d.number_of_severities by avg($d.duration) as $d.avg_duration
Il risultato sarà un registro della forma seguente:
[
{ "severity": "Debug", "number_of_severities": 10, avg_duration: 2000 }
{ "severity": "Warning", "number_of_severities": 50, avg_duration: 1000 },
...
]
È possibile applicare una funzione di aggregazione...
union
Il comando union concatena i risultati di due o più set di dati in un unico set di dati. Ciò consente agli utenti di combinare i risultati di più query in un unico insieme di dati. Un set di dati può essere un set di risultati inviato
al comando union e poi concatenato con un altro set di dati.
Usare l'unione quando è necessario aggiungere righe da un set di dati a un altro.
Quando si elaborano insiemi di dati di grandi dimensioni, per ottimizzare le prestazioni, considerare l'uso di filter per limitare le righe da ciascun insieme di dati prima di usare union.
Gli utenti sono limitati a un massimo di 10 comandi union per ogni query per i dati Insight priorità. Non ci sono limiti per gli altri dati.
In che modo union si differenzia da join
-
unioncombina gli insiemi di risultati aggiungendo righe da un set di dati a un altro. Non unisce o confronta le colonne di più documenti. -
joinabbina e combina le colonne di due tabelle in base a una condizione, creando righe che contengono i dati di entrambe le tabelle.
<query> | union <query>
Esempio di combinazione di 2 set di dati
Si hanno questi due insiemi di dati:
Registri per Team 58942
{ "id": "111", "name": "John" , "team.id": "58942" }
{ "id": "222", "name": "Emily", "team.id": "58942" }
{ "id": "333", "name": "Alice", "team.id": "58942" }
Registri per 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" }
E si desidera combinarli in un unico set di dati. È possibile farlo utilizzando union.
source logs(teamId=58942) | union logs(teamId=98361)
La query elabora i due set di dati:
source logs(teamId=58942): Recupera tutti i documenti perTeam 58942union logs (teamID=98361): Aggiunge il datasetTeam 98361al datasetTeam 58942
Il risultato sarà il seguente set di dati:
{ "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" }