DataPrime operadores

Este guia fornece um glossário dos operadores do IBM® Cloud Logs DataPrime.

block

A negação de filter. Filtra todos os eventos em que a condição é verdadeira. O mesmo efeito pode ser obtido com o uso do site filter com !(condition).

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

Os dados são expostos usando os seguintes campos:

  • $m - Metadados do evento

    • timestamp
    • severity- Os valores possíveis são Verbose, Debug, Info, Warning, Error, Critical
    • priorityclass- Os valores possíveis são high, medium, low
    • logid
  • $l - Rótulos de eventos

    • applicationname
    • subsystemname
    • category
    • classname
    • computername
    • methodname
    • threadid
    • ipaddress
  • $d -Os dados do usuário

bottom

Nenhuma variação de agrupamento: Limita as linhas retornadas a um número especificado e ordena o resultado por um conjunto de expressões.

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

Por exemplo, a consulta a seguir:

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

Resultará em registros do seguinte formato:

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

Variação de agrupamento: Limita as linhas retornadas a um número especificado e as agrupa por um conjunto de expressões de agregação e as ordena por um conjunto de expressões.

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 exemplo, a consulta a seguir:

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

Resultará em registros do seguinte formato:

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

As funções de agregação compatíveis estão listadas na seção "Funções de agregação".

choose

Deixe apenas os caminhos de teclado fornecidos, descartando todas as outras chaves. Oferece suporte total a keypaths aninhados na saída.

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

Exemplos:

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

convert

Converta os tipos de dados das chaves.

A palavra-chave datatypes é opcional e pode ser usada para facilitar a leitura.

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

Exemplos:

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

count

Retorna uma única linha contendo o número de linhas produzidas pelos operadores anteriores.

count [into <keypath>]

Um alias pode ser fornecido para substituir o keypath onde o resultado será gravado.

Por exemplo, a seguinte parte de uma consulta:

count into $d.num_rows

Resultará em uma única linha com o seguinte formato:

{ "num_rows": 7532 }

countby

Retorna uma linha que conta todas as linhas agrupadas pela expressão.

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

Um alias pode ser fornecido para substituir o caminho de chave no qual o resultado será gravado.

Por exemplo, a seguinte parte de uma consulta

countby $d.verb into $d.verb_count

Resultará em uma linha para cada grupo.

Ele é funcionalmente idêntico ao

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

create

Crie uma nova chave e defina seu valor como o resultado da expressão. A criação de chaves é granular, o que significa que as chaves pai no caminho não são substituídas.

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

A criação pode ser controlada com a adição das seguintes cláusulas:

  • A adição do endereço keypath exists permite escolher o que fazer quando o caminho da chave já existe.

    • overwrite- Substitui o valor antigo. Este é o valor padrão

    • fail- Falha na consulta

    • skip- Ignora a criação da chave

  • Adicionar keypath missing escolhe o que fazer quando o novo caminho de chave não existir.

    • create- Cria a chave. Este é o valor padrão

    • fail- Falha na consulta

    • skip- Ignora a criação da nova chave

  • Adding on datatype changed escolhe o que fazer se a chave já existir e os novos dados alterarem o tipo de dados do valor.

    • overwrite- Substitui o valor. Este é o valor padrão.

    • fail- Falha na consulta

    • skip- Deixa a chave com o valor (e o tipo) original

Exemplos:

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

Retorna uma linha para cada combinação distinta das expressões fornecidas.

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

Esse operador é funcionalmente idêntico ao groupby sem nenhuma função agregada.

enrich

Enriqueça seus registros usando contexto adicional de uma tabela de pesquisa.

Carregue sua tabela de pesquisa usando Fluxo de dados Ícone de fluxo de dados > Data Enrichment > Custom Enrichment.

enrich <value_to_lookup> into <enriched_key> using <lookup_table>
  • value_to_lookup- Uma expressão de cadeia de caracteres que será pesquisada na tabela de pesquisa.

  • enriched_key- Chave de destino para armazenar o resultado do enriquecimento.

  • lookup_table- O nome da tabela de enriquecimento personalizado a ser usada.

