DataPrime operadores

Esta guía ofrece un glosario de los operadores de IBM® Cloud Logs DataPrime.

block

La negación de filter. Filtra todos los eventos en los que la condición es verdadera. El mismo efecto puede conseguirse utilizando filter con !(condition).

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

Los datos se exponen utilizando los siguientes campos:

  • $m - Metadatos del evento

    • timestamp
    • severity- Los valores posibles son Verbose, Debug, Info, Warning, Error, Critical
    • priorityclass- Los valores posibles son high, medium, low
    • logid
  • $l - Etiquetas de eventos

    • applicationname
    • subsystemname
    • category
    • classname
    • computername
    • methodname
    • threadid
    • ipaddress
  • $d -Los datos del usuario

bottom

Sin variación de agrupación: Limita las filas devueltas a un número especificado y ordena el resultado por un conjunto de expresiones.

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

Por ejemplo, la siguiente consulta:

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

Resultará en registros de la siguiente forma:

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

Variación de agrupación: Limita las filas devueltas a un número especificado y las agrupa por un conjunto de expresiones de agregación y las ordena por un conjunto de expresiones.

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>]

Por ejemplo, la siguiente consulta:

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

Resultará en registros de la siguiente forma:

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

Las funciones de agregación compatibles se enumeran en la sección "Funciones de agregación".

choose

Deje sólo las rutas de teclas proporcionadas, descartando todas las demás teclas. Soporta completamente las rutas de teclado anidadas en la salida.

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

Ejemplos:

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

convert

Convierte los tipos de datos de las claves.

La palabra clave datatypes es opcional y puede utilizarse para facilitar la lectura.

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

Ejemplos:

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

count

Devuelve una única fila que contiene el número de filas producidas por los operadores precedentes.

count [into <keypath>]

Se puede proporcionar un alias para anular la ruta del teclado donde se escribirá el resultado.

Por ejemplo, la siguiente parte de una consulta:

count into $d.num_rows

Dará como resultado una única fila de la siguiente forma:

{ "num_rows": 7532 }

countby

Devuelve una fila que cuenta todas las filas agrupadas por la expresión.

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

Se puede proporcionar un alias para anular la ruta del teclado en la que se escribirá el resultado.

Por ejemplo, la siguiente parte de una consulta

countby $d.verb into $d.verb_count

Resultará en una fila para cada grupo.

Es funcionalmente idéntico a

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

create

