DataPrime opérateurs
Ce guide fournit un glossaire des opérateurs IBM® Cloud Logs DataPrime.
block
La négation de filter. Filtre tous les événements pour lesquels la condition est vraie. Le même effet peut être obtenu en utilisant filter avec !(condition).
block $d.status_code >= 200 && $d.status_code <= 299 # Leave all events which don't have a status code of 2xx
Les données sont exposées à l'aide des champs suivants :
-
$m - Métadonnées de l'événement
timestampseverity- Les valeurs possibles sontVerbose,Debug,Info,Warning,Error,Criticalpriorityclass- Les valeurs possibles sonthigh,medium,lowlogid
-
$l - Libellés des événements
applicationnamesubsystemnamecategoryclassnamecomputernamemethodnamethreadidipaddress
-
$d -Les données de l'utilisateur
bottom
Pas de variation de regroupement: Limite les lignes renvoyées à un nombre spécifié et ordonne le résultat en fonction d'un ensemble d'expressions.
order_direction := "descending"/"ascending" according to top/bottom
bottom <limit> <result_expression1> [as <alias>] [, <result_expression2> [as <alias2>], ...] by <orderby_expression> [as alias>]
Par exemple, la requête suivante :
bottom 5 $m.severity as $d.log_severity by $d.duration
Il en résultera des enregistrements de la forme suivante :
[
{ "log_severity": "Debug", "duration": 1000 }
{ "log_severity": "Warning", "duration": 2000 },
...
]
Variante de regroupement: Limite les lignes renvoyées à un nombre spécifié et les regroupe par un ensemble d'expressions d'agrégation et les ordonne par un ensemble d'expressions.
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>]
Par exemple, la requête suivante :
bottom 10 $m.severity, count() as $d.number_of_severities by avg($d.duration) as $d.avg_duration
Il en résultera des enregistrements de la forme suivante :
[
{ "severity": "Warning", "number_of_severities": 50, avg_duration: 1000 },
{ "severity": "Debug", "number_of_severities": 10, avg_duration: 2000 }
...
]
Les fonctions d'agrégation prises en charge sont énumérées dans la section "Fonctions d'agrégation".
choose
Ne laissez que les chemins d'accès fournis, en écartant toutes les autres clés. Prise en charge complète des chemins d'accès imbriqués dans la sortie.
(choose|select) <keypath1> [as <new_keypath>],<keypath2> [as <new_keypath>],...
Exemples :
choose $d.mysuperkey.myfield
choose $d.my_superkey.mykey as $d.important_value, 10 as $d.the_value_ten
convert
Convertir les types de données des clés.
Le mot-clé datatypes est facultatif et peut être utilisé pour des raisons de lisibilité.
(conv|convert) [datatypes] <keypath1>:<datatype1>,<keypath2>:<datatype2>,...
Exemples :
convert $d.level:number
conv datatypes $d.long:number,$d.lat:number
convert $d.data.color:number,$d.item:string
count
Renvoie une seule ligne contenant le nombre de lignes produites par les opérateurs précédents.
count [into <keypath>]
Un alias peut être fourni pour remplacer le chemin d'accès où le résultat sera écrit.
Par exemple, la partie suivante d'une requête :
count into $d.num_rows
Il en résultera une seule ligne de la forme suivante :
{ "num_rows": 7532 }
countby
Renvoie une ligne contenant toutes les lignes regroupées par l'expression.
countby <expression> [as <alias>] [into <keypath>]
Un alias peut être fourni pour remplacer le chemin d'accès au clavier dans lequel le résultat sera écrit.
Par exemple, la partie suivante d'une requête
countby $d.verb into $d.verb_count
Il en résultera une ligne pour chaque groupe.
Il est fonctionnellement identique à
groupby $data.verb calculate count() as $d.verb_count
create
Créez une nouvelle clé et définissez sa valeur comme étant le résultat de l'expression. La création de clés est granulaire, ce qui signifie que les clés parentales dans le chemin d'accès ne sont pas écrasées.
(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 création peut être contrôlée en ajoutant les clauses suivantes :
-
L'ajout de
keypath existspermet de choisir ce qu'il faut faire lorsque le chemin d'accès existe déjà.-
overwrite- écrase l'ancienne valeur. Il s'agit de la valeur par défaut -
fail- L'interrogation n'aboutit pas -
skip- Sauter la création de la clé
-
-
L'ajout de
keypath missingpermet de choisir ce qu'il faut faire lorsque le nouveau chemin d'accès n'existe pas.-
create- Crée la clé. Il s'agit de la valeur par défaut -
fail- L'interrogation n'aboutit pas -
skip- Sauter la création de la nouvelle clé
-
-
Adding on
datatype changedchoisit ce qu'il faut faire si la clé existe déjà et que les nouvelles données modifient le type de données de la valeur.-
overwrite- écrase la valeur. Il s'agit de la valeur par défaut. -
fail- L'interrogation n'aboutit pas -
skip- Laisse la clé avec la valeur (et le type) d'origine
-
Exemples :
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
Renvoie une ligne pour chaque combinaison distincte des expressions fournies.
distinct <expression> [as <alias>] [, <expression_2> [as <alias_2>], ...]
Cet opérateur est fonctionnellement identique à groupby sans aucune fonction d'agrégation.
enrich
Enrichissez vos journaux à l'aide d'un contexte supplémentaire provenant d'une table de consultation.
Téléchargez votre table de recherche en utilisant Flux de données > Data Enrichment > Custom Enrichment.
enrich <value_to_lookup> into <enriched_key> using <lookup_table>
-
value_to_lookup- Une expression sous forme de chaîne qui sera recherchée dans la table de recherche. -
enriched_key- Clé de destination pour stocker le résultat de l'enrichissement. -
lookup_table- Le nom du tableau d'enrichissement personnalisé à utiliser.
Les colonnes du tableau seront ajoutées en tant que sous-clés à la clé de destination. Si value_to_lookup est introuvable, la clé de destination sera nulle. Vous pouvez ensuite filtrer les résultats à l'aide des fonctionnalités
de DataPrime, par exemple en filtrant les journaux par valeur spécifique dans le champ enrichi.
Exemple :
Le journal original :
{
"userid": "111",
...
}
La table de recherche de l'enrichissement personnalisé s'appelle my_users:
| ID | Nom | Service |
|---|---|---|
| 111 | John | Finance |
| 222 | Emily | Technologie de l"information |
La requête suivante est exécutée :
enrich $d.userid into $d.user_enriched using my_users
Il en résultera le journal enrichi suivant :
{
"userid": "111",
"user_enriched": {
"ID": "111",
"Name": "John",
"Department": "Finance"
},
...
}
Tenez compte des éléments suivants lors de l'utilisation de enrich:
-
Exécutez la requête DataPrime source
lookup_tablepour afficher le tableau d'enrichissement. -
Si le journal original contient déjà la clé enrichie :
-
Si
value_to_lookupexiste danslookup_table, les sous-clés seront mises à jour avec la nouvelle valeur. Si le sitevalue_to_lookupn'existe pas, sa valeur actuelle sera conservée. -
Toutes les autres sous-clés qui ne sont pas des colonnes dans le site
lookup_tableconserveront leurs valeurs existantes.
-
-
Toutes les valeurs du site
lookup_tablesont considérées comme des chaînes de caractères. Ce qui signifie que :-
Le site
value_to_lookupdoit être une chaîne de caractères. -
Toutes les valeurs sont enrichies dans un format de chaîne de caractères. Vous pouvez ensuite les convertir dans le format de votre choix (par exemple, JSON, horodatage) à l'aide des fonctions appropriées.
-
extract
Extrait les données d'une chaîne de caractères dans un nouvel objet. Plusieurs méthodes d'extraction sont prises en charge.
(e|extract) <expression> into <keypath> using <extraction-type>(<extraction-params>) [datatypes keypath:datatype,keypath:datatype,...]
Les méthodes d'extraction prises en charge et leurs paramètres sont décrits ci-dessous :
-
regexp- Créer un nouvel objet basé sur l'expression rationnelle capture-groups -
e- Une expression régulière avec des noms capture-groups.
Exemple :
extract $d.my_text into $d.my_data using regexp(e=/user (?<user>.*) has logged in/)
-
kv- Extraire un nouvel objet d'une chaîne contenant des paires clé=valeur clé=valeur. -
pair_delimiter- Le délimiteur à attendre entre les paires. La valeur par défaut est (un espace) -
key_delimiter- Le délimiteur à utiliser pour séparer une clé d'une valeur. La valeur par défaut est =.
Exemples :
extract $d.text into $d.my_kvs using kv()
e $d.text into $d.my_kvs using kv(pair_delimiter=' ',key_delimiter='=')
-
jsonobject- Extraire un nouvel objet à partir d'une chaîne contenant un objet json encodé, en essayant éventuellement de désencoder la chaîne avant de la décoder en un objet json -
max_unescape_count- Nombre maximum de niveaux d'échappement à déséchapper avant d'analyser le json. Valeur par défaut : 1. S'il vaut 1 ou plus, le moteur détectera si la valeur contient une chaîne JSON échappée et l'échappera jusqu'à ce que le nombre de chaînes analysables ou le nombre maximum d'échappées soient dépassés.
Exemple :
e $d.json_message_as_str into $d.json_message using jsonobject(max_unescape_count=1)
Il est possible de fournir des informations sur les types de données dans le cadre de l'extraction, en utilisant la clause relative aux types de données. Par exemple, si l'on ajoute le type de données my_field:number à une extraction,
le chemin d'accès à l'extraction my_field sera un nombre au lieu d'une chaîne. Exemple :
extract $d.my_msg into $d.data using kv() datatypes my_field:number
Les données extraites sont toujours placées dans un nouveau chemin de clé sous la forme d'un objet, ce qui permet de poursuivre le traitement des nouvelles clés à l'intérieur de ce nouvel objet. Exemple :
# 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
Filtre les événements, en ne conservant que les événements pour lesquels la condition est évaluée comme étant vraie.
(f|filter|where) <condition-expression>
Exemples :
f $d.radius > 10
filter $m.severity.toUpperCase() == 'INFO'
filter $l.applicationname == 'myapp'
filter $l.applicationname == 'myapp' && $d.msg.contains('failure')
La comparaison avec null ne fonctionne que pour les valeurs scalaires et renvoie toujours null pour les sous-arbres JSON.
Lorsque l'on utilise une condition pour comparer un chemin de clé à null, cela ne fonctionne que pour les valeurs scalaires (chaîne de caractères, nombre, horodatage, etc.). Pour les objets JSON d'un document donné, la comparaison avec null renvoie toujours null.
Utilisez les fonctions de filtrage pour effectuer des recherches complexes.
Exemples :
filter in($l.applicationname, 'ibm-audit-event', 'ibm-platform-logs') #
filter ipInSubnet(ip_address, '155.64.5.20/24')
e - Filtrer les adresses IP dans une plage donnée. peut être couplé à des fonctions pour effectuer des recherches complexes avec très peu de syntaxe, par exemple en utilisant la fonction ipInSubnet:
filtre ipInSubnet(ip_address, ' 154.67.8.20/24 ')
groupby
Regroupe les résultats des opérateurs précédents en fonction des expressions de regroupement spécifiées et calcule les fonctions d'agrégation pour chaque groupe créé.
groupby <grouping_expression> [as <alias>] [, <grouping_expression_2> [as <alias_2>], ...] [calculate]
<aggregate_function> [as <result_keypath>]
[, <aggregate_function_2> [as <result_keypath_2], ...]
Par exemple, la requête suivante :
groupby $m.severity calculate sum($d.duration)
Il en résultera des enregistrements de la forme suivante :
{ "severity": "Warning", "_sum": 17045 }
Les chemins d'accès aux expressions de regroupement se trouvent toujours à l'adresse $d. Le mot-clé as permet de renommer le chemin d'accès aux expressions de regroupement et aux fonctions d'agrégation. Exemple :
groupby $l.applicationname as $d.app calculate sum($d.duration) as $d.sum_duration
Il en résultera des enregistrements de la forme suivante :
{ "app": "web-api", "sum_duration": 17045 }
Lorsque vous effectuez une requête à l'aide de l'opérateur groupby, vous pouvez appliquer une fonction d'agrégation (telle que avg, max,
sum) au groupe de résultats. Cette fonctionnalité vous permet de manipuler une expression d'agrégation à l'intérieur de l'expression elle-même, ce qui vous permet de calculer et de manipuler vos données simultanément.
join
Join fusionne les résultats de la requête actuelle (gauche) avec une seconde requête (droite) sur la base d'une condition spécifiée. Il offre de multiples formes pour contrôler la manière dont les données sont combinées et prend
en charge l'imbrication, ce qui permet à la bonne requête d'inclure sa propre commande join.
Join prend en charge trois variantes :
join left|join- Pour chaque événement de la requête de gauche, la commande sélectionne un événement correspondant dans la requête de droite en fonction de la condition spécifiée. Si aucune correspondance n'est trouvée, des lignes sont incluses pour tous les
événements de la requête de gauche. Les lignes non appariées de la requête de droite sont mises à
null. join full- Renvoie une ligne pour chaque événement, y compris ceux qui n'ont pas de correspondance dans l'une ou l'autre des requêtes (gauche ou droite), en remplissant les valeurs manquantes avec
null. join inner- Ne renvoie que les lignes pour lesquelles les résultats des deux requêtes ne sont pas nuls.
join cross- Associe chaque ligne de la requête de gauche à chaque ligne de la requête de droite, générant ainsi le produit cartésien complet. Contrairement aux autres types de
join,join crossne prend pas en chargeonouusing conditions. Il fonctionne de la même manière quejoin inner, mais sans aucun filtrage, et renvoie toutes les combinaisons de lignes possibles.
Pour left (par défaut), inner et full, vous pouvez spécifier une condition join en utilisant le mot clé on ou un chemin d'accès en utilisant le mot clé keyword. Le
produit cartésien est filtré pour ne conserver que les lignes pour lesquelles la condition est vraie ou pour lesquelles les valeurs des chemins d'accès correspondent des deux côtés.
Étant donné que toutes les jointures, quel que soit le modificateur, sont basées sur le produit cartésien, des résultats en double peuvent se produire si la condition join est remplie plusieurs fois. Pour éviter les duplications
involontaires, envisagez de prétraiter les sous-requêtes, par exemple en utilisant l'option distincte.
Syntaxe :
<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>
Où :
-
<right_side_query>- L'adresse<right_side_query>indique la nouvelle requête à laquelle il faut se joindre. -
<left_side_query>- Le<left_side_query>désigne la requête initiale, par exemple, dans la requêtesource logs | filter x != null | join ..., la requête de gauche estsource logs | filter x != null. -
<condition>- La condition si les résultats des deux requêtes doivent être combinés.Dans la condition, vous pouvez utiliser les préfixes
left=>etright=>pour faire référence aux événements des requêtes de gauche et de droite, respectivement. Elle n'est toutefois pas nécessaire si un chemin d'accès n'existe que dans une seule des requêtes.Lorsque vous utilisez l'opérateur
==(égalité) dans votre condition, il doit comparer un chemin de clé de la requête de gauche avec un chemin de clé de la requête de droite. Toutefois, étant donné que les chemins d'accès doivent être uniques ou préfixés parleft=>ouright=>, l'ordre des opérandes n'est pas important. -
<join_keypath_n>-<join_keypath_n>en tant que clé de jointure signifie que l'on joint les résultats pour lesquels un chemin d'accès donné est identique dans les résultats de la requête de gauche et de la requête de droite. -
<right_side_target>- Le chemin d'accès où les données jointes seront ajoutées à la requête en cours.
joinexemple
Vous disposez d'une table d' enrichissement personnalisée nommée users qui fournit des informations sur les identifiants liés aux noms :
{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }
Ces données fournissent des événements de connexion et des identifiants d'utilisateur, mais pas le nom d'utilisateur associé aux identifiants d'utilisateur.
{ "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" }
En utilisant join, vous pouvez utiliser une requête pour obtenir des données comprenant les données souhaitées.
source users | join (source logs | countby userid) on id == userid into logins
Cette demande est traitée comme suit :
-
Le
sourceest le tableau d'enrichissement personnalisé (users). -
Dans le champ
join, un décompte par le champuseridest généré. Nous obtenons ainsi nos statistiquescount. -
Le champ
idde la table d'enrichissement personnalisée est comparé au champuseriddes journaux. -
Le résultat est introduit dans la clé
logins. Si la cléloginsexiste déjà dans la requête de gauche, elle sera écrasée.
Exemple :
{ "id": "111", "name": "John", "logins": { "userid": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "userid": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }
Le résultat de la requête de droite se trouve maintenant dans le champ logins. Notez qu'il n'y a pas eu de connexion pour l'ID utilisateur 333 (Alice). Le champ logins est donc null car il n'y a pas eu
de résultat correspondant à la condition join.
join exemple avec le mot-clé using
Considérons que notre ensemble de données de connexion est :
{ "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" }
Dans ce cas, les données des deux côtés de la jointure comprennent le champ id. Dans ce cas, le mot-clé using peut être utilisé pour tirer parti des données communes :
source users | join (source logins | countby id) using id into logins
Le résultat sera similaire, mais au lieu de userid, c'est le champ id qui sera renvoyé.
{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
{ "id": "333", "name": "Alice", "logins": null }
Si vous avez deux champs qui sont nommés différemment mais qui simplifieraient votre requête join, vous pouvez utiliser move pour déplacer
l'un des champs afin que les chemins d'accès correspondent des deux côtés.
join exemple utilisant les mots-clés left=> et right=>
Vous pouvez utiliser les préfixes left=> et right=> pour faire référence aux événements des requêtes de gauche et de droite. Elle n'est toutefois pas nécessaire si un chemin d'accès n'existe que dans une seule
des requêtes.
En utilisant les données de l'exemple précédent, considérons la requête :
source users | join (source logins | countby id) on left=>id == right=>id into logins
Cela est nécessaire car les deux ensembles de données contiennent un champ portant le même nom (id). Pour que DataPrime puisse identifier un champ de manière unique, il doit savoir de quel côté de la requête nous nous référons.
Cette requête aboutira au même résultat que la précédente qui utilisait le mot-clé using.
Lorsque vous utilisez l'opérateur == (égalité) dans votre condition, il doit comparer un chemin de clé de la requête de gauche avec un chemin de clé de la requête de droite. Toutefois, étant donné que les chemins d'accès doivent
être uniques ou préfixés par left=> ou right=>, l'ordre des opérandes n'est pas important.
join fullexemple
Vous disposez d'une table d' enrichissement personnalisée nommée users qui fournit des informations sur les identifiants liés aux noms :
{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }
Prenons l'exemple de cet ensemble de données :
{ "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" }
Le deuxième ensemble de documents (requête de droite) comprend une entrée de journal avec "id": "001" qui n'existe pas dans le premier ensemble de documents (requête de gauche). Si vous utilisez une jointure
standard, cette entrée de la requête de droite sera ignorée et n'apparaîtra pas dans le résultat. Pour garantir que chaque champ id est inclus dans le résultat, qu'il apparaisse ou non dans la requête de gauche ou de droite,
vous pouvez utiliser join full:
source users | join full (source logins | countby id) using id into logins
Cette requête aboutit à :
{ "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 }
En utilisant join full, tous les champs id des deux ensembles de données sont préservés et toutes les valeurs manquantes sont définies dans null.
join full est particulièrement utile lorsque les résultats des deux requêtes comprennent des intervalles de temps. Par exemple, s'il manque dans les résultats de la requête de gauche un intervalle de temps pour une heure spécifique
(par exemple, XX:XX:XX), ce point de données est inclus dans join full. Cette fonction est particulièrement utile pour comparer deux séries temporelles sur un graphique.
join innerexemple
Si vous souhaitez supprimer les lignes ou les résultats des colonnes pour les requêtes de gauche ou de droite qui produisent une valeur nulle, utilisez join inner.
En utilisant les données précédentes, cette requête supprime les lignes dont les données ne sont pas appariées d'un côté ou de l'autre :
source users | join inner (source logins | countby id) using id into logins
-
La requête de gauche
source usersrécupère l'ensemble de données des utilisateurs contenant les champsidetname. -
La requête de droite (
source logins | countby id) permet de récupérer l'ensemble des logins, en les regroupant paridet en comptant les occurrences pour chaqueid. -
join innerfait correspondre les lignes oùidexiste dans les deux ensembles de données et fusionne les données en un seul enregistrement. -
Les lignes ne correspondant à aucun des deux ensembles de données sont exclues des résultats finaux.
Dans ce cas, pour les deux ensembles de documents ci-dessus, les résultats seront les suivants :
{ "id": "111", "name": "John", "logins": { "id": "111", "_count": 2 } }
{ "id": "222", "name": "Emily", "logins": { "id": "222", "_count": 3 } }
join crossexemple
join cross combine chaque ligne de la requête de gauche avec chaque ligne de la requête de droite, produisant ainsi un produit cartésien des deux ensembles.
Supposons que nous disposons des documents suivants provenant d'une table d'enrichissement personnalisée nommée users.
{ "id": "111", "name": "John" }
{ "id": "222", "name": "Emily" }
{ "id": "333", "name": "Alice" }
Considérons maintenant cet ensemble de documents nommé 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 requête suivante produira un produit cartésien des ensembles de données users et logs car join cross associe chaque ligne de la requête de gauche à chaque ligne de la requête de droite, quelles que
soient les conditions de correspondance.
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 requête permet d'associer chaque utilisateur à chaque entrée de journal : 3 lignes de users multipliées par 5 lignes de logs, ce qui donne 15 lignes. Chaque utilisateur (John, Emily, Alice)
est associé à chaque entrée de journal.
L'utilisation de join cross est particulièrement utile lorsque vous souhaitez obtenir une image complète de vos données, puis ajouter left ou right join à ces résultats.
Limites et considérations
Il y a des limites et des considérations à prendre en compte lorsque l'on inclut join dans une requête :
-
La condition
joinne prend en charge que l'égalité des chemins d'accès (==). Si plusieurs conditions d'égalité sont nécessaires, elles peuvent être combinées avec&&(logique et). -
L'un des côtés de la jointure (soit la requête actuelle, soit la requête de jointure) doit être petit (< 200MB ). Vous pouvez utiliser
filteretremovepour réduire la taille de la requête. -
Les jointures externes gauches exigent que toutes les colonnes de la condition soient non nulles. Les colonnes nulles ne seront pas jointes. Pour inclure les colonnes nulles de la requête de droite, utilisez
join full. Pour exclure toutes les colonnes nulles produites par les jointures gauche et droite, utilisezjoin inner.
limit
Limite la sortie aux premiers événements event-count.
limit <event-count>
Exemple :
limit 100
move
Déplacer une touche (y compris ses touches enfant, le cas échéant) vers un nouvel emplacement.
(m|move) <source-keypath> to <target-keypath>
Exemples :
move $d.my_data.hostname to $d.my_new_data.host
m $d.kubernetes.labels to $d.my_labels
multigroupby
multigroupby concatène les résultats de deux ou plusieurs requêtes incorporant groupby en un seul ensemble de données.
Utilisez multigroupby pour :
-
Efficacité : Les données ne sont analysées qu'une seule fois pour des requêtes multiples.
-
Synchronisation : Les résultats restent cohérents, évitant les divergences qui peuvent survenir lors de l'exécution de requêtes distinctes.
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], ...]
En utilisant le même alias app pour les deux groupes, la même signification sémantique est présentée comme un champ unifié. Dans l'exemple suivant, différents alias sont utilisés et les données sont combinées, mais non fusionnées.
Exemple - Multigroupby avec le même alias
Dans cet exemple, nous voulons regrouper nos journaux comme suit :
-
D'abord par
applicationname(app), puis parsubsystemname(ss), en fournissant des chiffres détaillés pour chaque combinaison. -
Ensuite, indépendamment de
applicationname, ce qui donne le nombre total de journaux pour chaque application, indépendamment desubsystems.
source logs
| multigroupby ($l.applicationname as app, $l.subsystemname as ss),($l.applicationname as app) calculate count() | orderby app,ss
Le résultat sera similaire à :
[
{
"_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
}
]
Les trois premières lignes représentent les chiffres pour chaque combinaison unique de app et ss. Par exemple, il existe 241 journaux dans lesquels l'application (app) est monitoring24 et
le sous-système (ss) est NO_SUBSYSTEM_NAME. De même, il existe 231 journaux pour la même application, mais avec le sous-système logs-opentelemetry-agent, et ainsi de suite.
La dernière ligne indique le nombre total de journaux pour l'application monitoring24, en regroupant tous les sous-systèmes. Ici, _count0 est 487, la somme de tous les comptes détaillés ci-dessus. Le champ ss est null pour indiquer qu'il s'agit du total pour l'ensemble de la demande.
En utilisant le même alias app pour les deux groupes, la même signification sémantique est présentée comme un champ unifié. Dans l'exemple suivant, différents alias sont utilisés et les données sont combinées, mais non fusionnées.
Exemple - Multigroupby avec différents alias
Examinons maintenant les effets de l'introduction de deux alias différents pour les requêtes. Dans ce cas, le premier groupe est appelé app1 pour applicationname combiné à ss, tandis que le deuxième groupe
est appelé app2 pour applicationname alone.
source logs | multigroupby ($l.applicationname as app1, $l.subsystemname as ss),($l.applicationname as app2) calculate count()
Le résultat sera similaire à :
[
{
"_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
}
]
En introduisant des alias distincts (app1 et app2), la requête maintient la distinction entre les deux groupes plutôt que de fusionner les données. Les lignes où app1 est renseigné et app2 est null correspondent au regroupement détaillé par applicationname et subsystemname. Par exemple, 241 journaux sont associés à app1 = "monitoring24" et ss = "logs-opentelemetry-agent".
Cela suit la première logique de regroupement.
La ligne où app2 est rempli et app1 est null reflète le nombre total pour le deuxième groupe, où les journaux sont agrégés uniquement par applicationname. Pour app2 = "monitoring24",
le nombre est de 487, et app1 et ss sont tous deux null pour indiquer cette agrégation de niveau supérieur.
En utilisant des alias distincts (app1 et app2), la requête ne fusionne pas les données, mais indique clairement à quel groupe appartient chaque résultat. La logique générale reste la même : des comptes détaillés
pour des combinaisons spécifiques et des comptes agrégés pour le total.
Limitations Multigroupby
multigroupby ne renvoie pas les lignes dupliquées pour les groupes dupliqués.
Si vous exécutez multigroupby avec app et ss, le résultat attendu (si les doublons étaient autorisés) pourrait ressembler à ceci :
[
{"app": "monitoring24", "ss": "logs-opentelemetry-agent", "_count0": 2},
{"app": "monitoring24", "ss": "logs-opentelemetry-collector", "_count0": 2}
]
En raison de cette limitation, multigroupby fusionnera ces doublons et ne renverra qu'une seule ligne pour chaque combinaison unique, même si cette combinaison apparaît plusieurs fois dans les données :
[
{"app": "monitoring24", "ss": "logs-opentelemetry-agent", "_count0": 2}
]
orderby / sortby / order by / sort by
Trier les données par ordre croissant/décroissant de la valeur de l'expression. L'ordre des expressions multiples est pris en charge.
(orderby|sortby|order by|sort by) <expression> [(asc|desc)] , ...
Exemples :
orderby $d.myfield.myfield
orderby $d.myfield.myfield:number desc
sortby $d.myfield desc
Le tri des valeurs numériques peut être effectué en coulant l'expression dans le type :, par exemple, <expression>: number. Dans certains cas, cette information est déduite automatiquement par le moteur.
redact
Remplacer toutes les sous-chaînes correspondant à un motif regexp à partir d'une valeur keypath, en masquant efficacement le contenu d'origine.
Le mot-clé correspondant est facultatif et peut être utilisé pour améliorer la lisibilité.
redact <keypath> [matching] /<regular-expression>/ to '<redacted_str>'
redact <keypath> [matching] <string> to '<redacted_str>'
Exemples :
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
Supprime un chemin d'accès de l'objet.
r|remove <keypath1> [ "," <keypath2> ]...
Exemples :
r $d.mydata.unneeded_key
remove $d.mysuperkey.service_name, $d.mysuperkey.unneeded_key
replace
Remplacer la valeur d'une clé par une nouvelle valeur.
Si la valeur de remplacement modifie le type de données du chemin de clé, les options suivantes sont disponibles :
-
skip- Le remplacement sera ignoré -
fail- La requête échouera -
overwrite- La nouvelle valeur remplacera la précédente, ce qui modifiera le type de données du chemin d'accès
replace <keypath> with <expression> [on datatype changed skip/fail/overwrite]
Exemples :
replace $d.message with null
replace $d.some_superkey.log_length_plus_10 with $d.original_log.length()+10 on datatype changed overwrite
roundtime
Arrondit l'heure de l'événement dans un intervalle de temps donné, en créant éventuellement une nouvelle clé pour le résultat.
-
Si
source-timestampn'est pas fourni,$m.timestampest utilisé comme horodatage source. -
Si
source-timestampest fourni, il doit être du type (ou coulé dans)timestamp.
Par défaut, le résultat arrondi est réécrit dans le chemin d'accès source source-timestamp. Si target-keypath est fourni, source-timestamp n'est pas modifié et le résultat est écrit dans un nouveau target-keypath.
Les intervalles de temps pris en charge sont les suivants :
- Xns - X nanosecondes (Attention à la résolution de l'horodatage source)
- Xms - X millisecondes
- Xs - X secondes
- Xm - X minutes
- Xh - X heures
- Xd - X jours
Et toute combinaison d'unités de temps supérieures à inférieures, par exemple, 1h30m15s.
roundtime [source-timestamp] to <time-interval> [into <target-keypath>]
Exemples :
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
Définissez la source de données sur laquelle votre requête DataPrime est basée.
(source|from) <data_store>
Où data_store peut être l'un ou l'autre :
-
logs -
Le nom de l'enrichissement personnalisé. Dans ce cas, la commande affichera le tableau d'enrichissement personnalisé.
Exemples :
source logs
stitch
La commande stitch réalise une union horizontale de deux ensembles de données, en les combinant côte à côte. Il aligne les lignes d'un ensemble de données sur celles d'un autre et concatène leurs colonnes, créant ainsi un ensemble
de données unique et unifié.
Lors de l'utilisation de la commande stitch:
-
Les ensembles de données doivent être ordonnés, car les lignes sont combinées dans l'ordre (c'est-à-dire que la ligne 1 de l'ensemble de données A est cousue avec la ligne 1 de l'ensemble de données B).
-
Si l'un des ensembles de données contient plus de lignes que l'autre, les lignes non appariées auront des valeurs nulles dans les colonnes assemblées.
-
L'ensemble de données résultant contiendra toutes les colonnes des deux ensembles de données.
stitch diffère de union. stitch combine les ensembles de données horizontalement en ajoutant les colonnes ligne par ligne. union ajoute les lignes verticalement, en empilant les ensembles de
données les uns sur les autres.
... | stitch (<subquery>) into <target-keypath>
Exemple :
Vous disposez de ces tableaux d' enrichissement personnalisés:
sales données :
{ "product": "Widget", "sales": 100 }
{ "product": "Gadget", "sales": 200 }
{ "product": "Dashboard", "sales": 150 }
revenue données :
{ "product": "Widget", "revenue": 5000 }
{ "product": "Gadget", "revenue": 8000 }
{ "product": "Dashboard", "revenue": 6000 }
Dans cette requête, vous combinerez ces ensembles de données côte à côte, en veillant à ce que chaque ligne d'un ensemble de données soit alignée sur la ligne correspondante de l'autre :
source sales | orderby product
| stitch (source revenue | orderby product) into combined_data
-
source salesrécupère toutes les lignes de l'ensemble de donnéessales, qui contient les produits et les chiffres de vente correspondants. -
orderby producttrie l'ensemble de donnéessalespar le champproductafin de créer un ordre cohérent pour l'alignement des lignes. -
stitch (source revenue | orderby product)récupère les lignes de l'ensemble de donnéesrevenueet les trie en fonction du champproduct. Les ensembles de donnéessalesetrevenuesont combinés horizontalement, en alignant les lignes en fonction de leur ordre après le tri. -
into combined_datastocke l'ensemble des données combinées dans une variable appeléecombined_data.
Le résultat de la requête est le suivant :
{ "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 } }
Si les ensembles de données ont des lignes inégales, la commande stitch remplit les valeurs manquantes avec null.
Par exemple, considérons les ensembles de données suivants :
sales (3 lignes):
{ "product": "Widget", "sales": 100 }
{ "product": "Gadget", "sales": 200 }
{ "product": "Dashboard", "sales": 150 }
revenue (2 lignes):
{ "product": "Widget", "revenue": 5000 }
{ "product": "Gadget", "revenue": 8000 }
Exécuter cette requête :
source sales | orderby product
| stitch (source revenue | orderby product) into combined_data
Donne le résultat suivant :
{ "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 Notes d'utilisation
-
Les rangées doivent être en corrélation logique pour que le piquage produise des résultats significatifs. Assurez-vous que les lignes des deux ensembles de données représentent les mêmes entités et sont dans le même ordre. Par exemple, si le champ
productde l'ensemble de donnéessalesne correspond pas au champproductde l'ensemble de donnéesrevenuepour les lignes correspondantes, le piquage ne fonctionnera pas comme prévu. -
Si les ensembles de données diffèrent en termes de nombre de lignes, le résultat inclura
nullpour les données manquantes dans l'ensemble de données le plus court.
top
Pas de variation de regroupement: Limite les lignes renvoyées à un nombre spécifié et ordonne le résultat en fonction d'un ensemble d'expressions.
order_direction := "descending"/"ascending" according to top/bottom
top <limit> <result_expression1> [as <alias>] [, <result_expression2> [as <alias2>], ...] by <orderby_expression> [as alias>]
Par exemple, la requête suivante :
top 5 $m.severity as $d.log_severity by $d.duration
Il en résultera des enregistrements de la forme suivante :
[
{ "log_severity": "Warning", "duration": 2000 },
{ "log_severity": "Debug", "duration": 1000 }
...
]
Variante de regroupement: Limite les lignes renvoyées à un nombre spécifié et les regroupe par un ensemble d'expressions d'agrégation et les ordonne par un ensemble d'expressions.
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>]
Par exemple, la requête suivante :
top 10 $m.severity, count() as $d.number_of_severities by avg($d.duration) as $d.avg_duration
Il en résultera des enregistrements de la forme suivante :
[
{ "severity": "Debug", "number_of_severities": 10, avg_duration: 2000 }
{ "severity": "Warning", "number_of_severities": 50, avg_duration: 1000 },
...
]
Vous pouvez appliquer une fonction d'agrégation...
union
La commande union concatène les résultats de deux ou plusieurs ensembles de données en un seul ensemble de données. Cela permet aux utilisateurs de combiner les résultats de plusieurs requêtes en un seul ensemble de données homogène.
Un ensemble de données peut être un ensemble de résultats envoyé à la commande union, puis concaténé avec un autre ensemble de données.
Utilisez l'union lorsque vous devez ajouter des lignes d'un ensemble de données à un autre.
Lors du traitement de grands ensembles de données, pour optimiser les performances, envisagez d'utiliser filter pour limiter les lignes de chaque ensemble de données avant d'utiliser union.
Les utilisateurs sont limités à un maximum de 10 commandes union par requête pour les données Informations de priorité. Il n'y a pas de limite pour les autres données.
En quoi union diffère-t-il de join
-
unioncombine des ensembles de résultats en ajoutant des lignes d'un ensemble de données à un autre. Il ne fusionne ni ne compare les colonnes de plusieurs documents. -
joinfait correspondre et combine les colonnes de deux tableaux en fonction d'une condition, créant ainsi des lignes qui contiennent des données provenant des deux tableaux.
<query> | union <query>
Exemple de combinaison de 2 ensembles de données
Vous disposez de ces deux ensembles de données :
Journaux pour Team 58942
{ "id": "111", "name": "John" , "team.id": "58942" }
{ "id": "222", "name": "Emily", "team.id": "58942" }
{ "id": "333", "name": "Alice", "team.id": "58942" }
Journaux pour 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" }
Et vous voulez les combiner en un seul ensemble de données. Vous pouvez le faire en utilisant union.
source logs(teamId=58942) | union logs(teamId=98361)
La requête traite les deux ensembles de données :
source logs(teamId=58942): Récupère tous les documents pourTeam 58942union logs (teamID=98361): Ajoute l'ensemble de donnéesTeam 98361à l'ensemble de donnéesTeam 58942
Il en résultera l'ensemble de données suivant :
{ "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" }