As colunas da tabela serão adicionadas como subchaves à chave de destino. Se value_to_lookup não for encontrado, a chave de destino será nula. Em seguida, você pode filtrar os resultados usando os recursos do site DataPrime, como filtrar os registros por valor específico no campo enriquecido.

Exemplo:

O registro original:

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

A tabela de pesquisa de enriquecimento personalizado chamada my_users:

Exemplo de tabela de pesquisa
ID Nome Departamento
111 John Finanças
222 Emily IT

Executando a seguinte consulta:

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

Resultará no seguinte registro enriquecido:

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

Considere o seguinte ao usar o site enrich:

  • Execute a fonte de consulta DataPrime lookup_table para visualizar a tabela de enriquecimento.

  • Se o registro original já contiver a chave enriquecida:

    • Se value_to_lookup existir em lookup_table, as subchaves serão atualizadas com o novo valor. Se o value_to_lookup não existir, seu valor atual permanecerá.

    • Quaisquer outras subchaves que não sejam colunas no site lookup_table permanecerão com seus valores existentes.

  • Todos os valores no site lookup_table são considerados cadeias de caracteres. Isso significa que:

    • O endereço value_to_lookup deve estar em um formato de cadeia de caracteres.

    • Todos os valores são enriquecidos em um formato de cadeia. Em seguida, você pode convertê-los em seu formato preferido (por exemplo, JSON, carimbo de data/hora) usando as funções apropriadas.

extract

Extrai dados de algum valor de string em um novo objeto. Há suporte para vários métodos de extração.

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

Veja a seguir os métodos de extração suportados e seus parâmetros:

  • regexp- Criar um novo objeto com base em grupos de captura regexp

  • e- Uma expressão regular com nomes capture-groups.

Exemplo:

extract $d.my_text into $d.my_data using regexp(e=/user (?<user>.*) has logged in/)
  • kv- Extrair um novo objeto de uma cadeia de caracteres que contém pares chave=valor chave=valor.

  • pair_delimiter- O delimitador a ser esperado entre os pares. O padrão é (um espaço)

  • key_delimiter- O delimitador que se espera separar entre uma chave e um valor. O padrão é =.

Exemplos:

extract $d.text into $d.my_kvs using kv()
e $d.text into $d.my_kvs using kv(pair_delimiter=' ',key_delimiter='=')
  • jsonobject- Extrair um novo objeto de uma cadeia de caracteres que contém um objeto json codificado, tentando potencialmente desfazer o escape da cadeia de caracteres antes de decodificá-la em um json

  • max_unescape_count- Número máximo de níveis de escape a serem removidos antes de analisar o json. O padrão é 1. Quando definido como 1 ou mais, o mecanismo detectará se o valor contém uma cadeia de caracteres JSON com escape e fará o unescape até que a contagem analisável ou máxima de unescape seja excedida.

Exemplo:

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

É possível fornecer informações de tipo de dados como parte da extração, usando a cláusula datatypes. Por exemplo, adicionar os tipos de dados my_field:number a uma extração faria com que a extração my_field keypath fosse um número em vez de uma cadeia de caracteres. Por exemplo:

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

Os dados extraídos sempre entram em um novo caminho de chave como um objeto, permitindo o processamento adicional das novas chaves dentro desse novo objeto. Por exemplo:

# 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 eventos, deixando apenas os eventos para os quais a condição é avaliada como verdadeira.

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

Exemplos:

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

A comparação com null funciona somente para valores escalares e sempre retornará null em subárvores JSON.

Ao usar uma condição para comparar um caminho de chave com nulo, isso só funcionará em valores escalares (cadeia de caracteres, número, registro de data e hora etc.). Para objetos JSON em um determinado documento, a comparação com null sempre retornará null.

Use filtros com funções para realizar pesquisas complexas.

Exemplos:

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

e - Filtro para endereços IP em um determinado intervalo. o filtro pode ser associado a funções para realizar pesquisas complexas com muito pouca sintaxe, por exemplo, usando a função ipInSubnet:

filtro ipInSubnet(ip_address, ' 154.67.8.20/24 ')