Crea una nueva clave y establece su valor en el resultado de la expresión. La creación de claves es granular, lo que significa que las claves padre de la ruta no se sobrescriben.

  (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 creación puede controlarse añadiendo las siguientes cláusulas:

  • Añadir keypath exists permite elegir qué hacer cuando el keypath ya existe.

    • overwrite- Sobrescribe el valor antiguo. Se trata del valor predeterminado

    • fail- Falla la consulta

    • skip- Omite la creación de la clave

  • Añadir keypath missing elige qué hacer cuando el nuevo keypath no existe.

    • create- Crea la llave. Se trata del valor predeterminado

    • fail- Falla la consulta

    • skip- Omite la creación de la nueva clave

  • Añadir en datatype changed elige qué hacer si la clave ya existe y los nuevos datos cambian el tipo de datos del valor.

    • overwrite- Sobrescribe el valor. Este es el valor predeterminado.

    • fail- Falla la consulta

    • skip- Deja la clave con el valor (y tipo) original

Ejemplos:

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

Devuelve una fila por cada combinación distinta de las expresiones proporcionadas.

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

Este operador es funcionalmente idéntico a groupby sin funciones de agregado.

enrich

Enriquezca sus registros utilizando el contexto adicional de una tabla de consulta.

Cargue su tabla de búsqueda usando Flujo de datos Icono de Flujo de datos > Enriquecimiento de datos > Enriquecimiento personalizado.

enrich <value_to_lookup> into <enriched_key> using <lookup_table>
  • value_to_lookup- Expresión de cadena que se buscará en la tabla de búsqueda.

  • enriched_key- Clave de destino para almacenar el resultado del enriquecimiento.

  • lookup_table- Nombre de la tabla de enriquecimiento personalizada que se va a utilizar.

Las columnas de la tabla se añadirán como subclaves a la clave de destino. Si no se encuentra value_to_lookup, la clave de destino será nula. A continuación, puede filtrar los resultados utilizando las funciones de DataPrime, como filtrar los registros por un valor específico del campo enriquecido.

Ejemplo:

El registro original:

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

La tabla de consulta de enriquecimiento personalizado denominada my_users:

Ejemplo de tabla de consulta
ID Nombre Departamento
111 Juan Finanzas
222 Emily TI

Ejecutando la siguiente consulta:

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

Dará como resultado el siguiente registro enriquecido:

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

Tenga en cuenta lo siguiente cuando utilice enrich:

  • Ejecute la fuente de consulta DataPrime lookup_table para ver la tabla de enriquecimiento.

  • Si el registro original ya contiene la clave enriquecida:

    • Si value_to_lookup existe en lookup_table, las subclaves se actualizarán con el nuevo valor. Si value_to_lookup no existe, se mantendrá su valor actual.

    • Cualquier otra subclave que no sea una columna en lookup_table permanecerá con sus valores actuales.

  • Todos los valores de lookup_table se consideran cadenas. Esto significa que:

    • La dirección value_to_lookup debe tener formato de cadena.

    • Todos los valores se enriquecen en un formato de cadena. A continuación, puede convertirlos al formato que prefiera (por ejemplo, JSON, timestamp) utilizando las funciones adecuadas.

extract

Extraer datos de algún valor de cadena a un nuevo objeto. Admite varios métodos de extracción.

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

A continuación se indican los métodos de extracción admitidos y sus parámetros:

  • regexp- Crear un nuevo objeto basado en regexp capture-groups

  • e- Una expresión regular con nombres captura-grupos.

Ejemplo:

extract $d.my_text into $d.my_data using regexp(e=/user (?<user>.*) has logged in/)
  • kv- Extraer un nuevo objeto de una cadena que contiene pares clave=valor clave=valor.

  • pair_delimiter- El delimitador que debe esperarse entre pares. Por defecto es (un espacio)

  • key_delimiter- El delimitador que se espera separar entre una clave y un valor. Por defecto es =.

Ejemplos:

extract $d.text into $d.my_kvs using kv()
e $d.text into $d.my_kvs using kv(pair_delimiter=' ',key_delimiter='=')
  • jsonobject- Extraer un nuevo objeto de una cadena contiene un objeto json codificado, potencialmente tratando de unescape la cadena antes de decodificarlo en un json

  • max_unescape_count- Número máximo de niveles de escape a desescapar antes de parsear el json. El valor predeterminado es 1. Cuando se establece en 1 o más, el motor detectará si el valor contiene una cadena JSON escapada y la desescape hasta que se exceda su parsable o el recuento máximo de desescape.

Ejemplo:

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

Es posible proporcionar información sobre el tipo de datos como parte de la extracción, utilizando la cláusula datatypes. Por ejemplo, si se añade el tipo de datos my_field:number a una extracción, la ruta clave del extracto my_field será un número en lugar de una cadena. Por ejemplo:

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

Los datos extraídos siempre van a un nuevo keypath como un objeto, permitiendo el procesamiento posterior de las nuevas claves dentro de ese nuevo objeto. Por ejemplo:

# 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 los eventos, dejando sólo los eventos para los que la condición se evalúa como verdadera.

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

Ejemplos:

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

La comparación con null sólo funciona para valores escalares y siempre devolverá null en subárboles JSON.

Cuando se utiliza una condición para comparar una ruta clave con null, esto sólo funcionará en valores escalares (cadena, número, marca de tiempo, etc.). Para objetos JSON dentro de un documento dado, la comparación con null siempre devolverá null.

Utilice filtros con funciones para realizar búsquedas complejas.

Ejemplos:

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

e - Filtrar por direcciones IP en un rango determinado. filter se puede combinar con funciones para realizar búsquedas complejas con muy poca sintaxis, por ejemplo utilizando la función ipInSubnet:

filtro ipInSubnet(ip_address, ' 154.67.8.20/24 ')

groupby

Agrupa los resultados de los operadores anteriores mediante las expresiones de agrupación especificadas y calcula funciones agregadas para cada grupo creado.

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

Por ejemplo, la siguiente consulta:

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

Resultará en registros de la siguiente forma:

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

Las rutas clave de las expresiones de agrupación estarán siempre bajo $d. Utilizando la palabra clave as, podemos renombrar la ruta clave para las expresiones de agrupación y las funciones de agregación. Por ejemplo:

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

Resultará en registros de la siguiente forma:

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

Al consultar con el operador groupby, puede aplicar una función de agregación (como avg, max, sum) al cubo de resultados. Esta función le permite manipular una expresión de agregación dentro de la propia expresión, lo que le permite calcular y manipular los datos simultáneamente.

join

Join fusiona los resultados de la consulta actual (izquierda) con una segunda consulta (derecha) en función de una condición especificada. Ofrece múltiples formas de controlar cómo se combinan los datos y admite el anidamiento, lo que permite que la consulta correcta incluya su propio comando join.

Join admite tres variantes:

join left|join
Para cada evento de la consulta izquierda, el comando selecciona un evento coincidente de la consulta derecha en función de la condición especificada. Si no se encuentra ninguna coincidencia, se incluyen las filas de todos los eventos de la consulta de la izquierda. Las filas no coincidentes de la consulta correcta se establecen en null.
join full
Devuelve una fila por cada suceso, incluidos los que pueden no coincidir en ninguna de las dos consultas (izquierda o derecha), rellenando los valores que faltan con null.
join inner
Sólo devuelve las filas en las que hay resultados no nulos de ambas consultas.
join cross
Empareja cada fila de la consulta izquierda con cada fila de la consulta derecha, generando el producto cartesiano completo. A diferencia de otros tipos de join, join cross no admite on ni using conditions. Funciona de forma similar a join inner pero sin ningún filtro, devolviendo todas las combinaciones de filas posibles.

Para left (por defecto), inner, y full, puede especificar una condición join utilizando la palabra clave on o una ruta clave utilizando la palabra clave keyword. El producto cartesiano se filtra para conservar sólo las filas en las que la condición es verdadera o en las que los valores de la ruta clave coinciden en ambos lados.

Dado que todas las uniones, independientemente del modificador, se basan en el producto cartesiano, pueden producirse resultados duplicados si la condición join coincide varias veces. Para evitar la duplicación involuntaria, considere la posibilidad de preprocesar las subconsultas, por ejemplo utilizando distinct.

Sintaxis:

<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>

Donde:

  • <right_side_query>- La dirección <right_side_query> indica la nueva consulta a la que se va a unir.

  • <left_side_query>- El <left_side_query> denota la consulta inicial, por ejemplo, en la consulta source logs | filter x != null | join ..., la consulta de la izquierda es source logs | filter x != null.

  • <condition>- La condición si se deben unir los resultados de ambas consultas.

    En la condición, puede utilizar los prefijos left=> y right=> para referirse a los eventos de las consultas izquierda y derecha, respectivamente. Sin embargo, no es necesario si sólo existe una ruta clave en una de las consultas.

    Al utilizar el operador == (igualdad) en su condición, debe comparar un keypath de la consulta izquierda con un keypath de la consulta derecha. Sin embargo, dado que las rutas clave deben ser únicas o ir precedidas de left=> o right=>, el orden de los operandos no es importante.

  • <join_keypath_n>- <join_keypath_n> como clave de unión significa unir resultados en los que una ruta clave determinada es igual en los resultados de la consulta de la izquierda y de la consulta de la derecha.

  • <right_side_target>- La ruta donde se añadirán los datos unidos a la consulta actual.

Ejemplo de join

Usted tiene esta tabla de enriquecimiento personalizada llamada users que proporciona información sobre los ID relacionados con los nombres:

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

Y estos datos proporcionan los eventos de inicio de sesión y los ID de usuario, pero no el nombre de usuario asociado a los ID de usuario.

{ "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 join puede utilizar una consulta para obtener los datos deseados.

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

Esta consulta se procesa del siguiente modo:

  • La source es la tabla de enriquecimiento personalizada (users).

  • En join, se genera un recuento por el campo userid. Así obtenemos las estadísticas de count.

  • El campo id de la tabla de enriquecimiento personalizada se compara con el campo userid de los registros.

  • El resultado se introduce en la tecla logins. Si la clave logins ya existe en la consulta de la izquierda, se sobrescribirá.

Por ejemplo:

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

El resultado de la consulta de la derecha se encuentra ahora dentro del campo logins. Tenga en cuenta que no hubo inicios de sesión para el ID de usuario 333 (Alice), por lo que el campo de inicios de sesión es null porque no hubo ningún resultado coincidente con la condición join.

join ejemplo con la palabra clave using

Considere si nuestro conjunto de datos de inicio de sesión es:

{ "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" }

En este caso, los datos de ambos lados de la unión incluyen el campo id. En este caso se puede utilizar la palabra clave using para aprovechar los datos comunes:

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

El resultado será similar, pero en lugar de userid, se devuelve el 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 }

Si tiene dos campos que se denominan de forma diferente pero que simplificarían su consulta en join, puede utilizar move para desplazar uno de los campos de modo que las rutas clave coincidan en ambos lados.

join ejemplo con las palabras clave left=> y right=>

Puede utilizar los prefijos left=> y right=> para referirse a los eventos de las consultas izquierda y derecha. Sin embargo, no es necesario si sólo existe una ruta clave en una de las consultas.

Utilizando los datos del ejemplo anterior, considere la consulta:

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

Esto es necesario porque ambos conjuntos de datos contienen un campo con el mismo nombre (id). Para que DataPrime identifique un campo de forma única, debe saber a qué lado de la consulta nos estamos refiriendo. El resultado de esta consulta será el mismo que el de la anterior, en la que se utilizó la palabra clave using.

Al utilizar el operador == (igualdad) en su condición, debe comparar un keypath de la consulta izquierda con un keypath de la consulta derecha. Sin embargo, dado que las rutas clave deben ser únicas o ir precedidas de left=> o right=>, el orden de los operandos no es importante.

Ejemplo de join full

Usted tiene esta tabla de enriquecimiento personalizada llamada users que proporciona información sobre los ID relacionados con los nombres:

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

Y considera este conjunto de datos:

{ "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" }

El segundo conjunto de documentos (consulta de la derecha) incluye una entrada de registro con "id": "001" que no existe en el primer conjunto de documentos (consulta de la izquierda). Si utiliza una unión estándar, esta entrada de la consulta derecha se ignorará y no aparecerá en el resultado. Para asegurarse de que todos los campos de id se incluyen en la salida, aparezcan o no en la consulta izquierda o derecha, puede utilizar join full:

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

Esta consulta da como resultado:

{ "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 }

Al utilizar join full, se conservan todos los campos id de ambos conjuntos de datos, y cualquier valor que falte se establece en null.

join full resulta especialmente útil cuando los resultados de ambas consultas incluyen buckets temporales. Por ejemplo, si a los resultados de la consulta de la izquierda les falta un bucket de tiempo para una hora específica (por ejemplo, XX:XX:XX), con join full se incluye este punto de datos. Esto resulta especialmente útil para comparar dos series temporales en un gráfico.

Ejemplo de join inner

Si desea eliminar cualquier fila si los resultados de columna de las consultas izquierda o derecha que producen un valor nulo, utilice join inner.

Utilizando los datos anteriores, esta consulta elimina las filas con datos no coincidentes de ambos lados:

source users | join inner (source logins | countby id) using id into logins
  • La consulta de la izquierda source users recupera el conjunto de datos de usuarios que contiene los campos id y name.

  • La consulta de la derecha (source logins | countby id) recupera el conjunto de datos de inicios de sesión, agrupándolos por id y contando las apariciones de cada id.

  • join inner hace coincidir las filas en las que id existe en ambos conjuntos de datos y fusiona los datos en un único registro.

  • Las filas sin coincidencias en ninguno de los dos conjuntos de datos se excluyen de los resultados finales.

En este caso, para los dos conjuntos de documentos anteriores, los resultados serán los siguientes:

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

Ejemplo de join cross

join cross combina cada fila de la consulta de la izquierda con cada fila de la consulta de la derecha, obteniendo un producto cartesiano de los dos conjuntos.

Supongamos que tenemos los siguientes documentos de una tabla de enriquecimiento personalizada denominada users.

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

Consideremos ahora este conjunto de documentos denominado 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 siguiente consulta producirá un producto cartesiano de los conjuntos de datos users y logs porque join cross empareja cada fila de la consulta de la izquierda con cada fila de la consulta de la derecha, independientemente de cualquier condición coincidente.

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 consulta da como resultado que cada usuario está emparejado con cada entrada del registro: 3 filas de users multiplicadas por 5 filas de logs, lo que da como resultado 15 filas. Cada usuario (John, Emily, Alice) se empareja con cada entrada de registro.

El uso de join cross es especialmente útil cuando se está interesado en ver una imagen completa de los datos y, a continuación, añadir left o right join a estos resultados.

Limitaciones y consideraciones

Existen limitaciones y consideraciones a la hora de incluir join en una consulta:

  • La condición join sólo admite la igualdad de rutas clave (==). Si se necesitan varias condiciones de igualdad, se pueden combinar con && (lógica y).

  • Uno de los lados de la unión (ya sea la consulta actual o la consulta de unión) debe ser pequeño (< 200MB ). Puede utilizar filter y remove para reducir el tamaño de la consulta.

  • Las uniones externas izquierdas requieren que todas las columnas de la condición no sean nulas. Las columnas nulas no se unirán. Para incluir columnas nulas de consulta a la derecha, utilice join full. Para excluir todas las columnas nulas producidas por las uniones izquierda y derecha, utilice join inner.

limit

Limita la salida a los primeros eventos de event-count.

limit <event-count>

Ejemplo:

limit 100

move

Mueve una tecla (incluyendo sus teclas hijas, si las hay) a una nueva ubicación.

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

Ejemplos:

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

multigroupby

multigroupby concatena los resultados de dos o más consultas incorporando groupby en un único conjunto de datos.

Utiliza multigroupby para:

  • Eficacia: Los datos se escanean una sola vez para múltiples consultas.

  • Sincronización: Los resultados se mantienen coherentes, evitando las discrepancias que pueden surgir al ejecutar consultas separadas.

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], ...]

Al utilizar el mismo alias app para ambas agrupaciones, se presenta el mismo significado semántico como un campo unificado. En el siguiente ejemplo, se utilizan alias diferentes y los datos se combinan, pero no se fusionan.

Ejemplo - Multigroupby con el mismo alias

En este ejemplo queremos agrupar nuestros registros de la siguiente manera:

  • Primero por applicationname (app) y después por subsystemname (ss), proporcionando recuentos detallados para cada combinación.

  • A continuación, independientemente por applicationname, lo que da un recuento total de registros para cada aplicación, independientemente de subsystems.

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

El resultado será similar 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
    }
]

Las tres primeras filas representan los recuentos de cada combinación única de app y ss. Por ejemplo, hay 241 registros en los que la aplicación (app) es monitoring24 y el subsistema (ss) es NO_SUBSYSTEM_NAME. Del mismo modo, hay 231 registros para la misma aplicación pero con el subsistema logs-opentelemetry-agent, y así sucesivamente.

La última fila proporciona un recuento total de registros para la aplicación monitoring24, agregando todos los subsistemas. Aquí, _count0 es 487, la suma de todos los recuentos detallados anteriormente. El campo ss es null para indicar que se trata del total de la solicitud en su conjunto.

Al utilizar el mismo alias app para ambas agrupaciones, se presenta el mismo significado semántico como un campo unificado. En el siguiente ejemplo, se utilizan alias diferentes y los datos se combinan, pero no se fusionan.