groupby

Agrupa os resultados dos operadores anteriores de acordo com as expressões de agrupamento especificadas e calcula as funções agregadas para cada grupo criado.

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 exemplo, a consulta a seguir:

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

Resultará em registros do seguinte formato:

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

Os caminhos de teclado para as expressões de agrupamento sempre estarão em $d. Usando a palavra-chave as, podemos renomear o caminho-chave para as expressões de agrupamento e funções de agregação. Por exemplo:

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

Resultará em registros do seguinte formato:

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

Ao fazer consultas com o operador groupby, você pode aplicar uma função de agregação (como avg, max, sum) ao grupo de resultados. Esse recurso permite que você manipule uma expressão de agregação dentro da própria expressão, o que possibilita calcular e manipular os dados simultaneamente.

join

Join mescla os resultados da consulta atual (esquerda) com uma segunda consulta (direita) com base em uma condição especificada. Ele oferece vários formulários para controlar como os dados são combinados e suporta aninhamento, permitindo que a consulta correta inclua seu próprio comando join.

Join suporta três variações:

join left|join
Para cada evento na consulta à esquerda, o comando seleciona um evento correspondente da consulta à direita com base na condição especificada. Se nenhuma correspondência for encontrada, as linhas serão incluídas para todos os eventos na consulta à esquerda. As linhas não correspondentes da consulta correta são definidas como null.
join full
Retorna uma linha para cada evento, incluindo aqueles que podem não ter uma correspondência em nenhuma das consultas (esquerda ou direita), preenchendo os valores ausentes com null.
join inner
Retorna apenas as linhas em que há resultados não nulos de ambas as consultas.
join cross
Emparelha cada linha da consulta da esquerda com cada linha da consulta da direita, gerando o produto cartesiano completo. Diferentemente de outros tipos de join, o join cross não é compatível com on ou using conditions. Funciona de forma semelhante a um join inner, mas sem qualquer filtragem, retornando todas as combinações de linhas possíveis.

Para left (padrão), inner e full, você pode especificar uma condição join usando a palavra-chave on ou um caminho-chave usando a palavra-chave keyword. O produto cartesiano é filtrado para reter apenas as linhas em que a condição é verdadeira ou em que os valores do caminho-chave correspondem em ambos os lados.

Como todas as uniões, independentemente do modificador, são baseadas no produto cartesiano, podem ocorrer resultados duplicados se a condição join corresponder várias vezes. Para evitar a duplicação não intencional, considere o pré-processamento de subconsultas, por exemplo, usando distinct.

Sintaxe:

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

Em que:

  • <right_side_query>- O endereço <right_side_query> indica a nova consulta a ser unida.

  • <left_side_query>- O <left_side_query> indica a consulta inicial, por exemplo, na consulta source logs | filter x != null | join ..., a consulta do lado esquerdo é source logs | filter x != null.

  • <condition>- A condição se os resultados de ambas as consultas devem ser unidos.

    Na condição, você pode usar os prefixos left=> e right=> para se referir aos eventos das consultas à esquerda e à direita, respectivamente. No entanto, isso não é necessário se um caminho-chave existir em apenas uma das consultas.

    Ao usar o operador == (igualdade) em sua condição, ele deve comparar um keypath da consulta à esquerda com um keypath da consulta à direita. No entanto, como os keypaths devem ser exclusivos ou prefixados com left=> ou right=>, a ordem dos operandos não é importante.

  • <join_keypath_n>- <join_keypath_n> como uma chave de união significa unir resultados em que um determinado caminho-chave é igual nos resultados da consulta do lado esquerdo e da consulta do lado direito.

  • <right_side_target>- O keypath onde os dados unidos serão adicionados à consulta atual.

joinexemplo

Você tem uma tabela de enriquecimento personalizada chamada users que fornece informações sobre IDs relacionadas a nomes:

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

E esses dados fornecem eventos de login e IDs de usuário, mas não o nome de usuário associado aos IDs de usuário.

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

Usando o site join, você pode usar uma consulta para retornar dados que incluam os dados desejados.

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