Ejemplo - Multigroupby con diferentes alias

Ahora, considere los efectos de introducir 2 alias diferentes para las consultas. En este caso, la primera agrupación se etiqueta como app1 para applicationname combinado con ss, mientras que la segunda agrupación se etiqueta como app2 para applicationname alone.

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

El resultado será similar 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
    }
]

Al introducir alias separados (app1 y app2), la consulta mantiene la distinción entre las dos agrupaciones en lugar de fusionar los datos. Las filas en las que app1 está poblado y app2 es null corresponden a la agrupación detallada por applicationname y subsystemname. Por ejemplo, 241 registros están asociados a app1 = "monitoring24" y ss = "logs-opentelemetry-agent". Esto sigue la primera lógica de agrupación.

La fila en la que app2 está poblada y app1 es null refleja el recuento total de la segunda agrupación, en la que los registros se agregan únicamente por applicationname. Para app2 = "monitoring24", el recuento es 487, y tanto app1 como ss son null para indicar esta agregación de nivel superior.

Al utilizar alias distintos (app1 y app2), la consulta no fusiona los datos, sino que deja claro a qué grupo pertenece cada resultado. La lógica general sigue siendo la misma: recuentos detallados para combinaciones específicas y recuentos agregados para el total.

Limitaciones de Multigroupby

multigroupby no devuelve filas duplicadas para conjuntos de grupos duplicados.

Si ejecuta multigroupby con app y ss, el resultado esperado (si se permitieran duplicados) podría ser el siguiente:

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

Debido a esta limitación, multigroupby fusionará estos duplicados y sólo devolverá una fila por cada combinación única, aunque dicha combinación aparezca varias veces en los datos:

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

orderby / sortby / order by / sort by

Ordena los datos por orden ascendente/descendente del valor de la expresión. Se admite la ordenación por varias expresiones.

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

Ejemplos:

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

La ordenación de valores numéricos puede realizarse mediante la conversión de la expresión al tipo:, por ejemplo, <expression>: number. En algunos casos, el motor lo deducirá automáticamente.

redact

Reemplaza todas las subcadenas que coincidan con un patrón regexp de algún valor keypath, ocultando de forma efectiva el contenido original.

La palabra clave de concordancia es opcional y puede utilizarse para aumentar la legibilidad.

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

Ejemplos:

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

Elimina una ruta clave del objeto.

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

Ejemplos:

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

replace

Sustituye el valor de alguna clave por un nuevo valor.

Si el valor de sustitución cambia el tipo de datos de la ruta clave, se dispone de las siguientes opciones:

  • skip- Se ignorará la sustitución

  • fail- La consulta fallará

  • overwrite- El nuevo valor sobrescribirá al anterior, cambiando el tipo de datos de la ruta clave

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