Essa consulta é processada da seguinte forma:

  • O source é a tabela de enriquecimento personalizada (users).

  • Em join, é gerada uma contagem pelo campo userid. Isso nos dá nossas estatísticas count.

  • O campo id na tabela de enriquecimento personalizado é comparado com o campo userid nos registros.

  • O resultado é inserido na chave logins. Se a chave logins já existir na consulta à esquerda, ela será substituída.

Por exemplo:

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

O resultado da consulta do lado direito agora está dentro do campo logins. Observe que não houve logins para o ID de usuário 333 (Alice), portanto, o campo logins é null porque não houve resultado correspondente à condição join.

join exemplo com a palavra-chave using

Considere se nosso conjunto de dados de 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" }

Nesse caso, os dados em ambos os lados da união incluem o campo id. Nesse caso, a palavra-chave using pode ser usada para aproveitar os dados comuns:

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

O resultado será semelhante, mas, em vez de userid, o campo id será retornado.

{ "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 você tiver dois campos com nomes diferentes, mas que simplificariam sua consulta em join, poderá usar move para mover um dos campos de modo que os caminhos-chave coincidam em ambos os lados.

join exemplo usando as palavras-chave left=> e right=>

Você pode usar os prefixos left=> e right=> para se referir aos eventos das consultas à esquerda e à direita. No entanto, isso não é necessário se um caminho-chave existir em apenas uma das consultas.

Usando os dados do exemplo anterior, considere a consulta:

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

Isso é necessário porque ambos os conjuntos de dados contêm um campo com o mesmo nome (id). Para que o DataPrime identifique um campo de forma exclusiva, ele deve saber a qual lado da consulta estamos nos referindo. Essa consulta resultará no mesmo resultado que a anterior, que usou a palavra-chave using.

Ao usar o operador == (igualdade) em sua condição, ele deve comparar um keypath da consulta à esquerda com um keypath da consulta à direita. No entanto, como os keypaths devem ser exclusivos ou prefixados com left=> ou right=>, a ordem dos operandos não é importante.

join fullexemplo

Você tem uma tabela de enriquecimento personalizada chamada users que fornece informações sobre IDs relacionadas a nomes:

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

E considere este conjunto de dados:

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

O segundo conjunto de documentos (consulta à direita) inclui uma entrada de registro com "id": "001" que não existe no primeiro conjunto de documentos (consulta à esquerda). Se você usar uma união padrão, essa entrada da consulta correta será ignorada e não aparecerá no resultado. Para garantir que todos os campos do site id sejam incluídos na saída, independentemente de aparecerem ou não na consulta à esquerda ou à direita, você pode usar join full:

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

Essa consulta resulta em:

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

Ao usar join full, todos os campos id de ambos os conjuntos de dados são preservados, e todos os valores ausentes são definidos como null.

join full é particularmente útil quando os resultados de ambas as consultas incluem intervalos de tempo. Por exemplo, se os resultados da consulta à esquerda não tiverem um intervalo de tempo para uma hora específica (por exemplo, XX:XX:XX), com join full esse ponto de dados será incluído. Isso é especialmente útil para comparar duas séries temporais em um gráfico.

join innerexemplo

Se você quiser remover qualquer linha ou resultado de coluna das consultas à esquerda ou à direita que produzam um valor nulo, use join inner.

Usando os dados anteriores, essa consulta remove as linhas com dados não correspondentes de ambos os lados:

source users | join inner (source logins | countby id) using id into logins
  • A consulta à esquerda source users recupera o conjunto de dados de usuários que contém os campos id e name.

  • A consulta correta (source logins | countby id) recupera o conjunto de dados de logins, agrupando por id e contando as ocorrências de cada id.

  • join inner corresponde às linhas em que id existe em ambos os conjuntos de dados e mescla os dados em um único registro.

  • As linhas sem correspondência em nenhum dos conjuntos de dados são excluídas dos resultados finais.

Nesse caso, para os dois conjuntos de documentos acima, os resultados serão os seguintes:

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

join crossexemplo

join cross combina cada linha da consulta da esquerda com cada linha da consulta da direita, produzindo um produto cartesiano dos dois conjuntos.

Suponha que temos os seguintes documentos de uma tabela de enriquecimento personalizada chamada users.

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

Agora, considere esse 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" }

A consulta a seguir produzirá um produto cartesiano dos conjuntos de dados users e logs porque join cross emparelha todas as linhas da consulta à esquerda com todas as linhas da consulta à direita, independentemente de quaisquer condições de correspondência.

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

A consulta resulta no emparelhamento de cada usuário com cada entrada de registro: 3 linhas de users multiplicadas por 5 linhas de logs, resultando em 15 linhas. Cada usuário (John, Emily, Alice) é emparelhado com cada entrada de registro.

O uso do join cross é especialmente útil quando você está interessado em ver um quadro completo dos seus dados e, em seguida, adicionar um left ou right join a esses resultados.

Limitações e considerações

Há limitações e considerações ao incluir o site join em uma consulta:

  • A condição join suporta apenas a igualdade de keypath (==). Se forem necessárias várias condições de igualdade, elas podem ser combinadas com && (logical and).

  • Um dos lados da união (consulta atual ou consulta de união) deve ser pequeno (< 200MB ). Você pode usar filter e remove para reduzir o tamanho da consulta.

  • As uniões externas à esquerda exigem que todas as colunas na condição sejam não nulas. As colunas nulas não serão unidas. Para incluir colunas nulas na consulta à direita, use join full. Para excluir todas as colunas nulas produzidas pelas uniões à esquerda e à direita, use join inner.

limit

Limita a saída aos primeiros event-count eventos.

limit <event-count>

Exemplo:

limit 100

move

Mover uma chave (incluindo suas chaves secundárias, se houver) para um novo local.

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

Exemplos:

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

multigroupby

multigroupby concatena os resultados de duas ou mais consultas incorporando groupby em um único conjunto de dados.

Use o site multigroupby para:

  • Eficiência: Os dados são verificados apenas uma vez para várias consultas.

  • Sincronização: Os resultados permanecem coerentes, evitando discrepâncias que podem surgir ao executar 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], ...]

Ao usar o mesmo pseudônimo app para ambos os agrupamentos, o mesmo significado semântico é apresentado como um campo unificado. No próximo exemplo, são usados aliases diferentes e os dados são combinados, mas não mesclados.

Exemplo - Multigroupby com o mesmo alias

Neste exemplo, queremos agrupar nossos registros da seguinte forma:

  • Primeiro por applicationname (app) e depois por subsystemname (ss), fornecendo contagens detalhadas para cada combinação.

  • Em seguida, independentemente de applicationname, obtém-se a contagem total de registros para cada aplicativo, independentemente de subsystems.

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

O resultado será semelhante 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
    }
]

As três primeiras linhas representam as contagens para cada combinação exclusiva de app e ss. Por exemplo, há 241 registros em que o aplicativo (app) é monitoring24 e o subsistema (ss) é NO_SUBSYSTEM_NAME. Da mesma forma, há 231 registros para o mesmo aplicativo, mas com o subsistema logs-opentelemetry-agent, e assim por diante.

A última linha fornece uma contagem total de logs para o aplicativo monitoring24, agregando todos os subsistemas. Aqui, _count0 é 487, a soma de todas as contagens detalhadas acima. O campo ss é null para indicar que esse é o total para o aplicativo como um todo.

Ao usar o mesmo pseudônimo app para ambos os agrupamentos, o mesmo significado semântico é apresentado como um campo unificado. No próximo exemplo, são usados aliases diferentes e os dados são combinados, mas não mesclados.

Exemplo - Multigroupby com aliases diferentes

Agora, considere os efeitos da introdução de dois aliases diferentes para as consultas. Nesse caso, o primeiro agrupamento é rotulado como app1 para applicationname combinado com ss, enquanto o segundo agrupamento é rotulado como app2 para applicationname alone.

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

O resultado será semelhante 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
    }
]