Ejemplos:

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

roundtime

Redondea la hora del evento en algún intervalo de tiempo, posiblemente creando una nueva clave para el resultado.

  • Si no se proporciona source-timestamp, se utilizará $m.timestamp como marca de tiempo de origen.

  • Si se proporciona source-timestamp, debe ser del tipo timestamp.

Por defecto, el resultado redondeado se vuelve a escribir en la ruta del teclado de origen source-timestamp. Si se proporciona target-keypath, source-timestamp no se modifica y el resultado se escribe en un nuevo target-keypath.

Los intervalos de tiempo admitidos son:

  • Xns - X nanosegundos (tenga cuidado con la resolución de la marca de tiempo de origen)
  • Xms - X milisegundos
  • Xs - X segundos
  • Xm - X minutos
  • Xh - X horas
  • Xd - X días

Y cualquier combinación de mayor a menor unidad de tiempo, por ejemplo, 1h30m15s.

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

Ejemplos:

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

Establezca la fuente de datos en la que se basa su consulta DataPrime.

(source|from) <data_store>

Donde data_store puede ser cualquiera de los dos:

  • logs

  • Nombre del enriquecimiento personalizado. En este caso, el comando mostrará la tabla de enriquecimiento personalizada.

Ejemplos:

source logs

stitch

El comando stitch realiza una unión horizontal de dos conjuntos de datos, combinándolos uno al lado del otro. Alinea las filas de un conjunto de datos con las de otro y concatena sus columnas, creando un único conjunto de datos unificado.

Al utilizar el comando stitch:

  • Los conjuntos de datos deben estar ordenados, ya que las filas se combinan en secuencia (es decir, la fila 1 del conjunto de datos A se cose con la fila 1 del conjunto de datos B).

  • Si un conjunto de datos tiene más filas que el otro, las filas no coincidentes tendrán valores nulos en las columnas unidas.

  • El conjunto de datos resultante contendrá todas las columnas de ambos conjuntos de datos.