Ao introduzir aliases separados (app1 e app2), a consulta mantém a distinção entre os dois agrupamentos em vez de mesclar os dados. As linhas em que app1 é preenchido e app2 é null correspondem ao agrupamento detalhado por applicationname e subsystemname. Por exemplo, 241 registros estão associados a app1 = "monitoring24" e ss = "logs-opentelemetry-agent". Isso segue a primeira lógica de agrupamento.

A linha em que app2 é preenchida e app1 é null reflete a contagem total do segundo agrupamento, em que os registros são agregados apenas por applicationname. Para app2 = "monitoring24", a contagem é 487, e tanto app1 quanto ss são null para indicar essa agregação de nível superior.

Ao usar aliases separados (app1 e app2), a consulta não mescla os dados, mas deixa claro a qual grupo cada resultado pertence. A lógica geral permanece a mesma: contagens detalhadas para combinações específicas e contagens agregadas para o total.

Multigroupby limitações

multigroupby não retorna linhas duplicadas para conjuntos de grupos duplicados.

Se você executar o site multigroupby com app e ss, o resultado esperado (se as duplicatas forem permitidas) poderá ser semelhante a este:

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

Devido a essa limitação, o site multigroupby mesclará essas duplicatas e retornará apenas uma linha para cada combinação exclusiva, mesmo que essa combinação ocorra várias vezes nos dados:

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

orderby / sortby / order by / sort by

Classifique os dados por ordem ascendente/descendente do valor da expressão. Há suporte para ordenação por várias expressões.

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

Exemplos:

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

A classificação de valores numéricos pode ser feita por meio da conversão da expressão para o tipo:, por exemplo, <expression>: number. Em alguns casos, isso será inferido automaticamente pelo mecanismo.

redact

Substitui todas as substrings que correspondem a um padrão regexp de algum valor keypath, ocultando efetivamente o conteúdo original.

A palavra-chave correspondente é opcional e pode ser usada para aumentar a legibilidade.

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

Exemplos:

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

Remove um keypath do objeto.

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

Exemplos:

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

replace

Substitui o valor de alguma chave por um novo valor.

Se o valor de substituição alterar o tipo de dados do caminho-chave, as seguintes opções estarão disponíveis:

  • skip- A substituição será ignorada

  • fail- A consulta falhará

  • overwrite- O novo valor substituirá o anterior, alterando o tipo de dados do keypath

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

Exemplos:

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

roundtime

Arredonda a hora do evento em algum intervalo de tempo, possivelmente criando uma nova chave para o resultado.

  • Se source-timestamp não for fornecido, $m.timestamp será usado como o registro de data e hora de origem.

  • Se source-timestamp for fornecido, ele deverá ser do tipo (ou convertido para) timestamp.

Por padrão, o resultado arredondado é gravado de volta no keypath de origem source-timestamp. Se em target-keypath for fornecido, então source-timestamp não será modificado e o resultado será gravado em um novo target-keypath.

Os intervalos de tempo suportados são:

  • Xns - X nanossegundos (tenha cuidado com a resolução do registro de data e hora de origem)
  • Xms - X milissegundos
  • Xs - X segundos
  • Xm - X minutos
  • Xh - X horas
  • Xd - X dias

E qualquer combinação de unidades de tempo maiores para menores, por exemplo, 1h30m15s.

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

Exemplos:

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

Defina a fonte de dados na qual sua consulta DataPrime se baseia.

(source|from) <data_store>

Onde data_store pode ser qualquer um:

  • logs

  • O nome do enriquecimento personalizado. Nesse caso, o comando exibirá a tabela de enriquecimento personalizada.

Exemplos:

source logs

stitch

O comando stitch executa uma união horizontal de dois conjuntos de dados, combinando-os lado a lado. Ele alinha as linhas de um conjunto de dados com as linhas de outro e concatena suas colunas, criando um conjunto de dados único e unificado.

Ao usar o comando stitch:

  • Os conjuntos de dados devem ser ordenados, pois as linhas são combinadas em sequência (ou seja, a linha 1 do conjunto de dados A é costurada com a linha 1 do conjunto de dados B).

  • Se um conjunto de dados tiver mais linhas do que o outro, as linhas não correspondentes terão valores nulos nas colunas unidas.

  • O conjunto de dados resultante conterá todas as colunas de ambos os conjuntos de dados.

stitch é diferente de union. stitch combina conjuntos de dados horizontalmente, anexando colunas linha por linha. union anexa linhas verticalmente, empilhando conjuntos de dados uns sobre os outros.

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

Exemplo:

Você tem essas tabelas de enriquecimento personalizadas:

sales conjunto de dados:

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

revenue conjunto de dados:

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

Nessa consulta, você combinará esses conjuntos de dados lado a lado, garantindo que cada linha de um conjunto de dados se alinhe com a linha correspondente do outro:

source sales | orderby product
| stitch (source revenue | orderby product) into combined_data
  • source sales obtém todas as linhas do conjunto de dados sales, que contém produtos e seus respectivos números de vendas.

  • orderby product classifica o conjunto de dados sales pelo campo product para criar uma ordem consistente para o alinhamento de linhas.

  • stitch (source revenue | orderby product) obtém linhas do conjunto de dados revenue e as classifica pelo campo product. Os conjuntos de dados sales e revenue são combinados horizontalmente, alinhando as linhas com base em sua ordem após a classificação.

  • into combined_data armazena o conjunto de dados combinado em uma variável chamada combined_data.

O resultado da consulta é:

{ "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 os conjuntos de dados tiverem linhas desiguais, o comando stitch preencherá os valores ausentes com null.

Por exemplo, considere os seguintes conjuntos de dados:

sales conjunto de dados (3 linhas):

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

revenue conjunto de dados (2 linhas):

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

Executando esta consulta:

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

Resulta em:

{ "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 Observações de uso

  • As linhas devem se correlacionar logicamente para que a costura produza resultados significativos. Certifique-se de que as linhas de ambos os conjuntos de dados representem as mesmas entidades e estejam na mesma ordem. Por exemplo, se o campo product no conjunto de dados sales não corresponder ao campo product no conjunto de dados revenue para as linhas correspondentes, a costura não funcionará como esperado.

  • Se os conjuntos de dados diferirem na contagem de linhas, o resultado incluirá null valores para dados ausentes no conjunto de dados mais curto.

top

Nenhuma variação de agrupamento: Limita as linhas retornadas a um número especificado e ordena o resultado por um conjunto de expressões.

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

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

Por exemplo, a consulta a seguir:

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

Resultará em registros do seguinte formato:

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

Variação de agrupamento: Limita as linhas retornadas a um número especificado e as agrupa por um conjunto de expressões de agregação e as ordena por um conjunto de expressões.

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 exemplo, a consulta a seguir:

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

Resultará em registros do seguinte formato:

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

Você pode aplicar uma função de agregação.

union

O comando union concatena os resultados de dois ou mais conjuntos de dados em um único conjunto de dados. Isso permite que os usuários combinem resultados de várias consultas em um único conjunto de dados. Um conjunto de dados pode ser um conjunto de resultados canalizado para o comando union e, em seguida, concatenado com outro conjunto de dados.

Use a união quando precisar anexar linhas de um conjunto de dados a outro.

Ao processar grandes conjuntos de dados, para otimizar o desempenho, considere usar filter para limitar as linhas de cada conjunto de dados antes de usar union.

Os usuários estão limitados a um máximo de 10 comandos union por consulta para dados Insights prioritários. Não há limite para outros dados.

Como o site union difere de join

  • union combina conjuntos de resultados anexando linhas de um conjunto de dados a outro. Ele não mescla ou compara colunas de vários documentos.

  • join corresponde e combina colunas de duas tabelas com base em uma condição, criando linhas que contêm dados de ambas as tabelas.

<query> | union <query>

Exemplo de combinação de 2 conjuntos de dados

Você tem esses dois conjuntos de dados:

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

E você deseja combiná-los em um único conjunto de dados. Você pode fazer isso usando union.

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

A consulta processa os dois conjuntos de dados:

  • source logs(teamId=58942): Recupera todos os documentos para Team 58942
  • union logs (teamID=98361): Anexa o conjunto de dados Team 98361 ao conjunto de dados Team 58942

Isso resultará no seguinte conjunto de dados:

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