stitch difiere de union. stitch combina conjuntos de datos horizontalmente añadiendo columnas fila por fila. union añade filas verticalmente, apilando conjuntos de datos unos sobre otros.

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

Ejemplo:

Tienes estas tablas de enriquecimiento personalizadas:

sales conjunto de datos:

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

revenue conjunto de datos:

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

En esta consulta combinará estos conjuntos de datos uno al lado del otro, asegurándose de que cada fila de un conjunto de datos se alinee con la fila correspondiente del otro:

source sales | orderby product
| stitch (source revenue | orderby product) into combined_data
  • source sales obtiene todas las filas del conjunto de datos sales, que contiene los productos y sus correspondientes cifras de ventas.

  • orderby product ordena el conjunto de datos sales por el campo product para crear un orden coherente para la alineación de las filas.

  • stitch (source revenue | orderby product) obtiene filas del conjunto de datos revenue y las ordena por el campo product. Los conjuntos de datos sales y revenue se combinan horizontalmente, alineando las filas en función de su orden tras la clasificación.

  • into combined_data almacena el conjunto de datos combinados en una variable denominada combined_data.

El resultado de la consulta es:

{ "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 los conjuntos de datos tienen filas desiguales, el comando stitch rellena los valores que faltan con null.

Por ejemplo, considere los siguientes conjuntos de datos:

sales conjunto de datos (3 filas):

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

revenue conjunto de datos (2 filas):

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

Ejecutando esta consulta:

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

Da como resultado:

{ "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 Notas de uso

  • Las filas deben correlacionarse lógicamente para que la costura produzca resultados significativos. Asegúrese de que las filas de ambos conjuntos de datos representan las mismas entidades y están en el mismo orden. Por ejemplo, si el campo product del conjunto de datos sales no coincide con el campo product del conjunto de datos revenue para las filas correspondientes, la costura no funcionará como se espera.

  • Si los conjuntos de datos difieren en el número de filas, el resultado incluirá null valores para los datos que falten en el conjunto de datos más corto.

top

Sin variación de agrupación: Limita las filas devueltas a un número especificado y ordena el resultado por un conjunto de expresiones.

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

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

Por ejemplo, la siguiente consulta:

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

Resultará en registros de la siguiente forma:

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

Variación de agrupación: Limita las filas devueltas a un número especificado y las agrupa por un conjunto de expresiones de agregación y las ordena por un conjunto de expresiones.

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>]

Por ejemplo, la siguiente consulta:

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

Resultará en registros de la siguiente forma:

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

Puede aplicar una función de agregación..

union

El comando union concatena los resultados de dos o más conjuntos de datos en uno solo. Esto permite a los usuarios combinar los resultados de varias consultas en un conjunto de datos sin fisuras. Un conjunto de datos puede ser un conjunto de resultados canalizado en el comando union y luego concatenado con otro conjunto de datos.

Utilice la unión cuando necesite añadir filas de un conjunto de datos a otro.

Al procesar grandes conjuntos de datos, para optimizar el rendimiento, considere la posibilidad de utilizar filter para limitar las filas de cada conjunto de datos antes de utilizar union.

Los usuarios están limitados a un máximo de 10 comandos union por consulta de datos Información prioritaria. No hay límite para otros datos.

En qué se diferencia union de join

  • union combina conjuntos de resultados añadiendo filas de un conjunto de datos a otro. No fusiona ni compara columnas de varios documentos.

  • join hace coincidir y combina columnas de dos tablas basándose en una condición, creando filas que contienen datos de ambas tablas.

<query> | union <query>

Ejemplo de combinación de 2 conjuntos de datos

Tienes estos 2 conjuntos de datos:

Registros para Team 58942

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

Registros para 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" }

Y quieres combinarlos en 1 conjunto de datos. Puede hacerlo a través de union.

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

La consulta procesa los dos conjuntos de datos:

  • source logs(teamId=58942): Recupera todos los documentos de Team 58942
  • union logs (teamID=98361): Añade el conjunto de datos Team 98361 al conjunto de datos Team 58942

El resultado será el siguiente conjunto de datos:

{ "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" }