Cortex XQL Command Reference
Tree viewThis book on one page — search it with your browser’s find (Ctrl+F / ⌘F), or jump from the tree.
Cortex XQL Command Reference
Cortex XQL (Extended Query Language) is a powerful query language used in the Cortex platform for threat hunting, investigation, and analytics across your security data. This reference provides comprehensive documentation for all XQL functions and pipeline stages.
XQL queries are composed of stages connected in a pipeline, with functions used within those stages to transform, filter, and analyze data. This reference is organized into two main sections:
- Functions – Built-in functions, indexes, and detailed reference pages.
- Stages – Pipeline stages, indexes, and detailed reference pages.
Functions
| Function | Description |
|---|---|
acos |
Calculate the inverse cosine (arccosine) of a numerical expression |
add |
|
approx_count |
|
approx_quantiles |
|
approx_top |
|
asin |
Calculate the inverse sine (arcsine) of a numerical expression |
array_all |
|
array_any |
|
array_length |
|
arrayconcat |
|
arraycreate |
|
arraydistinct |
|
arrayfilter |
|
arrayindex |
|
arrayindexof |
|
arraymap |
|
arraymerge |
|
arrayrange |
|
arraystring |
|
avg |
|
avg |
|
bitwise_and |
Perform a bitwise AND operation between two integer values |
bitwise_or |
Perform a bitwise OR operation between two integer values |
bitwise_sleft |
Perform a bitwise left shift operation on an integer value |
bitwise_sright |
Perform a bitwise right shift operation on an integer value |
bitwise_xor |
Perform a bitwise exclusive OR (XOR) operation between two integer values |
cbrt |
Calculate the cube root of a numeric value |
ceil |
Round a number up to the nearest integer |
coalesce |
|
concat |
|
convert_from_base_64 |
|
convert_to_base_64 |
|
cos |
Calculate the cosine of a numeric value specified in radians |
cosine_distance |
Calculate the cosine distance between two numeric vectors |
cot |
Calculate the cotangent of a numeric value specified in radians |
count |
|
count |
|
count_distinct |
|
csc |
Calculate the cosecant of a numeric value specified in radians |
current_time |
|
date_floor |
|
divide |
|
earliest |
|
euclidean_distance |
Calculate the Euclidean distance between two numeric vectors |
exp |
Calculate the value of e raised to the power of a numeric value |
extract_time |
|
extract_url_host |
|
extract_url_pub_suffix |
|
extract_url_registered_domain |
|
first |
|
first_value |
|
floor |
|
format_string |
|
format_timestamp |
|
greatest |
Return the largest value from a list of expressions |
if |
|
incidr |
|
incidr6 |
|
incidrlist |
|
int_to_ip |
|
ip_to_int |
|
is_ipv4 |
|
is_ipv6 |
|
is_known_private_ipv4 |
|
is_known_private_ipv6 |
|
json_extract |
|
json_extract_array |
|
json_extract_scalar |
|
json_extract_scalar_array |
|
json_path_extract |
|
json_functions_reference |
A comprehensive guide to the four JSON extraction functions |
lag |
|
last |
|
last_value |
|
latest |
|
least |
Return the smallest value from a list of expressions |
len |
|
list (comp) |
Collect all values of a field and return them as an array within the comp stage |
ln |
Calculate the natural logarithm (base e) of a numeric value |
log |
Calculate the logarithm of a numeric value with a specified base |
log10 |
Calculate the base-10 logarithm of a numeric value |
lowercase |
|
ltrim |
|
max (comp) |
Return the maximum value of a field within the comp stage |
max (windowcomp) |
Compute the maximum value of a field over a window of rows within the windowcomp stage |
md5 |
|
median (comp) |
Return the median value of a numeric field within the comp stage |
median (windowcomp) |
Compute the median value of a numeric field over a window of rows within the windowcomp stage |
min (comp) |
Return the minimum value of a field within the comp stage |
min (windowcomp) |
Compute the minimum value of a field over a window of rows within the windowcomp stage |
mod |
Calculate the remainder (modulus) of the division of two numeric values |
multiply |
|
object_create |
|
object_merge |
|
parse_epoch |
|
parse_timestamp |
|
pow |
|
power |
Raise a number to the power of another number (alias for pow) |
rand |
Generate a pseudo-random floating-point number between 0 and 1 |
range_bucket |
Determine which bucket a numeric value falls into given an array of boundaries |
rank (windowcomp) |
Assign a rank to each row within a partition in the windowcomp stage |
regexcapture |
|
regextract |
Extract a substring from a field value using a regular expression pattern |
replace |
|
replex |
|
round |
|
row_number (windowcomp) |
Assign a unique sequential integer to each row within a partition in the windowcomp stage |
rtrim |
|
safe_add |
Perform addition with overflow protection, returning null on overflow |
safe_divide |
Perform division with error protection, returning null on division by zero |
safe_multiply |
Perform multiplication with overflow protection, returning null on overflow |
safe_negate |
Negate a numeric value with overflow protection, returning null on overflow |
safe_subtract |
Perform subtraction with overflow protection, returning null on overflow |
sec |
Calculate the secant of a numeric value specified in radians |
sha1 |
|
sha256 |
|
sha512 |
|
sign |
Determine the sign of a numeric value (-1, 0, or 1) |
sin |
Calculate the sine of a numeric value specified in radians |
split |
|
sqrt |
Calculate the square root of a numeric value |
stddev_population (comp) |
Compute the population standard deviation of a numeric field within the comp stage |
stddev_population (windowcomp) |
Compute the population standard deviation of a numeric field over a window of rows within the windowcomp stage |
stddev_sample (comp) |
Compute the sample standard deviation of a numeric field within the comp stage |
stddev_sample (windowcomp) |
Compute the sample standard deviation of a numeric field over a window of rows within the windowcomp stage |
string_count |
|
subtract |
|
sum (comp) |
Compute the sum of a numeric field within the comp stage |
sum (windowcomp) |
Compute the sum of a numeric field over a window of rows within the windowcomp stage |
tan |
Calculate the tangent of a numeric value specified in radians |
time_frame_end |
|
timestamp_diff |
|
timestamp_seconds |
|
to_boolean |
|
to_epoch |
|
to_float |
|
to_integer |
|
to_json_string |
|
to_number |
|
to_string |
|
to_timestamp |
|
trim |
|
trunc |
Truncate a numeric value to a specified number of decimal places |
uppercase |
|
values |
Collect all distinct values of a field and return them as an array within the comp stage |
var |
Compute the variance of a numeric field within the comp stage |
wildcard_match |
Stages
| Stage | Description |
|---|---|
alter |
|
arrayexpand |
|
| bin | |
call |
|
comp |
|
config |
|
dataset |
|
dedup |
|
fields |
|
filter |
|
iploc |
|
join |
|
limit |
|
presets |
|
replacenull |
|
search |
|
sort |
|
tag |
|
target |
|
top |
|
transaction |
|
union |
|
view |
|
windowcomp |
Reference overview
Cortex XQL (Cortex Query Language) is the query language for threat hunting, investigation, and analytics across security data in Cortex.
XQL queries are built as pipelines. Stages connect with the pipe (|) operator. Functions run inside those stages to transform, filter, and analyze data.
This reference is organized into three main sections.
- Functions – Built-in functions for data manipulation, type conversion, string operations, math, bitwise operations, and more.
- XQL JSON Functions Reference – Reference for
json_extract,json_extract_scalar,json_extract_array, andjson_extract_scalar_array. - Stages – Pipeline stages that define query structure and flow.
- Browse the reference – Quick links to the main indexes and section entry points.
Browse the reference
Use this page for quick access to the main XQL reference sections.
Start here
Functions
Stages
Functions
XQL functions run inside stages and return a value.
Use this section to:
Functions overview
XQL functions run inside stages to transform, compare, and aggregate data.
They cover data manipulation, type conversion, string operations, math, arrays, JSON parsing, and more.
Functions list
The following table lists all available XQL functions:
| Function | Description |
|---|---|
acos |
Calculate the inverse cosine (arccosine) of a numerical expression |
add |
Calculate the sum of two numbers |
approx_count |
Return an approximate count of distinct values |
approx_quantiles |
Return approximate quantile boundaries |
approx_top |
Return the approximate top values |
asin |
Calculate the inverse sine (arcsine) of a numerical expression |
array_all |
Check if all elements in an array match a condition |
array_any |
Check if any element in an array matches a condition |
array_length |
Return the number of elements in an array |
arrayconcat |
Concatenate two arrays |
arraycreate |
Create an array from a list of values |
arraydistinct |
Return an array with duplicate values removed |
arrayfilter |
Filter elements of an array based on a condition |
arrayindex |
Return the element at a specified index in an array |
arrayindexof |
Return the index of a value in an array |
arraymap |
Apply a function to each element of an array |
arraymerge |
Merge multiple arrays into one |
arrayrange |
Create an array of sequential integers |
arraystring |
Convert an array to a string |
avg (with comp stage) |
Calculate the average value using the comp stage |
avg (with windowcomp stage) |
Calculate the average value using the windowcomp stage |
bitwise_and |
Perform a bitwise AND operation between two integer values |
bitwise_or |
Perform a bitwise OR operation between two integer values |
bitwise_sleft |
Perform a bitwise left shift operation on an integer value |
bitwise_sright |
Perform a bitwise right shift operation on an integer value |
bitwise_xor |
Perform a bitwise exclusive OR (XOR) operation between two integer values |
cbrt |
Calculate the cube root of a numeric value |
ceil |
Round a number up to the nearest integer |
coalesce |
Return the first non-null value from a list |
concat |
Concatenate two or more strings |
convert_from_base_64 |
Decode a Base64-encoded string |
convert_to_base_64 |
Encode a string to Base64 |
cos |
Calculate the cosine of a numeric value specified in radians |
cosine_distance |
Calculate the cosine distance between two numeric vectors |
cot |
Calculate the cotangent of a numeric value specified in radians |
count (with comp stage) |
Count values using the comp stage |
count (with windowcomp stage) |
Count values using the windowcomp stage |
count_distinct |
Count distinct values |
csc |
Calculate the cosecant of a numeric value specified in radians |
current_time |
Return the current timestamp |
date_floor |
Round a timestamp down to a specified time unit |
divide |
Divide one number by another |
earliest |
Return the earliest timestamp value |
euclidean_distance |
Calculate the Euclidean distance between two numeric vectors |
exp |
Calculate the value of e raised to the power of a numeric value |
extract_time |
Extract a time component from a timestamp |
extract_url_host |
Extract the host from a URL |
extract_url_pub_suffix |
Extract the public suffix from a URL |
extract_url_registered_domain |
Extract the registered domain from a URL |
first |
Return the first value in a group |
first_value |
Return the first value in a window |
floor |
Round a number down to the nearest integer |
format_string |
Format a string using a template |
format_timestamp |
Format a timestamp as a string |
greatest |
Return the largest value from a list of expressions |
hierarchy_match |
Check whether an asset belongs to an organizational hierarchy node |
if |
Return one of two values based on a condition |
incidr |
Check if an IPv4 address is within a CIDR range |
incidr6 |
Check if an IPv6 address is within a CIDR range |
incidrlist |
Check if an IP address is within a list of CIDR ranges |
int_to_ip |
Convert an integer to an IP address string |
ip_to_int |
Convert an IP address string to an integer |
is_ipv4 |
Check if a value is a valid IPv4 address |
is_ipv6 |
Check if a value is a valid IPv6 address |
is_known_private_ipv4 |
Check if an IPv4 address is a known private address |
is_known_private_ipv6 |
Check if an IPv6 address is a known private address |
json_extract |
Extract a value from a JSON string |
json_extract_array |
Extract an array from a JSON string |
json_extract_scalar |
Extract a scalar value from a JSON string |
json_extract_scalar_array |
Extract a scalar array from a JSON string |
json_path_extract |
Extract a value from a JSON string using a JSONPath expression |
json_functions_reference |
Decide which JSON functions to use |
lag |
Return the value of a field from a previous row in a window |
last |
Return the last value in a group |
last_value |
Return the last value in a window |
latest |
Return the latest timestamp value |
least |
Return the smallest value from a list of expressions |
len |
Return the length of a string or array |
list (with comp stage) |
Collect all values of a field and return them as an array within the comp stage |
ln |
Calculate the natural logarithm (base e) of a numeric value |
log |
Calculate the logarithm of a numeric value with a specified base |
log10 |
Calculate the base-10 logarithm of a numeric value |
lowercase |
Convert a string to lowercase |
ltrim |
Remove leading whitespace from a string |
max (with comp stage) |
Return the maximum value of a field within the comp stage |
max (with windowcomp stage) |
Compute the maximum value of a field over a window of rows within the windowcomp stage |
md5 |
Calculate the MD5 hash of a string |
median (with comp stage) |
Return the median value of a numeric field within the comp stage |
median (with windowcomp stage) |
Compute the median value of a numeric field over a window of rows within the windowcomp stage |
min (with comp stage) |
Return the minimum value of a field within the comp stage |
min (with windowcomp stage) |
Compute the minimum value of a field over a window of rows within the windowcomp stage |
mod |
Calculate the remainder (modulus) of the division of two numeric values |
multiply |
Multiply two numbers |
object_create |
Create a JSON object from key-value pairs |
object_merge |
Merge two JSON objects |
parse_epoch |
Parse an epoch timestamp |
parse_timestamp |
Parse a timestamp string |
pow |
Raise a number to a power |
power |
Raise a number to the power of another number (alias for pow) |
rand |
Generate a pseudo-random floating-point number between 0 and 1 |
range_bucket |
Determine which bucket a numeric value falls into given an array of boundaries |
rank (with windowcomp stage) |
Assign a rank to each row within a partition in the windowcomp stage |
regexcapture |
Extract substrings using a regular expression |
regextract |
Extract a substring from a field value using a regular expression pattern |
replace |
Replace occurrences of a substring |
replex |
Replace substrings using a regular expression |
round |
Round a number to a specified number of decimal places |
row_number (with windowcomp stage) |
Assign a unique sequential integer to each row within a partition in the windowcomp stage |
rtrim |
Remove trailing whitespace from a string |
safe_add |
Perform addition with overflow protection, returning null on overflow |
safe_divide |
Perform division with error protection, returning null on division by zero |
safe_multiply |
Perform multiplication with overflow protection, returning null on overflow |
safe_negate |
Negate a numeric value with overflow protection, returning null on overflow |
safe_subtract |
Perform subtraction with overflow protection, returning null on overflow |
sec |
Calculate the secant of a numeric value specified in radians |
sha1 |
Calculate the SHA-1 hash of a string |
sha256 |
Calculate the SHA-256 hash of a string |
sha512 |
Calculate the SHA-512 hash of a string |
sign |
Determine the sign of a numeric value (-1, 0, or 1) |
sin |
Calculate the sine of a numeric value specified in radians |
split |
Split a string into an array |
sqrt |
Calculate the square root of a numeric value |
stddev_population (with comp stage) |
Compute the population standard deviation of a numeric field within the comp stage |
stddev_population (with windowcomp stage) |
Compute the population standard deviation of a numeric field over a window of rows within the windowcomp stage |
stddev_sample (with comp stage) |
Compute the sample standard deviation of a numeric field within the comp stage |
stddev_sample (with windowcomp stage) |
Compute the sample standard deviation of a numeric field over a window of rows within the windowcomp stage |
string_count |
Count occurrences of a substring in a string |
subtract |
Subtract one number from another |
sum (with comp stage) |
Compute the sum of a numeric field within the comp stage |
sum (with windowcomp stage) |
Compute the sum of a numeric field over a window of rows within the windowcomp stage |
tan |
Calculate the tangent of a numeric value specified in radians |
time_frame_end |
Return the end of a time frame |
timestamp_diff |
Calculate the difference between two timestamps |
timestamp_seconds |
Convert a timestamp to seconds |
to_boolean |
Convert a value to a boolean |
to_epoch |
Convert a timestamp to an epoch value |
to_float |
Convert a value to a float |
to_integer |
Convert a value to an integer |
to_json_string |
Convert a value to a JSON string |
to_number |
Convert a value to a number |
to_string |
Convert a value to a string |
to_timestamp |
Convert a value to a timestamp |
trim |
Remove leading and trailing whitespace from a string |
trunc |
Truncate a numeric value to a specified number of decimal places |
uppercase |
Convert a string to uppercase |
values |
Collect all distinct values of a field and return them as an array within the comp stage |
var |
Compute the variance of a numeric field within the comp stage |
wildcard_match |
Check if a string matches a wildcard pattern |
acos
Use the acos() function to calculate the principal value of the inverse cosine (arccosine) of a numerical expression.
Syntax
acos(<numeric_expression>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
numeric_expression |
integer, float | Yes | The numerical value for which to calculate the arccosine. The value must be within the range of -1 to 1 (inclusive). |
Returns
Type: float
Description: The acos() function returns the principal value of the arccosine of the input in radians. The resulting value is within the range [0, π].
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The input
numeric_expressionmust fall within the closed interval [-1, 1]. - Out of Range Behavior: If the input is outside the range of -1 to 1, the function returns
NaN(Not a Number) ornull. - Null Handling: If the input expression is
null, the function returnsnull. - Radians to Degrees: The result is provided in radians. To convert the result to degrees, multiply the return value by
180 / PI(). - Common Use Cases: This function is typically utilized in the
alterstage for geometric calculations, spatial analysis, or normalizing data vectors.
Examples
Example 1: Calculate arccosine of a literal value
Goal: Calculate the inverse cosine for specific numerical literals to see the radian results.
XQL Code:
dataset = xdr_data | limit 1 | alter result1 = acos(1), result2 = acos(-1), result3 = acos(0) | fields result1, result2, result3
Explanation: You use acos() on three different literal values. The function calculates the principal value of the inverse cosine for each. The results are in radians.
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 0.0 | 3.14159... | 1.5708... |
Example 2: Calculate arccosine from a field value
Goal: Calculate the arccosine of values stored in a specific field, ensuring they are within the valid mathematical range.
XQL Code:
dataset = sample_xql_raw | filter duration_seconds >= -1 and duration_seconds <= 1 | alter arc_cos_val = acos(duration_seconds) | fields event_id, duration_seconds, arc_cos_val | limit 3
Explanation: This query first filters the dataset to ensure duration_seconds contains only values between -1 and 1, then computes the arccosine for each and stores it in arc_cos_val.
Related Articles
add
Use the add() function to calculate the sum of two numbers.
Syntax
add (<value_1>, <value_2>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
value_1 |
integer, float, string | Yes | The first numeric value or field. |
value_2 |
integer, float, string | Yes | The second numeric value or field. |
Returns
The add() function returns the mathematical sum of the two input parameters.
Usage notes
- The function operates on numbers, supporting integer literals and floating-point numbers.
- The function also accepts field values that represent numbers, even if those values are stored as a string data type (for example, an integer stored as text).
- The function is typically used within the
alterstage to create or modify fields based on calculated values.
Examples
Example 1: Adding an integer field and a literal integer
Goal: Add a fixed numerical value to an existing integer field (event_id) to create a new calculated field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_event_id = add(event_id, 100) // Adds 100 to the 'event_id' field | fields event_id, new_event_id | limit 3
Explanation: This query adds 100 to the event_id of each record, storing the result in a new field called new_event_id. For event_id 101, new_event_id becomes 201.
Output:
| event_id | new_event_id |
|---|---|
| 101 | 201 |
| 102 | 202 |
| 103 | 203 |
Example 2: Adding two integer literal values
Goal: Perform addition directly on two static integer values to create a constant new field for each record.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter sum_of_literals = add(500, 25) // Adds two literal integer values | fields event_id, sum_of_literals | limit 3
Explanation: This query adds the literal integers 500 and 25, producing a constant sum_of_literals value of 525 for each record.
Output:
| event_id | sum_of_literals |
|---|---|
| 101 | 525 |
| 102 | 525 |
| 103 | 525 |
Example 3: Adding a floating-point field and a literal float
Goal: Operate on a floating-point number field and a literal floating-point value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter increased_duration = add(duration_seconds, 0.5) // Adds 0.5 to 'duration_seconds' | fields event_id, duration_seconds, increased_duration | limit 3
Explanation: The duration_seconds field (a float) is increased by 0.5 for each record. For event_id 101 (duration 1.5), increased_duration becomes 2.0.
Output:
| event_id | duration_seconds | increased_duration |
|---|---|---|
| 101 | 1.5 | 2.0 |
| 102 | 0.8 | 1.3 |
| 103 | 10.2 | 10.7 |
Example 4: Adding an integer field and a negative literal
Goal: Handle a negative literal to effectively perform subtraction.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter adjusted_id = add(event_id, -10) // Subtracts 10 from 'event_id' | fields event_id, adjusted_id | limit 3
Explanation: This query subtracts 10 from the event_id of each record. For event_id 101, adjusted_id becomes 91.
Output:
| event_id | adjusted_id |
|---|---|
| 101 | 91 |
| 102 | 92 |
| 103 | 93 |
Example 5: Adding a number extracted as string and a literal
Goal: Use add() with a numeric value extracted from a JSON string field, which is first converted to a number.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter status_code_str = simple_json_data -> code // Extract 'code' as string | alter status_code_num = to_number(status_code_str) // Convert string to number | alter new_code_value = add(status_code_num, 50) // Add 50 to the numeric code | fields event_id, simple_json_data, new_code_value | limit 3
Explanation: For event_id 101, the code "200" is extracted as a string, converted to a number, and then 50 is added, resulting in new_code_value of 250. For event_id 102, $.code is NULL, so new_code_value will also be NULL.
Output:
| event_id | simple_json_data | new_code_value |
|---|---|---|
| 101 | "{"status": "ok", "code": 200} " | 250 |
| 102 | "{"status": "fail", "error": "access_denied"} " | NULL |
| 103 | "{"connection_id": "CONN-001", "protocol": "TCP"} " | NULL |
Example 6: Adding an element from an array field and a literal
Goal: Access an element from an array field and add a literal integer to it.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_numeric_code = arrayindex(numeric_codes, 0) // Get the first element of the array | alter increased_first_code = add(first_numeric_code, 10) // Add 10 to the first element | fields event_id, numeric_codes, increased_first_code | limit 3
Explanation: For event_id 101, the first element of numeric_codes (13) is extracted, and 10 is added to it, resulting in increased_first_code of 23.
Output:
| event_id | numeric_codes | increased_first_code |
|---|---|---|
| 101 | "[13, -47, 29, 82, -15] " | 23 |
| 102 | "[-21, 56, 13, -88, 42] " | -11 |
| 103 | "[90, -33, 7, 51, -62, 18] " | 100 |
Related articles
approx_count
Use the approx_count() function to calculate an approximate count of distinct values in a specified field.
Syntax
approx_count(<field>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
string | Yes | The name of the field for which you want to count distinct values. |
Returns
The approx_count() function returns a single approximate integer value representing the number of distinct values found in the specified field.
Usage notes
- The
approx_count()function is an approximate aggregate function. The function is designed to be more scalable in terms of memory usage and processing time compared to exact aggregate functions likecount_distinct(), especially for large datasets. - This function must be used with the
compstage. - You can use the
byclause in thecompstage to partition the data into groups, allowingapprox_count()to compute the approximate distinct count independently for each group. - You can use the
addrawdata = trueoption in thecompstage to include a column listing the raw data events that contributed to the aggregate result.
Examples
Example 1: Calculate approximate distinct count across the entire dataset
Goal: Calculate the approximate number of unique event_description values for all records in the dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp approx_count(event_description) as unique_event_descriptions
Explanation: This query computes the approximate number of unique event_description values present in the sample_xql_raw dataset and names the resulting field unique_event_descriptions.
Output:
| unique_event_descriptions |
|---|
| 10 |
Example 2: Calculate approximate distinct count grouped by another field
Goal: Calculate the approximate number of unique dst_domain values separately for successful and unsuccessful events.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp approx_count(dst_domain) as unique_domains_by_status by is_successful
Explanation: The query groups records by their is_successful status and then calculates the approximate number of unique dst_domain values for each group, presenting the counts in the unique_domains_by_status field.
Output:
| is_successful | unique_domains_by_status |
|---|---|
| true | 7 |
| false | 3 |
Example 3: Calculate approximate distinct count with raw data inclusion
Goal: Calculate the approximate distinct count of event_description grouped by is_successful and include the raw events that contributed to the calculation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp approx_count(event_description) as unique_descriptions_by_status by is_successful addrawdata = true as raw_events_for_distinct_count
Explanation: This query calculates the approximate distinct count of event_description grouped by is_successful. Additionally, addrawdata = true generates a new column named raw_events_for_distinct_count, which contains a JSON representation of the raw events that contributed to each computed approximate distinct count.
Output:
| is_successful | unique_descriptions_by_status | raw_events_for_distinct_count |
|---|---|---|
| true | 7 | [{"event_id": 101, "event_description": "User login successful", ...}, {"event_id": 103, "event_description": "Network connection established", ...}, ...] |
| false | 3 | [{"event_id": 102, "event_description": "File access attempt", ...}, {"event_id": 106, "event_description": "Unauthorized access detected", ...}, ...] |
Related articles
- Stages:
comp,config,limit - Functions:
approx_quantiles,approx_top,count_distinct
approx_quantiles
Use the approx_quantiles() function to calculate and return approximate boundaries for a specified field, producing an array of values that define the quantiles.
Syntax
approx_quantiles(<field>, <number>, <distinct>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
string, integer, float | Yes | The name of the field for which to calculate approximate quantiles. |
number |
integer | Yes | An integer specifying the number of quantiles to compute. The output array will contain <number> + 1 elements. |
distinct |
boolean | No | Determines whether to consider only distinct values (true) or all values (false). If omitted, the default is false. |
Returns
The approx_quantiles() function returns a single array containing <number> + 1 approximate values representing the boundaries of the quantiles. The first element represents the approximate minimum, and the last element represents the approximate maximum.
Usage notes
- The
approx_quantiles()function is an approximate aggregate function designed to produce approximate results, instead of exact results used with regular aggregate functions, which is more scalable in terms of memory usage and time. - This function must always be used with the
compstage. - You can use the
byclause withcompto calculate quantiles independently for different groups. - You can use the
addrawdata = trueoption to include a column listing the raw data events that contributed to the calculation. When you include raw data events, the query runs for up to 50 fields that you define and displays up to 100 events.
Examples
Example 1: Calculate approximate quantiles across the entire dataset
Goal: Calculate 3 approximate quantiles (4 boundaries) for the duration_seconds field across all records, considering all values (non-distinct).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp approx_quantiles(duration_seconds, 3) as approx_duration_quantiles
Explanation: This query calculates 3 quantiles for the duration_seconds field. The output is an array containing the approximate minimum, the 25th percentile, the 50th percentile (median), the 75th percentile, and the approximate maximum.
Output:
| approx_duration_quantiles |
|---|
| [0.05, 1.0, 3.55, 9.0, 60.0] |
Example 2: Calculate approximate quantiles grouped by field
Goal: Calculate 2 approximate quantiles (3 boundaries: min, median, max) for duration_seconds, grouped by the is_successful status.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp approx_quantiles(duration_seconds, 2) as approx_duration_quantiles by is_successful
Explanation: The query groups records by is_successful and calculates the approximate boundaries (min, median, max) of the duration_seconds values for each group.
Output:
| is_successful | approx_duration_quantiles |
|---|---|
| true | [0.1, 7.8, 60.0] |
| false | [0.05, 0.8, 2.1] |
Example 3: Calculate approximate quantiles for distinct values
Goal: Calculate 1 approximate quantile (2 boundaries: min, max) for event_description, considering only distinct values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp approx_quantiles(event_description, 1, true) as approx_event_description_range
Explanation: This query sets the third parameter to true, instructing the function to consider only unique event_description values. The query finds the alphabetically first and last descriptions.
Output:
| approx_event_description_range |
|---|
| ["API request throttled", "User login successful"] |
Related articles
- Stages:
comp,config,limit - Functions:
approx_count,approx_top
approx_top
Use the approx_top() function to return the most frequently occurring elements or highest-sum elements for a specified field. This approximate aggregate function produces results that are highly scalable in terms of memory usage and time compared to exact results from regular aggregate functions.
Syntax
comp approx_top(<string field>, <number>) [as <alias>[] [by <field1>[,<field2>...[][] [addrawdata = true|false [as <target field>[][]
comp approx_top(<string field>, <number>, <weight string field>) [as <alias>[] [by <field1>[,<field2>...[][][addrawdata = true|false [as <target field>[][]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| string field | string | Yes | The field for which to find the top elements. |
| number | integer | No | An integer specifying the number of top elements to return. If omitted, it defaults to up to 10 elements. |
| weight string field | numeric | No | A numeric field used to calculate the sum for each unique value in the first specified field, causing the function to return approximate sums instead of counts. |
Returns
The approx_top() function returns a single array containing up to the specified number of JSON objects (structs). For the count variant, each struct will have "value" (the unique field value) and "count" (its approximate number of occurrences) keys. For the sum variant, each struct will have "value" and "sum" keys, representing the approximate sum calculated using the weight string field.
Usage Notes
- The comp stage must always precede an approximate aggregate function like approx_top().
- You can use the optional
byclause to group rows based on one or more specified fields, which allows approx_top() to compute the approximate top elements independently for each group. - When you set the optional addrawdata parameter to true, the query processes up to 50 defined fields and includes a raw_data column displaying up to 100 raw data events that contributed to the aggregate result.
- New columns created by the comp stage are typically added as the last columns in the result set, and any other fields not explicitly included in the
byclause or as part of a calculated column is removed from the result set, including the _time system field.
Examples
Example 1: Calculating approximate top counts (no weight field)
Goal: Calculate the top 2 approximate counts of is_successful statuses across the entire dataset.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp approx_top(is_successful, 2) as top_successful_statuses
Explanation: The code identifies the top 2 most frequent values in the is_successful field. The result is an array of JSON objects, each with a "value" and a "count".
Output:
| top_successful_statuses |
|---|
| [{"value": true, "count": 7}, {"value": false, "count": 3}[] |
Example 2: Calculating approximate top sums (with weight field)
Goal: Calculate the top 2 dst_domain values by the sum of their duration_seconds across the entire dataset.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp approx_top(dst_domain, 2, duration_seconds) as top_domains_by_duration_sum
Explanation: The code computes the sum of duration_seconds for each unique dst_domain and then returns the top 2 dst_domain values based on these sums.
Output:
| top_domains_by_duration_sum |
|---|
| [{"value": "www.mongodb.com", "sum": 60.0}, {"value": "downloads.teamviewer.com", "sum": 15.3}[] |
Example 3: Calculating approximate top sums grouped by another field
Goal: Calculate the top 1 dst_domain by the sum of duration_seconds separately for is_successful = true and is_successful = false events.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp approx_top(dst_domain, 1, duration_seconds) as top_domain_durations_by_status by is_successful
Explanation: Groups records by their is_successful status and calculates the single dst_domain with the highest sum of duration_seconds for each group.
Output:
| is_successful | top_domain_durations_by_status |
|---|---|
| true | [{"value": "www.mongodb.com", "sum": 60.0}[] |
| false | [{"value": "sharepoint.microsoft.com", "sum": 2.1}[] |
Example 4: Calculating approximate top counts with raw data inclusion
Goal: Include the raw events that contribute to the approximate top count calculation by using the addrawdata = true option.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp approx_top(is_successful, 1) addrawdata = true as raw_data_for_top_is_successful
Explanation: The code computes the top 1 most frequent is_successful value and automatically generates a new column named raw_data_for_top_is_successful containing a JSON representation of the raw events that contributed to this result.
Output:
| top_successful_statuses | raw_data_for_top_is_successful |
|---|---|
| [{"value": true, "count": 7}[] | [{"event_id": 101, "is_successful": true, ...}, {"event_id": 103, "is_successful": true, ...}, ...[] (up to 100 events) |
Related Articles**
- Stages: comp, alter, config, timeframe
- Functions: approx_count, approx_quantiles
array_all
Use the array_all() function to determine if all elements within a specified array satisfy a defined boolean condition.
Syntax
array_all (<array>, "@element"<operator>"<array_element>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array |
array | Yes | The array field to evaluate. |
@element |
keyword | Yes | A special keyword representing each individual element within the array during evaluation. |
operator |
string | Yes | Any supported XQL comparison operator (for example, =, !=, >, <, >=, <=). |
array_element |
string, integer, float, boolean | Yes | The value or condition against which each array element is compared. |
Returns
The array_all() function returns a boolean value (true or false). The function returns true only if every single element in the array meets the condition; otherwise, the function returns false.
Usage notes
- The function implements a strict "AND" operation across all elements. If even one element fails the condition, the entire function returns
false. - The
array_all()function will returnfalseif run against an empty array. - The function is typically used within the
alterorfilterstages for data transformation or narrowing down results.
Examples
Example 1: Checking if all string tags are a specific value
Goal: Verify if every tag in the string_tags array is exactly "security".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter all_tags_are_security = array_all(string_tags, "@element" = "security") | fields event_id, string_tags, all_tags_are_security | limit 5
Explanation: For event_id 101, the array ["security", "login"] returns false because "login" is not "security". For event_id 104, [] (an empty array) returns false.
Output:
| EVENT_ID | STRING_TAGS | ALL_TAGS_ARE_SECURITY |
|---|---|---|
| 101 | ["security", "login"] | false |
| 102 | ["filesystem", "critical"] | false |
| 103 | ["network", "cloud"] | false |
| 104 | [] | false |
| 105 | ["data_ops"] | false |
Example 2: Checking if all numeric codes are greater than zero
Goal: Evaluate if every number in the numeric_codes array is greater than zero.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter all_codes_positive = array_all(numeric_codes, "@element" > 0) | fields event_id, numeric_codes, all_codes_positive | limit 5
Explanation: For event_id 101, the array [13, -47, 29, 82, -15] returns false because elements like -47 and -15 are not greater than zero. For event_id 104, [] (an empty array) returns false.
Output:
| EVENT_ID | NUMERIC_CODES | ALL_CODES_POSITIVE |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | false |
| 102 | [-21, 56, 13, -88, 42] | false |
| 103 | [90, -33, 7, 51, -62, 18] | false |
| 104 | [] | false |
| 105 | [77, -9, 35, -47, 61] | false |
Example 3: Checking if all string tags are NOT a specific value
Goal: Check if all tags in string_tags are not equal to "security" using the != operator.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter none_are_security = array_all(string_tags, "@element" != "security") | fields event_id, string_tags, none_are_security | limit 5
Explanation: For event_id 101, the array ["security", "login"] returns false because "security" is present in the array, failing the "not equal to security" condition. For event_id 102, the array ["filesystem", "critical"] returns true because neither "filesystem" nor "critical" are equal to "security".
Output:
| EVENT_ID | STRING_TAGS | NONE_ARE_SECURITY |
|---|---|---|
| 101 | ["security", "login"] | false |
| 102 | ["filesystem", "critical"] | true |
| 103 | ["network", "cloud"] | true |
| 104 | [] | false |
| 105 | ["data_ops"] | true |
Related articles
array_any
Use the array_any() function to determine if at least one element within a specified array satisfies a defined boolean condition. If at least one element meets the condition, the function returns true.
Syntax
array_any (<array>, "@element"<operator>"<array_element>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array |
array | Yes | The array field to be evaluated. |
condition |
string | Yes | A comparison expression enclosed in quotes. The condition must use the special keyword @element to represent the individual item being checked, followed by an operator and the value to compare against. |
Returns
The array_any() function returns a boolean value (true or false).
Usage notes
- The function iterates through the array and applies the condition to each element individually.
- The function implements a logical "OR" operation across the elements. If any single element satisfies the condition, the function returns
true. - If the input array is empty, the function returns
false. - Supported operators within the condition include standard comparison operators such as
=,!=,>,<,>=, and<=. - This function is typically used within the
alterorfilterstages to categorize data or narrow down results based on array contents.
Examples
Example 1: Check for specific string value
Goal: Check if the string_tags array contains the specific value "security".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter any_tag_is_security = array_any(string_tags, "@element" = "security") | fields event_id, string_tags, any_tag_is_security | limit 6
Explanation: The query evaluates the string_tags array for each event. If the string "security" is present as any element in the array, any_tag_is_security is set to true.
Output:
| EVENT_ID | STRING_TAGS | ANY_TAG_IS_SECURITY |
|---|---|---|
| 101 | ["security", "login"] | true |
| 102 | ["filesystem", "critical"] | false |
| 103 | ["network", "cloud"] | false |
| 104 | [] | false |
| 105 | ["data_ops"] | false |
| 106 | ["security", "attack"] | true |
Example 2: Check numeric threshold
Goal: Determine if any number within the numeric_codes array is greater than 50.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter any_code_gt_50 = array_any(numeric_codes, "@element" > 50) | fields event_id, numeric_codes, any_code_gt_50 | limit 5
Explanation: The query checks the numeric_codes array. If at least one number in the array is greater than 50, the result is true. Empty arrays return false.
Output:
| EVENT_ID | NUMERIC_CODES | ANY_CODE_GT_50 |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | true |
| 102 | [-21, 56, 13, -88, 42] | true |
| 103 | [90, -33, 7, 51, -62, 18] | true |
| 104 | [] | false |
| 105 | [77, -9, 35, -47, 61] | true |
Example 3: Check inequality
Goal: Determine if at least one tag in the string_tags array is not equal to "security".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter any_tag_is_not_security = array_any(string_tags, "@element" != "security") | fields event_id, string_tags, any_tag_is_not_security | limit 6
Explanation: The query returns true if it finds any element in the array that is not "security". For example, in event 101, even though "security" is present, the presence of "login" (which is != "security") makes the result true.
Output:
| EVENT_ID | STRING_TAGS | ANY_TAG_IS_NOT_SECURITY |
|---|---|---|
| 101 | ["security", "login"] | true |
| 102 | ["filesystem", "critical"] | true |
| 103 | ["network", "cloud"] | true |
| 104 | [] | false |
| 105 | ["data_ops"] | true |
| 106 | ["security", "attack"] | true |
Related articles
- Stages:
alter,filter - Functions:
array_all,arrayfilter - Datasets:
xdr_data
array_length
Use the array_length() function to return the number of elements in an array.
Syntax
array_length (<array>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array |
array | Yes | The array field you want to evaluate. |
Returns
The array_length() function returns an integer representing the count of elements in the specified array.
Usage notes
- If the input array is empty, the function returns
0. - The function provides a direct count of how many items are present within an array field.
- This function is typically used within the
alterstage to create new fields or modify existing ones by calculating array sizes. - The function can also be used in
filterstages to narrow down results based on string length.
Examples
Example 1: Calculating the length of a string array
Goal: Determine the number of string elements in an array field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter num_string_tags = array_length(string_tags) | fields event_id, string_tags, num_string_tags | limit 4
Explanation: For event_id 101, 102, and 103, string_tags contains two elements, so num_string_tags is 2. For event_id 104, string_tags contains one element, so num_string_tags is 1.
Output:
| EVENT_ID | STRING_TAGS | NUM_STRING_TAGS |
|---|---|---|
| 101 | ["security", "login"] | 2 |
| 102 | ["filesystem", "critical"] | 2 |
| 103 | ["network", "cloud"] | 2 |
| 104 | ["monitoring"] | 1 |
Example 2: Calculating the length of a numeric array
Goal: Determine the number of numeric elements in an array field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter num_numeric_codes = array_length(numeric_codes) | fields event_id, numeric_codes, num_numeric_codes | limit 6
Explanation: For event_id 101, 102, and 105, numeric_codes contains five elements. For event_id 103 and 106, numeric_codes contains six elements. For event_id 104, numeric_codes is an empty array, so num_numeric_codes is 0.
Output:
| EVENT_ID | NUMERIC_CODES | NUM_NUMERIC_CODES |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | 5 |
| 102 | [-21, 56, 13, -88, 42] | 5 |
| 103 | [90, -33, 7, 51, -62, 18] | 6 |
| 104 | [] | 0 |
| 105 | [77, -9, 35, -47, 61] | 5 |
| 106 | [-12, 24, 68, -59, 37, 80] | 6 |
Example 3: Calculating the length of an array of JSON objects
Goal: Determine the number of JSON objects contained within an array field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter num_json_objects = array_length(array_of_json_objects) | fields event_id, array_of_json_objects, num_json_objects | limit 4
Explanation: For event_id 101 and 103, array_of_json_objects contains two elements. For event_id 102, array_of_json_objects contains one element. For event_id 104, array_of_json_objects is an empty array, so num_json_objects is 0.
Output:
| EVENT_ID | ARRAY_OF_JSON_OBJECTS | NUM_JSON_OBJECTS |
|---|---|---|
| 101 | [{"action": "read", "file": "doc1.txt"}, {"action": "write", "file": "report.log"}] | 2 |
| 102 | [{"event": "file_open", "path": "/etc/passwd"}] | 1 |
| 103 | [{"conn_type": "outbound", "bytes": 1024}, {"conn_type": "inbound", "bytes": 512}] | 2 |
| 104 | [] | 0 |
Example 4: Using array_length() in a filter to check for non-empty arrays
Goal: Filter events to include only those where a specific array field is not empty.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter tags_count = array_length(string_tags) | filter tags_count > 0 | fields event_id, string_tags, tags_count | limit 5
Explanation: This query returns all events where the string_tags array has at least one element. No events with an empty string_tags array are present in this filtered result set.
Output:
| EVENT_ID | STRING_TAGS | TAGS_COUNT |
|---|---|---|
| 101 | ["security", "login"] | 2 |
| 102 | ["filesystem", "critical"] | 2 |
| 103 | ["network", "cloud"] | 2 |
| 104 | ["monitoring"] | 1 |
| 105 | ["data_ops"] | 1 |
Example 5: Using array_length() in a filter to check for a specific array size
Goal: Filter events to include only those where an array field contains a precise number of elements.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter codes_count = array_length(numeric_codes) | filter codes_count = 5 | fields event_id, numeric_codes, codes_count | limit 5
Explanation: Only events with exactly five elements in their numeric_codes array are returned, such as event_id 101, 102, and 105. Events like 103 (length 6) or 104 (length 0) are excluded by the filter.
Output:
| EVENT_ID | NUMERIC_CODES | CODES_COUNT |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | 5 |
| 102 | [-21, 56, 13, -88, 42] | 5 |
| 105 | [77, -9, 35, -47, 61] | 5 |
Related articles
arrayconcat
Use the arrayconcat() function to combine the elements of two or more specified arrays into a single, new array.
Syntax
arrayconcat (<array1>, <array2>[, <array3>...])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array1 |
array | Yes | The first array field whose elements will be combined. |
array2 |
array | Yes | The second array field whose elements will be combined. |
array3... |
array | No | Additional array fields to be combined. |
Returns
The arrayconcat() function returns a single, new array that contains all elements from the input arrays.
Usage notes
- All the elements within the input array fields must be of the same data type.
- The function joins the input arrays sequentially. The elements from
array1come first, followed by elements fromarray2, and so on, preserving their original order within each array. arrayconcat()simply joins the elements and does not inherently remove duplicate values. If you need a result array with only unique elements, apply thearraydistinct()function afterarrayconcat().- This function is typically employed within the
alterstage to create new fields or modify existing ones by combining array data.
Examples
Example 1: Concatenating two newly created arrays
Goal: Define two new arrays using arraycreate() and then concatenate them to form a single combined array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_part = arraycreate("componentA", "statusX") // Creates a new array | alter second_part = arraycreate("typeB", "severityY") // Creates another new array | alter combined_info = arrayconcat(first_part, second_part) // Concatenates the two new arrays | fields event_id, first_part, second_part, combined_info | limit 2
Explanation: For each record, two literal arrays, first_part and second_part, are created. The function then combines the elements of first_part followed by second_part into the combined_info array.
Output:
| EVENT_ID | FIRST_PART | SECOND_PART | COMBINED_INFO |
|---|---|---|---|
| 101 | ["componentA", "statusX"] | ["typeB", "severityY"] | ["componentA", "statusX", "typeB", "severityY"] |
| 102 | ["componentA", "statusX"] | ["typeB", "severityY"] | ["componentA", "statusX", "typeB", "severityY"] |
Example 2: Concatenating an existing array field with a newly created array
Goal: Combine the string_tags array field from the dataset with a new array created using arraycreate().
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_event_tags = arraycreate("audit", "compliance") // Creates a new array of tags | alter extended_string_tags = arrayconcat(string_tags, new_event_tags) // Concatenates existing string_tags with the new tags | fields event_id, string_tags, new_event_tags, extended_string_tags | limit 3
Explanation: For each event, new_event_tags is created. The existing string_tags are then concatenated with the elements from new_event_tags to form extended_string_tags. For example, event_id 101's tags are expanded to include "audit" and "compliance".
Output:
| EVENT_ID | STRING_TAGS | NEW_EVENT_TAGS | EXTENDED_STRING_TAGS |
|---|---|---|---|
| 101 | ["security", "login"] | ["audit", "compliance"] | ["security", "login", "audit", "compliance"] |
| 102 | ["filesystem", "critical"] | ["audit", "compliance"] | ["filesystem", "critical", "audit", "compliance"] |
| 103 | ["network", "cloud"] | ["audit", "compliance"] | ["network", "cloud", "audit", "compliance"] |
Example 3: Concatenating multiple derived arrays
Goal: Combine portions of the numeric_codes array using arrayrange() and a newly created array, demonstrating concatenation with more than two inputs.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_two_codes = arrayrange(numeric_codes, 0, 2) // Extracts elements at index 0 and 1 | alter next_two_codes = arrayrange(numeric_codes, 2, 4) // Extracts elements at index 2 and 3 | alter additional_codes = arraycreate(999, 1000) // Creates an array with two new numbers | alter all_combined_codes = arrayconcat(first_two_codes, next_two_codes, additional_codes) // Concatenates three arrays | fields event_id, numeric_codes, first_two_codes, next_two_codes, additional_codes, all_combined_codes | limit 3
Explanation: arrayrange() extracts specific slices (sub-arrays) from the numeric_codes array. arraycreate() is used to define an additional array. The function then takes these two derived arrays and the additional_codes array, joining all their elements into all_combined_codes.
Output:
| EVENT_ID | NUMERIC_CODES | FIRST_TWO_CODES | NEXT_TWO_CODES | ADDITIONAL_CODES | ALL_COMBINED_CODES |
|---|---|---|---|---|---|
| 101 | [13, -47, 29, 82, -15] | [13, -47] | [29, 82] | [999, 1000] | [13, -47, 29, 82, 999, 1000] |
| 102 | [-21, 56, 13, -88, 42] | [-21, 56] | [13, -88] | [999, 1000] | [-21, 56, 13, -88, 999, 1000] |
| 103 | [90, -33, 7, 51, -62, 18] | [90, -33] | [7, 51] | [999, 1000] | [90, -33, 7, 51, 999, 1000] |
Related articles
- Stages:
alter,config,fields,limit - Functions:
arraycreate,arraydistinct,arrayrange
arraycreate
Use the arraycreate() function to return a new array based on the given parameters defined for its elements.
Syntax
arraycreate ("<array_element1>", "<array_element2>",...)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
<array_element> |
string, integer, float, boolean | Yes | The values to include as elements in the new array. Must be enclosed in quotes if they are string literals. |
Returns
The arraycreate() function returns a single, new array containing the specified elements.
Usage notes
- All elements within the array created by
arraycreate()must be of the same data type. - The function returns the data types exactly as entered and doesn't implicitly convert string representations of numeric or boolean values. For example,
"123"remains a string"123"within the array, and isn't converted to a number. - If all elements are
NULL, the output is an empty array with no elements.
Examples
Example 1: Creating an array of string literals
Goal: Define a new array containing only direct string values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter custom_tags = arraycreate("alert", "investigation_needed") | fields event_id, custom_tags | limit 3
Explanation: For each record in sample_xql_raw, a new field named custom_tags is created. This field contains an array with two string elements: "alert" and "investigation_needed".
Output:
| EVENT_ID | CUSTOM_TAGS |
|---|---|
| 101 | ["alert", "investigation_needed"] |
| 102 | ["alert", "investigation_needed"] |
| 103 | ["alert", "investigation_needed"] |
Example 2: Creating an array with literals representing different data types (as strings)
Goal: Handle different types of literal values, specifically strings, numbers, and booleans, by treating them as string parameters.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter mixed_info = arraycreate("version_1.0", "123", "true", "45.67") | fields event_id, mixed_info | limit 3
Explanation: A mixed_info array is generated for each record. The query demonstrates that arraycreate() can incorporate various literal values into a single array, with all elements being treated as strings, adhering to the rule that all elements must be of the same data type.
Output:
| EVENT_ID | MIXED_INFO |
|---|---|
| 101 | ["version_1.0", "123", "true", "45.67"] |
| 102 | ["version_1.0", "123", "true", "45.67"] |
| 103 | ["version_1.0", "123", "true", "45.67"] |
Example 3: Creating an array by combining literals with existing field values
Goal: Dynamically build an array by including both static literal values and values from existing fields in each record.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_summary = arraycreate(to_string(event_id), event_description, to_string(is_successful)) | fields event_id, event_description, is_successful, event_summary | limit 3
Explanation: The to_string() function is used to convert the event_id (numeric) and is_successful (boolean) fields into strings, allowing them to be combined with the event_description (string) into a new array called event_summary. Each row will have a unique event_summary array reflecting its own event_id, event_description, and is_successful status.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL | EVENT_SUMMARY |
|---|---|---|---|
| 101 | "User login successful" | true | ["101", "User login successful", "true"] |
| 102 | "File access attempt" | false | ["102", "File access attempt", "false"] |
| 103 | "Network connection established" | true | ["103", "Network connection established", "true"] |
Example 4: Creating an array with derived values from JSON extraction
Goal: Incorporate values that are the result of other XQL functions, specifically json_extract_scalar() for extracting data from JSON fields.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter status_code = json_extract_scalar(simple_json_data, "$.code") | alter user_name = json_extract_scalar(nested_json_data, "$.user.name") | alter extracted_details = arraycreate(status_code, user_name) | fields event_id, simple_json_data, nested_json_data, extracted_details | limit 3
Explanation: status_code is created by extracting the code field from simple_json_data. user_name is created by extracting the user.name field from nested_json_data. extracted_details then combines these two (potentially NULL) string values into a new array. If all the input elements are NULL, then the output is an empty array.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | NESTED_JSON_DATA | EXTRACTED_DETAILS |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | {"user": {"id": "U1", "name": "Alice"}, ...} | ["200", "Alice"] |
| 102 | {"status": "fail", "error": "access_denied"} | {"process": {"name": "cmd.exe", "pid": 1234}, ...} | [] |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | {"source": {"ip": "172.16.0.1", "port": 5000}, ...} | [] |
Related articles
- Stages:
alter - Functions:
arrayconcat,to_string,json_extract_scalar - Datasets:
xdr_data
arraydistinct
Use the arraydistinct() function to return a new array containing only the unique values found in the original input array.
Syntax
arraydistinc (<array>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array |
array | Yes | The array field from which to extract unique elements. |
Returns
The arraydistinct() function returns a new array, where all elements are unique.
Usage notes
- Only one instance of each value is retained in the resulting array.
- The function operates on elements as they are typed. For example, if "100" (string) and 100 (number) were distinct elements in the input array, they would be considered distinct in the output.
- If the input array is empty,
arraydistinct()will return an empty array.
Examples
Example 1: Removing duplicate string literals from a newly created array
Goal: Create an array with intentional string duplicates and then process it to retain only unique string values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter raw_array_with_duplicates = arraycreate("alert", "security", "alert", "investigation_needed", "security") | alter distinct_tags = arraydistinct(raw_array_with_duplicates) | fields event_id, raw_array_with_duplicates, distinct_tags | limit 3
Explanation: A new field raw_array_with_duplicates is created for each record using arraycreate(), containing repeated string values "alert" and "security". arraydistinct() is then applied to produce distinct_tags, which contains only the unique string values.
Output:
| EVENT_ID | RAW_ARRAY_WITH_DUPLICATES | DISTINCT_TAGS |
|---|---|---|
| 101 | ["alert", "security", "alert", "investigation_needed", "security"] | ["alert", "security", "investigation_needed"] |
| 102 | ["alert", "security", "alert", "investigation_needed", "security"] | ["alert", "security", "investigation_needed"] |
| 103 | ["alert", "security", "alert", "investigation_needed", "security"] | ["alert", "security", "investigation_needed"] |
Example 2: Removing duplicate numeric literals from a newly created array
Goal: Process an array composed of numeric literals, including duplicates, and yield an array with only unique numeric values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter raw_numbers_with_duplicates = arraycreate(100, 50, 100, 50, 25, 100) | alter distinct_numbers = arraydistinct(raw_numbers_with_duplicates) | fields event_id, raw_numbers_with_duplicates, distinct_numbers | limit 3
Explanation: raw_numbers_with_duplicates is created as an array of integers with repeated values. arraydistinct() effectively identifies and removes these numerical duplicates, resulting in distinct_numbers containing only the unique integer values.
Output:
| EVENT_ID | RAW_NUMBERS_WITH_DUPLICATES | DISTINCT_NUMBERS |
|---|---|---|
| 101 | [100, 50, 100, 50, 25, 100] | [100, 50, 25] |
| 102 | [100, 50, 100, 50, 25, 100] | [100, 50, 25] |
| 103 | [100, 50, 100, 50, 25, 100] | [100, 50, 25] |
Example 3: Applying arraydistinct() to an existing array field
Goal: Demonstrate how arraydistinct() handles an existing array field that does not contain duplicates within its individual elements.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter original_tags = string_tags | alter processed_tags = arraydistinct(original_tags) | fields event_id, original_tags, processed_tags | limit 3
Explanation: The original_tags field holds the existing string_tags array. arraydistinct() processes this array to produce processed_tags. In cases where the original array contains no duplicates, the output array will be identical to the input.
Output:
| EVENT_ID | ORIGINAL_TAGS | PROCESSED_TAGS |
|---|---|---|
| 101 | ["security", "login"] | ["security", "login"] |
| 102 | ["filesystem", "critical"] | ["filesystem", "critical"] |
| 103 | ["network", "cloud"] | ["network", "cloud"] |
Example 4: arraydistinct() on an array constructed from mixed field values with duplicates
Goal: Build an array by combining elements from different fields, introducing an explicit duplicate, and then use arraydistinct() to resolve it.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_tag = arrayindex(string_tags, 0) | alter combined_values_raw = arraycreate(first_tag, first_tag, to_string(event_id)) | alter unique_combined_values = arraydistinct(combined_values_raw) | fields event_id, combined_values_raw, unique_combined_values | limit 3
Explanation: combined_values_raw is constructed using string elements (first_tag repeated, and event_id converted to a string), creating a duplicate. arraydistinct() processes this array, removing the repeated first_tag to yield unique_combined_values.
Output:
| EVENT_ID | COMBINED_VALUES_RAW | UNIQUE_COMBINED_VALUES |
|---|---|---|
| 101 | ["security", "security", "101"] | ["security", "101"] |
| 102 | ["filesystem", "filesystem", "102"] | ["filesystem", "102"] |
| 103 | ["network", "network", "103"] | ["network", "103"] |
Example 5: arraydistinct() on a concatenated array with duplicates
Goal: Use arraydistinct() on an array formed by concatenating an existing array with itself, which inherently introduces duplicates.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter duplicate_numeric_codes = numeric_codes | alter duplicated_numeric_array = arrayconcat(numeric_codes, duplicate_numeric_codes) | alter distinct_concatenated_numeric = arraydistinct(duplicated_numeric_array) | fields event_id, duplicate_numeric_codes, duplicated_numeric_array, distinct_concatenated_numeric | limit 3
Explanation: arrayconcat() is used to join the numeric_codes array with itself, creating duplicated_numeric_array. arraydistinct() is then applied, effectively reducing it back to the original set of unique elements in distinct_concatenated_numeric.
Output:
| EVENT_ID | DUPLICATE_NUMERIC_CODES | DUPLICATED_NUMERIC_ARRAY | DISTINCT_CONCATENATED_NUMERIC |
|---|---|---|---|
| 101 | [13, -47, 29, 82, -15] | [13, -47, 29, 82, -15, 13, -47, 29, 82, -15] | [13, -47, 29, 82, -15] |
| 102 | [-21, 56, 13, -88, 42] | [-21, 56, 13, -88, 42, -21, 56, 13, -88, 42] | [-21, 56, 13, -88, 42] |
| 103 | [90, -33, 7, 51, -62, 18] | [90, -33, 7, 51, -62, 18, 90, -33, 7, 51, -62, 18] | [90, -33, 7, 51, -62, 18] |
Related articles
- Stages:
alter,config,fields,limit - Functions:
arraycreate,arrayindex,arrayconcat,to_string
arrayfilter
Use the arrayfilter() function to create a new array containing only the elements from the original input array that satisfy a specified boolean condition.
Syntax
arrayfilter (<array>, <condition>)
or
arrayfilter (<array>, "@element"<operator>"<array_element>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array |
array | Yes | The array field to filter. |
@element |
keyword | Yes | A special keyword that refers to each individual element within the array during the evaluation of the condition. |
operator |
operator | Yes | Any supported XQL comparison operator, such as =, !=, >, <, >=, or <=. |
array_element |
string, integer, float, boolean | Yes | The value or condition against which each array element is compared. |
Returns
The arrayfilter() function returns a new array containing only the elements that meet the specified condition.
Usage notes
- The specified condition is applied individually to every element in the input array.
- If the input array is empty, the function will return an empty array.
- This function is commonly used within the
alterorfilterstages to perform data transformations or to narrow down query results.
Examples
Example 1: Filtering a string array for specific elements
Goal: Filter the string_tags array to include only tags that match the specific value "security".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter security_tags = arrayfilter(string_tags, "@element" = "security") | fields event_id, string_tags, security_tags | limit 3
Explanation: For event_id 101, "security" matches the condition, so it is included in the new array, while "login" is excluded. For events 102 and 103, no elements match, resulting in an empty array.
Output:
| EVENT_ID | STRING_TAGS | SECURITY_TAGS |
|---|---|---|
| 101 | ["security", "login"] | ["security"] |
| 102 | ["filesystem", "critical"] | [] |
| 103 | ["network", "cloud"] | [] |
Example 2: Filtering a numeric array for values greater than a threshold
Goal: Filter the numeric_codes array to include only numbers greater than 50.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter large_numeric_codes = arrayfilter(numeric_codes, "@element" > 50) | fields event_id, numeric_codes, large_numeric_codes | limit 3
Explanation: The function iterates through the numeric_codes array. For event_id 101, only 82 is greater than 50. For 102, only 56 is greater. For 103, both 90 and 51 are retained.
Output:
| EVENT_ID | NUMERIC_CODES | LARGE_NUMERIC_CODES |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | [82] |
| 102 | [-21, 56, 13, -88, 42] | [56] |
| 103 | [90, -33, 7, 51, -62, 18] | [90, 51] |
Example 3: Filtering a string array for elements not equal to a value
Goal: Filter the string_tags array to include only tags that are not equal to "login".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter non_login_tags = arrayfilter(string_tags, "@element" != "login") | fields event_id, string_tags, non_login_tags | limit 3
Explanation: For event_id 101, "security" is not "login", so it is included, while "login" is excluded. For events 102 and 103, all elements satisfy the condition (are not "login"), so the entire arrays are retained.
Output:
| EVENT_ID | STRING_TAGS | NON_LOGIN_TAGS |
|---|---|---|
| 101 | ["security", "login"] | ["security"] |
| 102 | ["filesystem", "critical"] | ["filesystem", "critical"] |
| 103 | ["network", "cloud"] | ["network", "cloud"] |
Example 4: Filtering an array and checking its length in a filter stage
Goal: Create a new array by filtering string_tags for elements containing the substring "crit", and then filter the dataset to only show records where this new array is not empty.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter critical_event_tags = arrayfilter(string_tags, "@element" contains "crit") | filter array_length(critical_event_tags) > 0 | fields event_id, string_tags, critical_event_tags | limit 3
Explanation: First, critical_event_tags is created containing only tags that include "crit". For event_id 102, this results in ["critical"]. The filter stage then uses array_length() to retain only records where the filtered array has elements.
Output:
| EVENT_ID | STRING_TAGS | CRITICAL_EVENT_TAGS |
|---|---|---|
| 102 | ["filesystem", "critical"] | ["critical"] |
Related articles
- Stages:
alter,filter,fields - Functions:
array_length - Datasets:
xdr_data
arrayindex
Use the arrayindex() function to retrieve a single element from a specified array by its numerical position, or index.
Syntax
arrayindex (<array>, <index>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array |
array | Yes | The array from which you want to extract an element. |
index |
integer | Yes | An integer representing the zero-based position of the element you want to retrieve (for example, 0 for the first element, 1 for the second, and so on). |
Returns
The arrayindex() function returns a single value, which is the element located at the specified index within the array.
Usage notes
- Array elements are accessed using a zero-based index, meaning the first element is at index
0, the second at index1, etc. - If the specified index is beyond the array's boundaries or if the array itself is empty,
arrayindex()will returnNULLfor the field and not an empty array. - This function supports negative indices (for example,
-1for the last element,-2for the second to last element).
Examples
Example 1: Extracting the first element (Index 0) from a string array
Goal: Retrieve the first string tag from the string_tags array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_tag = arrayindex(string_tags, 0) // Extracts the first element | fields event_id, string_tags, first_tag | limit 3
Explanation: For each event_id, the function extracts the first string element (index 0) from the string_tags array.
Output:
| event_id | string_tags | first_tag |
|---|---|---|
| 101 | ["security", "login"] | "security" |
| 102 | ["filesystem", "critical"] | "filesystem" |
| 103 | ["network", "cloud"] | "network" |
Example 2: Extracting a middle element (Index 2) from a numeric array
Goal: Retrieve the third numeric code (at index 2) from the numeric_codes array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter third_numeric_code = arrayindex(numeric_codes, 2) // Extracts the element at index 2 | fields event_id, numeric_codes, third_numeric_code | limit 3
Explanation: For each event_id, the function extracts the element at index 2 (the third element) from the numeric_codes array.
Output:
| event_id | numeric_codes | third_numeric_code |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | 29 |
| 102 | [-21, 56, 13, -88, 42] | 13 |
| 103 | [90, -33, 7, 51, -62, 18] | 7 |
Example 3: Handling an empty array
Goal: Demonstrate the behavior when attempting to extract an element from an empty array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 104 // Focus on the event with an empty array | alter first_numeric_code_empty = arrayindex(numeric_codes, 0) // Attempt to extract from empty array | fields event_id, numeric_codes, first_numeric_code_empty | limit 1
Explanation: For event_id 104, the numeric_codes array is empty. As expected, the function returns NULL when no element exists at the specified index due to an empty array.
Output:
| event_id | numeric_codes | first_numeric_code_empty |
|---|---|---|
| 104 | [] | NULL |
Example 4: Handling an out-of-bounds index
Goal: Demonstrate the behavior when the specified index is beyond the actual size of the array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter out_of_bounds_code = arrayindex(numeric_codes, 100) // Index 100 is far beyond array size | fields event_id, numeric_codes, out_of_bounds_code | limit 3
Explanation: For all event_ids, numeric_codes does not have an element at index 100. The function correctly returns NULL when the index is out of bounds.
Output:
| event_id | numeric_codes | out_of_bounds_code |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | NULL |
| 102 | [-21, 56, 13, -88, 42] | NULL |
| 103 | [90, -33, 7, 51, -62, 18] | NULL |
Example 5: Retrieving the last element (-1 Index)
Goal: Extract the last element from an array using the negative index -1.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter last_numeric_code = arrayindex(numeric_codes, -1) // Extracts the last element using negative index | fields event_id, numeric_codes, last_numeric_code | limit 3
Explanation: Using index -1 retrieves the final element of the numeric_codes array for each record.
Output:
| event_id | numeric_codes | last_numeric_code |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | -15 |
| 102 | [-21, 56, 13, -88, 42] | 42 |
| 103 | [90, -33, 7, 51, -62, 18] | 18 |
Example 6: Retrieving the second to last element (-2 Index)
Goal: Retrieve the second to last element from an array using the negative index -2.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter second_to_last_numeric_code = arrayindex(numeric_codes, -2) // Extracts the second to last element | fields event_id, numeric_codes, second_to_last_numeric_code | limit 3
Explanation: Using index -2 retrieves the element immediately preceding the last element in the numeric_codes array.
Output:
| event_id | numeric_codes | second_to_last_numeric_code |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | 82 |
| 102 | [-21, 56, 13, -88, 42] | -88 |
| 103 | [90, -33, 7, 51, -62, 18] | -62 |
Related articles
- Stages:
alter - Functions:
arraycreate,array_length
arrayindexof
Use the arrayindexof() function to return the index of the first occurrence of a specified element in an array that satisfies a condition, or 0 if a general boolean condition matches.
Syntax
arrayindexof (<array>, <condition>) arrayindexof (<array>, "@element"<operator>"<array element>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array |
array | Yes | The array field to evaluate. |
condition |
boolean | No | A boolean expression that evaluates to true or false for the array. |
@element |
keyword | No | A special keyword representing each individual element within the array during evaluation. |
operator |
operator | No | Any supported XQL comparison operator, such as =, !=, >, <, >=, <=. |
array_element |
string, integer, float, boolean | No | The value or condition against which each array element is compared. |
Returns
The arrayindexof() function returns an integer (0 or a 0-based index) or NULL.
Usage notes
- If the condition is a general boolean expression not using
@element, the function returns0if the array is not empty and the condition is true. - If the condition uses
@elementto check individual array elements, the function returns the 0-based index of the first array element that satisfies the condition. - If the input array is empty,
arrayindexof()returnsNULL. - If the condition (general or
@element-based) is not met by any element, the function returnsNULL.
Examples
Example 1: General condition - checking array length
Goal: Check if the string_tags array contains more than one element using a general condition.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter has_multiple_tags = arrayindexof(string_tags, array_length(string_tags) > 1) | fields event_id, string_tags, has_multiple_tags | limit 4
Explanation: The query uses the arrayindexof(<array>, <condition>) variant. For event_id 101, 102, and 103, the length is 2, so the condition matches and returns 0. For event_id 104, the length is 1, so the condition fails and returns NULL.
Output:
| EVENT_ID | STRING_TAGS | HAS_MULTIPLE_TAGS |
|---|---|---|
| 101 | ["security", "login"] | 0 |
| 102 | ["filesystem", "critical"] | 0 |
| 103 | ["network", "cloud"] | 0 |
| 104 | ["monitoring"] | NULL |
Example 2: Element-specific condition - checking for a specific string value
Goal: Find the index of the first occurrence of the tag "login" in the string_tags array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_index_of_login_tag = arrayindexof(string_tags, "@element" = "login") | fields event_id, string_tags, first_index_of_login_tag | limit 5
Explanation: The query uses the @element keyword to check each item. For event_id 101, "login" is found at index 1, so 1 is returned. For other events where "login" is missing, NULL is returned.
Output:
| EVENT_ID | STRING_TAGS | FIRST_INDEX_OF_LOGIN_TAG |
|---|---|---|
| 101 | ["security", "login"] | 1 |
| 102 | ["filesystem", "critical"] | NULL |
| 103 | ["network", "cloud"] | NULL |
| 104 | ["monitoring"] | NULL |
| 105 | ["data_ops"] | NULL |
Example 3: Element-specific condition - checking for a numeric value greater than a threshold
Goal: Find the index of the first numeric code in the numeric_codes array that is greater than 50.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_index_of_large_code = arrayindexof(numeric_codes, "@element" > 50) | fields event_id, numeric_codes, first_index_of_large_code | limit 6
Explanation: This query searches the entire array and returns the index of the first match. For event_id 101, 82 is the first value > 50 (at index 3). For event_id 102, 56 is the first match (at index 1).
Output:
| EVENT_ID | NUMERIC_CODES | FIRST_INDEX_OF_LARGE_CODE |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | 3 |
| 102 | [-21, 56, 13, -88, 42] | 1 |
| 103 | [90, -33, 7, 51, -62, 18] | 0 |
| 104 | [] | NULL |
| 105 | [77, -9, 35, -47, 61] | 0 |
| 106 | [-12, 24, 68, -59, 37, 80] | 2 |
Example 4: Element-specific condition - checking for a value not equal to a specific string
Goal: Find the index of the first element in string_tags that is not "security".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_index_of_non_security = arrayindexof(string_tags, "@element" != "security") | fields event_id, string_tags, first_index_of_non_security | limit 5
Explanation: For event_id 101, "security" is at index 0, but "login" is at index 1 and matches the condition != "security", so 1 is returned. For event_id 102, "filesystem" at index 0 matches, so 0 is returned.
Output:
| EVENT_ID | STRING_TAGS | FIRST_INDEX_OF_NON_SECURITY |
|---|---|---|
| 101 | ["security", "login"] | 1 |
| 102 | ["filesystem", "critical"] | 0 |
| 103 | ["network", "cloud"] | 0 |
| 104 | ["monitoring"] | 0 |
| 105 | ["data_ops"] | 0 |
Example 5: Handling an empty array explicitly
Goal: Demonstrate that arrayindexof() returns NULL when applied to an empty array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 104 // Focus on the event with an empty array | alter index_in_empty_array = arrayindexof(numeric_codes, "@element" = 0) | fields event_id, numeric_codes, index_in_empty_array | limit 1
Explanation: For event_id 104, the numeric_codes array is empty. As per the function's definition, if the array is empty, NULL is returned.
Output:
| EVENT_ID | NUMERIC_CODES | INDEX_IN_EMPTY_ARRAY |
|---|---|---|
| 104 | [] | NULL |
Related articles
arraymap
Use the arraymap() function to apply a specified callable function to every element of an input array, returning a new array containing the transformed elements.
Syntax
arraymap (<array>, <function()>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array |
array | Yes | The array whose elements you want to transform. |
function() |
function | Yes | The function to apply to each element of the array. Use the special keyword "@element" as a placeholder for the current array element being processed. |
Returns
The arraymap() function returns a new array, where each element is the result of applying the specified function to the corresponding element of the original array.
Usage notes
- The function iterates through each element, applies the defined transformation, and collects the results into a new array.
- When the function applied within
arraymap()needs to reference the current array element being processed, it uses"@element"as a placeholder for that element. arraymap()is typically used within thealterorfilterstages for data transformations.
Examples
Example 1: Applying a simple mathematical transformation to a numeric array
Goal: Multiply each element in a numeric array by a specific constant.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter multiplied_codes = arraymap(numeric_codes, multiply("@element", 10)) | fields event_id, numeric_codes, multiplied_codes | limit 4
Explanation: For each record, arraymap() iterates over the numeric_codes array. The multiply() function takes each "@element" (for example, 13) and multiplies it by 10. The results form the new multiplied_codes array. An empty input array (event_id 104) results in an empty output array.
Output:
| EVENT_ID | NUMERIC_CODES | MULTIPLIED_CODES |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | [130, -470, 290, 820, -150] |
| 102 | [-21, 56, 13, -88, 42] | [-210, 560, 130, -880, 420] |
| 103 | [90, -33, 7, 51, -62, 18] | [900, -330, 70, 510, -620, 180] |
| 104 | [] | [] |
Example 2: Applying a string transformation (uppercase) to a string array
Goal: Convert all string elements within an array to uppercase.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter uppercase_tags = arraymap(string_tags, uppercase("@element")) | fields event_id, string_tags, uppercase_tags | limit 4
Explanation: The arraymap() function processes each element in string_tags (for example, "security"). The uppercase() function converts "@element" to its uppercase equivalent. The transformed elements form the uppercase_tags array.
Output:
| EVENT_ID | STRING_TAGS | UPPERCASE_TAGS |
|---|---|---|
| 101 | ["security", "login"] | ["SECURITY", "LOGIN"] |
| 102 | ["filesystem", "critical"] | ["FILESYSTEM", "CRITICAL"] |
| 103 | ["network", "cloud"] | ["NETWORK", "CLOUD"] |
| 104 | ["monitoring"] | ["MONITORING"] |
Example 3: Applying a conditional transformation (replacing negative values) to a numeric array
Goal: Replace any negative numbers in an array with 0, while keeping positive numbers unchanged.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter positive_codes = arraymap(numeric_codes, if("@element" < 0, 0, "@element")) | fields event_id, numeric_codes, positive_codes | limit 4
Explanation: For each number in numeric_codes, the if() function checks if "@element" is less than 0. If true, it is replaced with 0; otherwise, the original "@element" value is retained.
Output:
| EVENT_ID | NUMERIC_CODES | POSITIVE_CODES |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | [13, 0, 29, 82, 0] |
| 102 | [-21, 56, 13, -88, 42] | [0, 56, 13, 0, 42] |
| 103 | [90, -33, 7, 51, -62, 18] | [90, 0, 7, 51, 0, 18] |
| 104 | [] | [] |
Example 4: Extracting scalar values from JSON Objects within an array
Goal: Iterate through an array of JSON objects and extract a specific scalar value (for example, action or event) from each object into a new array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_actions = arraymap(array_of_json_objects, coalesce( json_extract_scalar(to_json_string("@element"), "$.action"), json_extract_scalar(to_json_string("@element"), "$.event") )) | fields event_id, array_of_json_objects, extracted_actions | limit 4
Explanation: arraymap() iterates over each JSON object within array_of_json_objects. For each @element (a JSON object), to_json_string() converts it to a string. json_extract_scalar() then attempts to extract the action field. If not found, it tries to extract the event field. coalesce() returns the first non-null result.
Output:
| EVENT_ID | ARRAY_OF_JSON_OBJECTS | EXTRACTED_ACTIONS |
|---|---|---|
| 101 | [{"action": "read", "file": "doc1.txt"}, {"action": "write", "file": "report.log"}] | ["read", "write"] |
| 102 | [{"event": "file_open", "path": "/etc/passwd"}] | ["file_open"] |
| 103 | [{"conn_type": "outbound", "bytes": 1024}, {"conn_type": "inbound", "bytes": 512}] | [] |
| 104 | [] | [] |
Related articles
- Stages:
alter,config,fields,limit - Functions:
multiply,uppercase,if,coalesce,json_extract_scalar,to_json_string
arraymerge
Use the arraymerge() function to flatten an input array containing JSON strings representing arrays into a single, merged XQL array.
Syntax
arraymerge (<field>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
array | Yes | A single array field whose elements are JSON strings, where each JSON string represents an array (for example, ["value1", "value2"]). |
Returns
The arraymerge() function returns a new, flattened XQL-native array containing all elements from the inner JSON-string-represented arrays.
Usage notes
- The function strictly requires an array where each element is a valid JSON string that represents an array.
- The function flattens the structure, taking an array of arrays (represented as JSON strings) and reducing it to a single-dimensional array.
- This function is commonly used in conjunction with
arraymap()when the internal function ofarraymap()produces JSON strings of arrays.
Examples
Example 1: Merging artificially constructed arrays (literal JSON strings)
Goal: Demonstrate the core functionality by creating an array where each element is a JSON string representing an array, and then flattening them into a single array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter json_array_str_part1 = to_json_string(arraycreate("tag1", "tag2")) // Creates JSON string '["tag1", "tag2"]' | alter json_array_str_part2 = to_json_string(arraycreate("valueA", "valueB")) // Creates JSON string '["valueA", "valueB"]' | alter input_array_for_merge = arraycreate(json_array_str_part1, json_array_str_part2) // Creates an array of these JSON strings: ['["tag1", "tag2"]', '["valueA", "valueB"]'] | alter merged_result = arraymerge(input_array_for_merge) | fields event_id, merged_result | limit 2
Explanation: The query first creates two string representations of arrays (json_array_str_part1 and json_array_str_part2) using arraycreate() and to_json_string(). The query then combines these into input_array_for_merge. Finally, arraymerge() extracts the elements from within each JSON string in the input array and combines them into a single, flattened merged_result array.
Output:
| EVENT_ID | MERGED_RESULT |
|---|---|
| 101 | ["tag1", "tag2", "valueA", "valueB"] |
| 102 | ["tag1", "tag2", "valueA", "valueB"] |
Example 2: Merging scalar values extracted and wrapped into arrays via arraymap()
Goal: Demonstrate how to process an array of JSON objects, extract specific scalar values, wrap them into new conceptual arrays, convert them to JSON strings, and finally flatten the result using arraymerge().
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter mapped_json_arrays_as_strings = arraymap( array_of_json_objects, to_json_string( // Converts the dynamically created array into a JSON string arraycreate( // Creates a new temporary array from extracted scalars to_string(coalesce(json_extract_scalar(to_json_string("@element"), "$.action"), json_extract_scalar(to_json_string("@element"), "$.event"))), // Extracts 'action' or 'event' to_string(coalesce(json_extract_scalar(to_json_string("@element"), "$.file"), json_extract_scalar(to_json_string("@element"), "$.path"), json_extract_scalar(to_json_string("@element"), "$.conn_type"))) // Extracts 'file', 'path', or 'conn_type' ) ) ) | alter flattened_array = arraymerge(mapped_json_arrays_as_strings) | fields event_id, array_of_json_objects, flattened_array | limit 4
Explanation: arraymap() iterates over each JSON object in array_of_json_objects. For each element, it extracts specific scalar values (like action, event, file, path) using json_extract_scalar() and wraps them into a temporary array using arraycreate(). to_json_string() converts this temporary array into a JSON string. The result of arraymap() is an array of these JSON strings. Finally, arraymerge() flattens all the inner elements from these strings into a single flattened_array.
Output:
| EVENT_ID | ARRAY_OF_JSON_OBJECTS | FLATTENED_ARRAY |
|---|---|---|
| 101 | [{"action": "read", "file": "doc1.txt"}, {"action": "write", "file": "report.log"}] | ["read", "doc1.txt", "write", "report.log"] |
| 102 | [{"event": "file_open", "path": "/etc/passwd"}] | ["file_open", "/etc/passwd"] |
| 103 | [{"conn_type": "outbound", "bytes": 1024}, {"conn_type": "inbound", "bytes": 512}] | ["outbound", "inbound"] |
| 104 | [] | [] |
Example 2: Merge IP addresses extracted from a nested map
Goal: Create a single consolidated array containing all IPv4 addresses found within the agent_interface_map field. This query extracts the "ipv4" element from each object in the map and merges them into a flattened array.
XQL Code:
dataset = sample_xql_raw | alter a = arraymerge(arraymap(agent_interface_map, to_json_string(json_extract_array(to_json_string("@element"), "$.ipv4"))))
Explanation:
- The query processes the agent_interface_map, which is an array of objects.
- arraymap() iterates through each element (@element) in the array.
- to_json_string() converts the element to a JSON string so it can be parsed.
- json_extract_array(..., "$.ipv4") locates and extracts the IPv4 addresses associated with the "ipv4" key in each object.
- arraymerge() takes the resulting nested arrays and flattens them into a single, comprehensive array assigned to the field 'a'.
Output:
| agent_interface_map | a |
|---|---|
| [{"ipv4":["10.0.0.1"],"name":"eth0"},{"ipv4":["192.168.1.1"],"name":"wlan0"}] | ["10.0.0.1", "192.168.1.1"] |
| [{"ipv4":["172.16.0.5", "172.16.0.6"],"name":"eth1"}] | ["172.16.0.5", "172.16.0.6"] |
Related articles
- Stages:
alter,config,fields,limit - Functions:
arraycreate,to_json_string,arraymap,json_extract_scalar,to_string,coalesce
arrayrange
Use the arrayrange() function to return a new array containing a subset of elements from an original array. The subset is defined by a specified start index (inclusive) and an end index (exclusive).
Syntax
arrayrange (<array>, <start>, <end>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array |
array | Yes | The array from which you want to extract a portion. |
start |
integer | Yes | An integer representing the 0-based index where the new array slice should begin (inclusive). |
end |
integer | Yes | An integer representing the 0-based index where the new array slice should end (exclusive). |
Returns
The arrayrange() function returns a new XQL-native array, which is a slice of the original array.
Usage notes
- Array indices in XQL are 0-based, meaning the first element is at index 0.
- The element at the
<start>index is included, but the element at the<end>index is not included in the result. - If the
<end>index is greater than the last element's actual index in the array, the function will return elements from the<start>index up to the end of the original array. - If the input array is null or empty, or if the start index is out of bounds or greater than or equal to the end index,
arrayrange()will typically return an empty or null array.
Examples
Example 1: Extracting a standard slice from a numeric array
Goal: This example demonstrates extracting a portion from the numeric_codes array using typical start and end indices.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_three_codes = arrayrange(numeric_codes, 0, 3) // Extracts elements from index 0 up to (but not including) index 3 | fields event_id, numeric_codes, first_three_codes | limit 3
Explanation: The numeric_codes field contains arrays of integers. arrayrange(numeric_codes, 0, 3) creates a new array for each record, taking elements starting from index 0 and stopping before index 3 (i.e., elements at indices 0, 1, and 2).
Output:
| event_id | numeric_codes | first_three_codes |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | [13, -47, 29] |
| 102 | [-21, 56, 13, -88, 42] | [-21, 56, 13] |
| 103 | [90, -33, 7, 51, -62, 18] | [90, -33, 7] |
Example 2: Extracting a slice where the end index is beyond the array's length
Goal: This example demonstrates the behavior of arrayrange() when the specified end index exceeds the actual number of elements in the array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter slice_to_end = arrayrange(numeric_codes, 2, 100) // Starts at index 2, goes to actual end if 100 is out of bounds | fields event_id, numeric_codes, slice_to_end | limit 3
Explanation: arrayrange(numeric_codes, 2, 100) attempts to extract elements starting from index 2 up to index 99. Because the numeric_codes arrays typically have fewer than 100 elements, the function correctly returns all elements from index 2 to the actual end of each array.
Output:
| event_id | numeric_codes | slice_to_end |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | [29, 82, -15] |
| 102 | [-21, 56, 13, -88, 42] | [13, -88, 42] |
| 103 | [90, -33, 7, 51, -62, 18] | [7, 51, -62, 18] |
Example 3: Extracting a slice from a string array
Goal: This example illustrates arrayrange() applied to a string array, demonstrating its versatility across different data types.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter middle_tags = arrayrange(string_tags, 1, 3) // Extracts elements from index 1 up to (but not including) index 3 | fields event_id, string_tags, middle_tags | limit 3
Explanation: The string_tags field contains arrays of strings. arrayrange(string_tags, 1, 3) extracts elements starting from index 1 and stopping before index 3. For the sample data, this often results in just the second element as most string_tags arrays have only two elements (indices 0 and 1).
Output:
| event_id | string_tags | middle_tags |
|---|---|---|
| 101 | ["security", "login"] | ["login"] |
| 102 | ["filesystem", "critical"] | ["critical"] |
| 103 | ["network", "cloud"] | ["cloud"] |
Example 4: Handling an empty array input
Goal: This example demonstrates how arrayrange() behaves when the input array is empty.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 104 // Event ID 104 has an empty 'array_of_json_objects' | alter empty_array_slice = arrayrange(array_of_json_objects, 0, 1) // Attempts to extract from an empty array | fields event_id, array_of_json_objects, empty_array_slice | limit 1
Explanation: event_id 104 in sample_xql_raw has an empty array_of_json_objects field. When arrayrange() is applied to an empty array, it returns an empty array, indicating that no elements could be extracted from the specified range.
Output:
| event_id | array_of_json_objects | empty_array_slice |
|---|---|---|
| 104 | [] | [] |
Example 5: Using arrayrange() with dynamically created arrays
Goal: This example shows arrayrange() applied to an array that is explicitly constructed within the query using arraycreate().
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter dynamic_numbers = arraycreate(10, 20, 30, 40, 50, 60, 70) // Creates a new array | alter dynamic_slice = arrayrange(dynamic_numbers, 2, 5) // Extracts elements from index 2 up to (but not including) index 5 | fields event_id, dynamic_numbers, dynamic_slice | limit 2
Explanation: dynamic_numbers is a new array created on the fly with a set of integer values. arrayrange(dynamic_numbers, 2, 5) then extracts the elements at indices 2, 3, and 4 from this newly created array, resulting in [30, 40, 50].
Output:
| event_id | dynamic_numbers | dynamic_slice |
|---|---|---|
| 101 | [10, 20, 30, 40, 50, 60, 70] | [30, 40, 50] |
| 102 | [10, 20, 30, 40, 50, 60, 70] | [30, 40, 50] |
Related articles
arraystring
Use the arraystring() function to convert an array into a single string by joining its elements with a specified delimiter.
Syntax
arraystring (<array>, <delimiter>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array |
array | Yes | The array field whose elements you want to concatenate into a single string. |
delimiter |
string | Yes | A string literal that will be used to join the elements of the array. |
Returns
The arraystring() function returns a single string where each element of the original array is separated by the specified delimiter.
Usage notes
- The function requires an existing XQL-native array field as input.
- The function operates on XQL arrays and implicitly converts elements to strings for concatenation.
- The specified delimiter is inserted between each element of the original array in the resulting string.
- If the input array is empty (for example,
[]), the function returns an empty string (""). - This function is typically used within the
alterstage to create new fields or modify existing ones, but can also be used infilterstages.
Examples
Example 1: Converting a string array to a string with a comma and space delimiter
Goal: Convert an array of strings into a single string, separating each element with a comma and a space.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter combined_tags = arraystring(string_tags, ", ") | fields event_id, string_tags, combined_tags | limit 3
Explanation: The string_tags field contains arrays of strings. The arraystring() function converts each array into a single string, using ", " as the separator between elements.
Output:
| EVENT_ID | STRING_TAGS | COMBINED_TAGS |
|---|---|---|
| 101 | ["security", "login"] | "security, login" |
| 102 | ["filesystem", "critical"] | "filesystem, critical" |
| 103 | ["network", "cloud"] | "network, cloud" |
Example 2: Converting a numeric array to a string with a pipe delimiter
Goal: Join elements of a numeric array into a single string separated by a pipe character.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter numeric_codes_as_strings = arraymap(numeric_codes, to_string("@element")) | alter combined_codes = arraystring(numeric_codes_as_strings, " | ") | fields event_id, numeric_codes, numeric_codes_as_strings, combined_codes | limit 3
Explanation: The numeric_codes field contains arrays of integers. First, arraymap() iterates through each number and converts it to a string using to_string(), creating a new array numeric_codes_as_strings. Then, arraystring() concatenates the elements of this string array using the specified " | " delimiter.
Output:
| EVENT_ID | NUMERIC_CODES | NUMERIC_CODES_AS_STRINGS | COMBINED_CODES |
|---|---|---|---|
| 101 | [13, -47, 29, 82, -15] | ["13", "-47", "29", "82", "-15"] | 13 |
| 102 | [-21, 56, 13, -88, 42] | ["-21", "56", "13", "-88", "42"] | -21 |
| 103 | [90, -33, 7, 51, -62, 18] | ["90", "-33", "7", "51", "-62", "18"] | 90 |
Example 3: Handling an empty array input
Goal: Demonstrate the behavior of the function when the input array is empty.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 104 | alter empty_array_to_string = arraystring(array_of_json_objects, "-") | fields event_id, array_of_json_objects, empty_array_to_string | limit 1
Explanation: When arraystring() is applied to an empty array ([]), it returns an empty string (""), as there are no elements to join.
Output:
| EVENT_ID | ARRAY_OF_JSON_OBJECTS | EMPTY_ARRAY_TO_STRING |
|---|---|---|
| 104 | [] | "" |
Example 4: Converting a dynamically sliced array to a string
Goal: Apply the function to a portion of a numeric array created using arrayrange.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_two_numeric_codes = arrayrange(numeric_codes, 0, 2) | alter sliced_codes_as_strings = arraymap(first_two_numeric_codes, to_string("@element")) | alter sliced_codes_string = arraystring(sliced_codes_as_strings, ", ") | fields event_id, numeric_codes, first_two_numeric_codes, sliced_codes_as_strings, sliced_codes_string | limit 3
Explanation: First, arrayrange(numeric_codes, 0, 2) extracts the first two elements of numeric_codes. Then, arraymap() converts these numeric elements to strings. Finally, arraystring() concatenates these string elements using ", " as the delimiter.
Output:
| EVENT_ID | NUMERIC_CODES | FIRST_TWO_NUMERIC_CODES | SLICED_CODES_AS_STRINGS | SLICED_CODES_STRING |
|---|---|---|---|---|
| 101 | [13, -47, 29, 82, -15] | [13, -47] | ["13", "-47"] | "13, -47" |
| 102 | [-21, 56, 13, -88, 42] | [-21, 56] | ["-21", "56"] | "-21, 56" |
| 103 | [90, -33, 7, 51, -62, 18] | [90, -33] | ["90", "-33"] | "90, -33" |
Example 5: Using arraystring() in a filter stage
Goal: Filter records by creating a string from an array and checking for a specific substring.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter combined_tags_for_filter = arraystring(string_tags, "-") | filter combined_tags_for_filter contains "security" | fields event_id, string_tags, combined_tags_for_filter | limit 3
Explanation: The combined_tags_for_filter field is created by joining string_tags elements with a hyphen. The filter stage then checks if this new string field contains the substring "security". Only Event IDs containing "security" in their tags are returned.
Output:
| EVENT_ID | STRING_TAGS | COMBINED_TAGS_FOR_FILTER |
|---|---|---|
| 101 | ["security", "login"] | "security-login" |
| 106 | ["security", "attack"] | "security-attack" |
Example 6: Converting application transitions to a delimited string and deduplicating
Goal: Retrieve non-null application ID transitions, convert the transition arrays into strings delimited by " : ", and remove duplicate transition strings based on the insertion time.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields action_app_id_transitions as aait | alter transitions_string = arraystring(aait, " : ") | dedup transitions_string by asc _time | filter aait != null
Explanation: The query first filters the sample_xql_raw dataset to include only records where action_app_id_transitions contains data. The query renames the field to aait for brevity. The arraystring() function then takes each array of transitions and joins the elements into a single string using " : " as the separator. Finally, the dedup stage ensures that only unique transition strings are retained, ordered by the timestamp.
Output:
| aait | transitions_string |
|---|---|
| ["App_1", "App_2", "App_3"] | "App_1 : App_2 : App_3" |
| ["App_A", "App_B"] | "App_A : App_B" |
| ["App_1", "App_5"] | "App_1 : App_5" |
Related articles
asin
Use the asin() function to calculate the principal value of the inverse sine (arcsine) of a numerical expression.
Syntax
asin(<numeric_expression>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
numeric_expression |
integer, float | Yes | The numerical value for which to calculate the arcsine. The value must be within the range of -1 to 1 (inclusive). |
Returns
Type: float
Description: The asin() function returns the principal value of the arcsine of the input in radians. The resulting value is within the range [-π/2, π/2].
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The input
numeric_expressionmust fall within the closed interval [-1, 1]. - Out of Range Behavior: If the input is outside the range of -1 to 1, the function returns
NaN(Not a Number) ornull. - Null Handling: If the input expression is
null, the function returnsnull. - Radians to Degrees: The result is provided in radians. To convert the result to degrees, multiply the return value by
180 / PI(). - Common Use Cases: This function is typically used within the
alterstage for geometric calculations, spatial analysis, or normalizing data vectors.
Examples
Example 1: Calculate arcsine of literal values
Goal: Calculate the inverse sine for specific numerical literals to see the radian results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = asin(0), result2 = asin(1), result3 = asin(-1) | fields result1, result2, result3
Explanation: You use asin() on three different literal values. asin(0) returns 0.0, asin(1) returns approximately 1.5708 (π/2), and asin(-1) returns approximately -1.5708 (-π/2).
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 0.0 | 1.5708 | -1.5708 |
Example 2: Calculate arcsine from a field value
Goal: Calculate the arcsine of values stored in a specific field, ensuring they are within the valid mathematical range.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter duration_seconds >= -1 and duration_seconds <= 1 | alter arc_sin_val = asin(duration_seconds) | fields event_id, duration_seconds, arc_sin_val | limit 3
Explanation: This query first filters the dataset to ensure duration_seconds contains only values between -1 and 1, then computes the arcsine for each and stores it in arc_sin_val.
Output:
| EVENT_ID | DURATION_SECONDS | ARC_SIN_VAL |
|---|---|---|
| 101 | 0.5 | 0.5236 |
| 102 | -0.3 | -0.3047 |
| 103 | 1.0 | 1.5708 |
Related articles
avg (comp)
Use the avg() function to calculate the average value of a numerical field within a group of rows. When used with the comp stage, it computes a single statistical average for the specified field across all records sharing matching values defined in a grouping clause.
Syntax
comp avg(<field>) [as <alias>] [by <field1>[,<field2>...]] [addrawdata = true|false [as <target field>]]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | integer, float | Yes | The numerical field for which to calculate the average. |
| alias | string | No | An optional name for the resulting average field. |
| field1, field2... | any | No | Optional fields used to group rows for independent average calculations. |
| addrawdata | boolean | No | If true, includes a column listing the raw events contributing to the aggregate. Defaults to false. |
| target field | string | No | An optional alias for the raw data column if addrawdata is true. |
Returns
The avg() function returns a single numerical value representing the average of the input field for the specified group.
Usage Notes
- The avg() function operates exclusively on numerical fields, including both integers and floating-point numbers.
- The comp stage must always precede the avg() function.
- When the comp stage is used, the system field _time is removed from the result set unless explicitly included in a by clause.
- Calculated columns created by the comp stage are typically appended as the last columns in the result set.
- If addrawdata is set to true, the query supports up to 50 defined fields and displays up to 100 raw events.
Examples
Example 1: Average a field across the entire dataset
Goal: Calculate the average value of the duration_seconds field for all records in the dataset without grouping.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp avg(duration_seconds) as overall_avg_duration
Explanation: The avg() function computes the mean of all duration_seconds values present in the sample_xql_raw dataset and names the result overall_avg_duration.
Output:
| overall_avg_duration |
|---|
| 10.285 |
Example 2: Average a field grouped by another field
Goal: Calculate the average duration_seconds separately for successful and unsuccessful events.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp avg(duration_seconds) as avg_duration_by_status by is_successful
Explanation: This code groups records by their is_successful status and then calculates the average duration_seconds for each distinct group.
Output:
| is_successful | avg_duration_by_status |
|---|---|
| true | 14.271428571428571 |
| false | 0.9833333333333333 |
Example 3: Average with raw data inclusion
Goal: Calculate average duration and include the JSON representation of raw events that contributed to each group.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields is_successful, duration_seconds | comp avg(duration_seconds) by is_successful addrawdata = true as raw_events_for_avg
Explanation: This code calculates the average duration_seconds grouped by is_successful and uses the addrawdata = true option to generate a column containing the underlying raw data for each aggregate.
Output:
| is_successful | avg_duration_by_status | raw_events_for_avg |
|---|---|---|
| true | 14.271428571428571 | [{"is_successful": true, "duration_seconds": 1.5}, ...] |
| false | 0.9833333333333333 | [{"is_successful": false, "duration_seconds": 0.8}, ...] |
Related Articles
avg (windowcomp)
Use the avg() function within the windowcomp stage to calculate and return a single average value of a specified numerical field over a defined "window" or group of rows. The resulting average value is then presented for each row within that window frame, allowing for contextual statistical analysis without collapsing rows.
Syntax
windowcomp avg(<field>) [by <field> [,<field>,...]] [sort [asc|desc] <field1> [, [asc|desc] <field2>,...]] [between 0|null|<number>|-<number> [and 0|null|<number>|-<number>] [frame_type=range]] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | numeric | Yes | The numerical field for which the average will be calculated. |
| by field | string | No | Partitions the data into distinct groups, allowing the avg() function to operate independently within each of these partitions. |
| sort field | string | No | Defines the order of rows within each partition. This ordering is critical when defining a window using the between clause. |
| between clause | string | No | Defines the "window frame"—a specific range of rows relative to the current row—over which the avg() function calculates. |
| alias | string | No | Assigns an alias name to the new column displaying the result. |
Returns
The avg() function returns a single numerical value representing the average for the defined window. This value is displayed in a new column for every row in the group of rows it applies to.
Usage Notes
- The windowcomp stage must always precede analytic functions like avg() that calculate statistics.
- Only one function can be defined per field within a single windowcomp stage.
- If the between clause is omitted, the default window typically encompasses the entire partition.
Examples
Example 1: avg() over an entire partition (default window)
Goal: Calculate the average of duration_seconds for all events within each is_successful group (partition), and replicate this single average value for every row in that group.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, duration_seconds | windowcomp avg(duration_seconds) by is_successful as avg_in_partition | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: The by is_successful clause partitions the data into two groups: one for false and one for true. The avg() function then calculates the average of the duration_seconds field for each partition. The result is a single average value for each partition, which is then displayed for every row in that partition. The sort clause ensures the rows are ordered by is_successful,_time, and event_id for consistent presentation of the data.
Output:
| _time | event_id | is_successful | duration_seconds | avg_in_partition |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | 0.8 | 0.9833 |
| 2023-10-26 10:40:10 UTC | 106 | false | 2.1 | 0.9833 |
| 2023-10-26 10:55:55 UTC | 109 | false | 0.05 | 0.9833 |
| 2023-10-26 10:00:00 UTC | 101 | true | 1.5 | 14.2714 |
| 2023-10-26 10:15:15 UTC | 103 | true | 10.2 | 14.2714 |
| 2023-10-26 10:20:00 UTC | 104 | true | 0.1 | 14.2714 |
| 2023-10-26 10:30:45 UTC | 105 | true | 5.0 | 14.2714 |
| 2023-10-26 10:45:00 UTC | 107 | true | 7.8 | 14.2714 |
| 2023-10-26 10:50:20 UTC | 108 | true | 15.3 | 14.2714 |
| 2023-10-26 11:00:10 UTC | 110 | true | 60.0 | 14.2714 |
Example 2: avg() with a rolling window (preceding 2 rows and current row)**
Goal: Calculate a rolling average from the duration_seconds of the current row and the two immediately preceding rows within its partition, ordered by _time.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, duration_seconds | windowcomp avg(duration_seconds) by is_successful sort asc _time between -2 and 0 as rolling_avg | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: The code defines a rolling window using between -2 and 0 which includes the current row (0) and the two immediately preceding rows (-2, -1) within its partition. For each row, the avg() function calculates the average of duration_seconds strictly within this rolling window. If there are not enough preceding rows, the window starts from the beginning of the partition.
Output:
| _time | event_id | is_successful | duration_seconds | rolling_avg |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | 0.8 | 0.8 |
| 2023-10-26 10:40:10 UTC | 106 | false | 2.1 | 1.45 |
| 2023-10-26 10:55:55 UTC | 109 | false | 0.05 | 0.9833 |
| 2023-10-26 10:00:00 UTC | 101 | true | 1.5 | 1.5 |
| 2023-10-26 10:15:15 UTC | 103 | true | 10.2 | 5.85 |
| 2023-10-26 10:20:00 UTC | 104 | true | 0.1 | 3.9333 |
| 2023-10-26 10:30:45 UTC | 105 | true | 5.0 | 5.1 |
| 2023-10-26 10:45:00 UTC | 107 | true | 7.8 | 4.3 |
| 2023-10-26 10:50:20 UTC | 108 | true | 15.3 | 9.3667 |
| 2023-10-26 11:00:10 UTC | 110 | true | 60.0 | 27.7 |
Example 3: avg() with a fixed window (current row to unbounded following row)
Goal: Calculate the average for each row over a window that starts from the current row and extends to the end of its partition.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, duration_seconds | windowcomp avg(duration_seconds) by is_successful sort asc _time between 0 and null as avg_from_current | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: The code uses the between 0 and null clause to set a window starting from the current row (0) through to the very end of the partition (null). For each row, the avg() calculates the average of duration_seconds utilizing the current row's value up to the last value in its is_successful partition.
Output:
| _time | event_id | is_successful | duration_seconds | avg_from_current |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | 0.8 | 0.9833 |
| 2023-10-26 10:40:10 UTC | 106 | false | 2.1 | 1.075 |
| 2023-10-26 10:55:55 UTC | 109 | false | 0.05 | 0.05 |
| 2023-10-26 10:00:00 UTC | 101 | true | 1.5 | 14.2714 |
| 2023-10-26 10:15:15 UTC | 103 | true | 10.2 | 16.4 |
| 2023-10-26 10:20:00 UTC | 104 | true | 0.1 | 17.64 |
| 2023-10-26 10:30:45 UTC | 105 | true | 5.0 | 22.025 |
| 2023-10-26 10:45:00 UTC | 107 | true | 7.8 | 27.7 |
| 2023-10-26 10:50:20 UTC | 108 | true | 15.3 | 37.65 |
| 2023-10-26 11:00:10 UTC | 110 | true | 60.0 | 60.0 |
Related Articles
- Stages: windowcomp, config, timeframe, dataset, fields, sort, limit
- Functions: count, max, median, min, sum, stddev_population, stddev_sample
bitwise_and
Use the bitwise_and() function to perform a bitwise AND operation between two integer values.
Syntax
bitwise_and (<left_clause>, <right_clause>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
left_clause |
integer | Yes | The first integer value or field on which to perform the bitwise AND. |
right_clause |
integer | Yes | The second integer value or field to AND against the first value. |
Returns
The bitwise_and() function returns an integer representing the result of the bitwise AND operation between the two input parameters.
Usage notes
- The function performs a bitwise AND (
&) operation, comparing each bit of the first operand to the corresponding bit of the second operand. If both bits are 1, the corresponding result bit is set to 1; otherwise, it is set to 0. - Both parameters must be integers. Passing a string value will result in a validation error.
- This function is commonly used to check whether specific bit flags are set in a bitmask field.
- The function supports hexadecimal integer values when used with
to_integer()(for example,to_integer("0x02")). - The function is typically used within the
alterorfilterstages to create computed fields or filter events based on bitwise conditions.
Examples
Example 1: Check a specific bit flag in an integer field
Goal: Use a bit mask to check whether a specific flag (bit 1, value 2) is set in the xdm.case.score field.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter flag_check = bitwise_and(xdm.case.score, 2) | fields event_id, xdm.case.score, flag_check | limit 3
Explanation: This query performs a bitwise AND between xdm.case.score and 2 (binary 10). If bit 1 is set in xdm.case.score, flag_check will be 2; otherwise, it will be 0.
Output:
| event_id | xdm.case.score | flag_check |
|---|---|---|
| 101 | 7 | 2 |
| 102 | 4 | 0 |
| 103 | 3 | 2 |
Example 2: Filter events using a bitwise AND with hexadecimal values
Goal: Filter events where a specific bit flag (0x02) is set in the xdm.case.score field, using hexadecimal notation.
XQL code:
config timeframe = 1d | dataset = xdr_data | filter bitwise_and(xdm.case.score, to_integer("0x02")) > 0 | fields event_id, xdm.case.score | limit 3
Explanation: This query filters for events where bit 1 (value 2) is set in xdm.case.score. The to_integer("0x02") converts the hexadecimal value 0x02 to the integer 2, which is used as the bitmask. The bitwise_and() result is either 2 (bit is set) or 0 (bit is not set). Only events where the result is greater than 0 pass the filter.
Output:
| event_id | xdm.case.score |
|---|---|
| 103 | 7 |
| 107 | 15 |
| 112 | 6 |
Example 3: Mask out the lower 8 bits of an integer field
Goal: Extract the lower 8 bits from a numeric field using a bit mask of 255 (binary 11111111).
XQL code:
config timeframe = 1d | dataset = xdr_data | alter lower_byte = bitwise_and(action_status, 255) | fields event_id, action_status, lower_byte | limit 3
Explanation: This query isolates the lower 8 bits of the action_status field. For a value of 258 (binary 100000010), the result is 2 (binary 00000010).
Output:
| event_id | action_status | lower_byte |
|---|---|---|
| 101 | 258 | 2 |
| 102 | 511 | 255 |
| 103 | 1024 | 0 |
Related articles
- Stages:
alter,config,filter,fields,limit - Functions:
bitwise_or,bitwise_xor,bitwise_sleft,bitwise_sright,to_integer
bitwise_or
Use the bitwise_or() function to perform a bitwise OR operation between two integer values.
Syntax
bitwise_or (<left_clause>, <right_clause>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
left_clause |
integer | Yes | The first integer value or field on which to perform the bitwise OR. |
right_clause |
integer | Yes | The second integer value or field to OR against the first value. |
Returns
The bitwise_or() function returns an integer representing the result of the bitwise OR operation between the two input parameters.
Usage notes
- The function performs a bitwise OR (
|) operation, comparing each bit of the first operand to the corresponding bit of the second operand. If either bit is 1, the corresponding result bit is set to 1; otherwise, it is set to 0. - Both parameters must be integers. Passing a string value will result in a validation error.
- This function is commonly used to set specific bit flags or combine multiple bitmask values into a single field.
- The function supports hexadecimal integer values when used with
to_integer()(for example,to_integer("0x000b")). - The function is typically used within the
alterorfilterstages to create computed fields or filter events based on bitwise conditions.
Examples
Example 1: Set a specific bit flag in an integer field
Goal: Set bit 2 (value 4) in the event_type field, ensuring that flag is always present in the result.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter with_flag = bitwise_or(event_type, 4) | fields event_id, event_type, with_flag | limit 3
Explanation: This query performs a bitwise OR between event_type and 4 (binary 100). If event_type is 3 (binary 011), the result is 7 (binary 111), ensuring bit 2 is set.
Output:
| event_id | event_type | with_flag |
|---|---|---|
| 101 | 3 | 7 |
| 102 | 5 | 5 |
| 103 | 0 | 4 |
Example 2: Combine two hexadecimal values and filter
Goal: Combine two hexadecimal values using bitwise OR and filter events where the result exceeds a threshold.
XQL code:
config timeframe = 1d | dataset = xdr_data | filter bitwise_or(to_integer("0x0004"), to_integer("0x000b")) > 2 | fields event_id, event_type | limit 3
Explanation: This query computes the bitwise OR of 0x0004 (decimal 4, binary 0100) and 0x000b (decimal 11, binary 1011), resulting in 15 (binary 1111). Since 15 > 2, all events pass the filter.
Output:
| event_id | event_type |
|---|---|
| 101 | 5 |
| 102 | 3 |
| 103 | 7 |
Example 3: Merge flags from two separate fields
Goal: Merge the bit flags from two separate integer fields into a single combined field.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter combined_flags = bitwise_or(permission_read, permission_write) | fields event_id, permission_read, permission_write, combined_flags | limit 3
Explanation: This query combines the bit flags from permission_read and permission_write. For example, if permission_read is 1 (binary 01) and permission_write is 2 (binary 10), the result is 3 (binary 11), indicating both permissions are active.
Output:
| event_id | permission_read | permission_write | combined_flags |
|---|---|---|---|
| 101 | 1 | 2 | 3 |
| 102 | 4 | 1 | 5 |
| 103 | 0 | 8 | 8 |
Related articles
- Stages:
alter,config,filter,fields,limit - Functions:
bitwise_and,bitwise_xor,bitwise_sleft,bitwise_sright,to_integer
bitwise_sleft
Use the bitwise_sleft() function to perform a bitwise left shift operation on an integer value by a specified number of positions.
Syntax
bitwise_sleft (<left_clause>, <right_clause>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
left_clause |
integer | Yes | The integer value or field whose bits are to be shifted left. |
right_clause |
integer | Yes | The number of bit positions to shift left. |
Returns
The bitwise_sleft() function returns an integer representing the result of shifting the bits of the first parameter to the left by the number of positions specified in the second parameter.
Usage notes
- The function performs a bitwise left shift (
<<) operation, moving each bit of the value to the left by the specified number of positions. New bits on the right are filled with 0. - Each left shift by 1 position effectively multiplies the value by 2. Shifting left by
npositions multiplies the value by 2^n. - Both parameters must be integers. Passing a string value will result in a validation error.
- This function is useful for constructing bitmask values, scaling values by powers of two, or encoding data into specific bit positions.
- The function is typically used within the
alterorfilterstages to create computed fields or filter events based on bitwise conditions.
Examples
Example 1: Shift a field value left by 1 position
Goal: Double the value of the event_type field by shifting its bits one position to the left.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter doubled_type = bitwise_sleft(event_type, 1) | fields event_id, event_type, doubled_type | limit 3
Explanation: This query shifts the bits of event_type one position to the left, effectively multiplying by 2. For a value of 5 (binary 101), the result is 10 (binary 1010).
Output:
| event_id | event_type | doubled_type |
|---|---|---|
| 101 | 5 | 10 |
| 102 | 3 | 6 |
| 103 | 7 | 14 |
Example 2: Create a bitmask from a bit position
Goal: Convert a bit position number into its corresponding bitmask value by shifting 1 to the left.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter bitmask = bitwise_sleft(1, bit_position) | fields event_id, bit_position, bitmask | limit 3
Explanation: This query creates a bitmask by shifting the value 1 left by the number of positions specified in bit_position. For position 3, the result is 8 (binary 1000). For position 0, the result is 1 (binary 1).
Output:
| event_id | bit_position | bitmask |
|---|---|---|
| 101 | 0 | 1 |
| 102 | 3 | 8 |
| 103 | 7 | 128 |
Example 3: Scale a value by a power of two and filter
Goal: Multiply the action_status field by 256 (2^8) by shifting left 8 positions, then filter for results above a threshold.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter upper_byte = bitwise_sleft(action_status, 8) | filter upper_byte > 512 | fields event_id, action_status, upper_byte | limit 3
Explanation: This query shifts action_status left by 8 positions, multiplying it by 256. For a value of 3, the result is 768. Only results greater than 512 pass the filter.
Output:
| event_id | action_status | upper_byte |
|---|---|---|
| 102 | 3 | 768 |
| 103 | 10 | 2560 |
| 105 | 5 | 1280 |
Related articles
- Stages:
alter,config,filter,fields,limit - Functions:
bitwise_sright,bitwise_and,bitwise_or,bitwise_xor,to_integer
bitwise_sright
Use the bitwise_sright() function to perform a bitwise right shift operation on an integer value by a specified number of positions.
Syntax
bitwise_sright (<left_clause>, <right_clause>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
left_clause |
integer | Yes | The integer value or field whose bits are to be shifted right. |
right_clause |
integer | Yes | The number of bit positions to shift right. |
Returns
The bitwise_sright() function returns an integer representing the result of shifting the bits of the first parameter to the right by the number of positions specified in the second parameter.
Usage notes
- The function performs a bitwise right shift (
>>) operation, moving each bit of the value to the right by the specified number of positions. Bits shifted beyond the least significant position are discarded. - Each right shift by 1 position effectively performs integer division by 2. Shifting right by
npositions divides the value by 2^n (discarding any remainder). - Both parameters must be integers. Passing a string value will result in a validation error.
- This function is useful for extracting values from specific bit positions within a packed integer, or for dividing by powers of two.
- The function is typically used within the
alterorfilterstages to create computed fields or filter events based on bitwise conditions.
Examples
Example 1: Shift a field value right by 1 position
Goal: Halve the value of the event_type field by shifting its bits one position to the right.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter halved_type = bitwise_sright(event_type, 1) | fields event_id, event_type, halved_type | limit 3
Explanation: This query shifts the bits of event_type one position to the right, effectively performing integer division by 2. For a value of 7 (binary 111), the result is 3 (binary 11).
Output:
| event_id | event_type | halved_type |
|---|---|---|
| 101 | 7 | 3 |
| 102 | 10 | 5 |
| 103 | 4 | 2 |
Example 2: Extract the upper byte from a 16-bit value
Goal: Extract the upper 8 bits from a 16-bit integer field by shifting right 8 positions.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter upper_byte = bitwise_sright(action_status, 8) | fields event_id, action_status, upper_byte | limit 3
Explanation: This query shifts action_status right by 8 positions, extracting the upper byte. For a value of 512 (binary 0000001000000000), the result is 2. For 1024, the result is 4.
Output:
| event_id | action_status | upper_byte |
|---|---|---|
| 101 | 512 | 2 |
| 102 | 1024 | 4 |
| 103 | 256 | 1 |
Example 3: Check a specific bit by shifting and masking
Goal: Determine whether bit 4 is set in the event_type field by shifting right 4 positions and checking the least significant bit with bitwise_and().
XQL code:
config timeframe = 1d | dataset = xdr_data | alter bit4_value = bitwise_and(bitwise_sright(event_type, 4), 1) | fields event_id, event_type, bit4_value | limit 3
Explanation: This query first shifts event_type right by 4 positions, then uses bitwise_and() with 1 to isolate the least significant bit. If bit 4 was set in the original value, the result is 1; otherwise, it is 0. For a value of 16 (binary 10000), the result is 1.
Output:
| event_id | event_type | bit4_value |
|---|---|---|
| 101 | 16 | 1 |
| 102 | 7 | 0 |
| 103 | 31 | 1 |
Related articles
- Stages:
alter,config,filter,fields,limit - Functions:
bitwise_sleft,bitwise_and,bitwise_or,bitwise_xor,to_integer
bitwise_xor
Use the bitwise_xor() function to perform a bitwise exclusive OR (XOR) operation between two integer values.
Syntax
bitwise_xor (<left_clause>, <right_clause>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
left_clause |
integer | Yes | The first integer value or field on which to perform the bitwise XOR. |
right_clause |
integer | Yes | The second integer value or field to XOR against the first value. |
Returns
The bitwise_xor() function returns an integer representing the result of the bitwise exclusive OR operation between the two input parameters.
Usage notes
- The function performs a bitwise XOR (
^) operation, comparing each bit of the first operand to the corresponding bit of the second operand. If the bits are different, the corresponding result bit is set to 1; if the bits are the same, it is set to 0. - Both parameters must be integers. Passing a string value will result in a validation error.
- This function is commonly used to toggle specific bit flags, detect differences between two bitmask fields, or perform simple obfuscation.
- The XOR operation is its own inverse: applying
bitwise_xor()twice with the same value returns the original value (for example,bitwise_xor(bitwise_xor(a, b), b)equalsa). - The function is typically used within the
alterorfilterstages to create computed fields or filter events based on bitwise conditions.
Examples
Example 1: Toggle a specific bit flag in an integer field
Goal: Toggle bit 2 (value 4) in the event_type field. If the bit is set, it will be cleared; if it is cleared, it will be set.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter toggled_type = bitwise_xor(event_type, 4) | fields event_id, event_type, toggled_type | limit 3
Explanation: This query performs a bitwise XOR between event_type and 4 (binary 100). For a value of 7 (binary 111), bit 2 is cleared, resulting in 3 (binary 011). For a value of 3 (binary 011), bit 2 is set, resulting in 7 (binary 111).
Output:
| event_id | event_type | toggled_type |
|---|---|---|
| 101 | 7 | 3 |
| 102 | 3 | 7 |
| 103 | 5 | 1 |
Example 2: Detect differences between two bitmask fields
Goal: Identify which bits differ between two integer fields by computing their XOR.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter diff_bits = bitwise_xor(permission_before, permission_after) | fields event_id, permission_before, permission_after, diff_bits | limit 3
Explanation: This query computes the XOR of permission_before and permission_after. The result contains 1-bits only in positions where the two fields differ. For values 7 (binary 111) and 5 (binary 101), the result is 2 (binary 010), indicating bit 1 changed.
Output:
| event_id | permission_before | permission_after | diff_bits |
|---|---|---|---|
| 101 | 7 | 5 | 2 |
| 102 | 3 | 3 | 0 |
| 103 | 12 | 9 | 5 |
Example 3: Filter events where specific bits changed
Goal: Filter for events where at least one of the lower 4 bits changed between two status fields.
XQL code:
config timeframe = 1d | dataset = xdr_data | alter changed_bits = bitwise_and(bitwise_xor(status_before, status_after), 15) | filter changed_bits > 0 | fields event_id, status_before, status_after, changed_bits | limit 3
Explanation: This query first computes the XOR of status_before and status_after to find all differing bits, then uses bitwise_and() with 15 (binary 1111) to isolate the lower 4 bits. Only events where at least one of the lower 4 bits changed pass the filter.
Output:
| event_id | status_before | status_after | changed_bits |
|---|---|---|---|
| 101 | 7 | 5 | 2 |
| 103 | 12 | 9 | 5 |
| 106 | 15 | 0 | 15 |
Related articles
- Stages:
alter,config,filter,fields,limit - Functions:
bitwise_and,bitwise_or,bitwise_sleft,bitwise_sright,to_integer
cbrt
Use the cbrt() function to calculate the cube root of a numeric value.
Syntax
cbrt(<number>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The numeric value for which to calculate the cube root. Any real number is valid, including negative numbers. |
Returns
Type: float
Description: The cbrt() function returns the cube root of the input value. If the input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The
cbrt()function accepts any real number, including negative numbers and zero. - Null Handling: If the input expression is
null, the function returnsnull. - Negative Numbers: Unlike square root (
sqrt()), the cube root of a negative number is a valid real number. For example,cbrt(-8)returns-2.0. - Identity Values:
cbrt(0)returns0.0,cbrt(1)returns1.0, andcbrt(-1)returns-1.0. - Common Use Cases: This function is typically used within the
alterstage for mathematical transformations, volume calculations, and data normalization.
Examples
Example 1: Calculate cube root of literal values
Goal: Calculate the cube root for specific numeric literals to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = cbrt(8), result2 = cbrt(27), result3 = cbrt(-8) | fields result1, result2, result3
Explanation: You use cbrt() on three different literal values. cbrt(8) returns 2.0, cbrt(27) returns 3.0, and cbrt(-8) returns -2.0, demonstrating that the function handles negative inputs correctly.
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 2.0 | 3.0 | -2.0 |
Example 2: Calculate cube root from a field value
Goal: Calculate the cube root of values stored in a dataset field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter cube_root_val = cbrt(numeric_value) | fields event_id, numeric_value, cube_root_val | limit 3
Explanation: This query computes the cube root for each value in the numeric_value field using cbrt() in the alter stage and stores the result in cube_root_val. No filtering is needed since cbrt() accepts any real number.
Output:
| EVENT_ID | NUMERIC_VALUE | CUBE_ROOT_VAL |
|---|---|---|
| 101 | 125.0 | 5.0 |
| 102 | -27.0 | -3.0 |
| 103 | 1000.0 | 10.0 |
Example 3: Combine cube root with other operations
Goal: Use the cube root function as part of a larger mathematical expression.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter volume = multiply(numeric_value, multiply(numeric_value, numeric_value)) | alter side_length = cbrt(volume) | fields event_id, numeric_value, volume, side_length | limit 3
Explanation: This query first cubes the numeric_value to simulate a volume, then applies cbrt() to recover the original side length. The result in side_length should match the original numeric_value, demonstrating that cbrt() is the inverse of cubing.
Output:
| EVENT_ID | NUMERIC_VALUE | VOLUME | SIDE_LENGTH |
|---|---|---|---|
| 101 | 3.0 | 27.0 | 3.0 |
| 102 | 5.0 | 125.0 | 5.0 |
| 103 | 10.0 | 1000.0 | 10.0 |
Related articles
ceil
Use the ceil() function to convert a field containing a number and return an integer rounded up to the nearest whole number.
Syntax
ceil (<number>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The numeric value to round up. |
Returns
The ceil() function returns an integer representing the input number rounded up to the nearest whole number.
Usage notes
- The function accepts a field that contains a number, meaning it can take integers or floating-point numbers as input.
- The function explicitly rounds the number up to the nearest whole integer.
- For positive numbers, this behavior rounds up past the decimal part (for example, 1.1 becomes 2).
- For negative numbers, it rounds toward zero (for example, -2.5 becomes -2).
Examples
Example 1: Round up positive floating-point field
Goal: Round the duration_seconds field up to the nearest integer.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter ceiled_duration = ceil(duration_seconds) | fields event_id, duration_seconds, ceiled_duration | limit 3
Explanation: This query creates a new field, ceiled_duration, by taking the duration_seconds (for example, 1.5, 0.8) and rounding it up. For 1.5, it becomes 2; for 0.8, it becomes 1.
Output:
| EVENT_ID | DURATION_SECONDS | CEILED_DURATION |
|---|---|---|
| 101 | 1.5 | 2 |
| 102 | 0.8 | 1 |
| 103 | 10.2 | 11 |
Example 2: Round up calculated floating-point value
Goal: Round the result of a division operation on an integer field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter divided_event_id = divide(event_id, 3) | alter ceiled_divided_id = ceil(divided_event_id) | fields event_id, divided_event_id, ceiled_divided_id | limit 3
Explanation: Here, event_id (for example, 101) is divided by 3, resulting in 33.666.... The ceil() function then rounds this up to 34.
Output:
| EVENT_ID | DIVIDED_EVENT_ID | CEILED_DIVIDED_ID |
|---|---|---|
| 101 | 33.666666 | 34 |
| 102 | 34.0 | 34 |
| 103 | 34.333333 | 35 |
Example 3: Round up negative number
Goal: Round a negative floating-point number to demonstrate rounding towards zero.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter negative_value = subtract(0, duration_seconds) | alter ceiled_negative = ceil(negative_value) | fields event_id, duration_seconds, negative_value, ceiled_negative | limit 3
Explanation: This query negates the duration_seconds field and then applies ceil(). For a negative value like -1.5, ceil() rounds toward zero, resulting in -1. For -0.8, it becomes 0.
Output:
| EVENT_ID | DURATION_SECONDS | NEGATIVE_VALUE | CEILED_NEGATIVE |
|---|---|---|---|
| 101 | 1.5 | -1.5 | -1 |
| 102 | 0.8 | -0.8 | 0 |
| 103 | 10.2 | -10.2 | -10 |
Example 4: Round up number extracted from JSON
Goal: Round a numeric value extracted from a JSON field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 110 | alter json_size_string = simple_json_data -> size_gb | alter json_size_number = to_number(json_size_string) | alter ceiled_json_size = ceil(json_size_number) | fields event_id, simple_json_data, json_size_number, ceiled_json_size | limit 1
Explanation: This query extracts the size_gb value from the simple_json_data field (for example, "500" for event_id 110). The query then converts this string to a number and applies ceil(), which for an integer like 500 would result in 500.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | JSON_SIZE_NUMBER | CEILED_JSON_SIZE |
|---|---|---|---|
| 110 | {"backup_id": "DB-005", "size_gb": 500} | 500 | 500 |
Related articles
coalesce
Use the coalesce() function to return the first non-NULL value from a defined list of input fields or expressions.
Syntax
coalesce (<field_1>, <field_2>, ...<field_n>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field_n |
Any | Yes | An arbitrary number of fields or expressions. The function evaluates them from left to right. |
Returns
The coalesce() function returns a single value whose data type matches the first non-NULL argument it encounters. If all arguments are NULL, the function returns NULL.
Usage notes
- Arguments are evaluated strictly from left to right. When a non-NULL value is found, the evaluation stops, and that value is returned.
- This function is valuable for ensuring data completeness and providing fall-back mechanisms, allowing you to define a prioritized list of data sources for a single field.
Examples
Example 1: Coalescing literal values of different types
Goal: Demonstrate the core "first non-NULL" behavior by providing various literal values, including NULLs, of different data types.
XQL code:
config timeframe = 1d // Sets the query timeframe | dataset = sample_xql_raw // Specifies the dataset to use | alter chosen_value_str = coalesce(NULL, "Fallback String", "Another Option") // First non-NULL string | alter chosen_value_int = coalesce(NULL, 123, NULL, 456) // First non-NULL integer | alter chosen_value_bool = coalesce(false, NULL, true) // First non-NULL boolean | fields event_id, chosen_value_str, chosen_value_int, chosen_value_bool | limit 3
Explanation: For chosen_value_str, coalesce() skips NULL and returns "Fallback String". For chosen_value_int, it returns 123. For chosen_value_bool, it returns false. This demonstrates the function's ability to handle various data types and select the first available non-NULL literal.
Output:
| EVENT_ID | CHOSEN_VALUE_STR | CHOSEN_VALUE_INT | CHOSEN_VALUE_BOOL |
|---|---|---|---|
| 101 | Fallback String | 123 | false |
| 102 | Fallback String | 123 | false |
| 103 | Fallback String | 123 | false |
Example 2: Coalescing existing fields
Goal: Use coalesce() with existing fields, specifically leveraging a field that can be NULL (dst_domain) and one that is always present (event_description) as a fallback.
XQL code:
config timeframe = 1d // Sets the query timeframe | dataset = sample_xql_raw // Specifies the dataset to use // dst_domain is NULL for event_id 105, event_description is always present | alter primary_or_fallback_description = coalesce(dst_domain, event_description) | fields event_id, dst_domain, event_description, primary_or_fallback_description | limit 5
Explanation: For events where dst_domain is not NULL (for example, event 101-104), coalesce() returns the dst_domain. For event 105, where dst_domain is NULL, coalesce() falls back to event_description, providing "Data transformation".
Output:
| EVENT_ID | DST_DOMAIN | EVENT_DESCRIPTION | PRIMARY_OR_FALLBACK_DESCRIPTION |
|---|---|---|---|
| 101 | ec2.amazonaws.com | User login successful | ec2.amazonaws.com |
| 102 | sts.amazonaws.com | File access attempt | sts.amazonaws.com |
| 103 | www.google.com | Network connection established | www.google.com |
| 104 | dropbox.com | System heartbeat | dropbox.com |
| 105 | NULL | Data transformation | Data transformation |
Example 3: Coalescing multiple JSON paths for a single concept
Goal: Handle variations in JSON data where different keys might represent the same logical piece of information (for example, status code under code or error).
XQL code:
config timeframe = 1d // Sets the query timeframe | dataset = sample_xql_raw // Specifies the dataset to use // Extract 'code' or 'error' from JSON, using the first available | alter status_code = coalesce(simple_json_data -> code, simple_json_data -> error) | fields event_id, simple_json_data, status_code | limit 3
Explanation: For event 101, code (200) is found first. For event 102, code is not present, so error ("access_denied") is returned. For event 103, neither code nor error_code exists, resulting in NULL.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | STATUS_CODE |
|---|---|---|
| 101 | {"status": "ok", "code": 200} | 200 |
| 102 | {"status": "fail", "error": "access_denied"} | access_denied |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL |
Example 4: Coalescing complex nested JSON paths for a unified identifier
Goal: Extract a "principal name" from multiple possible nested JSON paths within the nested_json_data field, such as user.name, process.name, client.id, or db.name.
XQL code:
config timeframe = 1d // Sets the query timeframe | dataset = sample_xql_raw // Specifies the dataset to use | filter event_id in(101, 102, 108, 109, 110) // Attempt to find a 'principal_name' from various nested JSON paths | alter principal_name = coalesce( nested_json_data -> user.name, nested_json_data -> process.name, nested_json_data -> client.id, nested_json_data -> db.name ) | fields event_id, nested_json_data, principal_name | limit 5
Explanation: For event 101, user.name ("Alice") is found first. For event 102, user.name is missing, but process.name ("cmd.exe") is present. For event 108, none of the specified paths exist, resulting in NULL. For event 109, client.id ("C2") is found. For event 110, db.name ("prod_db") is found.
Output:
| EVENT_ID | NESTED_JSON_DATA | PRINCIPAL_NAME |
|---|---|---|
| 101 | {"user": {"id": "U1", "name": "Alice"}, "session": {"start": "10:00", "type": "web"}} | Alice |
| 102 | {"process": {"name": "cmd.exe", "pid": 1234}, "target": {"path": "/var/log", "permission": "rwx"}} | cmd.exe |
| 108 | {"system":{"hostname":"webserver01","os":"Linux"},"patch":{"version":"1.2.3"}} | NULL |
| 109 | {"client":{"id":"C2","api_key":"xyz"},"request":{"endpoint":"/data","rate":100}} | C2 |
| 110 | {"db":{"name":"prod_db","type":"SQL"},"storage":{"location":"S3","cost_usd":15}} | prod_db |
Example 5: Selecting the first non-null username from multiple fields
Goal: Evaluate three different username fields (actor_primary_username, os_actor_primary_username, and causality_actor_primary_username) and return the first available (non-null) value to populate a single username column.
XQL code:
|dataset = sample_xql_raw | fields actor_primary_username, os_actor_primary_username, causality_actor_primary_username | alter username = coalesce(actor_primary_username, os_actor_primary_username, causality_actor_primary_username)
Explanation: The coalesce() function checks the provided arguments in order from left to right. The function returns the value of the first field that is not null. If actor_primary_username is null, it checks os_actor_primary_username, and so on. This is a common technique for normalizing data when the same information might be stored in different fields depending on the event source.
Output:
| actor_primary_username | os_actor_primary_username | causality_actor_primary_username | username |
|---|---|---|---|
| null | "admin_user" | "system" | "admin_user" |
| "jsmith" | "jsmith_os" | null | "jsmith" |
| null | null | "root" | "root" |
| null | null | null | null |
Related articles
concat
Use the concat() function to join two or more strings into a single, cohesive string.
Syntax
concat (<string1>, <string2>, ...)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string1, string2, ... |
string | Yes | The string expressions whose values will be joined. Two or more strings are required. |
Returns
The concat() function returns a single string.
Usage notes
- The function strictly accepts string parameters.
- The
concat()function will not perform any implicit conversion of other data types to strings. - Explicit
to_string()conversion is necessary for non-string values (such as integers, floats, or booleans) to ensure type compatibility. - If any of the values passed to
concat()areNULL, the function will returnNULL.
Examples
Example 1: Concatenating two string literal values
Goal: Join two static string values into a new field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter static_message = concat("Investigation: ", "Started") | fields event_id, static_message | limit 3
Explanation: For each record, the concat() function combines the two literal strings "Investigation: " and "Started", resulting in the value "Investigation: Started" for all records.
Output:
| EVENT_ID | STATIC_MESSAGE |
|---|---|
| 101 | "Investigation: Started" |
| 102 | "Investigation: Started" |
| 103 | "Investigation: Started" |
Example 2: Concatenating a string literal with a field value
Goal: Join a fixed string prefix with the value of an existing field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_label = concat("Event ID: ", to_string(event_id)) | fields event_id, event_label | limit 3
Explanation: The to_string(event_id) function converts the numeric event_id into its string representation. concat() then joins the literal string "Event ID: " with the string version of the event_id, creating a unique event_label for each record.
Output:
| EVENT_ID | EVENT_LABEL |
|---|---|
| 101 | "Event ID: 101" |
| 102 | "Event ID: 102" |
| 103 | "Event ID: 103" |
Example 3: Concatenating multiple field values
Goal: Combine values from multiple existing fields into a single string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_summary = concat(event_description, " (Success: ", to_string(is_successful), ", Duration: ", to_string(duration_seconds), ")") | fields event_id, event_description, is_successful, duration_seconds, event_summary | limit 3
Explanation: The functions to_string(is_successful) and to_string(duration_seconds) convert the boolean and numeric fields into strings. concat() then combines event_description, literal strings like " (Success: ", and the converted string representations into event_summary.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL | DURATION_SECONDS | EVENT_SUMMARY |
|---|---|---|---|---|
| 101 | "User login successful" | true | 1.5 | "User login successful (Success: true, Duration: 1.5)" |
| 102 | "File access attempt" | false | 0.8 | "File access attempt (Success: false, Duration: 0.8)" |
| 103 | "Network connection established" | true | 10.2 | "Network connection established (Success: true, Duration: 10.2)" |
Example 4: Concatenating extracted JSON scalar values
Goal: Use concat() with values extracted from a JSON field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter status_code_value = coalesce(simple_json_data -> code, simple_json_data -> error_code) | alter full_status_message = concat("Status: ", status_code_value) | fields event_id, simple_json_data, status_code_value, full_status_message | limit 3
Explanation: The coalesce function attempts to get either code or error_code from simple_json_data as a string. concat() combines "Status: " with the extracted status_code_value. Because concat() returns NULL if any input is NULL, full_status_message is NULL for event 103 where neither key exists.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | STATUS_CODE_VALUE | FULL_STATUS_MESSAGE |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | "200" | "Status: 200" |
| 102 | {"status": "fail", "error": "access_denied"} | "access_denied" | "Status: access_denied" |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL | NULL |
Example 5: Concatenating converted boot time values
Goal: Use concat() to prepend a string prefix to a converted timestamp field.
XQL code:
dataset = xdr_data | fields action_boot_time as abt | filter abt != null | alter abt_string = concat("str: ", to_string(abt)) | limit 1
Explanation: The query filters the xdr_data dataset to find the first record where action_boot_time is not NULL. Since action_boot_time is typically a numeric or timestamp type, the to_string() function is used to convert it before the concat() function joins it with the literal prefix "str: ".
Output:
| ABT | ABT_STRING |
|---|---|
| 1675238400 | "str: 1675238400" |
Related articles
convert_from_base_64
Use the convert_from_base_64() function to decode a base64-encoded input string and return it in its original, decoded string format.
Syntax
convert_from_base_64 ("<base64-encoded input>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
encoded_string |
string | Yes | The base64-encoded string to decode. |
Returns
The convert_from_base_64() function returns the decoded value as a string.
Usage notes
- The function requires a single string input that is base64-encoded.
- The function consistently returns the decoded value as a string.
- The function is typically employed within the
alterstage to create new fields or modify existing ones by decoding string data. - The function can also be used within a
filterstage if the decoding result is needed for a conditional check.
Examples
Example 1: Decoding a basic literal base64 string
Goal: Decode a common base64 string that represents "Hello world".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter decoded_string = convert_from_base_64("SGVsbG8gd29ybGQ=") | fields event_id, decoded_string | limit 3
Explanation: This query adds a new field, decoded_string, which contains the plain text "Hello world" after decoding the provided base64 literal.
Output:
| EVENT_ID | DECODED_STRING |
|---|---|
| 101 | "Hello world" |
| 102 | "Hello world" |
| 103 | "Hello world" |
Example 2: Decoding a literal base64 string representing JSON
Goal: Decode a base64 string that, when decoded, forms a JSON object. This shows the ability to handle more complex string content.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter decoded_json_string = convert_from_base_64("eyJsZXZlbCI6ICJpbmZvIiwgIm1lc3NhZ2UiOiAiU3lzdGVtIHN0YXJ0ZWQifQ==") | fields event_id, decoded_json_string | limit 3
Explanation: The query decodes the base64 string, resulting in a JSON-formatted string as the value for decoded_json_string.
Output:
| EVENT_ID | DECODED_JSON_STRING |
|---|---|
| 101 | "{"level": "info", "message": "System started"}" |
| 102 | "{"level": "info", "message": "System started"}" |
| 103 | "{"level": "info", "message": "System started"}" |
Example 3: Handling an invalid base64 input
Goal: Illustrate the function's behavior when provided with a string that is not a valid base64 encoding.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter invalid_decode_attempt = convert_from_base_64("NotABase64String!") | fields event_id, invalid_decode_attempt | limit 3
Explanation: When the input string is not a valid base64 format, the convert_from_base_64() function still attempts to return the decoded string.
Output:
| EVENT_ID | INVALID_DECODE_ATTEMPT |
|---|---|
| 101 | "6@\u0005\u001e넭)" |
| 102 | "6@\u0005\u001e넭)" |
| 103 | "6@\u0005\u001e넭)" |
Example 4: Decoding an empty base64 string
Goal: Show the result of decoding an empty base64 string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter decoded_empty_string = convert_from_base_64("") | fields event_id, decoded_empty_string | limit 3
Explanation: Decoding an empty base64 string results in an empty string.
Output:
| EVENT_ID | DECODED_EMPTY_STRING |
|---|---|
| 101 | "" |
| 102 | "" |
| 103 | "" |
Related articles
- Stages:
alter,config,fields,limit - Functions:
convert_to_base_64
convert_to_base_64
Use the convert_to_base_64() function to encode an input string into its base64 representation.
Syntax
convert_to_base_64 ("<input_string>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
input_string |
string | Yes | The string to be base64 encoded. |
Returns
The convert_to_base_64() function returns the base64-encoded value as a string.
Usage notes
- The function requires a single string input.
- The function will return
NULLif the input isNULL. - This function is typically employed within the
alterstage to create new fields or modify existing ones by encoding string data. - The function can also be used within a
filterstage if the encoding result is needed for a conditional check.
Examples
Example 1: Encoding a basic literal string
Goal: Encode a simple literal string to its base64 representation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter encoded_string = convert_to_base_64("Hello world") | fields event_id, encoded_string | limit 3
Explanation: This query adds a new field, encoded_string, which contains the base64-encoded representation of "Hello world".
Output:
| EVENT_ID | ENCODED_STRING |
|---|---|
| 101 | SGVsbG8gd29ybGQ= |
| 102 | SGVsbG8gd29ybGQ= |
| 103 | SGVsbG8gd29ybGQ= |
Example 2: Encoding an existing string field
Goal: Encode values from an existing string field in the dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter encoded_description = convert_to_base_64(event_description) | fields event_id, event_description, encoded_description | limit 3
Explanation: The query creates encoded_description by applying base64 encoding to the event_description field for each record.
Output:
| EVENT_ID | EVENT_DESCRIPTION | ENCODED_DESCRIPTION |
|---|---|---|
| 101 | User login successful | VXNlciBsb2dpbiBzdWNjZXNzZnVs |
| 102 | File access attempt | RmlsZSBhY2Nlc3MgYXR0ZW1wdA== |
| 103 | Network connection established | TmV0d29yayBjb25uZWN0aW9uIGVzdGFibGlzaGVk |
Example 3: Encoding a string derived from a numeric field
Goal: Convert a numeric field to a string and then encode it to base64.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_string = to_string(event_id) | alter encoded_id = convert_to_base_64(event_id_string) | fields event_id, event_id_string, encoded_id | limit 3
Explanation: The event_id is first converted to a string using to_string(), and then convert_to_base_64() encodes this string.
Output:
| EVENT_ID | EVENT_ID_STRING | ENCODED_ID |
|---|---|---|
| 101 | 101 | MTAx |
| 102 | 102 | MTAy |
| 103 | 103 | MTAz |
Example 4: Encoding an empty string
Goal: Encode an empty string to observe the result.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter encoded_empty_string = convert_to_base_64("") | fields event_id, encoded_empty_string | limit 3
Explanation: Encoding an empty string results in an empty string.
Output:
| EVENT_ID | ENCODED_EMPTY_STRING |
|---|---|
| 101 | |
| 102 | |
| 103 |
Example 5: Handling NULL input
Goal: Observe the behavior when a NULL input is provided to the function.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter encoded_null_field = convert_to_base_64(dst_domain) | fields event_id, dst_domain, encoded_null_field | limit 5
Explanation: When the input to convert_to_base_64() is NULL (such as dst_domain for event 105), the function consistently returns NULL for the output field.
Output:
| EVENT_ID | DST_DOMAIN | ENCODED_NULL_FIELD |
|---|---|---|
| 101 | ec2.amazonaws.com | ZWMyLmFtYXpvbmF3cy5jb20= |
| 102 | sts.amazonaws.com | c3RzLmFtYXpvbmF3cy5jb20= |
| 103 | www.google.com | d3d3Lmdvb2dsZS5jb20= |
| 104 | dropbox.com | ZHJvcGJveC5jb20= |
| 105 | NULL | NULL |
Related articles
- Stages:
alter,fields - Functions:
convert_from_base_64,to_string - Datasets:
xdr_data
cos
Use the cos() function to calculate the cosine of a numeric value specified in radians.
Syntax
cos(<numeric_expression>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
numeric_expression |
integer, float | Yes | The angle in radians for which to calculate the cosine. Any real number is valid. |
Returns
Type: float
Description: The cos() function returns the cosine of the input angle. The resulting value is within the range [-1, 1].
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The
cos()function accepts any real number as input. The input is interpreted as an angle in radians. - Null Handling: If the input expression is
null, the function returnsnull. - Degrees to Radians: If your input is in degrees, convert it to radians first by multiplying by
PI() / 180. - Periodicity: The cosine function is periodic with period 2π, meaning
cos(x) = cos(x + 2π). - Key Values:
cos(0)returns1.0,cos(π/2)returns0.0,cos(π)returns-1.0. - Common Use Cases: This function is typically used within the
alterstage for trigonometric calculations, signal processing, coordinate transformations, and distance computations.
Examples
Example 1: Calculate cosine of literal values
Goal: Calculate the cosine for specific radian values to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = cos(0), result2 = cos(pi()), result3 = cos(divide(pi(), 2)) | fields result1, result2, result3
Explanation: You use cos() on three different radian values. cos(0) returns 1.0, cos(π) returns -1.0, and cos(π/2) returns approximately 0.0 (a very small number close to zero due to floating-point precision).
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 1.0 | -1.0 | 0.0 |
Example 2: Calculate cosine from a field value
Goal: Calculate the cosine of values stored in a dataset field, treating them as angles in radians.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter cos_val = cos(numeric_value) | fields event_id, numeric_value, cos_val | limit 3
Explanation: This query computes the cosine for each value in the numeric_value field and stores the result in cos_val. Since cos() accepts any real number, no filtering is needed.
Output:
| EVENT_ID | NUMERIC_VALUE | COS_VAL |
|---|---|---|
| 101 | 0.0 | 1.0 |
| 102 | 1.5708 | 0.0 |
| 103 | 3.14159 | -1.0 |
Example 3: Use cosine in a distance calculation
Goal: Use the cosine function as part of a spherical distance calculation between two points.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter cos_angle = cos(duration_seconds) | alter scaled_cos = multiply(cos_angle, numeric_value) | fields event_id, duration_seconds, cos_angle, numeric_value, scaled_cos | limit 3
Explanation: This query calculates the cosine of duration_seconds (treated as an angle in radians) and then multiplies the result by numeric_value to produce a scaled cosine value, which is a common pattern in coordinate transformations.
Output:
| EVENT_ID | DURATION_SECONDS | COS_ANGLE | NUMERIC_VALUE | SCALED_COS |
|---|---|---|---|---|
| 101 | 0.0 | 1.0 | 5.0 | 5.0 |
| 102 | 1.5708 | 0.0 | 3.0 | 0.0 |
| 103 | 3.14159 | -1.0 | 7.0 | -7.0 |
Related articles
cosine_distance
Use the cosine_distance() function to calculate the cosine distance between two numeric vectors (arrays). The cosine distance measures the dissimilarity between two vectors based on the angle between them.
Syntax
cosine_distance(<vector1>, <vector2>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
vector1 |
array of integers or floats | Yes | The first numeric vector (array). Must have the same length as vector2. |
vector2 |
array of integers or floats | Yes | The second numeric vector (array). Must have the same length as vector1. |
Returns
Type: float
Description: The cosine_distance() function returns a value between 0 and 2, where 0 indicates identical direction, 1 indicates orthogonal (perpendicular) vectors, and 2 indicates opposite directions. If either input is null or the vectors have different lengths, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Vector Length: Both input vectors must have the same number of elements. If they differ in length, the function returns
null. - Vector Type: Only float values are supported for the input vectors.
- Null Handling: If either input expression is
null, the function returnsnull. - Zero Vectors: If either vector is a zero vector (all elements are 0), the result is undefined and may return
NaNornull. - Relationship to Cosine Similarity: Cosine distance = 1 - cosine similarity. A cosine distance of 0 means the vectors are identical in direction (cosine similarity of 1).
- Common Use Cases: This function is typically used within the
alterstage for similarity analysis, text comparison using embedding vectors, anomaly detection, and machine learning feature comparison.
Examples
Example 1: Calculate cosine distance between literal vectors
Goal: Calculate the cosine distance between specific vector pairs to verify known results.
XQL code:
dataset = xdr_data | limit 1 | alter dist1 = cosine_distance(arraycreate(1.0, 0.0, 0.0), arraycreate(1.0, 0.0, 0.0)) | alter dist2 = cosine_distance(arraycreate(1.0, 0.0, 0.0), arraycreate(0.0, 1.0, 0.0)) | fields dist1, dist2
Explanation: cosine_distance of two identical vectors (1.0, 0.0, 0.0) returns 0.0 (no distance). The distance between (1.0, 0.0, 0.0) and (0.0, 1.0, 0.0) returns 1.0 since these vectors are orthogonal (perpendicular).
Output:
| DIST1 | DIST2 |
|---|---|
| 0.0 | 1.0 |
Example 2: Calculate cosine distance between field vectors
Goal: Compute the cosine distance between two array fields in a dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_codes != null | alter reference_vector = arraycreate(1.0, 2.0, 3.0, 4.0, 5.0) | alter cos_dist = cosine_distance(numeric_codes, reference_vector) | fields event_id, numeric_codes, cos_dist | limit 3
Explanation: This query creates a reference vector and computes the cosine distance between each record's numeric_codes array and the reference vector. Lower values indicate the vectors point in a more similar direction.
Output:
| EVENT_ID | NUMERIC_CODES | COS_DIST |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | 0.8523 |
| 102 | [-21, 56, 13, -88, 42] | 1.3241 |
| 103 | [90, -33, 7, 51, -62, 18] | null |
Example 3: Compare similarity of two records
Goal: Use cosine distance to determine how similar two records are based on their numeric arrays.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_codes != null and array_length(numeric_codes) = 5 | alter ref = arraycreate(10.0, 20.0, 30.0, 40.0, 50.0) | alter distance = cosine_distance(numeric_codes, ref) | alter similarity = subtract(1, distance) | fields event_id, numeric_codes, distance, similarity | sort asc distance | limit 3
Explanation: This query computes the cosine distance between each record's numeric_codes and a reference vector, then derives the cosine similarity as 1 - distance. Results are sorted by distance ascending, showing the most similar records first.
Output:
| EVENT_ID | NUMERIC_CODES | DISTANCE | SIMILARITY |
|---|---|---|---|
| 105 | [8, 15, 25, 35, 45] | 0.0123 | 0.9877 |
| 101 | [13, -47, 29, 82, -15] | 0.8523 | 0.1477 |
| 102 | [-21, 56, 13, -88, 42] | 1.3241 | -0.3241 |
Related articles
- Stages:
alter,filter,fields,sort,limit - Functions:
euclidean_distance(),arraycreate(),array_length() - Datasets:
xdr_data
cot
Use the cot() function to calculate the cotangent of a numeric value specified in radians. The cotangent is the reciprocal of the tangent function.
Syntax
cot(<numeric_expression>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
numeric_expression |
integer, float | Yes | The angle in radians for which to calculate the cotangent. The value must not be zero or a multiple of π. |
Returns
Type: float
Description: The cot() function returns the cotangent of the input angle, which is equivalent to cos(x) / sin(x) or 1 / tan(x). If the input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The
cot()function accepts any real number except values wheresin(x) = 0(i.e., multiples of π), where the cotangent is undefined. - Undefined Values: At
x = 0and multiples of π, the function returnsinfinity,NaN, ornullsince the cotangent is undefined at these points. - Null Handling: If the input expression is
null, the function returnsnull. - Relationship:
cot(x) = 1 / tan(x) = cos(x) / sin(x). - Common Use Cases: This function is typically used within the
alterstage for trigonometric calculations, geometric analysis, and engineering computations.
Examples
Example 1: Calculate cotangent of literal values
Goal: Calculate the cotangent for specific radian values to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = cot(divide(pi(), 4)), result2 = cot(divide(pi(), 2)), result3 = cot(1) | fields result1, result2, result3
Explanation: You use cot() on three different radian values. cot(π/4) returns 1.0 (since tan(π/4) = 1), cot(π/2) returns approximately 0.0 (since tan(π/2) approaches infinity), and cot(1) returns approximately 0.6421.
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 1.0 | 0.0 | 0.64209 |
Example 2: Calculate cotangent from a field value
Goal: Calculate the cotangent of values stored in a dataset field, filtering out values near zero.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value != 0 | alter cot_val = cot(numeric_value) | fields event_id, numeric_value, cot_val | limit 3
Explanation: This query filters out zero values (where cotangent is undefined), then computes the cotangent for each remaining value in the numeric_value field.
Output:
| EVENT_ID | NUMERIC_VALUE | COT_VAL |
|---|---|---|
| 101 | 0.5 | 1.83049 |
| 102 | 1.0 | 0.64209 |
| 103 | 2.0 | -0.45766 |
Example 3: Verify cotangent as reciprocal of tangent
Goal: Demonstrate that cot(x) equals 1 / tan(x) by computing both and comparing.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value != 0 | alter cot_val = cot(numeric_value) | alter reciprocal_tan = divide(1, tan(numeric_value)) | fields event_id, numeric_value, cot_val, reciprocal_tan | limit 3
Explanation: This query computes both cot(numeric_value) and 1 / tan(numeric_value) to verify they produce the same result, confirming the mathematical identity cot(x) = 1 / tan(x).
Output:
| EVENT_ID | NUMERIC_VALUE | COT_VAL | RECIPROCAL_TAN |
|---|---|---|---|
| 101 | 0.5 | 1.83049 | 1.83049 |
| 102 | 1.0 | 0.64209 | 0.64209 |
| 103 | 2.0 | -0.45766 | -0.45766 |
Related articles
count_distinct
Use the count_distinct() function within a comp stage to calculate and return a single count representing the number of unique values found for a specified field over a group of rows.
Syntax
SQL
| comp count_distinct() [as ] [by [,...]] [addrawdata = true | false [as ]] |
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | string, integer, float, boolean | Yes | The field for which you want to count the number of unique values. |
| alias | string | No | The alias name for the output column, assigned using the as clause. |
| field1, field2 | string, integer, float, boolean | No | The field(s) used to partition the data into distinct groups via the by clause. |
| addrawdata | boolean | No | When set to true, introduces a raw data column into the output that lists the raw data events contributing to the aggregate result. |
| target field | string | No | The alias name for the raw data column when addrawdata is set to true. |
Returns
The count_distinct() function returns a single numerical count value representing the number of unique values found for the specified field.
Usage Notes
- Use count_distinct() to retrieve the number of unique values in the result set, whereas the count() function retrieves the total number of values.
- The comp stage must always precede an aggregate or approximate aggregate function like count_distinct().
- New columns generated by the comp stage (including the distinct count itself) are typically appended as the last columns in the result set.
- Any other fields not explicitly included in the by clause or as part of a calculated column will be removed from the result set, including all system fields like _time.
- When addrawdata is set to true, the query processes up to 50 defined fields and displays up to 100 events.
Examples
Example 1: Counting Unique Values of a Specific Field Across the Entire Dataset (No Grouping)
Goal: Calculate the total number of unique event_description values in the sample_xql_raw dataset.
XQL Code:
SQL
config timeframe = 1d\
| dataset = sample_xql_raw\
| comp count_distinct(event_description) as unique_event_descriptions\
| limit 1
Explanation: This query computes the number of unique event_description values present in the sample_xql_raw dataset and names the resulting field unique_event_descriptions. Since all event_description values in sample_xql_raw are distinct, the count will be the total number of events.
Output:
| unique_event_descriptions |
|---|
| 10 |
**Example 2: Counting Unique Values of a Specific Field, Grouped by Another Field
Goal: Calculate the number of unique event_description values separately for successful (true) and unsuccessful (false) events.
XQL Code:
SQL
config timeframe = 1d\
| dataset = sample_xql_raw\
| comp count_distinct(event_description) as unique_descriptions_by_status by is_successful\
| limit 3
Explanation: The query groups records by their is_successful status and then counts the unique event_description values for each group, presenting the counts in the unique_descriptions_by_status field. As all event_description values in sample_xql_raw are unique, this effectively counts the number of events in each is_successful group.
Output:
| is_successful | unique_descriptions_by_status |
|---|---|
| true | 7 |
| false | 3 |
Example 3: Counting Unique Values of a Derived Field (JSON Extraction and Conversion)
Goal: Calculate the count of unique numerical values (derived from code or error_code fields within simple_json_data) after extraction and conversion.
XQL Code:
SQL
config timeframe = 1d\
| dataset = sample_xql_raw\
| alter json_code_number = to_number(coalesce(simple_json_data -> code, simple_json_data -> error_code))\
| comp count_distinct(json_code_number) as unique_codes_count\
| limit 1
Explanation: This query first extracts a numerical code or error_code from simple_json_data using syntactic sugar and coalesce(). to_number() converts the extracted string to a numerical type. Then, count_distinct() counts how many unique numerical codes were found across the dataset. Based on sample_xql_raw, event ID 101 has code 200, and event ID 109 has error_code 429, resulting in 2 unique values.
Output:
| unique_codes_count |
|---|
| 2 |
Example 4: Counting Unique Numerical Values from an Array Element
Goal: Count the number of unique first elements from the numeric_codes array.
XQL Code:
SQL
config timeframe = 1d\
| dataset = sample_xql_raw\
| alter first_numeric_val = arrayindex(numeric_codes, 0)\
| comp count_distinct(first_numeric_val) as unique_first_numeric_values\
| limit 1
Explanation: This query uses arrayindex() to access the first numeric code from the numeric_codes array for each record. The count_distinct() function then calculates the number of unique non-null values found among these extracted first elements.
Output:
| unique_first_numeric_values |
|---|
| 9 |
Example 5: Counting Unique Values with Raw Data Inclusion (addrawdata=true)
Goal: Include the raw events that contribute to each unique count using the addrawdata = true option.
XQL Code:
SQL
config timeframe = 1d\
| dataset = sample_xql_raw\
| comp count_distinct(event_id) as distinct_ids by is_successful addrawdata = true as raw_events_for_distinct_count\
| limit 3
Explanation: This query calculates the unique count of event_id values grouped by is_successful. Additionally, addrawdata = true generates a new column named raw_events_for_distinct_count, which contains a JSON representation of the raw events that contributed to each computed distinct count.
Output:
| distinct_ids | is_successful | raw_events_for_distinct_count |
|---|---|---|
| 7 | true | JSON representation of raw data for 7 unique events (truncated) |
| 3 | false | JSON representation of raw data for 3 unique events (truncated) |
Related Articles
- Stages: comp, alter
- Functions: count(), approx_count()
count (comp)
Use the count() function within a comp stage to calculate and return the number of non-null values found for a specified field, or the total number of rows if no field is specified, over a group of rows.
Syntax
comp count([ <field>]) [as <alias>] [by <field1>[,<field2>...]] [addrawdata = true|false [as <target field>]]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | string, integer, float, boolean | No | The field to count non-null values for. |
| alias | string | No | The alias name of the field, using the as clause. |
| field1, field2 | string, integer, float, boolean | No | The fields used to group rows in the by clause. |
| addrawdata | boolean | No | When set to true, introduces a raw_data column into the output, listing the raw data events that contributed to the aggregate result. |
| target field | string | No | The alias name for the raw data column when addrawdata is set to true. |
Returns
The count() function returns a single count value representing the number of rows or non-null values.
Usage Notes
- When a field is provided, it exclusively counts non-null values.
- Without a specified field, it calculates and returns the total number of rows, including those with null values.
- The comp stage or the windowcomp stage must always precede count().
- New columns generated by the comp stage (including the count itself) are typically appended as the last columns in the result set.
- Any other fields not explicitly included in the by clause or as part of a calculated column will be removed from the result set, including all system fields.
- When addrawdata is true, the query processes up to 50 defined fields and displays up to 100 events.
Examples
Example 1: Counting all rows across the entire dataset (no field specified)
Goal: Compute the total number of records in the sample_xql_raw dataset, including any with null values, without applying any grouping.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp count() as total_events
Explanation: This query computes the total number of rows in the sample_xql_raw dataset and names the resulting field total_events. Because no field is specified in count(), it includes all rows.
Output:
| total_events |
|---|
| 10 |
Example 2: Counting non-null values of a specific field across the entire dataset (field specified)
Goal: Count the number of records where the event_description field is not null, across the entire dataset.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp count(event_description) as non_null_descriptions
Explanation: The query calculates the count of records that have a non-null event_description value in the sample_xql_raw dataset.
Output:
| non_null_descriptions |
|---|
| 10 |
Example 3: Counting non-null values of a specific field, grouped by another field
Goal: Calculate the count of event_id occurrences separately for successful (true) and unsuccessful (false) events.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp count(event_id) as events_by_status by is_successful
Explanation: The query groups records by their is_successful status and then counts the non-null event_id for each group, presenting the counts in the events_by_status field.
Output:
| is_successful | events_by_status |
|---|---|
| true | 7 |
| false | 3 |
Example 4: Counting a value extracted and converted from JSON data
Goal: Calculate the count of records where a numerical value (from code or error_code) is successfully extracted from a JSON field (simple_json_data) and converted to a number.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | alter json_code_number = to_number(coalesce(simple_json_data \-> code, simple_json_data \-> error_code) | comp count(json_code_number) as count_of_codes | limit 1
Explanation: This query first attempts to extract either the code or error_code from the simple_json_data field using json_extract_scalar(), with coalesce() handling potential nulls. to_number() then converts these to a numerical type. Finally, count() computes the number of these converted numerical values, automatically excluding records where the extraction resulted in a null value.
Output:
| count_of_codes |
|---|
| 2 |
Example 5: Counting a numerical value from an array element
Goal: Count events where a specific numeric element from an array field (numeric_codes) exists and is not null.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_numeric_val = arrayindex(numeric_codes, 0) | comp count(first_numeric_val) as count_first_numeric_code | limit 1
Explanation: This query uses arrayindex() to access the first numeric code from the numeric_codes array for each record. The count() function then calculates the number of records where this extracted value is not null, excluding records where the array is empty (like event ID 104) or the first element is null.
Output:
| count_first_numeric_code |
|---|
| 9 |
Example 6: Counting with raw data inclusion (addrawdata=true)
Goal: Include the raw events that contribute to each count by using the addrawdata = true option.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp count(event_id) by is_successful addrawdata = true as raw_events_for_count | limit 3
Explanation: Similar to Variant 3, this query calculates the count of event_id grouped by is_successful. Additionally, addrawdata = true generates a new column named raw_events_for_count, which contains a JSON representation of the raw events that contributed to each computed count.
Output:
| is_successful | raw_events_for_count |
|---|---|
| true | JSON representation of raw data for 7 events (truncated) |
| false | JSON representation of raw data for 3 events (truncated) |
Related Articles
- Stages: comp, alter
- Functions: count_distinct(), approx_count()
count (windowcomp)
Use the count() function within a windowcomp stage to calculate and return a single count value over a defined window or group of rows, presenting the result for each row within that window frame. The function can operate by counting non-null values for a specified field, or by counting the total number of rows within the window when no field is specified.
Syntax
windowcomp count([<field>]) [by <field> [,<field>,...]] [sort [asc|desc] <field1> [, [asc|desc] <field2>,...]] [between 0|null|<number>|-<number> [and 0|null|<number>|-<number>] [frame_type=range]] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | string, integer, float, boolean | No | The field to count non-null values for. If omitted, the function counts all rows including those with null values. |
| by field | string, integer, float, boolean | No | The field(s) used to partition the data into distinct groups, allowing the function to operate independently within each partition. |
| sort field | string, integer, float, boolean | No | Defines the order of rows within each partition, which is critical when defining a window using the between clause. |
| between boundaries | integer, null | No | Defines the "window frame" (a specific range of rows) relative to the current row over which the count is calculated. |
| frame_type | string | No | Specifies whether the window is defined by rows (the default) or a value range. |
| alias | string | No | The alias name for the output column, assigned using the as clause. |
Returns
The count() function returns a single numerical value representing the count. This value is displayed in a new column for every row in the group of rows it applies to.
Usage Notes
- Defining a field for count() is optional; providing a field counts non-null values, while omitting it counts total rows.
- The by clause partitions the data into distinct groups, and the count() function operates independently within each of these partitions, meaning a separate count is computed for each group.
- The sort clause is mandatory for many windowcomp functions as it defines the order of rows within each partition, which is critical when defining a window using the between clause.
- If the between clause is omitted, the default window used is typically the entire partition.
- The windowcomp stage must always precede analytic functions like count() that calculate statistics.
- Only one function can be defined per field within a single windowcomp stage.
Examples
Example 1: Over an entire partition (no field specified - counts all rows)
Goal: Calculate the total number of events (rows) for all events within each is_successful group, replicating this total count value for every row in that group.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, event_description | windowcomp count() by is_successful sort asc _time as count_in_partition | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: For the false partition, there are 3 rows, so the count_in_partition is 3 for each row in this partition. For the true partition, there are 7 rows, so the count is 7 for each row in that partition.
Output:
| _time | event_id | is_successful | event_description | count_in_partition |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | "File access attempt" | 3 |
| 2023-10-26 10:40:10 UTC | 106 | false | "Unauthorized access detected" | 3 |
| 2023-10-26 10:55:55 UTC | 109 | false | "API request throttled" | 3 |
| 2023-10-26 10:00:00 UTC | 101 | true | "User login successful" | 7 |
| 2023-10-26 10:15:15 UTC | 103 | true | "Network connection established" | 7 |
| 2023-10-26 10:20:00 UTC | 104 | true | "System heartbeat" | 7 |
| 2023-10-26 10:30:45 UTC | 105 | true | "Data transformation" | 7 |
| 2023-10-26 10:45:00 UTC | 107 | true | "Cloud resource modification" | 7 |
| 2023-10-26 10:50:20 UTC | 108 | true | "Software update initiated" | 7 |
| 2023-10-26 11:00:10 UTC | 110 | true | "Database backup completed" | 7 |
Example 2: Over an entire partition (field specified - counts non-null values)
Goal: Calculate the count of event_description specifically to count non-null occurrences of that field for all events within each is_successful group.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, event_description | windowcomp count(event_description) by is_successful as non_null_count_in_partition | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: Because all event_description values in the dataset are non-null, the counts for each partition are identical to counting all rows (3 for false and 7 for true), explicitly demonstrating that count(field) only counts non-null instances.
Output:
| _time | event_id | is_successful | event_description | non_null_count_in_partition |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | "File access attempt" | 3 |
| 2023-10-26 10:40:10 UTC | 106 | false | "Unauthorized access detected" | 3 |
| 2023-10-26 10:55:55 UTC | 109 | false | "API request throttled" | 3 |
| 2023-10-26 10:00:00 UTC | 101 | true | "User login successful" | 7 |
| 2023-10-26 10:15:15 UTC | 103 | true | "Network connection established" | 7 |
| 2023-10-26 10:20:00 UTC | 104 | true | "System heartbeat" | 7 |
| 2023-10-26 10:30:45 UTC | 105 | true | "Data transformation" | 7 |
| 2023-10-26 10:45:00 UTC | 107 | true | "Cloud resource modification" | 7 |
| 2023-10-26 10:50:20 UTC | 108 | true | "Software update initiated" | 7 |
| 2023-10-26 11:00:10 UTC | 110 | true | "Database backup completed" | 7 |
Example 3: Rolling window (preceding 2 rows and current row, no field)
Goal: Count the total number of rows within the current row and the two immediately preceding rows within its partition, operating on a sliding window ordered by _time.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, event_description | windowcomp count() by is_successful sort asc _time between -2 and 0 as rolling_count | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: The between -2 and 0 clause defines a window including the current row and the two preceding rows. For each row, the count() calculates the number of rows within its specific rolling window, starting from the beginning of the partition if there are not enough preceding rows.
Output:
| _time | event_id | is_successful | event_description | rolling_count |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | "File access attempt" | 1 |
| 2023-10-26 10:40:10 UTC | 106 | false | "Unauthorized access detected" | 2 |
| 2023-10-26 10:55:55 UTC | 109 | false | "API request throttled" | 3 |
| 2023-10-26 10:00:00 UTC | 101 | true | "User login successful" | 1 |
| 2023-10-26 10:15:15 UTC | 103 | true | "Network connection established" | 2 |
| 2023-10-26 10:20:00 UTC | 104 | true | "System heartbeat" | 3 |
| 2023-10-26 10:30:45 UTC | 105 | true | "Data transformation" | 3 |
| 2023-10-26 10:45:00 UTC | 107 | true | "Cloud resource modification" | 3 |
| 2023-10-26 10:50:20 UTC | 108 | true | "Software update initiated" | 3 |
| 2023-10-26 11:00:10 UTC | 110 | true | "Database backup completed" | 3 |
Example 4: Fixed window (current row to unbounded following, field specified)
Goal: Calculate the count of non-null event_description values for each row over a fixed window that starts from the current row and extends to the end of its partition.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, event_description | windowcomp count(event_description) by is_successful sort asc _time between 0 and null as count_from_current | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: The between 0 and null clause defines a window starting from the current row to the very end of the partition. count(event_description) dynamically updates for each row to represent the remaining number of non-null values.
Output:
| _time | event_id | is_successful | event_description | count_from_current |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | "File access attempt" | 3 |
| 2023-10-26 10:40:10 UTC | 106 | false | "Unauthorized access detected" | 2 |
| 2023-10-26 10:55:55 UTC | 109 | false | "API request throttled" | 1 |
| 2023-10-26 10:00:00 UTC | 101 | true | "User login successful" | 7 |
| 2023-10-26 10:15:15 UTC | 103 | true | "Network connection established" | 6 |
| 2023-10-26 10:20:00 UTC | 104 | true | "System heartbeat" | 5 |
| 2023-10-26 10:30:45 UTC | 105 | true | "Data transformation" | 4 |
| 2023-10-26 10:45:00 UTC | 107 | true | "Cloud resource modification" | 3 |
| 2023-10-26 10:50:20 UTC | 108 | true | "Software update initiated" | 2 |
| 2023-10-26 11:00:10 UTC | 110 | true | "Database backup completed" | 1 |
Related Articles
- Stages: windowcomp, comp, alter
- Functions: count()
csc
Use the csc() function to calculate the cosecant of a numeric value specified in radians. The cosecant is the reciprocal of the sine function.
Syntax
csc(<numeric_expression>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
numeric_expression |
integer, float | Yes | The angle in radians for which to calculate the cosecant. The value must not be zero or a multiple of π. |
Returns
Type: float
Description: The csc() function returns the cosecant of the input angle, which is equivalent to 1 / sin(x). If the input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The
csc()function accepts any real number except values wheresin(x) = 0(i.e., multiples of π, including zero), where the cosecant is undefined. - Undefined Values: At
x = 0and multiples of π, the function returnsinfinity,NaN, ornullsince the cosecant is undefined at these points. - Null Handling: If the input expression is
null, the function returnsnull. - Relationship:
csc(x) = 1 / sin(x). - Result Range: The result is always ≤ -1 or ≥ 1 (never between -1 and 1).
- Common Use Cases: This function is typically used within the
alterstage for trigonometric calculations, wave analysis, and engineering computations.
Examples
Example 1: Calculate cosecant of literal values
Goal: Calculate the cosecant for specific radian values to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = csc(divide(pi(), 2)), result2 = csc(divide(pi(), 6)), result3 = csc(1) | fields result1, result2, result3
Explanation: You use csc() on three different radian values. csc(π/2) returns 1.0 (since sin(π/2) = 1), csc(π/6) returns 2.0 (since sin(π/6) = 0.5), and csc(1) returns approximately 1.1884.
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 1.0 | 2.0 | 1.18840 |
Example 2: Calculate cosecant from a field value
Goal: Calculate the cosecant of values stored in a dataset field, filtering out values near zero.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value != 0 | alter csc_val = csc(numeric_value) | fields event_id, numeric_value, csc_val | limit 3
Explanation: This query filters out zero values (where cosecant is undefined), then computes the cosecant for each remaining value in the numeric_value field.
Output:
| EVENT_ID | NUMERIC_VALUE | CSC_VAL |
|---|---|---|
| 101 | 0.5 | 2.08583 |
| 102 | 1.0 | 1.18840 |
| 103 | 1.5708 | 1.0 |
Example 3: Verify cosecant as reciprocal of sine
Goal: Demonstrate that csc(x) equals 1 / sin(x) by computing both and comparing.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value != 0 | alter csc_val = csc(numeric_value) | alter reciprocal_sin = divide(1, sin(numeric_value)) | fields event_id, numeric_value, csc_val, reciprocal_sin | limit 3
Explanation: This query computes both csc(numeric_value) and 1 / sin(numeric_value) to verify they produce the same result, confirming the mathematical identity csc(x) = 1 / sin(x).
Output:
| EVENT_ID | NUMERIC_VALUE | CSC_VAL | RECIPROCAL_SIN |
|---|---|---|---|
| 101 | 0.5 | 2.08583 | 2.08583 |
| 102 | 1.0 | 1.18840 | 1.18840 |
| 103 | 1.5708 | 1.0 | 1.0 |
Related articles
current_time
Use the current_time() function to return a TIMESTAMP value representing the exact time at which the query is executed.
Syntax
current_time()
Parameters
The current_time() function does not accept any parameters.
Returns
The current_time() function returns a TIMESTAMP representing the current system time.
Usage notes
- The functıon is particularly useful for calculations that require the current moment as a reference point, such as determining the age of an event or establishing dynamic time windows.
- The function returns the timestamp according to the default Timestamp Format specified in Server Settings.
- The function is typically used within the
alterorfilterstages.
Examples
Example 1: Assigning current_time() to a new field in an alter stage
Goal: Create a new field that holds the current timestamp for each record.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter current_query_timestamp = current_time() | fields event_id, current_query_timestamp | limit 3
Explanation: The current_time() function provides the exact time of query execution, which is then assigned to the current_query_timestamp field for every record.
Output:
| EVENT_ID | CURRENT_QUERY_TIMESTAMP |
|---|---|
| 101 | Jul 25th 2024 14:30:00 |
| 102 | Jul 25th 2024 14:30:00 |
| 103 | Jul 25th 2024 14:30:00 |
Example 2: Using current_time() within timestamp_diff() in a filter stage
Goal: Filter events that occurred more than 1 day ago relative to the current time.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter timestamp_diff(current_time(), _time, "DAY") > 1 | fields event_id, _time | limit 3
Explanation: The timestamp_diff() function calculates the difference between the current time and the event's _time. The filter stage retains only those records where the difference is greater than 1 day.
Output:
| EVENT_ID | _TIME |
|---|---|
| 101 | Oct 26th 2023 10:00:00 |
| 102 | Oct 26th 2023 10:05:30 |
| 103 | Oct 26th 2023 10:15:15 |
Example 3: Using current_time() within date_floor() in an alter Stage
Goal: Round the current time down to the nearest week.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter current_week_start = date_floor(current_time(), "w") | fields event_id, current_week_start | limit 3
Explanation: The date_floor() function, when applied to current_time(), truncates the timestamp to the beginning of the specified unit ("w" for week).
Output:
| EVENT_ID | CURRENT_WEEK_START |
|---|---|
| 101 | Jul 21st 2024 00:00:00 |
| 102 | Jul 21st 2024 00:00:00 |
| 103 | Jul 21st 2024 00:00:00 |
Example 4: Using current_time() within extract_time() in an alter Stage
Goal: Extract a specific part of the current time, such as the hour.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter current_hour = extract_time(current_time(), "HOUR") | fields event_id, current_hour | limit 3
Explanation: The extract_time() function isolates the "HOUR" component from the current timestamp provided by current_time(), returning an integer representing that hour.
Output:
| EVENT_ID | CURRENT_HOUR |
|---|---|
| 101 | 14 |
| 102 | 14 |
| 103 | 14 |
Example 5: Filtering events based on process execution age
Goal: From the xdr_data dataset, retrieve events from the last 24 hours where the actor process began running more than 30 days prior to the current time.
XQL Code:
dataset = sample_xql_raw | filter timestamp_diff(current_time(), to_timestamp(actor_process_execution_time, "MILLIS"), "DAY") > 30
Explanation: This query uses current_time() to get the present timestamp and to_timestamp() to convert the actor_process_execution_time (stored in milliseconds) into a standard timestamp format. The timestamp_diff() function then calculates the number of days between these two points. The filter stage ensures only records with a difference greater than 30 days are returned.
Output
| event_id | actor_process_execution_time | _time | calculated_days_old |
|---|---|---|---|
| 5521 | 1693569600000 | 2023-10-15 08:30:00 UTC | 44 |
| 5589 | 1691064000000 | 2023-10-15 09:12:00 UTC | 73 |
| 5602 | 1688212800000 | 2023-10-15 10:05:00 UTC | 106 |
Related articles
- Stages:
alter,filter - Functions:
timestamp_diff,date_floor,extract_time - Datasets:
xdr_data
date_floor
Use the date_floor() function to return a new timestamp that is rounded down to the nearest whole value of a specified time unit.
Syntax
date_floor (<timestamp field>, "<time_unit>" [, "<time zone>"])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
timestamp field |
timestamp | Yes | The input timestamp value, originating from a field or the result of another function. |
time_unit |
string | Yes | The unit to which the timestamp should be rounded down. Supported values are y (year), mo (month), w (week), d (day), or h (hour). This parameter is not case-sensitive. |
time_zone |
string | No | The time zone to apply for the calculation. This can be an hours offset (for example, +08:00) or a time zone name from the List of Supported Time Zones, (for example, America/Chicago). If omitted, the default is UTC. |
Returns
The date_floor() function returns a TIMESTAMP value rounded down to the beginning of the specified time unit.
Usage notes
- The function always rounds the timestamp down to the beginning of the specified time unit. For example,
date_floor("2023-10-26 10:30:00 UTC", "h")results in2023-10-26 10:00:00. - Supported time units (
y,mo,w,d,h) are not case-sensitive. - This function is typically used within
alterorfilterstages to perform data transformations for time-based aggregation or analysis.
Examples
Example 1: Rounding _time to the nearest hour (default UTC)
Goal: Round the _time field to the beginning of the hour using the default UTC time zone.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter floored_hour = date_floor(_time, "h") | fields event_id, _time, floored_hour | limit 3
Explanation: The query rounds the _time field down to the start of the hour. For events occurring at 10:05:30 or 10:15:15, the result is 10:00:00.
Output:
| event_id | _time | floored_hour |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | Oct 26th 2023 10:00:00 |
| 102 | Oct 26th 2023 10:05:30 | Oct 26th 2023 10:00:00 |
| 103 | Oct 26th 2023 10:15:15 | Oct 26th 2023 10:00:00 |
Example 2: Rounding _time to the nearest day (default UTC)
Goal: Round the _time field to the beginning of the day using the default UTC time zone.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter floored_day = date_floor(_time, "d") | fields event_id, _time, floored_day | limit 3
Explanation: All _time values are rounded down to the very beginning of the day (midnight UTC) on October 26th, 2023.
Output:
| event_id | _time | floored_day |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | Oct 26th 2023 00:00:00 |
| 102 | Oct 26th 2023 10:05:30 | Oct 26th 2023 00:00:00 |
| 103 | Oct 26th 2023 10:15:15 | Oct 26th 2023 00:00:00 |
Example 3: Rounding _time to the nearest week (default UTC)
Goal: Round the _time field to the beginning of the week using the default UTC time zone.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter floored_week = date_floor(_time, "w") | fields event_id, _time, floored_week | limit 3
Explanation: Because October 26th, 2023, falls within the week starting Sunday, October 22nd, 2023, all timestamps are rounded down to the beginning of that week (midnight UTC on October 22nd).
Output:
| event_id | _time | floored_week |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | Oct 22nd 2023 00:00:00 |
| 102 | Oct 26th 2023 10:05:30 | Oct 22nd 2023 00:00:00 |
| 103 | Oct 26th 2023 10:15:15 | Oct 22nd 2023 00:00:00 |
Example 4: Rounding _time to the nearest month (default UTC)
Goal: Round the _time field to the beginning of the month using the default UTC time zone.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter floored_month = date_floor(_time, "mo") | fields event_id, _time, floored_month | limit 3
Explanation: All _time values are rounded down to the very beginning of October 2023 (midnight UTC on October 1st).
Output:
| event_id | _time | floored_month |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | Oct 1st 2023 00:00:00 |
| 102 | Oct 26th 2023 10:05:30 | Oct 1st 2023 00:00:00 |
| 103 | Oct 26th 2023 10:15:15 | Oct 1st 2023 00:00:00 |
Example 5: Rounding _time to the nearest year (default UTC)
Goal: Round the _time field to the beginning of the year using the default UTC time zone.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter floored_year = date_floor(_time, "y") | fields event_id, _time, floored_year | limit 3
Explanation: All _time values are rounded down to the very beginning of 2023 (midnight UTC on January 1st).
Output:
| event_id | _time | floored_year |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | Jan 1st 2023 00:00:00 |
| 102 | Oct 26th 2023 10:05:30 | Jan 1st 2023 00:00:00 |
| 103 | Oct 26th 2023 10:15:15 | Jan 1st 2023 00:00:00 |
Example 6: Rounding current_time() to the nearest day with a specific time zone
Goal: Round the current time (assumed here as Jul 25th 2024 14:30:00 UTC) to the start of the day in a specific time zone ("America/Los_Angeles").
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter current_time_val = current_time() | alter floored_day_la = date_floor(current_time_val, "d", "America/Los_Angeles") | fields event_id, current_time_val, floored_day_la | limit 3
Explanation: The function converts the UTC time to the Los Angeles time zone (PDT, UTC-7), rounds it to the start of that day (midnight PDT), and returns the timestamp. Midnight PDT translates to 07:00:00 UTC.
Output:
| event_id | current_time_val | floored_day_la |
|---|---|---|
| 101 | Jul 25th 2024 14:30:00 | Jul 25th 2024 07:00:00 |
| 102 | Jul 25th 2024 14:30:00 | Jul 25th 2024 07:00:00 |
| 103 | Jul 25th 2024 14:30:00 | Jul 25th 2024 07:00:00 |
Example 7: Filtering events relative to the start of the week with timezone adjustment
Goal: Return up to 100 records from the xdr_data dataset where the event time (_time) is earlier than a calculated timestamp. The calculation determines the start of the current week in the "America/Los_Angeles" timezone and subtracts exactly 24 days (2,073,600 seconds) from that point.
XQL Code:
dataset = sample_xql_raw | filter _time < to_timestamp(add(to_epoch(date_floor(current_time(),"w", "America/Los_Angeles")),-2073600)) | limit 100
Explanation: This query performs a multi-step time transformation to create a dynamic filter:
- current_time() retrieves the present time.
- date_floor(..., "w", "America/Los_Angeles") rounds that time down to the beginning of the week based on Los Angeles time.
- to_epoch(...) converts that "start of week" timestamp into a Unix epoch integer (seconds).
- add(..., -2073600) subtracts 2,073,600 seconds (equivalent to 24 days) from the epoch value.
- to_timestamp(...) converts the resulting integer back into a standard timestamp format.
- The filter stage then compares the _time of every record against this calculated value.
Output:
| _time | event_id | event_type |
|---|---|---|
| 2023-10-01 14:20:00 UTC | 88412 | ENHANCED_EVENT_LOG |
| 2023-09-28 09:15:30 UTC | 88305 | STORYLINE |
| 2023-09-25 22:10:00 UTC | 88112 | BROWSER_QUERY |
Related articles
- Stages:
alter,filter - Functions:
current_time
div
Use the div() function to perform integer division of two numeric values, returning the quotient without the remainder.
Syntax
div(<dividend>, <divisor>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
dividend |
integer, float | Yes | The number to be divided (numerator). |
divisor |
integer, float | Yes | The number to divide by (denominator). Must not be zero. |
Returns
Type: integer
Description: The div() function returns the integer quotient of the division, truncating any fractional part. If either input is null or the divisor is zero, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Integer Division: Unlike the
divide()function which returns a float,div()performs integer (truncated) division and returns only the whole number part of the quotient. - Division by Zero: If the
divisoris zero, the function returnsnullor raises an error. - Null Handling: If either input expression is
null, the function returnsnull. - Truncation Direction: The result is truncated toward zero. For example,
div(7, 2)returns3anddiv(-7, 2)returns-3. - Common Use Cases: This function is typically used within the
alterstage for bucketing values, calculating whole units, and performing modular arithmetic in combination withmod().
Examples
Example 1: Integer division of literal values
Goal: Perform integer division on specific numeric literals to verify the truncation behavior.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = div(10, 3), result2 = div(7, 2), result3 = div(-7, 2) | fields result1, result2, result3
Explanation: div(10, 3) returns 3 (10 ÷ 3 = 3 remainder 1), div(7, 2) returns 3 (7 ÷ 2 = 3 remainder 1), and div(-7, 2) returns -3 (truncated toward zero).
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 3 | 3 | -3 |
Example 2: Integer division from field values
Goal: Use integer division to calculate how many complete hours are in a duration measured in seconds.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter complete_hours = div(to_integer(multiply(duration_seconds, 3600)), 3600) | fields event_id, duration_seconds, complete_hours | limit 3
Explanation: This query converts duration_seconds to a larger value and then uses div() to find the number of complete hours, discarding any fractional hour.
Output:
| EVENT_ID | DURATION_SECONDS | COMPLETE_HOURS |
|---|---|---|
| 101 | 7200.5 | 7200 |
| 102 | 3661.0 | 3661 |
| 103 | 1800.0 | 1800 |
Example 3: Combine div with mod for quotient and remainder
Goal: Use div() and mod() together to decompose a value into its quotient and remainder.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter quotient = div(event_id, 10) | alter remainder = mod(event_id, 10) | fields event_id, quotient, remainder | limit 3
Explanation: This query decomposes event_id into its quotient and remainder when divided by 10. For example, event_id 101 gives quotient 10 and remainder 1, since 101 = 10 × 10 + 1.
Output:
| EVENT_ID | QUOTIENT | REMAINDER |
|---|---|---|
| 101 | 10 | 1 |
| 102 | 10 | 2 |
| 103 | 10 | 3 |
Related articles
divide
Use the divide() function to perform arithmetic division, calculating the quotient of two numbers.
Syntax
divide (<string> | <integer> | <float>, <string> | <integer> | <float>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
numerator |
integer, float, string | Yes | The number to be divided (the dividend). |
denominator |
integer, float, string | Yes | The number by which to divide (the divisor). |
Returns
The divide() function returns the numerical quotient of the two input parameters.
Usage notes
- The function accepts numeric literals (integers, floating-point numbers) or field values that represent numbers.
- The function supports input values provided as a string data type (for example, an integer stored as a string).
- The function can handle negative numbers.
- This function is typically used within the
alterstage to create or modify fields.
Examples
Example 1: Dividing an integer field by an integer literal
Goal: Calculate a new field by dividing an existing integer field (event_id) by a fixed integer value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter divided_event_id = divide(event_id, 2) | fields event_id, divided_event_id | limit 3
Explanation: This query calculates a new field, divided_event_id, by dividing each event_id (an integer) by 2.
Output:
| event_id | divided_event_id |
|---|---|
| 101 | 50.5 |
| 102 | 51.0 |
| 103 | 51.5 |
Example 2: Dividing a floating-point field by an integer literal
Goal: Calculate a new field by dividing a floating-point field (duration_seconds) by an integer literal.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter divided_duration = divide(duration_seconds, 5) | fields event_id, duration_seconds, divided_duration | limit 3
Explanation: This query divides duration_seconds (which contains decimal values) by 5, producing a new floating-point value in divided_duration.
Output:
| event_id | duration_seconds | divided_duration |
|---|---|---|
| 101 | 1.5 | 0.3 |
| 102 | 0.8 | 0.16 |
| 103 | 10.2 | 2.04 |
Example 3: Dividing a floating-point field by a floating-point literal
Goal: Divide a floating-point number field by a decimal literal.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter precise_division = divide(duration_seconds, 0.25) | fields event_id, duration_seconds, precise_division | limit 3
Explanation: This query divides duration_seconds by 0.25, resulting in precise_division which will also be a floating-point number.
Output:
| event_id | duration_seconds | precise_division |
|---|---|---|
| 101 | 1.5 | 6.0 |
| 102 | 0.8 | 3.2 |
| 103 | 10.2 | 40.8 |
Example 4: Dividing a numeric literal by a negative literal
Goal: Perform division using a negative literal value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter negative_literal_division = divide(100, -4) | fields event_id, negative_literal_division | limit 3
Explanation: This query divides the positive literal 100 by the negative literal -4, producing a constant -25.0 for the negative_literal_division field across all records.
Output:
| event_id | negative_literal_division |
|---|---|
| 101 | -25.0 |
| 102 | -25.0 |
| 103 | -25.0 |
Example 5: Dividing a string-converted-to-number field
Goal: Divide a numeric value that was extracted as a string from a JSON field and converted to a number.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter simple_json_data != null | alter json_code_string = simple_json_data -> code | alter json_code_number = to_number(json_code_string) | alter divided_json_code = divide(json_code_number, 100) | fields event_id, simple_json_data, json_code_number, divided_json_code | limit 3
Explanation: The query extracts the code "200" as a string, converts it to a number, and then divides it by 100, resulting in divided_json_code of 2.0. Records where the field is null will result in NULL.
Output:
| event_id | simple_json_data | json_code_number | divided_json_code |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | 200 | 2.0 |
| 102 | {"status": "fail", "error": "access_denied"} | NULL | NULL |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL | NULL |
Related articles
earliest
Use the earliest() function to retrieve the chronologically oldest value of a specified field within a grouped set of records.
Syntax
earliest(<field>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | any | Yes | The field from which to extract the earliest value based on chronological order. |
Returns
The earliest() function returns the value of the specified field from the oldest event in the evaluated group. The data type of the returned value matches the data type of the input field.
Usage Notes
- The earliest() function is an aggregate function and must be used within the comp stage.
- The chronological order of the records is determined by the underlying time field (such as _time) associated with the data events.
- If the earliest record contains a NULL value for the evaluated field, the function will return NULL.
- This function pairs frequently with the comp stage's by clause to find the first occurrence of an activity (like a process execution or login) per user or host.
Examples
Example 1: Identify the First Process Executed per Host
Goal: Find the earliest recorded process name that was executed on each endpoint within the queried time frame.
XQL Code:
config timeframe \= 1d | dataset \= xdr_data | filter action_process_image_name \!= null | comp earliest(action_process_image_name) as first_process by agent_hostname | fields agent_hostname, first_process | limit 3
Explanation: You use the comp stage to group the events by agent_hostname. For each unique host, the earliest() function evaluates the timeline of the records and returns the action_process_image_name associated with the chronologically oldest event in that group. The result is assigned to the first_process alias.
Output:
| AGENT_HOSTNAME | FIRST_PROCESS |
|---|---|
| endpoint-win-01 | C:\Windows\System32\smss.exe |
| endpoint-mac-02 | /sbin/launchd |
| srv-linux-03 | /usr/lib/systemd/systemd |
Related Articles
euclidean_distance
Use the euclidean_distance() function to calculate the Euclidean distance between two numeric vectors (arrays). The Euclidean distance is the straight-line distance between two points in multi-dimensional space.
Syntax
euclidean_distance(<vector1>, <vector2>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
vector1 |
array of integers or floats | Yes | The first numeric vector (array). Must have the same length as vector2. |
vector2 |
array of integers or floats | Yes | The second numeric vector (array). Must have the same length as vector1. |
Returns
Type: float
Description: The euclidean_distance() function returns a non-negative float representing the straight-line distance between the two input vectors. A value of 0.0 indicates identical vectors. If either input is null or the vectors have different lengths, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Vector Length: Both input vectors must have the same number of elements. If they differ in length, the function returns
null. - Vector Type: Only float values are supported for the input vectors.
- Null Handling: If either input expression is
null, the function returnsnull. - Non-Negative Result: The result is always ≥ 0. A result of
0.0means the two vectors are identical. - Formula: The Euclidean distance is calculated as
sqrt(sum((v1[i] - v2[i])^2))for all elementsi. - Common Use Cases: This function is typically used within the
alterstage for similarity analysis, anomaly detection, clustering, and comparing feature vectors in machine learning workflows.
Examples
Example 1: Calculate Euclidean distance between literal vectors
Goal: Calculate the Euclidean distance between specific vector pairs to verify known results.
XQL code:
dataset = xdr_data | limit 1 | alter dist1 = euclidean_distance(arraycreate(0.0, 0.0), arraycreate(3.0, 4.0)) | alter dist2 = euclidean_distance(arraycreate(1.0, 2.0, 3.0), arraycreate(1.0, 2.0, 3.0)) | fields dist1, dist2
Explanation: The distance between (0.0,0.0) and (3.0,4.0) is 5.0 (a classic 3-4-5 right triangle). The distance between two identical vectors (1.0,2.0,3.0) is 0.0.
Output:
| DIST1 | DIST2 |
|---|---|
| 5.0 | 0.0 |
Example 2: Calculate Euclidean distance between field vectors
Goal: Compute the Euclidean distance between an array field and a reference vector.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_codes != null and array_length(numeric_codes) = 5 | alter reference_vector = arraycreate(10.0, 20.0, 30.0, 40.0, 50.0) | alter euc_dist = euclidean_distance(numeric_codes, reference_vector) | fields event_id, numeric_codes, euc_dist | limit 3
Explanation: This query creates a reference vector and computes the Euclidean distance between each record's numeric_codes array and the reference vector. Lower values indicate the vectors are closer together in multi-dimensional space.
Output:
| EVENT_ID | NUMERIC_CODES | EUC_DIST |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | 107.35 |
| 102 | [-21, 56, 13, -88, 42] | 148.92 |
| 105 | [8, 15, 25, 35, 45] | 9.95 |
Example 3: Find most similar records using Euclidean distance
Goal: Sort records by their Euclidean distance to a reference vector to find the most similar ones.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_codes != null and array_length(numeric_codes) = 5 | alter ref = arraycreate(10.0, 20.0, 30.0, 40.0, 50.0) | alter distance = euclidean_distance(numeric_codes, ref) | fields event_id, numeric_codes, distance | sort asc distance | limit 3
Explanation: This query computes the Euclidean distance between each record's numeric_codes and a reference vector, then sorts by distance ascending to show the most similar records first.
Output:
| EVENT_ID | NUMERIC_CODES | DISTANCE |
|---|---|---|
| 105 | [8, 15, 25, 35, 45] | 9.95 |
| 101 | [13, -47, 29, 82, -15] | 107.35 |
| 102 | [-21, 56, 13, -88, 42] | 148.92 |
Related articles
- Stages:
alter,filter,fields,sort,limit - Functions:
cosine_distance(),arraycreate(),array_length(),sqrt() - Datasets:
xdr_data
exp
Use the exp() function to calculate the value of Euler's number e raised to the power of a numeric value.
Syntax
exp(<number>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The exponent to which e (approximately 2.71828) is raised. Any real number is valid. |
Returns
Type: float
Description: The exp() function returns e raised to the power of the input value (e^x). If the input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The
exp()function accepts any real number as input. - Null Handling: If the input expression is
null, the function returnsnull. - Identity Value:
exp(0)always returns1.0, sincee^0 = 1. - Inverse Relationship: The
exp()function is the inverse of the natural logarithmln(). That is,exp(ln(x)) = xforx > 0. - Overflow: For very large positive input values, the result may overflow to infinity.
- Underflow: For very large negative input values, the result approaches
0.0. - Common Use Cases: This function is typically used within the
alterstage for exponential growth/decay modeling, probability calculations, and scientific computations.
Examples
Example 1: Calculate exponential of literal values
Goal: Calculate e raised to specific powers to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = exp(0), result2 = exp(1), result3 = exp(-1) | fields result1, result2, result3
Explanation: You use exp() on three different literal values. exp(0) returns 1.0, exp(1) returns approximately 2.71828 (the value of e), and exp(-1) returns approximately 0.36788 (1/e).
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 1.0 | 2.71828 | 0.36788 |
Example 2: Calculate exponential from a field value
Goal: Calculate the exponential of values stored in a dataset field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter exp_result = exp(duration_seconds) | fields event_id, duration_seconds, exp_result | limit 3
Explanation: This query computes e raised to the power of each value in the duration_seconds field using exp() in the alter stage. No filtering is needed since exp() accepts any real number.
Output:
| EVENT_ID | DURATION_SECONDS | EXP_RESULT |
|---|---|---|
| 101 | 0.0 | 1.0 |
| 102 | 1.0 | 2.71828 |
| 103 | 2.0 | 7.38906 |
Example 3: Verify inverse relationship with ln
Goal: Demonstrate that exp() and ln() are inverse functions by applying both sequentially.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value > 0 | alter ln_val = ln(numeric_value) | alter exp_ln_val = exp(ln_val) | fields event_id, numeric_value, ln_val, exp_ln_val | limit 3
Explanation: This query first computes the natural logarithm of numeric_value, then applies exp() to the result. The final value exp_ln_val should match the original numeric_value, confirming the inverse relationship exp(ln(x)) = x.
Output:
| EVENT_ID | NUMERIC_VALUE | LN_VAL | EXP_LN_VAL |
|---|---|---|---|
| 101 | 5.0 | 1.60944 | 5.0 |
| 102 | 10.0 | 2.30259 | 10.0 |
| 103 | 100.0 | 4.60517 | 100.0 |
Related articles
extract_time
Use the extract_time() function to isolate and return specific components of a timestamp, such as the year, month, or hour.
Important Note: The values returned by extract_time() are always based on GMT (Greenwich Mean Time), even if your server settings for Timezone or Timestamp Format are adjusted.
Syntax
extract_time (<timestamp>, <part>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
timestamp |
timestamp | Yes | The input timestamp value, originating from a field or the result of another function. |
part |
string | Yes | The specific unit of the timestamp to extract. |
Returns
The extract_time() function returns a numerical value (Integer or Number) representing the extracted portion of the timestamp.
Usage notes
- The values returned by
extract_time()are always based on GMT (Greenwich Mean Time) even if you've adjusted the Timezone or Timestamp Format server settings. For more information on the server settings, see Configure server settings. - The
partparameter is not case-sensitive, but the string must match one of the supported keywords. - The supported keywords for the
partparameter are:DAY: Day of the month (1-31).DAYOFWEEK: Day of the week (1=Monday, 7=Sunday).DAYOFYEAR: Day of the year (1-366).HOUR: Hour of the day (0-23).MICROSECOND: Microseconds.MILLISECOND: Milliseconds.MINUTE: Minute of the hour (0-59).MONTH: Month of the year (1-12).QUARTER: Quarter of the year (1-4).SECOND: Second of the minute (0-59).YEAR: Year (for example, 2023).
Examples
Example 1: Extracting the YEAR
Goal: Extract the year from the _time field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_year = extract_time(_time, "YEAR") | fields event_id, _time, event_year | limit 3
Explanation: The event_year field shows the integer year (2023) extracted from each event's _time timestamp.
Output:
| EVENT_ID | _TIME | EVENT_YEAR |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 2023 |
| 102 | Oct 26th 2023 10:05:30 | 2023 |
| 103 | Oct 26th 2023 10:15:15 | 2023 |
Example 2: Extracting the MONTH
Goal: Extract the month from the _time field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_month = extract_time(_time, "MONTH") | fields event_id, _time, event_month | limit 3
Explanation: The event_month field shows the integer month (10 for October) extracted from each event's _time timestamp.
Output:
| EVENT_ID | _TIME | EVENT_MONTH |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 10 |
| 102 | Oct 26th 2023 10:05:30 | 10 |
| 103 | Oct 26th 2023 10:15:15 | 10 |
Example 3: Extracting the DAY
Goal: Extract the day of the month from the _time field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_day = extract_time(_time, "DAY") | fields event_id, _time, event_day | limit 3
Explanation: The event_day field shows the integer day of the month (26) extracted from each event's _time timestamp.
Output:
| EVENT_ID | _TIME | EVENT_DAY |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 26 |
| 102 | Oct 26th 2023 10:05:30 | 26 |
| 103 | Oct 26th 2023 10:15:15 | 26 |
Example 4: Extracting the DAYOFWEEK
Goal: Extract the day of the week from the _time field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_day_of_week = extract_time(_time, "DAYOFWEEK") | fields event_id, _time, event_day_of_week | limit 3
Explanation: The event_day_of_week field shows the integer day of the week (4 for Thursday) extracted from each event's _time timestamp.
Output:
| EVENT_ID | _TIME | EVENT_DAY_OF_WEEK |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 4 |
| 102 | Oct 26th 2023 10:05:30 | 4 |
| 103 | Oct 26th 2023 10:15:15 | 4 |
Example 5: Extracting the DAYOFYEAR
Goal: Extract the day of the year from the _time field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_day_of_year = extract_time(_time, "DAYOFYEAR") | fields event_id, _time, event_day_of_year | limit 3
Explanation: The event_day_of_year field shows the integer day of the year (299) extracted from each event's _time timestamp.
Output:
| EVENT_ID | _TIME | EVENT_DAY_OF_YEAR |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 299 |
| 102 | Oct 26th 2023 10:05:30 | 299 |
| 103 | Oct 26th 2023 10:15:15 | 299 |
Example 6: Extracting the HOUR
Goal: Extract the hour from the _time field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_hour = extract_time(_time, "HOUR") | fields event_id, _time, event_hour | limit 3
Explanation: The event_hour field shows the integer hour (10) extracted from each event's _time timestamp.
Output:
| EVENT_ID | _TIME | EVENT_HOUR |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 10 |
| 102 | Oct 26th 2023 10:05:30 | 10 |
| 103 | Oct 26th 2023 10:15:15 | 10 |
Example 7: Extracting the MINUTE
Goal: Extract the minute from the _time field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_minute = extract_time(_time, "MINUTE") | fields event_id, _time, event_minute | limit 3
Explanation: The event_minute field shows the integer minute extracted from each event's _time timestamp.
Output:
| EVENT_ID | _TIME | EVENT_MINUTE |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 0 |
| 102 | Oct 26th 2023 10:05:30 | 5 |
| 103 | Oct 26th 2023 10:15:15 | 15 |
Example 8: Extracting the SECOND
Goal: Extract the second from the _time field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_second = extract_time(_time, "SECOND") | fields event_id, _time, event_second | limit 3
Explanation: The event_second field shows the integer second extracted from each event's _time timestamp.
Output:
| EVENT_ID | _TIME | EVENT_SECOND |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 0 |
| 102 | Oct 26th 2023 10:05:30 | 30 |
| 103 | Oct 26th 2023 10:15:15 | 15 |
Example 9: Extracting the MILLISECOND
Goal: Extract the milliseconds from a timestamp. Because the sample data does not explicitly display milliseconds, this example uses current_time() for demonstration.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter current_ts_val = current_time() // Conceptual: Jul 25th 2024 14:30:45.123 | alter ms_part = extract_time(current_ts_val, "MILLISECOND") | fields event_id, current_ts_val, ms_part | limit 3
Explanation: The ms_part field shows the millisecond component (123) extracted from the current time. This illustrates the function's capability with higher precision timestamps.
Output:
| EVENT_ID | CURRENT_TS_VAL | MS_PART |
|---|---|---|
| 101 | Jul 25th 2024 14:30:45 | 123 |
| 102 | Jul 25th 2024 14:30:45 | 123 |
| 103 | Jul 25th 2024 14:30:45 | 123 |
Example 10: Extracting the MICROSECOND
Goal: Extract the microseconds from a timestamp. Because the sample data does not explicitly display microseconds, this example uses current_time() for demonstration.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter current_ts_val = current_time() // Conceptual: Jul 25th 2024 14:30:45.123456 | alter us_part = extract_time(current_ts_val, "MICROSECOND") | fields event_id, current_ts_val, us_part | limit 3
Explanation: The us_part field shows the microsecond component (123456) extracted from the current time, demonstrating the function's precision.
Output:
| EVENT_ID | CURRENT_TS_VAL | US_PART |
|---|---|---|
| 101 | Jul 25th 2024 14:30:45 | 123456 |
| 102 | Jul 25th 2024 14:30:45 | 123456 |
| 103 | Jul 25th 2024 14:30:45 | 123456 |
Example 11: Extracting the QUARTER
Goal: Extract the quarter of the year from the _time field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_quarter = extract_time(_time, "QUARTER") | fields event_id, _time, event_quarter | limit 3
Explanation: The event_quarter field shows the integer quarter of the year (4) extracted from each event's _time timestamp.
Output:
| EVENT_ID | _TIME | EVENT_QUARTER |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 4 |
| 102 | Oct 26th 2023 10:05:30 | 4 |
| 103 | Oct 26th 2023 10:15:15 | 4 |
Related articles
- Stages:
alter,config,fields,limit - Functions:
current_time
extract_url_host
Use the extract_url_host() function to return the host portion of a given URL string.
Syntax
extract_url_host (<url_string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
url_string |
string | Yes | The input string literal or field containing the URL from which the host needs to be extracted. |
Returns
The extract_url_host() function returns a string representing the host of the URL.
Usage notes
- The function always returns the host value in lowercase characters, regardless of the input URL's original casing.
- This function is typically used within the
alterstage to create new fields or modify existing ones based on extracted URL data, or within thefilterstage for conditional logic. - If the input
url_stringis NULL, the function returns NULL.
Examples
Example 1: Basic host extraction from a standard URL
Goal: Extract the host from a common HTTPS URL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_host = extract_url_host("https://www.paloaltonetworks.com") | fields event_id, extracted_host | limit 1
Explanation: The query extracts the host "www.paloaltonetworks.com" from the provided URL string.
Output:
| EVENT_ID | EXTRACTED_HOST |
|---|---|
| 101 | www.paloaltonetworks.com |
Example 2: Host extraction from a URL with user, password, and port
Goal: Extract the host from a complex URL that includes user credentials and port numbers.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_host_complex = extract_url_host("//user:password@a.b:80/path?query") | fields event_id, extracted_host_complex | limit 1
Explanation: extract_url_host() successfully isolates "a.b" as the host, ignoring the user, password, port, path, and query parameters.
Output:
| EVENT_ID | EXTRACTED_HOST_COMPLEX |
|---|---|
| 101 | a.b |
Example 3: Host extraction with mixed-case input
Goal: Extract the host from a URL containing uppercase letters, demonstrating the automatic lowercasing behavior.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_host_lowercase = extract_url_host("www.Example.Co.UK") | fields event_id, extracted_host_lowercase | limit 1
Explanation: Despite "www.Example.Co.UK" having mixed casing, the function returns "www.example.co.uk" in all lowercase, demonstrating its built-in lowercasing behavior.
Output:
| EVENT_ID | EXTRACTED_HOST_LOWERCASE |
|---|---|
| 101 | <www.example.co.uk> |
Example 4: Host extraction from a URL with multiple suffixes/paths
Goal: Extract the full hostname from a URL that includes subdomains and extended paths.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_host_path = extract_url_host("https://www.test.paloaltonetworks.com/suffix/another_suffix") | fields event_id, extracted_host_path | limit 1
Explanation: The function correctly identifies the entire host, including subdomains, regardless of the trailing path components.
Output:
| EVENT_ID | EXTRACTED_HOST_PATH |
|---|---|
| 101 | www.test.paloaltonetworks.com |
Example 5: Handling NULL input
Goal: Demonstrate the function's behavior when provided with a NULL input.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter null_url_input = NULL | alter extracted_host_from_null = extract_url_host(null_url_input) | fields event_id, null_url_input, extracted_host_from_null | limit 1
Explanation: Consistent with standard XQL function behavior, if the input to extract_url_host() is NULL, the function returns NULL.
Output:
| EVENT_ID | NULL_URL_INPUT | EXTRACTED_HOST_FROM_NULL |
|---|---|---|
| 101 | NULL | NULL |
Example: Host extraction from a URL string
Goal: Return a single record from the sample_xql_raw dataset showing the extracted host name from a specific URL string ("https://www.test.paloaltonetworks.com").
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | alter url_host = extract_url_host("https://www.test.paloaltonetworks.com") | fields url_host | limit 1
Explanation:
- The query starts by accessing the xdr_data dataset.
- The alter stage creates a new field named url_host.
- The extract_url_host() function parses the provided URL string and isolates the host component (www.test.paloaltonetworks.com).
- The fields stage restricts the final output to only show the newly created url_host column.
- The limit 1 stage ensures that only a single result is returned.
Output:
| url_host |
|---|
| "www.test.paloaltonetworks.com" |
Related articles
- Stages:
alter,config,fields,limit - Functions:
extract_url_pub_suffix,extract_url_registered_domain - Datasets:
xdr_data
extract_url_pub_suffix
Use the extract_url_pub_suffix() function to return the public suffix of a given URL string (for example, "com", "org", "net").
Syntax
extract_url_pub_suffix ("<URL>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
<URL> |
string | Yes | The input string literal or field containing the URL from which the public suffix needs to be extracted. |
Returns
The extract_url_pub_suffix() function returns a string representing the public suffix of the URL.
Usage notes
- The function requires a string value representing a URL as input.
- The function always returns the public suffix value in lowercase characters, regardless of the input URL's original casing.
- This function is typically used within the
alterstage to create new fields or modify existing ones based on extracted URL data, or within thefilterstage for conditional logic.
Examples
Example 1: Basic public suffix extraction from a standard URL
Goal: Extract the public suffix from a common HTTPS URL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_pub_suffix = extract_url_pub_suffix("https://www.paloaltonetworks.com") | fields event_id, extracted_pub_suffix | limit 1
Explanation: The query extracts "com" as the public suffix from the URL "https://www.paloaltonetworks.com".
Output:
| EVENT_ID | EXTRACTED_PUB_SUFFIX |
|---|---|
| 101 | "com" |
Example 2: Public suffix extraction from a URL with multiple suffixes/paths
Goal: correctly identify only the public suffix from a URL that includes subdomains and extended paths.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_pub_suffix_complex = extract_url_pub_suffix("https://www.test.paloaltonetworks.com/suffix/another_suffix") | fields event_id, extracted_pub_suffix_complex | limit 1
Explanation: The function correctly isolates "com" as the public suffix, ignoring subdomains and path components.
Output:
| EVENT_ID | EXTRACTED_PUB_SUFFIX_COMPLEX |
|---|---|
| 101 | "com" |
Example 3: Public suffix extraction with mixed-case input
Goal: Demonstrate that the function returns the public suffix in lowercase characters, even if the input URL contains uppercase letters.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_pub_suffix_lowercase = extract_url_pub_suffix("www.Example.Co.UK") | fields event_id, extracted_pub_suffix_lowercase | limit 1
Explanation: Despite "www.Example.Co.UK" having mixed casing, the function returns "uk" in all lowercase, demonstrating its built-in lowercasing behavior.
Output:
| EVENT_ID | EXTRACTED_PUB_SUFFIX_LOWERCASE |
|---|---|
| 101 | "uk" |
Example 4: Handling NULL input
Goal: Demonstrate the function's behavior when provided with a NULL input.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter null_url_input = NULL | alter extracted_pub_suffix_from_null = extract_url_pub_suffix(null_url_input) | fields event_id, null_url_input, extracted_pub_suffix_from_null | limit 1
Explanation: Consistent with standard XQL function behavior, if the input to extract_url_pub_suffix() is NULL, the function returns NULL.
Output:
| EVENT_ID | NULL_URL_INPUT | EXTRACTED_PUB_SUFFIX_FROM_NULL |
|---|---|---|
| 101 | NULL | NULL |
Related articles
- Stages:
alter,filter - Functions:
extract_url_host,extract_url_registered_domain - Datasets:
xdr_data
extract_url_registered_domain
Use the extract_url_registered_domain() function to retrieve the registered domain (also known as the registerable domain) from a URL string. This typically consists of the public suffix plus one preceding label (for example, extracting paloaltonetworks.com from www.paloaltonetworks.com).
Syntax
extract_url_registered_domain ("<URL>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
<URL> |
string | Yes | The input string literal or field containing the URL from which the registered domain is extracted. |
Returns
The extract_url_registered_domain() function returns a string representing the registered domain of the URL.
Usage notes
- The function accepts a string value representing a URL as input.
- The function always returns the registered domain value in lowercase characters, regardless of the casing in the input URL.
- If the input URL structure does not contain a recognizable registered domain (such as a private IP address or a malformed URL), the function returns
NULL. - If the input value is
NULL, the function returnsNULL.
Examples
Example 1: Basic registered domain extraction from a standard URL
Goal: Extract the registered domain from a standard HTTPS URL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_registered_domain = extract_url_registered_domain("https://www.paloaltonetworks.com") | fields event_id, extracted_registered_domain | limit 1
Explanation: The query extracts "paloaltonetworks.com" as the registered domain from the URL "https://www.paloaltonetworks.com".
Output:
| EVENT_ID | EXTRACTED_REGISTERED_DOMAIN |
|---|---|
| 101 | paloaltonetworks.com |
Example 2: Registered domain extraction from a URL with multiple subdomains/paths
Goal: Extract the registered domain from a URL that includes multiple subdomains and extended path components.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_registered_domain_complex = extract_url_registered_domain("https://docs.global.paloaltonetworks.com/xql/api") | fields event_id, extracted_registered_domain_complex | limit 1
Explanation: The function correctly isolates "paloaltonetworks.com" as the registered domain, ignoring the "docs.global" subdomains and the "/xql/api" path components.
Output:
| EVENT_ID | EXTRACTED_REGISTERED_DOMAIN_COMPLEX |
|---|---|
| 101 | paloaltonetworks.com |
Example 3: Registered domain extraction with mixed-case input
Goal: Extract the registered domain from a URL containing uppercase letters to demonstrate automatic lowercasing.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_registered_domain_lowercase = extract_url_registered_domain("WWW.EXAMPLE.Co.UK/docs") | fields event_id, extracted_registered_domain_lowercase | limit 1
Explanation: Despite the input "WWW.EXAMPLE.Co.UK/docs" having mixed casing, the function returns the registered domain "example.co.uk" in all lowercase characters.
Output:
| EVENT_ID | EXTRACTED_REGISTERED_DOMAIN_LOWERCASE |
|---|---|
| 101 | example.co.uk |
Example 4: Handling URLs without a recognizable registered domain
Goal: Demonstrate the function's behavior when provided with inputs that do not represent a recognizable registered domain, such as malformed URLs or private IP addresses.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter invalid_url_registered_domain = extract_url_registered_domain("//user:password@a.b:80/path?query") | alter private_ip_registered_domain = extract_url_registered_domain("192.168.1.10") | fields event_id, invalid_url_registered_domain, private_ip_registered_domain | limit 1
Explanation: For the malformed URL and the private IP address "192.168.1.10", the function cannot determine a registered domain and returns NULL.
Output:
| EVENT_ID | INVALID_URL_REGISTERED_DOMAIN | PRIVATE_IP_REGISTERED_DOMAIN |
|---|---|---|
| 101 | NULL | NULL |
Example 5: Handling NULL input
Goal: Demonstrate the behavior when the input field is NULL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 105 | alter extracted_registered_domain_from_null = extract_url_registered_domain(dst_domain) | fields event_id, dst_domain, extracted_registered_domain_from_null | limit 1
Explanation: The dst_domain field is NULL for event 105. Consistent with standard XQL function behavior, the function returns NULL.
Output:
| EVENT_ID | DST_DOMAIN | EXTRACTED_REGISTERED_DOMAIN_FROM_NULL |
|---|---|---|
| 105 | NULL | NULL |
Related articles
- Stages:
alter,config,fields,filter,limit - Functions:
extract_url_host,extract_url_pub_suffix
first
Use the first() function to retrieve the first chronologically recorded value of a specified field within a grouped set of records.
Syntax
first(<field>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | any | Yes | The field from which to extract the first recorded value based on chronological order. |
Returns
The first() function returns the value of the specified field from the oldest event in the evaluated group. The data type of the returned value matches the data type of the input field.
Usage Notes
- The first() function is an aggregate function and must be used within the comp stage.
- The chronological order of the records is determined by the underlying time field (such as _time) associated with the data events.
- If the first record contains a NULL value for the evaluated field, the function will return NULL.
- This function is frequently used in threat hunting to identify the initial occurrence of an artifact or behavior, such as the first command executed in a session or the initial process started by a specific user.
Examples
Example 1: Identify the First Process Executed per Host
Goal: Find the first recorded process name that was executed on each endpoint within the queried time frame.
XQL Code:
config timeframe = 1d | dataset = xdr_data | filter action_process_image_name != null | comp first(action_process_image_name) as first_process by agent_hostname | fields agent_hostname, first_process | limit 3
Explanation: You use the comp stage to group the events by agent_hostname. For each unique host, the first() function evaluates the timeline of the records and returns the action_process_image_name associated with the chronologically oldest event in that group. The result is assigned to the first_process alias.
Output:
| AGENT_HOSTNAME | FIRST_PROCESS |
|---|---|
| endpoint-win-01 | C:\Windows\System32\smss.exe |
| endpoint-mac-02 | /sbin/launchd |
| srv-linux-03 | /usr/lib/systemd/systemd |
Example 2: Retrieve the First Command Line for a Process
Goal: Identify the first command line argument used to execute a specific process across your environment.
XQL Code:
config timeframe = 1d | dataset = xdr_data | filter action_process_image_name = "powershell.exe" | comp first(action_process_image_command_line) as initial_cmd by agent_hostname | fields agent_hostname, initial_cmd | limit 2
Explanation: This query filters for execution events involving powershell.exe. Using the comp stage, it groups the results by agent_hostname and uses the first() function to extract the chronologically first command line argument executed by PowerShell on that host.
Output:
| AGENT_HOSTNAME | INITIAL_CMD |
|---|---|
| endpoint-win-01 | powershell.exe -ExecutionPolicy Bypass -File C:\scripts\setup.ps1 |
| srv-win-02 | "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile |
Related Articles
first_value
Use the first_value() function to retrieve the first value of a specified field within an ordered partition of records, typically used for baseline comparisons across a sequence of events.
Syntax
first_value(<field>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | any | Yes | The field from which to extract the first recorded value based on the window's defined ordering. |
Returns
The first_value() function returns the value of the specified field from the first row of the evaluated window frame. The data type of the returned value matches the data type of the input field.
Usage Notes
- The first_value() function is a window function and must be used strictly within the windowcomp stage.
- The chronological or logical order of the records is determined by the order by clause within the over() partition statement.
- Unlike the first() aggregate function used in the comp stage, first_value() appends the retrieved baseline value to every row in the partition without collapsing the dataset, enabling row-by-row comparative analysis.
- If the evaluated field for the first row in the window is NULL, the function will return NULL for the records in that window frame.
Examples
Example 1: Establish an Initial Process Baseline per Host**
Goal: Identify the first recorded process name executed on each endpoint and append this baseline value alongside all subsequent process executions to spot deviations.
XQL Code:
config timeframe = 1d | dataset = xdr_data | filter action_process_image_name != null | windowcomp first_value(action_process_image_name) as initial_process over(partition by agent_hostname order by _time asc) | fields _time, agent_hostname, action_process_image_name, initial_process | limit 3
Explanation: You use the windowcomp stage to partition the events by agent_hostname and order them chronologically using _time asc. The first_value() function evaluates this ordered window and captures the first action_process_image_name encountered in each partition. This value is assigned to the initial_process alias and appended to every row for that host, allowing you to easily compare the current process (action_process_image_name) against the first process (initial_process).
Output:
| _TIME | AGENT_HOSTNAME | ACTION_PROCESS_IMAGE_NAME | INITIAL_PROCESS |
|---|---|---|---|
| 2023-10-26 10:00:00 UTC | endpoint-win-01 | C:\Windows\System32\smss.exe | C:\Windows\System32\smss.exe |
| 2023-10-26 10:05:30 UTC | endpoint-win-01 | C:\Windows\System32\cmd.exe | C:\Windows\System32\smss.exe |
| 2023-10-26 10:20:00 UTC | endpoint-win-01 | C:\Windows\System32\powershell.exe | C:\Windows\System32\smss.exe |
Example 2: Return the first value of a field
Goal: Extract the original remote port in a network connection.
XQL Code:
dataset = xdr_data | filter event_type = ENUM.NETWORK | filter action_remote_port != null | windowcomp first_value(action_remote_port) as first_remote_port over(partition by agent_hostname order by _time asc) | fields agent_hostname, action_remote_port, first_remote_port, _time | sort asc agent_hostname , _time
Explanation: The windowcomp partition operates within the parameters defined in the over() partition statement. The query organizes the data to evaluate by agent_hostname according to the ascending chronological order of its creation time. The results returned in the new field first_remote_port provide the remote port value of the earliest creation time event for each agent hostname. Because this calculation utilizes the windowcomp stage, all lines of the dataset are returned along with this new field value.
Output:
| AGENT_HOSTNAME | ACTION_REMOTE_PORT | FIRST_REMOTE_PORT | _TIME |
|---|---|---|---|
| mac-agent-1 | 443 | 443 | Mar 26th 2026 09:26:07 |
| mac-agent-1 | 443 | 443 | Mar 26th 2026 09:26:08 |
| mac-agent-1 | 80 | 443 | Mar 26th 2026 09:26:09 |
Related Articles
- Stages: windowcomp, filter, fields, limit
- Functions: last_value(), first(), lag()
- Datasets: xdr_data
floor
Use the floor() function to convert a field containing a number and return an integer rounded down to the nearest whole number.
Syntax
floor (<number>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The numeric value to round down. |
Returns
The floor() function returns an integer representing the input number rounded down to the nearest whole number.
Usage notes
- The function accepts a field that contains a number, meaning it can take integers or floating-point numbers as input.
- The function explicitly rounds the number down to the nearest whole integer.
- For positive numbers, this behavior truncates the decimal part (for example, 1.9 becomes 1).
- For negative numbers, it rounds to the next more negative integer (for example, -2.5 becomes -3).
Examples
Example 1: Round down positive floating-point field
Goal: Round the duration_seconds field down to the nearest integer.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter floored_duration = floor(duration_seconds) | fields event_id, duration_seconds, floored_duration | limit 3
Explanation: This query creates a new field, floored_duration, by taking the duration_seconds (for example, 1.5, 0.8) and rounding it down. For 1.5, it becomes 1; for 0.8, it becomes 0.
Output:
| EVENT_ID | DURATION_SECONDS | FLOORED_DURATION |
|---|---|---|
| 101 | 1.5 | 1 |
| 102 | 0.8 | 0 |
| 103 | 10.2 | 10 |
Example 2: Round down calculated floating-point value
Goal: Round the result of a division operation on an integer field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter divided_event_id = divide(event_id, 3) | alter floored_divided_id = floor(divided_event_id) | fields event_id, divided_event_id, floored_divided_id | limit 3
Explanation: Here, event_id (for example, 101) is divided by 3, resulting in 33.666.... The floor() function then rounds this down to 33.
Output:
| EVENT_ID | DIVIDED_EVENT_ID | FLOORED_DIVIDED_ID |
|---|---|---|
| 101 | 33.666666 | 33 |
| 102 | 34.0 | 34 |
| 103 | 34.333333 | 34 |
Example 3: Round down negative number
Goal: Round a negative number extracted from an array field to demonstrate rounding towards negative infinity.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_numeric_code = arrayindex(numeric_codes, 1) | alter floored_negative_code = floor(first_numeric_code) | fields event_id, numeric_codes, first_numeric_code, floored_negative_code | limit 3
Explanation: For event_id 101, first_numeric_code is -47. The floor() of -47 is still -47 as it's an integer. If a negative float like -2.5 were present, floor() would convert it to -3.
Output:
| EVENT_ID | NUMERIC_CODES | FIRST_NUMERIC_CODE | FLOORED_NEGATIVE_CODE |
|---|---|---|---|
| 101 | [13, -47, 29, 82, -15] | -47 | -47 |
| 102 | [-21, 56, 13, -88, 42] | 56 | 56 |
| 103 | [90, -33, 7, 51, -62, 18] | -33 | -33 |
Example 4: Round down number extracted from JSON
Goal: Round a numeric value extracted from a JSON field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 110 | alter json_size_string = simple_json_data -> size_gb | alter json_size_number = to_number(json_size_string) | alter floored_json_size = floor(json_size_number) | fields event_id, simple_json_data, json_size_number, floored_json_size | limit 1
Explanation: This query extracts the size_gb value from the simple_json_data field (for example, "500" for event_id 110). The query then converts this string to a number and applies floor(), which for an integer like 500 would result in 500.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | JSON_SIZE_NUMBER | FLOORED_JSON_SIZE |
|---|---|---|---|
| 110 | {"backup_id": "DB-005", "size_gb": 500} | 500 | 500 |
Related articles
- Stages:
alter,config,fields,limit,filter - Functions:
divide,arrayindex,json_extract_scalar,to_number
format_string
Use the format_string() function to construct dynamic strings by inserting values into a predefined format.
Syntax
format_string ("<format_string>", <field_1>, <field_2>, ...<field_n>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
format_string |
string | Yes | A string literal that contains zero or more format specifiers initiated by the % symbol (for example, %s, %d). |
field_n |
string, integer | Yes | A variable-length list of additional arguments whose values will be inserted into the format string. Each argument must match the type expected by its corresponding format specifier. |
Returns
The format_string() function returns a single string containing the formatted text with argument values inserted.
Usage notes
- Common format specifiers include
%sfor string values and%dfor integer values. - You can use padding and width specifiers (for example,
%10d,%05d,%-10s) to control output alignment and formatting. - The function requires strict type compatibility between arguments and specifiers. The function does not implicitly convert types (for example, a floating-point number passed to
%dwill fail). - Use explicit type conversion functions like
to_string()orto_integer()to ensure non-matching values (like booleans or floats) are compatible with the specifiers. - Note that
to_number()converts strings to floating-point numbers, which are incompatible with the%d(integer) specifier; useto_integer()instead.
Examples
Example 1: Basic string substitution (%s)
Goal: Combine literal text with string field values using the %s specifier.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_message = format_string("Description: %s. Domain: %s.", event_description, dst_domain) | fields event_id, event_message | limit 3
Explanation: The event_description and dst_domain fields, which are strings, are directly inserted into the format string at the %s placeholders.
Output:
| EVENT_ID | EVENT_MESSAGE |
|---|---|
| 101 | "Description: User login successful. Domain: ec2.amazonaws.com." |
| 102 | "Description: File access attempt. Domain: sts.amazonaws.com." |
| 103 | "Description: Network connection established. Domain: www.google.com." |
Example 2: Integer substitution (%d)
Goal: Embed integer field values into a string using the %d specifier.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter formatted_id = format_string("Event #%d occurred.", event_id) | fields event_id, formatted_id | limit 3
Explanation: The event_id (an integer) is converted to its string representation and inserted into the output string where %d is specified.
Output:
| EVENT_ID | FORMATTED_ID |
|---|---|
| 101 | "Event #101 occurred." |
| 102 | "Event #102 occurred." |
| 103 | "Event #103 occurred." |
Example 3: Combining different data types
Goal: Combine values of different original data types (boolean, float) into a single formatted string using explicit conversion.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter detailed_status = format_string("Successful: %s, Duration: %s seconds", to_string(is_successful), to_string(duration_seconds)) | fields event_id, is_successful, duration_seconds, detailed_status | limit 3
Explanation: to_string(is_successful) converts the boolean to "true" or "false". to_string(duration_seconds) converts the float to a string like "1.5". format_string() then constructs the final string using these string representations for the %s specifiers.
Output:
| EVENT_ID | IS_SUCCESSFUL | DURATION_SECONDS | DETAILED_STATUS |
|---|---|---|---|
| 101 | true | 1.5 | "Successful: true, Duration: 1.5 seconds" |
| 102 | false | 0.8 | "Successful: false, Duration: 0.8 seconds" |
| 103 | true | 10.2 | "Successful: true, Duration: 10.2 seconds" |
Example 4: Padding and zero-padding for integers
Goal: Utilize padding specifiers with %d and %s to control width and alignment.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter padded_event_id = format_string("ID: %05d | Full ID: %-10s | Raw: %s", event_id, to_string(event_id), to_string(event_id)) | fields event_id, padded_event_id | limit 3
Explanation: %05d pads event_id with leading zeros to a width of 5. %-10s left-justifies the string version within 10 characters. %s performs basic substitution.
Output:
| EVENT_ID | PADDED_EVENT_ID |
|---|---|
| 101 | ID: 00101 |
| 102 | ID: 00101 |
| 103 | ID: 00101 |
Example 5: Formatting extracted JSON scalar values with integer conversion
Goal: Extract a numeric string from JSON, convert it to an integer, and format it with %d.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter status_code_string = coalesce(simple_json_data -> code, simple_json_data -> error_code) | alter status_int = to_integer(status_code_string) | alter formatted_status = format_string("API Status: %d", status_int) | fields event_id, simple_json_data, formatted_status | limit 3
Explanation: The query extracts the code as a string and explicitly converts it to an integer using to_integer(). This ensures compatibility with the %d specifier, which would fail if a float (from to_number) were passed.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | FORMATTED_STATUS |
|---|---|---|
| 101 | {"status": "ok", "code": 200} | "API Status: 200" |
| 102 | {"status": "fail", "error": "access_denied"} | NULL |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL |
Related articles
format_timestamp
Use the format_timestamp() function to return a string by formatting a given timestamp according to a specified string format.
Syntax
format_timestamp ("<format string>", <timestamp field> [, "<time zone>"])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
format_string |
string | Yes | The string literal that defines how the timestamp will be formatted (for example, %Y/%m/%d %H:%M:%S). |
timestamp_field |
timestamp | Yes | The timestamp value to be formatted. |
time_zone |
string | No | An optional time zone specified using either an hours offset (for example, +08:00) or a time zone name (for example, America/Chicago). The default is UTC. |
Returns
The format_timestamp() function returns a string representation of the timestamp.
Usage notes
- The function requires a format string and a timestamp field as input.
- An optional time zone can be specified to adjust the displayed time.
- If no time zone is configured, the function defaults to UTC.
- This function is typically used within the
alterstage to create new fields containing formatted time strings.
Examples
Example 1: Without a time zone configured
Goal: Format the _time field into a specific string format using the default UTC time zone.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_time = format_timestamp("%Y/%m/%d %H:%M:%S", _time) | fields event_id, _time, new_time | limit 3
Explanation: The _time field, which is in UTC, is formatted directly into a string. Since no time zone is specified in the format_timestamp() function, the output new_time string reflects the UTC time.
Output:
| EVENT_ID | _TIME | NEW_TIME |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 2023/10/26 10:00:00 |
| 102 | Oct 26th 2023 10:05:30 | 2023/10/26 10:05:30 |
| 103 | Oct 26th 2023 10:15:15 | 2023/10/26 10:15:15 |
Example 2: With a time zone configured using an hours offset
Goal: Format the _time field into a string, adjusting the time by a specific hours offset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_time = format_timestamp("%Y/%m/%d %H:%M:%S", _time, "+03:00") | fields event_id, _time, new_time | limit 3
Explanation: The _time field (UTC) is adjusted by adding three hours (+03:00) before it is formatted into the new_time string. For example, 10:00:00 UTC becomes 13:00:00 in the formatted string.
Output:
| EVENT_ID | _TIME | NEW_TIME |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 2023/10/26 13:00:00 |
| 102 | Oct 26th 2023 10:05:30 | 2023/10/26 13:05:30 |
| 103 | Oct 26th 2023 10:15:15 | 2023/10/26 13:15:15 |
Example 3: With a time zone name configured
Goal: Format the _time field into a string, applying a specific named time zone.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_time = format_timestamp("%Y/%m/%d %H:%M:%S", _time, "America/Chicago") | fields event_id, _time, new_time | limit 3
Explanation: The _time field (UTC) is converted to the America/Chicago time zone (UTC-5 for this date) before being formatted. For example, 10:00:00 UTC becomes 05:00:00 in the formatted new_time string.
Output:
| EVENT_ID | _TIME | NEW_TIME |
|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | 2023/10/26 05:00:00 |
| 102 | Oct 26th 2023 10:05:30 | 2023/10/26 05:05:30 |
| 103 | Oct 26th 2023 10:15:15 | 2023/10/26 05:15:15 |
Related articles
- Stages:
alter,config,fields,limit - Functions:
parse_timestamp,to_timestamp
greatest
Use the greatest() function to return the largest value from a list of expressions.
Syntax
greatest(<expression1>, <expression2> [, ...])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
expression1 |
integer, float, string, timestamp | Yes | The first value to compare. |
expression2 |
integer, float, string, timestamp | Yes | The second value to compare. |
... |
integer, float, string, timestamp | No | Additional values to compare. Any number of additional expressions can be provided. |
Returns
Type: Same as input type
Description: The greatest() function returns the largest value among all the provided expressions. If any input is null, the function may skip null values or return null depending on the implementation.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Multiple Arguments: The function accepts two or more arguments and returns the maximum value among them.
- Type Consistency: All arguments should be of compatible types for meaningful comparison.
- Null Handling: If all inputs are
null, the function returnsnull. If some inputs arenull, the function typically returns the greatest non-null value. - String Comparison: When comparing strings, the function uses lexicographic (alphabetical) ordering.
- Relationship to least(): The
greatest()function is the counterpart ofleast(), which returns the smallest value. - Common Use Cases: This function is typically used within the
alterstage for selecting the maximum value across multiple fields, implementing upper bounds, and data normalization.
Examples
Example 1: Find greatest among literal values
Goal: Find the largest value from a set of numeric literals.
XQL code:
dataset = xdr_data | limit 1 | alter max_val = greatest(10, 25, 5, 42, 18) | fields max_val
Explanation: The greatest() function compares all five literal values and returns 42, the largest among them.
Output:
| MAX_VAL |
|---|
| 42 |
Example 2: Find greatest value across multiple fields
Goal: Find the largest value among multiple numeric fields for each record.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter max_field = greatest(event_id, numeric_value, duration_seconds) | fields event_id, numeric_value, duration_seconds, max_field | limit 3
Explanation: This query compares the values of event_id, numeric_value, and duration_seconds for each record and returns the largest value in max_field.
Output:
| EVENT_ID | NUMERIC_VALUE | DURATION_SECONDS | MAX_FIELD |
|---|---|---|---|
| 101 | 5.0 | 1.5 | 101 |
| 102 | 200.0 | 0.8 | 200.0 |
| 103 | 50.0 | 10.2 | 103 |
Example 3: Implement an upper bound using greatest
Goal: Ensure a value is at least a minimum threshold by using greatest() as a lower clamp.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter clamped_duration = greatest(duration_seconds, 1.0) | fields event_id, duration_seconds, clamped_duration | limit 3
Explanation: This query ensures that clamped_duration is at least 1.0 by returning the greater of duration_seconds and 1.0. Values below 1.0 are raised to 1.0, while values above remain unchanged.
Output:
| EVENT_ID | DURATION_SECONDS | CLAMPED_DURATION |
|---|---|---|
| 101 | 1.5 | 1.5 |
| 102 | 0.8 | 1.0 |
| 103 | 10.2 | 10.2 |
Related articles
hierarchy_match
Use the hierarchy_match() function to determine whether an asset belongs to a specified node in the organizational (org) asset hierarchy. You can match against the hierarchy path (the ordered list of container names from the org root down to a specific node), a specific hierarchy node ID (id_path), or both. Calling the function with no arguments matches every asset (equivalent to *).
The function is only available when the org asset hierarchy is enabled for your tenant, and it operates on the asset hierarchy fields xdm.asset.hierarchy.path (the chain of container names joined by /) and xdm.asset.hierarchy.id_path (the ID of the deepest node in that path). It is intended for asset datasets (for example, asset_inventory) and is not supported inside correlation rules.
Syntax
hierarchy_match(<path_segments>, <id_path>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
path_segments |
array | No | An ordered list of the container names from the org root down to the target node (for example, ["Org", "ou1", "ou2"]). Segments are joined with / and matched as a path prefix, so the node and all of its descendants match. The path contains only container levels (organization, OUs, management groups, folders) — not the leaf account/project/subscription. If omitted (or an empty array), no path restriction is applied and all paths match. As a shorthand, passing a single string value is treated as the id_path argument. |
id_path |
string | No | The resource ID of a specific hierarchy node — the ID of the deepest container in the path (for example, an OU ID, management-group ID, or folder ID). Use it to unambiguously target a node even when names are duplicated. When provided, it must match the asset's id_path. If omitted, no ID restriction is applied. |
Returns
Type: boolean
Description: The hierarchy_match() function returns true if the asset belongs to the specified org hierarchy node (satisfying both the path and ID conditions that were supplied), and false otherwise.
Usage notes
- Path vs. id_path: The
pathandid_pathdescribe the same container node from two angles:pathis the chain of container names, andid_pathis the ID of the deepest node in that chain. Neither includes the account/project/subscription. - Disambiguating duplicate names: Use
id_pathwhen container names are ambiguous. For example, if two different OUs are both namedProduction, matching on the path name alone is ambiguous — supplying the OU'sid_pathpins the match to exactly the OU you mean. - Combinable, optional parameters: Both parameters are optional and can be combined:
hierarchy_match()— matches all assets (no restriction).hierarchy_match(arraycreate("Org", "ou1"))— path-only match (the node and all its descendants).hierarchy_match(null, "ou-a1b2-prod01")— ID-only match (match the node with this exact ID, on any path).hierarchy_match("ou-a1b2-prod01")— shorthand for an ID-only match.hierarchy_match(arraycreate("Org", "ou1"), "ou-a1b2-prod01")— matches only when both the path prefix and the ID condition are satisfied.
- Prefix, case-sensitive, literal matching: The path match is a prefix match: it matches the exact path as well as any child path beneath it. It is case-sensitive and matches literal characters (wildcard characters such as
%and_in path segments are treated literally, not as wildcards). - Ambiguous scalar + ID is rejected: Passing a single scalar/string value together with an explicit
id_pathis ambiguous and is rejected with a validation error. Use an array for the first argument whenever you also supply an ID. - Negation: To negate a match (find assets that do not belong to a node), compare the result to
false(for example,hierarchy_match(...) = false) or use!= true. - Typical use: This function is typically used within the
filterstage to scope results to an org hierarchy node, or within thealterstage to tag records with their hierarchy membership. -
Cloud hierarchy structure: The org hierarchy mirrors the native resource-organization model of each cloud provider. In every case the hierarchy stops at the container level — the leaf account, project, or subscription is not part of the path or the
id_path. Thepath_segmentsargument is the ordered list of the display names of the container levels (not their IDs, and not the leaf), andid_pathis the ID of the deepest container node in the path. Matching onpath_segmentsalone selects the target container node and all of its descendants, which is useful for scoping to an entire OU, management group, or folder subtree.Cloud Provider Container Levels (org root → node) Leaf (not part of hierarchy path/id_path) Example Path Example id_path(ID of deepest node)AWS Organization → Organizational Unit (OU) Account Acme Corp/ProductionOU ID: ou-a1b2-prod01Azure Management Group → (nested Management Groups) Subscription Tenant Root Group/PlatformManagement Group ID: mg-platformGCP Organization → Folder(s) Project acme.com/ProductionFolder ID: folders/574839201122
Examples
Example 1: Scope to an AWS organizational unit
Goal: Return only the assets that belong to the AWS Production OU under the Acme Corp organization, including every account nested beneath that OU.
XQL code:
config timeframe = 1d | dataset = asset_inventory | filter hierarchy_match(arraycreate("Acme Corp", "Production")) | fields asset_id, asset_name, cloud_provider, xdm.asset.hierarchy.path | limit 3
Explanation: You apply a path-only match in a filter stage. The path contains only the container levels (organization and OU), so matching on Acme Corp/Production returns every asset in any account under the Production OU (and its sub-OUs), because the match is a prefix match.
Output:
| ASSET_ID | ASSET_NAME | CLOUD_PROVIDER | XDM.ASSET.HIERARCHY.PATH |
|---|---|---|---|
| i-0a1b2c3d | payments-api-01 | AWS | Acme Corp/Production |
| i-0e4f5g6h | orders-worker-02 | AWS | Acme Corp/Production |
| i-0i7j8k9l | billing-db-01 | AWS | Acme Corp/Production/Billing |
Example 2: Disambiguate an OU by ID
Goal: Two OUs are both named Production under different parents. Return only the assets under the specific Production OU whose ID is ou-a1b2-prod01.
XQL code:
config timeframe = 1d | dataset = asset_inventory | filter hierarchy_match(arraycreate("Acme Corp", "Production"), "ou-a1b2-prod01") = true | fields asset_id, asset_name, xdm.asset.hierarchy.path, xdm.asset.hierarchy.id_path | limit 3
Explanation: Because the OU name alone is ambiguous, you combine the path prefix (Acme Corp/Production) with the OU's ID as id_path. An asset is returned only when its path starts with Acme Corp/Production and its id_path equals ou-a1b2-prod01, so only the intended OU is matched.
Output:
| ASSET_ID | ASSET_NAME | XDM.ASSET.HIERARCHY.PATH | XDM.ASSET.HIERARCHY.ID_PATH |
|---|---|---|---|
| i-0a1b2c3d | payments-api-01 | Acme Corp/Production | ou-a1b2-prod01 |
| i-0m1n2o3p | payments-cache-01 | Acme Corp/Production | ou-a1b2-prod01 |
| i-0q4r5s6t | payments-lb-01 | Acme Corp/Production | ou-a1b2-prod01 |
Example 3: Scope to an Azure management group
Goal: Tag assets that live under the Azure Platform management group (any subscription beneath it), starting from the Tenant Root Group.
XQL code:
config timeframe = 1d | dataset = asset_inventory | alter in_platform_mg = hierarchy_match(arraycreate("Tenant Root Group", "Platform")) | fields asset_id, cloud_provider, xdm.asset.hierarchy.path, in_platform_mg | limit 3
Explanation: You use a path-only match in an alter stage. In Azure the path contains the management-group chain (Management Group → nested Management Groups) and stops above the subscription, so matching on Tenant Root Group/Platform returns true for every asset in any subscription nested under the Platform management group, and false otherwise.
Output:
| ASSET_ID | CLOUD_PROVIDER | XDM.ASSET.HIERARCHY.PATH | IN_PLATFORM_MG |
|---|---|---|---|
| vm-web-01 | AZURE | Tenant Root Group/Platform | true |
| vm-api-02 | AZURE | Tenant Root Group/Platform/Prod | true |
| vm-sales-03 | AZURE | Tenant Root Group/Business | false |
Example 4: Pin to a specific Azure management group by ID
Goal: Return only the assets under the Platform management group whose ID is mg-platform.
XQL code:
config timeframe = 1d | dataset = asset_inventory | filter hierarchy_match(arraycreate("Tenant Root Group", "Platform"), "mg-platform") = true | fields asset_id, asset_name, xdm.asset.hierarchy.path, xdm.asset.hierarchy.id_path | limit 3
Explanation: You combine the management-group path prefix (Tenant Root Group/Platform) with the management group's ID as id_path. Only assets whose path starts with Tenant Root Group/Platform and whose id_path equals mg-platform are returned — the ID pins the match to the exact management group.
Output:
| ASSET_ID | ASSET_NAME | XDM.ASSET.HIERARCHY.PATH | XDM.ASSET.HIERARCHY.ID_PATH |
|---|---|---|---|
| vm-web-01 | payments-web-01 | Tenant Root Group/Platform | mg-platform |
| vm-web-02 | payments-web-02 | Tenant Root Group/Platform | mg-platform |
| st-blob-01 | payments-storage | Tenant Root Group/Platform | mg-platform |
Example 5: Scope to a GCP folder
Goal: Return only the assets that belong to the GCP Production folder under the acme.com organization, including every project nested inside that folder.
XQL code:
config timeframe = 1d | dataset = asset_inventory | filter hierarchy_match(arraycreate("acme.com", "Production")) | fields asset_id, asset_name, cloud_provider, xdm.asset.hierarchy.path | limit 3
Explanation: In GCP the path contains the organization and its folders and stops above the project. A path-only match on acme.com/Production returns every asset in any project inside the Production folder (and any sub-folders), because the match is a prefix match.
Output:
| ASSET_ID | ASSET_NAME | CLOUD_PROVIDER | XDM.ASSET.HIERARCHY.PATH |
|---|---|---|---|
| gce-inst-01 | payments-prod-vm | GCP | acme.com/Production |
| gce-inst-02 | orders-prod-vm | GCP | acme.com/Production |
| gcs-bucket-01 | billing-prod-data | GCP | acme.com/Production/Billing |
Example 6: Pin to a specific GCP folder by ID
Goal: Return only the assets under the Production folder whose ID is folders/574839201122.
XQL code:
config timeframe = 1d | dataset = asset_inventory | filter hierarchy_match(arraycreate("acme.com", "Production"), "folders/574839201122") = true | fields asset_id, asset_name, xdm.asset.hierarchy.path, xdm.asset.hierarchy.id_path | limit 3
Explanation: You combine the folder path prefix (acme.com/Production) with the folder's ID as id_path. Only assets whose path starts with acme.com/Production and whose id_path equals folders/574839201122 are returned, pinning the match to the exact folder even if another folder shares the same name.
Output:
| ASSET_ID | ASSET_NAME | XDM.ASSET.HIERARCHY.PATH | XDM.ASSET.HIERARCHY.ID_PATH |
|---|---|---|---|
| gce-inst-01 | payments-prod-vm | acme.com/Production | folders/574839201122 |
| gce-disk-01 | payments-prod-disk | acme.com/Production | folders/574839201122 |
| gcs-bucket-02 | payments-prod-bucket | acme.com/Production | folders/574839201122 |
Example 7: Exclude a hierarchy node (negation)
Goal: Return all assets except those in the Acme Corp/Sandbox OU.
XQL code:
config timeframe = 1d | dataset = asset_inventory | filter hierarchy_match(arraycreate("Acme Corp", "Sandbox")) = false | fields asset_id, cloud_provider, xdm.asset.hierarchy.path | limit 3
Explanation: Comparing the result of hierarchy_match() to false inverts the match, so every asset that does not live under the Acme Corp/Sandbox container is returned. This is useful for excluding non-production or sandbox scopes from a query.
Output:
| ASSET_ID | CLOUD_PROVIDER | XDM.ASSET.HIERARCHY.PATH |
|---|---|---|
| i-0a1b2c3d | AWS | Acme Corp/Production |
| vm-web-01 | AZURE | Tenant Root Group/Platform |
| gce-inst-01 | GCP | acme.com/Production |
Related articles
- Stages: filter, alter, fields
- Functions: arraycreate(), wildcard_match, coalesce()
- Datasets:
asset_inventory
if
Use the if() function to evaluate a boolean condition and return a specific value based on whether the result is true or false.
Syntax
if (<boolean expression>, <true_return_expression>[, <false_return_expression>])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
boolean_expression |
boolean | Yes | The condition that the function evaluates to either true or false. |
true_return_expression |
string, integer, float, boolean | Yes | The value returned if the boolean expression evaluates to true. |
false_return_expression |
string, integer, float, boolean | No | The value returned if the boolean expression evaluates to false. If omitted, the function returns NULL. |
Returns
The if() function returns the value of the true_return_expression if the condition is met. If the condition is not met, it returns the false_return_expression, or NULL if the false return expression is not provided.
Usage notes
- The first parameter must always be a boolean expression that evaluates to either true or false.
- If the
false_return_expressionis omitted and the boolean expression evaluates to false, the function returnsNULL. - It is a best practice for the
true_return_expressionandfalse_return_expressionto return compatible data types (for example, both strings or both integers) to ensure predictable results. - The function supports nested
if/elselogic, allowing you to chain multiple conditions sequentially.
Examples
Example 1: Basic if with a boolean field
Goal: Categorize events as "Success" or "Failure" based on an existing boolean field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_outcome_status = if(is_successful = true, "Success", "Failure") | fields event_id, is_successful, event_outcome_status | limit 5
Explanation: The query evaluates the is_successful field. If it is true, the new field event_outcome_status is set to "Success"; otherwise, it is set to "Failure".
Output:
| EVENT_ID | IS_SUCCESSFUL | EVENT_OUTCOME_STATUS |
|---|---|---|
| 101 | true | "Success" |
| 102 | false | "Failure" |
| 103 | true | "Success" |
| 104 | true | "Success" |
| 105 | true | "Success" |
Example 2: if with a numeric comparison
Goal: Classify events based on a numerical threshold using the duration_seconds field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter duration_category = if(duration_seconds > 5.0, "Long Duration", "Short Duration") | fields event_id, duration_seconds, duration_category | limit 5
Explanation: The query checks if duration_seconds is greater than 5.0. If true, duration_category is labeled "Long Duration"; otherwise, it is labeled "Short Duration".
Output:
| EVENT_ID | DURATION_SECONDS | DURATION_CATEGORY |
|---|---|---|
| 101 | 1.5 | "Short Duration" |
| 102 | 0.8 | "Short Duration" |
| 103 | 10.2 | "Long Duration" |
| 104 | 0.1 | "Short Duration" |
| 105 | 5.0 | "Short Duration" |
Example 3: if with string matching
Goal: Categorize event_id into distinct ranges using nested conditions to assign a descriptive string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_category = if( event_id <= 103, "Low Event ID", event_id <= 106, "Medium Event ID", "High Event ID") | fields event_id, event_category | limit 5
Explanation: The query evaluates conditions sequentially. If event_id is 103 or less, it assigns "Low Event ID". If that fails but it is 106 or less, it assigns "Medium Event ID". Otherwise, it assigns "High Event ID".
Output:
| EVENT_ID | EVENT_CATEGORY |
|---|---|
| 101 | Low Event ID |
| 102 | Low Event ID |
| 103 | Low Event ID |
| 104 | Medium Event ID |
| 105 | Medium Event ID |
Example 4: if with nested if for complex logic
Goal: Create granular categories based on both the is_successful status and duration_seconds using nested if() functions.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter detailed_status = if( is_successful = true, if( duration_seconds > 10.0, "Success - Long Duration", "Success - Short Duration" ), "Failure" ) | fields event_id, is_successful, duration_seconds, detailed_status | limit 5
Explanation: If is_successful is true, a nested if checks duration_seconds. If duration is greater than 10.0, it returns "Success - Long Duration", otherwise "Success - Short Duration". If is_successful is false, it returns "Failure".
Output:
| EVENT_ID | IS_SUCCESSFUL | DURATION_SECONDS | DETAILED_STATUS |
|---|---|---|---|
| 101 | true | 1.5 | "Success - Short Duration" |
| 102 | false | 0.8 | "Failure" |
| 103 | true | 10.2 | "Success - Long Duration" |
| 104 | true | 0.1 | "Success - Short Duration" |
| 105 | true | 5.0 | "Success - Short Duration" |
Example 5: if returning numeric values with multiplication
Goal: Conditionally modify a numeric value using the multiply() function based on an event ID threshold.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter threshold_event_id = if(event_id > 104, multiply(event_id, 10), event_id) | fields event_id, threshold_event_id | limit 5
Explanation: If event_id is greater than 104, the new field threshold_event_id contains the event_id multiplied by 10. Otherwise, it contains the original event_id.
Output:
| EVENT_ID | THRESHOLD_EVENT_ID |
|---|---|
| 101 | 101 |
| 102 | 102 |
| 103 | 103 |
| 104 | 104 |
| 105 | 1050 |
Example 6: if with omitted false return expression
Goal: Demonstrate that if() returns NULL when the condition is false and no false return expression is specified.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter google_traffic_tag = if(dst_domain = "www.google.com", "Google Traffic") | fields event_id, dst_domain, google_traffic_tag | limit 5
Explanation: The query checks if dst_domain equals "www.google.com". If true, it returns "Google Traffic". Because no false return value is provided, it returns NULL for all other domains.
Output:
| EVENT_ID | DST_DOMAIN | GOOGLE_TRAFFIC_TAG |
|---|---|---|
| 101 | "ec2.amazonaws.com" | NULL |
| 102 | "sts.amazonaws.com" | NULL |
| 103 | "www.google.com" | "Google Traffic" |
| 104 | "dropbox.com" | NULL |
| 105 | NULL | NULL |
Example 7: Remove file extensions conditionally
Goal: Use conditional logic to check if a process name contains ".exe" and remove that substring if present, otherwise return the lowercase process name.
XQL Code:
dataset = sample_xql_raw | fields action_process_image_name as apin | filter apin != null | alter remove_exe_process = if(lowercase(apin) contains ".exe", // boolean expression replace(lowercase(apin),".exe",""), // return if true lowercase(apin)) // return if false | limit 10
Explanation: The query first filters for records where the process image name is not null and aliases it as apin. The query then uses the if() function to evaluate a boolean expression: whether the lowercase version of the field apin contains the string ".exe".
- If the condition is true, the
replace()function is called to find the ".exe" substring and substitute it with an empty string, effectively removing the extension. - If the condition is false, it returns the lowercase name as is. The result of this logic is stored in a new field called
remove_exe_process.
Output:
| apin | remove_exe_process |
|---|---|
| cmd.exe | cmd |
| POWERSHELL.EXE | powershell |
| svchost.exe | svchost |
| python3 | python3 |
Example: Categorize local IP addresses using conditional logic
Goal: Evaluate the action_local_ip field from the last 7 days of sample_xql_raw to identify and label specific local IP ranges (10.x.x.x, 172.x.x.x, or 192.168.x.x) in a new column, returning null if no match is found.
XQL Code:
config timeframe = 7d | dataset = sample_xql_raw | limit 1 | alter check_ip = if(action_local_ip ~= "^10", //boolean expression1 "Local 10", // true return expression1 action_local_ip ~= "^172", //boolean expression2 "Local 172 ?", //true return expression2 action_local_ip ~= "^192\.168", //boolean expression3 "Local 192") //true return expression3
Explanation: The query targets the sample_xql_raw dataset for a 7-day period and limits the output to a single record. The query uses the alter stage to create a new field, check_ip, driven by the if() function. The function sequentially evaluates three regular expression matches (~=) against the action_local_ip field:
- If the IP starts with "10", it returns "Local 10".
- If the first condition is false and the IP starts with "172", it returns "Local 172 ?".
- If the previous conditions are false and the IP starts with "192.168", it returns "Local 192".
- If none of these conditions are met, the function returns
null.
Output:
| action_local_ip | check_ip |
|---|---|
| 192.168.1.50 | Local 192 |
Related articles
incidr
Use the incidr() function to determine if an IPv4 address is contained within one or more specified Classless Inter-Domain Routing (CIDR) blocks. The function returns true if the address falls within any of the defined ranges, and false otherwise.
Syntax
incidr (<ipv4_address_field>, "<cidr_range1>[, <cidr_range2>...]")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
ipv4_address_field |
string | Yes | The field containing the IPv4 address (or a string literal) to evaluate. |
cidr_ranges |
string | Yes | A string literal containing one or more IPv4 ranges in CIDR notation (for example, "192.168.1.0/24"), separated by commas. |
Returns
The incidr() function returns a boolean value (true or false).
Usage notes
- The first parameter must contain an IPv4 address contained in an IPv4 field. For production purposes, this IPv4 address will normally be carried in a field that you retrieve from a dataset. For manual usage, assign the IPv4 address to a field, and then use that field with this function.
- This function is specifically designed for IPv4 addresses. For IPv6, use the
incidr6()function. - You can define multiple CIDR ranges within the second parameter string by separating them with commas.
- When multiple CIDR ranges are provided, the function uses logical OR logic. If the IP address falls within any of the specified ranges, the function returns
true. - This function is commonly used within the
filterstage to narrow down results based on network segments (for example, separating internal traffic from external traffic). - To check if an IP is not in a range, you can use the syntax
not incidr().
Examples
Example 1: Check if IP is in a single CIDR block (match)
Goal: Filter for records where the ipv4_address falls within a specific private network range (192.168.1.0/24).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv4_address incidr("192.168.1.0/24") | fields event_id, ipv4_address | limit 5
Explanation: The query evaluates the ipv4_address for each record. The query returns the record with event_id 101 because its IP (192.168.1.10) is within the 192.168.1.0/24 range.
Output:
| EVENT_ID | IPV4_ADDRESS |
|---|---|
| 101 | 192.168.1.10 |
Example 2: Check if IP is in a single CIDR block (no match)
Goal: Filter for records where the ipv4_address falls within the 10.0.0.0/8 private network range.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv4_address incidr("10.0.0.0/8") | fields event_id, ipv4_address | limit 5
Explanation: The query checks if the ipv4_address is in the 10.0.0.0/8 range. The query returns event_id 102 because its IP (10.0.0.5) falls within this block. Other records with different IPs (like 192.168.x.x) are excluded.
Output:
| EVENT_ID | IPV4_ADDRESS |
|---|---|
| 102 | 10.0.0.5 |
Example 3: Check if IP address is in multiple CIDR blocks (logical OR)
Goal: Filter for records where the ipv4_address falls within either the 10.0.0.0/8 range or the 192.168.1.0/24 range.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv4_address incidr("10.0.0.0/8, 192.168.1.0/24") | fields event_id, ipv4_address | limit 5
Explanation: The query uses a comma-separated list of CIDRs. The query returns event_id 101 because 192.168.1.10 matches the second CIDR, and event_id 102 because 10.0.0.5 matches the first CIDR. This demonstrates the logical OR behavior.
Output:
| EVENT_ID | IPV4_ADDRESS |
|---|---|
| 101 | 192.168.1.10 |
| 102 | 10.0.0.5 |
Example 4: Exclude IP addresses in multiple CIDR blocks (not incidr)
Goal: Filter for records where the ipv4_address does not fall within common private IPv4 ranges, effectively filtering for public IPs.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv4_address not incidr("10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16") | fields event_id, ipv4_address | limit 5
Explanation: The query uses not incidr to exclude any IP addresses found in the specified private ranges. The query returns event_id 106 because its IP (203.0.113.15) is a public address and does not match any of the provided private CIDRs.
Output:
| EVENT_ID | IPV4_ADDRESS |
|---|---|
| 106 | 203.0.113.15 |
Related articles
- Stages:
filter - Functions:
incidr6,incidrlist - Datasets:
xdr_data
incidr6
Use the incidr6() function to determine if an IPv6 address falls within one or more specified Classless Inter-Domain Routing (CIDR) blocks.
Syntax
incidr6 (<ipv6_address_field>, "<cidr6_range1>[, <cidr6_range2>...]")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
ipv6_address_field |
string, ip | Yes | The IPv6 address field (or explicit string literal) to evaluate. |
cidr6_range |
string | Yes | One or more IPv6 CIDR ranges, provided as a comma-separated string enclosed in double quotes (for example, "2001:db8::/32" or "2001:db8::/32, 2001:db8:cafe::/48"). |
Returns
The incidr6() function returns a boolean value (true or false). The function returns true if the address falls within any of the defined ranges, and false otherwise.
Usage notes
- This function is designed specifically for IPv6 addresses. Use
incidr()for IPv4 addresses. - The first parameter must contain an IPv6 address contained in an IPv6 field. For production purposes, this IPv6 address will normally be carried in a field that you retrieve from a dataset. For manual usage, assign the IPv6 address to a field, and then use that field with this function.
- When multiple CIDR ranges are provided in the second parameter (separated by commas), the function applies a logical OR operation. If the IPv6 address matches any of the listed ranges, the function returns
true. - This function is commonly used within the
filterstage to narrow down results based on network segments or specific IP ranges.
Examples
Example 1: Check against a single IPv6 CIDR
Goal: Filter for records where the ipv6_address falls within a specific /32 global unicast CIDR block.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv6_address incidr6("2001:0db8::/32") | fields event_id, ipv6_address | limit 5
Explanation: The query evaluates the ipv6_address field for each record. The query returns only those records where the address (for example, 2001:0db8::1) falls within the 2001:0db8::/32 range.
Output:
| EVENT_ID | IPV6_ADDRESS |
|---|---|
| 103 | 2001:0db8::1 |
| 107 | 2001:0db8:cafe::1 |
| 109 | 2001:0db8:1234::abcd |
Example 2: Check against multiple IPv6 CIDRs
Goal: Filter for records where the ipv6_address falls within either of the specified IPv6 CIDR ranges.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv6_address incidr6("2001:0db8:cafe::/48, 2001:0db8:1234::/48") | fields event_id, ipv6_address | limit 5
Explanation: The query uses a comma-separated list of CIDRs. The query returns records where the ipv6_address matches either the first range (2001:0db8:cafe::/48) OR the second range (2001:0db8:1234::/48). Event ID 107 matches the first, and Event ID 109 matches the second.
Output:
| EVENT_ID | IPV6_ADDRESS |
|---|---|
| 107 | 2001:0db8:cafe::1 |
| 109 | 2001:0db8:1234::abcd |
Related articles
- Stages:
filter - Functions:
incidr,incidrlist
incidrlist
Use the incidrlist() function to check if all IP addresses provided in a comma-separated list are contained within a given IPv4 CIDR range.
Syntax
incidrlis (<IP_address list>, <CIDR_range>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
IP_address list |
string | Yes | A string containing one or more IPv4 addresses, separated by commas. |
CIDR_range |
string | Yes | A string literal specifying an IPv4 range in CIDR notation (for example, "192.168.1.0/24"). |
Returns
The incidrlist() function returns a boolean value (true or false).
Usage notes
incidrlist()returnstrueonly if all IP addresses within the address list fall within the specified CIDR range.- If even one IP address in the list is outside the CIDR, the function returns
false. - The input
CIDR_rangeonly accepts a single CIDR range. If more are provided, the query fails.
Examples
Example 1: All IP addresses in list match the CIDR range
Goal: Check if a list of IP addresses are all within a specific subnet.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter all_ips_in_range = incidrlist("192.168.1.10,192.168.10.20", "192.168.0.0/16") | fields event_id, all_ips_in_range | limit 3
Explanation: For every record, the incidrlist() function evaluates if both 192.168.1.10 and 192.168.10.20 are within the 192.168.0.0/16 range. Because both are private IP addresses within this broader range, the function consistently returns true.
Output:
| EVENT_ID | ALL_IPS_IN_RANGE |
|---|---|
| 101 | true |
| 102 | true |
| 103 | true |
Example 2: Not all IP addresses in list match the CIDR range
Goal: Check a list containing a public IP against a private CIDR range.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter not_all_ips_in_range = incidrlist("192.168.1.10,203.0.113.15", "192.168.0.0/16") | fields event_id, not_all_ips_in_range | limit 3
Explanation: The incidrlist() function checks each IP address in the list. Because 203.0.113.15 is not within 192.168.0.0/16, the condition that all IP addresses must be in range is not met, resulting in false for every record.
Output:
| EVENT_ID | NOT_ALL_IPS_IN_RANGE |
|---|---|
| 101 | false |
| 102 | false |
| 103 | false |
Example: Check an array of IP addresses against a CIDR range
Goal: Evaluate whether any IP address within an array matches a specific CIDR block by first converting the array into a comma-separated string.
XQL Code:
dataset = panw_ngfw_traffic_raw | filter dest_ip != null | comp values(dest_ip) as dips by source_ip, action | alter dips = arraystring(dips, ", ") | alter inrange = incidrlist(dips, "192.168.10.0/24") | fields source_ip, action, dips, inrange | limit 100
Explanation: The query targets the panw_ngfw_traffic_raw dataset, filtering out records where the destination IP is null. The query then uses the comp stage to aggregate all unique dest_ip values into an array named dips, grouped by source_ip and action.
- Since the
incidrlist()function requires a string input, thearraystring()function converts thedipsarray into a single string with values separated by a comma and a space. - The
incidrlist()function then evaluates this string to determine if any of the IP addresses contained within it fall inside the "192.168.10.0/24" network range. - The result is stored in the
inrangefield as a boolean (trueorfalse).
Output:
| source_ip | action | dips | inrange |
|---|---|---|---|
| 10.1.1.5 | allow | 192.168.10.15, 8.8.8.8, 172.16.0.1 | true |
| 10.1.1.10 | deny | 1.1.1.1, 10.50.50.2 | false |
Related articles
int_to_ip
Use the int_to_ip() function to convert a signed integer representation of an IPv4 address into its standard dotted-decimal string equivalent.
Syntax
int_to_ip(<IPv4_integer>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
IPv4_integer |
integer | Yes | The integer value that represents an IPv4 address. |
Returns
The int_to_ip() function returns the corresponding IPv4 address as a string.
Usage notes
- This function is the inverse of the
ip_to_int()function, which converts a string representation of an IPv4 address to an integer. - The function safely handles signed integers, meaning it can process both positive and negative integer inputs to produce valid IP address strings.
- Ideally, this function is utilized within the
alterstage to create new fields or modify existing ones based on the converted IP address.
Examples
Example 1: Convert standard positive integer to IPv4
Goal: Convert a standard positive integer representing an IPv4 address to its dotted-decimal string form.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter converted_ip = int_to_ip(75643532) | fields event_id, converted_ip | limit 3
Explanation: The query creates a new field converted_ip by converting the integer 75643532 to its IPv4 string equivalent, which is "4.130.58.140".
Output:
| EVENT_ID | CONVERTED_IP |
|---|---|
| 101 | 4.130.58.140 |
| 102 | 4.130.58.140 |
| 103 | 4.130.58.140 |
Example 2: Convert negative integer to IPv4
Goal: Convert a negative integer, which represents an IPv4 address in a different byte order, to its corresponding dotted-decimal string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter converted_ip = int_to_ip(-75643532) | fields event_id, converted_ip | limit 3
Explanation: The query creates a new field converted_ip by converting the integer -75643532 to its IPv4 string equivalent, which is "251.125.197.116".
Output:
| EVENT_ID | CONVERTED_IP |
|---|---|
| 101 | 251.125.197.116 |
| 102 | 251.125.197.116 |
| 103 | 251.125.197.116 |
Example 3: Convert zero to IPv4
Goal: Convert the integer 0 to its IPv4 address string representation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter converted_ip = int_to_ip(0) | fields event_id, converted_ip | limit 3
Explanation: The query creates converted_ip by converting 0 to its IPv4 string equivalent, "0.0.0.0".
Output:
| EVENT_ID | CONVERTED_IP |
|---|---|
| 101 | 0.0.0.0 |
| 102 | 0.0.0.0 |
| 103 | 0.0.0.0 |
Example 4: Convert large positive integer to IPv4 (broadcast address)
Goal: Convert the maximum unsigned 32-bit integer to its IPv4 address string representation, which corresponds to the broadcast address.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter converted_ip = int_to_ip(4294967295) // Converts the integer 4294967295 (2^32 - 1) to an IPv4 address | fields event_id, converted_ip | limit 3
Explanation: The query creates a new field converted_ip by converting the integer 4294967295 (which is ) to its IPv4 string equivalent, "255.255.255.255".
Output:
| EVENT_ID | CONVERTED_IP |
|---|---|
| 101 | 255.255.255.255 |
| 102 | 255.255.255.255 |
| 103 | 255.255.255.255 |
Related articles
ip_to_int
Use the ip_to_int() function to safely convert a string representation of an IPv4 address into its signed integer equivalent.
Syntax
ip_to_int (<IPv4_address>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
IPv4_address |
string | Yes | The string representation of a valid IPv4 address. |
Returns
The ip_to_int() function returns the signed integer representation of the provided IPv4 address string.
Usage notes
- This function is designed to safely convert a string representation of an IPv4 address into its signed integer equivalent.
- This conversion is crucial for scenarios where numerical operations or comparisons are required on IP addresses, or for storing them in an integer format.
ip_to_int()is the inverse ofint_to_ip(), which converts an integer representation of an IPv4 address back to its string format.- This function was previously known as
safe_ip_to_int(). - If the input
IPv4_addressisNULL, the function returnsNULL.
Examples
Example 1: Converting a literal IPv4 address string
Goal: Convert a static string representation of an IPv4 address into its integer form.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter converted_ip_int = ip_to_int("48.49.50.51") // Converts the literal string "48.49.50.51" to an integer | fields event_id, converted_ip_int | limit 3
Explanation: The query creates a new field converted_ip_int by converting the literal IPv4 string "48.49.50.51" to its integer equivalent, which is 808530483. This value is constant across all returned records.
Output:
| EVENT_ID | CONVERTED_IP_INT |
|---|---|
| 101 | 808530483 |
| 102 | 808530483 |
| 103 | 808530483 |
Example 2: Converting an IPv4 address from a dataset field
Goal: Apply the function to the ipv4_address field present in the dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter converted_ip_from_field = ip_to_int(ipv4_address) // Converts the ipv4_address field to an integer | fields event_id, ipv4_address, converted_ip_from_field | limit 6
Explanation: For each record, ipv4_address is converted to its integer representation in the converted_ip_from_field. Records with a NULL ipv4_address (like event_id 103) will also result in a NULL converted_ip_from_field.
Output:
| EVENT_ID | IPV4_ADDRESS | CONVERTED_IP_FROM_FIELD |
|---|---|---|
| 101 | 192.168.1.10 | 3232235786 |
| 102 | 10.0.0.5 | 167772165 |
| 103 | NULL | NULL |
| 104 | 172.31.255.255 | 2892780543 |
| 105 | 192.168.10.20 | 3232238100 |
| 106 | 203.0.113.15 | 3407889679 |
Example 3: Handling NULL input
Goal: Demonstrate behavior when provided with a NULL input, by filtering for records where ipv4_address is NULL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv4_address = null // Focus on records where ipv4_address is NULL | alter converted_null_ip_int = ip_to_int(ipv4_address) // Attempts conversion of NULL | fields event_id, ipv4_address, converted_null_ip_int | limit 3
Explanation: As is standard behavior for XQL functions when encountering null inputs, ip_to_int() returns NULL when its input ipv4_address is NULL.
Output:
| EVENT_ID | IPV4_ADDRESS | CONVERTED_NULL_IP_INT |
|---|---|---|
| 103 | NULL | NULL |
| 107 | NULL | NULL |
| 109 | NULL | NULL |
Example 4: Converting a private IPv4 address
Goal: Target a specific private IPv4 address from the dataset to demonstrate its conversion.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 102 // Selects event with a private IP: 10.0.0.5 | alter private_ip_as_int = ip_to_int(ipv4_address) // Converts the private IPv4 string to integer | fields event_id, ipv4_address, private_ip_as_int | limit 1
Explanation: The private IP address "10.0.0.5" is successfully converted to its corresponding integer value 167772165.
Output:
| EVENT_ID | IPV4_ADDRESS | PRIVATE_IP_AS_INT |
|---|---|---|
| 102 | 10.0.0.5 | 167772165 |
Example 5: Converting a public IPv4 address
Goal: Target a specific public IPv4 address from the dataset to demonstrate its conversion.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 106 // Selects event with a public IP: 203.0.113.15 | alter public_ip_as_int = ip_to_int(ipv4_address) // Converts the public IPv4 string to integer | fields event_id, ipv4_address, public_ip_as_int | limit 1
Explanation: The public IP address "203.0.113.15" is successfully converted to its corresponding integer value 3407889679.
Output:
| EVENT_ID | IPV4_ADDRESS | PUBLIC_IP_AS_INT |
|---|---|---|
| 106 | 203.0.113.15 | 3407889679 |
Related articles
is_ipv4
Use the is_ipv4() function to determine if a string value represents a valid IPv4 address.
Syntax
is_ipv4(<string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The string field or literal value to evaluate for IPv4 validity. |
Returns
The is_ipv4() function returns a boolean value: true if the string is a valid IPv4 address, and false otherwise.
Usage Notes
The function expects a string input and will return NULL if the input field is NULL.
Validation is strictly for IPv4 dotted-decimal format (for example, "192.168.1.1").
This function is typically used within the alter stage to tag records or within the filter stage to isolate specific traffic types.
Examples
Example 1: Validate IPv4 Addresses in a Dataset
Goal: Identify which records in the dataset contain a valid IPv4 address in the ipv4_address field.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | alter valid_ip = is_ipv4(ipv4_address) | fields event_id, ipv4_address, valid_ip | limit 3
Explanation: You use the is_ipv4() function to check the ipv4_address field. For record 101, the is_ipv4() function returns true because "192.168.1.10" is a valid IPv4 address. For record 103, where the field is NULL, the is_ipv4() function returns NULL.
Output:
| EVENT_ID | IPV4_ADDRESS | VALID_IP |
|---|---|---|
| 101 | 192.168.1.10 | true |
| 102 | 10.0.0.5 | true |
| 103 | NULL | NULL |
Example 2: Filtering for Valid IPv4 Traffic
Goal: Filter the result set to return only those records that have a valid IPv4 address.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | filter is_ipv4(ipv4_address) = true | fields event_id, ipv4_address | limit 2
Explanation: You apply the is_ipv4() function directly within a filter stage to exclude any records where the ipv4_address field does not contain a properly formatted IPv4 address.
Output:
| EVENT_ID | IPV4_ADDRESS |
|---|---|
| 101 | 192.168.1.10 |
| 102 | 10.0.0.5 |
Related Articles
- Stages: alter, filter, fields, limit
- Functions: incidr(), int_to_ip(), ip_to_int()
is_ipv6
Use the is_ipv6() function to determine if a string value represents a valid IPv6 address.
Syntax
is_ipv6(<string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| string | string | Yes | The string field or literal value to evaluate for IPv6 validity. The IPv6 address can be either an explicit string using quotes (for example, "2606:4700:4700::1111") or a string field. |
Returns
The is_ipv6() function returns a boolean value: true if the string is a valid IPv6 address, and false otherwise.
Usage Notes
- The function expects a string input and will return NULL if the input field is NULL or not present.
- Validation is strictly for IPv6 address formats. The function will return false for standard IPv4 addresses (for example, "1.1.1.1").
- This function is typically used within the
alterstage to tag records, or within thefilterstage to isolate specific IPv6 network traffic.
Examples
Example 1: Filter the IPv6 Addresses
Goal: Filter a dataset to evaluate an ip field and return only the records containing a valid IPv6 address.
XQL Code:
dataset = ips_test_raw | alter IsIpv6 = is_ipv6(ip) | filter IsIpv6
Explanation: You use the is_ipv6() function in the alter stage to check the ip field and assign the boolean result to a new field named IsIpv6. Next, you apply the filter stage to return only the rows where IsIpv6 evaluates to true. While the original dataset contained IPv4 addresses like "1.1.1.1" and "192.168.1.100" (which evaluate to false), the filtered output retains only the valid IPv6 addresses "FF0E::1" and "2606:4700:4700::1111".
Output:
| _TIME | IP | _VENDOR | _PRODUCT | ISIPV6 |
|---|---|---|---|---|
| Mar 26th 2025 19:26:07 | FF0E::1 | ips | test | true |
| Mar 26th 2025 19:26:07 | 2606:4700:4700::1111 | ips | test | true |
Related Articles
- Stages: alter, filter
- Functions: is_ipv4(), is_known_private_ipv4(), is_known_private_ipv6(), incidr6()
- Datasets: ips_test_raw
is_known_private_ipv4
Use the is_known_private_ipv4() function to determine if a string value represents a known private, non-routable IPv4 address.
Syntax
is_known_private_ipv4(<string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| string | string | Yes | The string field or literal value representing an IPv4 address to evaluate. |
Returns
The is_known_private_ipv4() function returns a boolean value true if the string is a valid private IPv4 address (such as those defined in RFC 1918), and false otherwise.
Usage Notes
- The function expects a string input and returns
NULLif the input field isNULLor does not evaluate to a valid IPv4 address. - The function evaluates standard private and special-purpose IP address spaces, typically including 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, loopback addresses (127.0.0.0/8), and link-local addresses (169.254.0.0/16).
- This function is frequently used within the
alterstage to tag internal network traffic, or within thefilterstage to exclude internal communication from external threat hunts.
Examples
Example 1: Identify Private IPv4 Addresses in a Dataset
Goal: Identify which records in the dataset contain a known private IPv4 address in the ipv4_address field.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | alter is_private = is_known_private_ipv4(ipv4_address) | fields event_id, ipv4_address, is_private | limit 3
Explanation: You use the is_known_private_ipv4() function to check the ipv4_address field. For record 101, the function returns true because "10.0.0.5" belongs to a private subnet. For record 102, it returns false because "8.8.8.8" is a public routable IP. For record 103, where the field is NULL, it returns NULL.
Output:
| EVENT_ID | IPV4_ADDRESS | IS_PRIVATE |
|---|---|---|
| 101 | 10.0.0.5 | true |
| 102 | 8.8.8.8 | false |
| 103 | NULL | NULL |
Example 2: Filtering for External (Public) IPv4 Traffic
Goal: Filter the result set to return only those records that do not contain a private IPv4 address.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | filter is_known_private_ipv4(ipv4_address) = false | fields event_id, ipv4_address | limit 2
Explanation: You apply the is_known_private_ipv4() function directly within a filter stage and check for false to isolate external (public) IP addresses, filtering out any internal traffic.
Output:
| EVENT_ID | IPV4_ADDRESS |
|---|---|
| 102 | 8.8.8.8 |
| 104 | 1.1.1.1 |
Related Articles
is_known_private_ipv6
Use the is_known_private_ipv6() function to determine if a string value represents a known private, non-routable IPv6 address.
Syntax
is_known_private_ipv6(\<string\>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| string | string | Yes | The string field or literal value representing an IPv6 address to evaluate. |
Returns
The is_known_private_ipv6() function returns a boolean value: true if the string is a valid private IPv6 address (such as those defined in RFC 4193 for Unique Local Addresses), and false otherwise.
Usage Notes
- The function expects a string input and will return NULL if the input field is NULL or does not evaluate to a valid IPv6 address.
- The function evaluates standard private and special-purpose IPv6 address spaces, typically including Unique Local Addresses (ULA) within the fc00::/7 block (which includes fd00::/8), loopback addresses (::1/128), and link-local addresses (fe80::/10).
- This function is frequently used within the alter stage to tag internal network traffic, or within the filter stage to exclude internal communication from external threat hunts.
Examples
Example 1: Identify Private IPv6 Addresses in a Dataset
Goal: Identify which records in the dataset contain a known private IPv6 address in the ip field.
XQL Code:
dataset = ips_test_raw | alter is_private = is_known_private_ipv6(ip) | fields _time, ip, is_private | limit 3
Explanation: You use the is_known_private_ipv6() function in the alter stage to check the ip field. For the first record, the function returns true because fc00::1 is a Unique Local Address (ULA) and thus a private subnet. For the second record, it returns false because 2606:4700:4700::1111 is a public routable IPv6 address. For the third record, where the field is an IPv4 address, it returns NULL.
Output:
| _TIME | IP | IS_PRIVATE |
|---|---|---|
| Mar 26th 2025 19:26:07 | fc00::1 | true |
| Mar 26th 2025 19:26:07 | 2606:4700:4700::1111 | false |
| Mar 26th 2025 19:26:07 | 10.0.0.5 | NULL |
Example 2: Filtering for External (Public) IPv6 Traffic
Goal: Filter a dataset to return only those records that contain a valid IPv6 address that is not a private address.
XQL Code:
dataset = ips_test_raw | filter is_ipv6(ip) and is_known_private_ipv6(ip) = false | fields _time, ip
Explanation: You apply both the is_ipv6() and is_known_private_ipv6() functions directly within a filter stage. By ensuring the address is a valid IPv6 format and checking for false on the private evaluation, you isolate external (public) IPv6 addresses, filtering out any internal traffic or standard IPv4 data.
Output:
| _TIME | IP |
|---|---|
| Mar 26th 2025 19:26:07 | 2606:4700:4700::1111 |
| Mar 26th 2025 19:26:07 | 2001:db8:3333:4444:5555:6666:7777:8888 |
Related Articles
- Stages: alter, filter, fields, limit
- Functions: is_ipv6(), is_known_private_ipv4(), incidr6()
- Datasets: ips_test_raw
json_extract
Use the json_extract() function to extract a specific JSON object or array from within a larger JSON-formatted string by navigating a specified path.
Syntax
json_extract (<json_object_formatted_string>, <json_path>)
Syntactic Sugar Format
<json_object_formatted_string> -> <json_path>{}
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
json_object_formatted_string |
string | Yes | The field containing the JSON string from which to extract data. If the field is an object or array, use to_json_string() to convert it first. |
json_path |
string | Yes | The path to the data within the JSON object. In regular syntax, it starts with $. In syntactic sugar, the $ is omitted. Use brackets ['key'] or ["key"] for keys with special characters. |
Returns
The json_extract() function returns a string representation of the extracted JSON object or array.
Usage notes
- Input requirement: The function requires a field that contains a JSON-formatted string. If your field is a native XQL object or array, you must convert it using
to_json_string()before extraction. - Output format: The function always returns a string. If the path points to a scalar value (string, number, boolean), it returns that value quoted as a JSON literal string. For direct scalar extraction without quotes (for numbers/booleans), consider using
json_extract_scalar(). - Case sensitivity: JSON field names are case-sensitive. The key in your
json_pathmust exactly match the case of the field name in the JSON object. - Handling special characters: When a field name in the path contains special characters like a dot (
.) or colon (:):- Regular syntax: Use the syntax
json_extract(<json_object_formatted_string>, "['<json_field>']"). - Syntactic sugar syntax: Use the syntax
<json_object_formatted_string> -> ["<json_field>"]{}.
- Regular syntax: Use the syntax
- Error handling: If the input string is not a valid JSON object, or if the specified
json_pathdoes not exist, the function returnsNULL.
Examples
Example 1: Basic object property extraction
Goal: Extract a nested JSON object from a parent object.
XQL code:
Regular Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter extracted_user_info = json_extract(to_json_string(nested_json_data), "$.user") | fields event_id, nested_json_data, extracted_user_info | limit 1
Syntactic Sugar Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter extracted_user_info = to_json_string(nested_json_data) -> user{} | fields event_id, nested_json_data, extracted_user_info | limit 1
Explanation: For event_id 101, the nested_json_data field contains a user object. The query converts the field to a JSON string and extracts the entire nested object, including keys and values.
Output:
| EVENT_ID | NESTED_JSON_DATA | EXTRACTED_USER_INFO |
|---|---|---|
| 101 | {"user": {"id": "U1", "name": "Alice"}, "session": {...}} | {"id": "U1", "name": "Alice"} |
Example 2: Extracting a deeper nested object property
Goal: Navigate deeper into a JSON structure to extract a specific nested object.
XQL code:
Regular Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter extracted_session_info = json_extract(to_json_string(nested_json_data), "$.session") | fields event_id, nested_json_data, extracted_session_info | limit 1
Syntactic Sugar Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter extracted_session_info = to_json_string(nested_json_data) -> session{} | fields event_id, nested_json_data, extracted_session_info | limit 1
Explanation: The query extracts the session object, which is nested within nested_json_data, holding the session details.
Output:
| EVENT_ID | NESTED_JSON_DATA | EXTRACTED_SESSION_INFO |
|---|---|---|
| 101 | {"user": {...}, "session": {"start": "10:00", "type": "web"}} | {"start": "10:00", "type": "web"} |
Example 3: Extracting a JSON object from an array using index
Goal: Extract a specific JSON object from an array field using its index.
XQL code:
Regular Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter extracted_first_action_obj = json_extract(to_json_string(array_of_json_objects), "$[0]") | fields event_id, array_of_json_objects, extracted_first_action_obj | limit 1
Syntactic Sugar Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter extracted_first_action_obj = to_json_string(array_of_json_objects) -> [0]{} | fields event_id, array_of_json_objects, extracted_first_action_obj | limit 1
Explanation: The field array_of_json_objects contains an array of objects. The path $[0] (or [0]{}) extracts the first object in the array as a string.
Output:
| EVENT_ID | ARRAY_OF_JSON_OBJECTS | EXTRACTED_FIRST_ACTION_OBJ |
|---|---|---|
| 101 | [{"action": "read", "file": "doc1.txt"}, {"action": "write", ...}] | {"action": "read", "file": "doc1.txt"} |
Example 4: Extracting the entire JSON field content (root extraction)
Goal: Extract the complete content of a JSON-formatted field as a string.
XQL code:
Regular Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter extracted_full_json = json_extract(to_json_string(simple_json_data), "$") | fields event_id, simple_json_data, extracted_full_json | limit 1
Syntactic Sugar Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter extracted_full_json = to_json_string(simple_json_data) -> {} | fields event_id, simple_json_data, extracted_full_json | limit 1
Explanation: Using $ or {} with an empty string as the path signifies that the entire JSON content is to be extracted and returned.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | EXTRACTED_FULL_JSON |
|---|---|---|
| 101 | {"status": "ok", "code": 200} | {"status": "ok", "code": 200} |
Example 5: Extraction with a key containing special characters
Goal: Extract data when a key name contains special characters like a dot (.).
XQL code:
Regular Syntax
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_with_special_key = to_string("{\"device.info\": {\"model\": \"XDR Agent\", \"version\": \"8.0\"}}") | alter extracted_special_key_obj = json_extract(json_with_special_key, "$['device.info']") | fields event_id, json_with_special_key, extracted_special_key_obj
Syntactic Sugar Syntax
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_with_special_key = to_string("{\"device.info\": {\"model\": \"XDR Agent\", \"version\": \"8.0\"}}") | alter extracted_special_key_obj = json_with_special_key -> ["device.info"]{} | fields event_id, json_with_special_key, extracted_special_key_obj
Explanation: The key device.info contains a dot. In regular syntax, it is enclosed in single quotes and brackets ['device.info']. In syntactic sugar, it uses double quotes and brackets ["device.info"].
Output:
| EVENT_ID | JSON_WITH_SPECIAL_KEY | EXTRACTED_SPECIAL_KEY_OBJ |
|---|---|---|
| 101 | {"device.info": {"model": "XDR Agent", "version": "8.0"}} | {"model": "XDR Agent", "version": "8.0"} |
Example 6: Handling a path that does not exist
Goal: Demonstrate behavior when the specified JSON path is not found.
XQL code:
Regular Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 103 | alter extracted_non_existent = json_extract(to_json_string(simple_json_data), "$.status") | fields event_id, simple_json_data, extracted_non_existent | limit 1
Syntactic Sugar Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 103 | alter extracted_non_existent = to_json_string(simple_json_data) -> status{} | fields event_id, simple_json_data, extracted_non_existent | limit 1
Explanation: For event_id 103, the simple_json_data field does not contain a status key. The function returns NULL.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | EXTRACTED_NON_EXISTENT |
|---|---|---|
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL |
Example 7: Handling non-JSON formatted string input
Goal: Demonstrate behavior when the input is not valid JSON.
XQL code:
Regular Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter non_json_input = event_description | alter result_from_non_json = json_extract(non_json_input, "$") | fields event_id, non_json_input, result_from_non_json | limit 1
Syntactic Sugar Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter non_json_input = event_description | alter result_from_non_json = non_json_input -> {} | fields event_id, non_json_input, result_from_non_json | limit 1
Explanation: The event_description field is a plain string ("User login successful"), not a JSON structure. The function fails to parse it and returns NULL.
Output:
| EVENT_ID | NON_JSON_INPUT | RESULT_FROM_NON_JSON |
|---|---|---|
| 101 | "User login successful" | NULL |
Example 8: Using to_json_string() for explicit type conversion
Goal: Ensure input is a valid JSON string by explicitly converting a native object field.
XQL code:
Regular Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter nested_data_as_string = to_json_string(nested_json_data) | alter extracted_user_id = json_extract(nested_data_as_string, "$.user.id") | fields event_id, nested_json_data, nested_data_as_string, extracted_user_id | limit 1
Syntactic Sugar Syntax
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter nested_data_as_string = to_json_string(nested_json_data) | alter extracted_user_id = nested_data_as_string -> user.id{} | fields event_id, nested_json_data, nested_data_as_string, extracted_user_id | limit 1
Explanation: The nested_json_data field is an object. to_json_string() is used to convert it into a valid JSON string required by json_extract(). The value "U1" is extracted as the string "U1".
Output:
| EVENT_ID | NESTED_JSON_DATA | NESTED_DATA_AS_STRING | EXTRACTED_USER_ID |
|---|---|---|---|
| 101 | {"user": {"id": "U1", "name": "Alice"}, ...} | {"user": {"id": "U1", "name": "Alice"}, ...} (as string) | ""U1"" |
Related articles
- Stages:
alter - Functions:
json_extract_scalar,json_extract_array,to_json_string - Datasets:
xdr_data
json_extract_array
Use the json_extract_array() function to accept a string that represents a JSON array and returns an XQL-native array. This function is crucial for transforming JSON-formatted array data into a format that XQL can natively process for further analysis.
Syntax
Regular syntax
json_extract_array (<json_array_string>, <json_path>)
Syntactic Sugar syntax
<json_array_string> -> <json_path>[]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
json_array_string |
string | Yes | The string that represents a JSON array. To convert a field to a JSON-formatted string, use the to_json_string() function. |
json_path |
string | Yes | The argument that identifies the data of the JSON object you want to extract using dot-notation. In regular syntax, the root is represented by $. |
Returns
The json_extract_array() function returns an XQL-native array.
Usage notes
- The function requires a string that represents a JSON array as input.
- JSON field names are case-sensitive. The key-to-field pairing in your XQL query must be identical to the JSON for results to be found.
- When a field in the
<json_path>contains special characters like a dot (.) or colon (:), specific syntax is required:- Regular Syntax**: Use brackets with single quotes:
json_extract_array(<json_array_string>, "['<json_field>']"). - Syntactic Sugar**: Use brackets with double quotes:
<json_array_string> -> ["<json_field>"][].
- Regular Syntax**: Use brackets with single quotes:
- The
$symbol representing the root of the JSON structure is required in the regular syntax but is not required in the syntactic sugar format.
Examples
Example 1: Extracting a root-level JSON array
Goal: Extract a direct JSON array from the array_of_json_objects field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_array = json_extract_array(to_json_string(array_of_json_objects), "$") | fields event_id, array_of_json_objects, extracted_array | limit 2
Explanation: This query demonstrates extracting a direct JSON array. The syntactic sugar equivalent is to_json_string(array_of_json_objects) -> [].
Output:
| EVENT_ID | ARRAY_OF_JSON_OBJECTS | EXTRACTED_ARRAY |
|---|---|---|
| 101 | [{"action": "read", "file": "doc1.txt"}, {"action": "write", "file": "report.log"}] | [{"action": "read", "file": "doc1.txt"}, {"action": "write", "file": "report.log"}] |
| 102 | [{"event": "file_open", "path": "/etc/passwd"}] | [{"event": "file_open", "path": "/etc/passwd"}] |
Example 2: Extracting a nested array with special characters in key
Goal: Extract an array where a key in the path contains a special character (a dot), demonstrating proper escaping.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_ips = json_extract_array(to_json_string(json_with_nested_array), "$['device.info']['ip.addresses']") | fields event_id, json_with_nested_array, extracted_ips | limit 2
Explanation: The device.info and ip.addresses keys are enclosed in single quotes within brackets (['device.info']['ip.addresses']) because they contain a dot, as per XQL syntax rules for regular JSON path. The syntactic sugar equivalent is to_json_string(json_with_nested_array) -> ["device.info"]["ip.addresses"][].
Output:
| EVENT_ID | JSON_WITH_NESTED_ARRAY | EXTRACTED_IPS |
|---|---|---|
| 101 | {"device.info": {"ip.addresses": ["172.16.6.7", "172.16.8.9"]}} | ["172.16.6.7", "172.16.8.9"] |
| 102 | {"device.info": {"ip.addresses": ["10.1.2.3", "10.2.3.4"]}} | ["10.1.2.3", "10.2.3.4"] |
Example 3: Extracting an XQL numeric array converted to JSON string
Goal: Convert a native XQL array (numeric_codes) to a JSON string and then extract the entire array back.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_numeric = json_extract_array(to_json_string(numeric_codes), "$") | fields event_id, numeric_codes, extracted_numeric | limit 2
Explanation: The query converts the native array to a JSON string and then extracts it. The syntactic sugar equivalent is to_json_string(numeric_codes) -> [].
Output:
| EVENT_ID | NUMERIC_CODES | EXTRACTED_NUMERIC |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | [13, -47, 29, 82, -15] |
| 102 | [-21, 56, 13, -88, 42] | [-21, 56, 13, -88, 42] |
Example 4: Demonstrating XQL-native array output and element access
Goal: Showcase that json_extract_array() returns an XQL-native array that can be manipulated by other array functions like arrayindex().
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter ip_addresses_array = to_json_string(json_with_nested_array) -> ["device.info"]["ip.addresses"][] | alter first_ip = arrayindex(ip_addresses_array, 0) | fields event_id, json_with_nested_array, ip_addresses_array, first_ip | limit 2
Explanation: The ip_addresses_array is successfully extracted as an XQL-native array using json_extract_array() (syntactic sugar syntax used here). Subsequently, arrayindex() is used to retrieve the first element from this XQL-native array.
Output:
| EVENT_ID | JSON_WITH_NESTED_ARRAY | IP_ADDRESSES_ARRAY | FIRST_IP |
|---|---|---|---|
| 101 | {"device.info": {"ip.addresses": ["172.16.6.7", "172.16.8.9"]}} | ["172.16.6.7", "172.16.8.9"] | "172.16.6.7" |
| 102 | {"device.info": {"ip.addresses": ["10.1.2.3", "10.2.3.4"]}} | ["10.1.2.3", "10.2.3.4"] | "10.1.2.3" |
Related articles
- Stages:
alter,fields - Functions:
to_json_string,arrayindex - Datasets:
xdr_data
json_extract_scalar
Use the json_extract_scalar() function to retrieve a single, atomic value—such as a string, number, or boolean—from a JSON object.
Syntax
json_extract_scalar (<json_object_formatted_string>, <json_path>)
Syntactic Sugar syntax
<json_object_formatted_string> -> <field_path>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
json_object_formatted_string |
string | Yes | The string representation of the JSON object. |
json_path |
string | Yes | The path to the specific scalar value to extract, typically starting with $ to represent the root. |
Returns
The json_extract_scalar() function returns the extracted value as a string. If the targeted JSON field is an object or an array, or if the path does not exist, the function returns NULL.
Usage notes
- The input
<json_object_formatted_string>must be a string representation of a JSON object. You may need to useto_json_string()to convert fields likenested_json_databefore extraction. - This function always returns the extracted value as a string. To use the value as a number or boolean, you must chain functions like
to_integer(),to_float(), orto_boolean(). - JSON field names are case-sensitive. The key in your
json_pathmust match the case in the JSON object exactly. - XQL supports a "syntactic sugar" format for this function:
<json_object_formatted_string> -> <field_path>. In this format, the leading$is not required. - When a field name within the
<json_path>contains special characters like a dot (.) or colon (:):- In regular syntax, enclose the field in single quotes within brackets: json_extract_scalar(<json_object_formatted_string>, "['<json_field>']").
- In Syntactic Sugar syntax, enclose the field in double quotes within brackets: <json_object_formatted_string> -> ["<json_field>"].
Examples
Example 1: Extracting a top-level string scalar value (status)
Goal: Extract a simple string value directly from the simple_json_data field using both regular syntax and syntactic sugar.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_status = json_extract_scalar(to_json_string(simple_json_data), "$.status") | fields event_id, simple_json_data, extracted_status | limit 2
Explanation: This query converts simple_json_data to a JSON string and extracts the value associated with the "status" key.
Output:
| event_id | simple_json_data | extracted_status |
|---|---|---|
| 101 | {"status": "ok", "code": 200} | "ok" |
| 102 | {"status": "fail", "error": "access_denied"} | "fail" |
Example 2: Extracting a numeric scalar value (code) and converting to integer
Goal: Extract a numeric value (which returns as a string) and explicitly convert it to an integer.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_code_str = json_extract_scalar(to_json_string(simple_json_data), "$.code") | alter extracted_code_int = to_integer(extracted_code_str) | fields event_id, simple_json_data, extracted_code_str, extracted_code_int | limit 2
Explanation: For event 101, the code "200" is extracted as a string and then converted to the integer 200. For event 102, the code field does not exist, so NULL is returned.
Output:
| event_id | simple_json_data | extracted_code_str | extracted_code_int |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | "200" | 200 |
| 102 | {"status": "fail", "error": "access_denied"} | NULL | NULL |
Example 3: Extracting a nested string scalar value (user.name)
Goal: Traverse a nested JSON structure to extract a specific scalar value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_username = json_extract_scalar(to_json_string(nested_json_data), "$.user.name") | fields event_id, nested_json_data, extracted_username | limit 2
Explanation: For event 101, the query navigates to user.name and extracts "Alice". For event 102, the user object is not present, resulting in NULL.
Output:
| event_id | nested_json_data | extracted_username |
|---|---|---|
| 101 | {"user": {"id": "U1", "name": "Alice"}, ...} | "Alice" |
| 102 | {"process": {"name": "cmd.exe", "pid": 1234}, ...} | NULL |
Example 4: Handling special characters in nested key names
Goal: Extract a value where the key name contains a special character (a dot), requiring specific bracket notation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter test_json_data = to_json_string("{\"a.b\": {\"scalar_field\": \"Special Value\"}}") | alter extracted_special_char_regular = json_extract_scalar(test_json_data, "$['a.b'].scalar_field") | fields event_id, test_json_data, extracted_special_char_regular
Explanation: The key 'a.b' is enclosed in single quotes within brackets ['a.b'] because it contains a dot, adhering to XQL's regular JSON path rules.
Output:
| event_id | test_json_data | extracted_special_char_regular |
|---|---|---|
| 101 | {"a.b": {"scalar_field": "Special Value"}} | "Special Value" |
Example 5: Attempting to extract an object or array (returns NULL)
Goal: Demonstrate that the function returns NULL when the targeted path points to a complex structure (object or array) instead of a scalar.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_array_as_scalar = json_extract_scalar(to_json_string(array_of_json_objects), "$") | fields event_id, array_of_json_objects, extracted_array_as_scalar | limit 2
Explanation: Attempting to extract the root $ of array_of_json_objects (which is an array) using json_extract_scalar results in NULL because it is designed only for scalar values.
Output:
| event_id | array_of_json_objects | extracted_array_as_scalar |
|---|---|---|
| 101 | [{"action": "read", ...}] | NULL |
| 102 | [{"event": "file_open", ...}] | NULL |
Example 6: Handling non-existent paths (returns NULL)
Goal: Demonstrate the behavior when the specified JSON path does not exist in the object.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_non_existent = json_extract_scalar(to_json_string(simple_json_data), "$.nonExistentField") | fields event_id, simple_json_data, extracted_non_existent | limit 2
Explanation: Because nonExistentField is not present in the JSON structure, the function gracefully returns NULL.
Output:
| event_id | simple_json_data | extracted_non_existent |
|---|---|---|
| 101 | {"status": "ok", "code": 200} | NULL |
| 102 | {"status": "fail", "error": "access_denied"} | NULL |
Example 7: Filtering using an XQL-native datatype
Goal: Return the storage_device_drive_type value from the action_file_device_info field, and return the record if it is 1.
XQL code:
dataset = xdr_data | fields action_file_device_info as afdi | alter sdn = to_integer(json_extract_scalar(to_json_string(afdi), "$.storage_device_drive_type")) | filter sdn = 1 | limit 10
Explanation: This query converts the action_file_device_info object to a JSON string using to_json_string(), and then uses json_extract_scalar() to extract the storage_device_drive_type value. Because the extraction returns a string, to_integer() is used to cast the value into an XQL-native integer datatype before the filter stage evaluates if the value equals 1.
Output:
| AFDI | SDN |
|---|---|
| {"storage_device_drive_type": 1, "vendor": "SanDisk"} | 1 |
| {"storage_device_drive_type": 1, "vendor": "Samsung"} | 1 |
Example 8: Filtering using a string
Goal: Return the storage_device_drive_type value from the action_file_device_info field, and return the record if it matches the string value of "1".
XQL code:
dataset = xdr_data | fields action_file_device_info as afdi | alter sdn = json_extract_scalar(to_json_string(afdi), "$.storage_device_drive_type") | filter sdn = "1" | limit 10
Explanation: Similar to the first example, this query extracts the storage_device_drive_type value as a string. However, instead of converting the datatype, the filter stage evaluates the result directly against the string literal "1".
Output:
| AFDI | SDN |
|---|---|
| {"storage_device_drive_type": "1", "vendor": "SanDisk"} | "1" |
| {"storage_device_drive_type": "1", "vendor": "Samsung"} | "1" |
Example 9: Filtering using Syntactic Sugar Format
Goal: Return the storage_device_drive_type value from the action_file_device_info field using the shorthand syntactic sugar format.
XQL code:
dataset = xdr_data | fields action_file_device_info as afdi | alter sdn = to_integer(to_json_string(afdi)->storage_device_drive_type) | filter sdn = 1 | limit 10
Explanation: This query achieves the exact same result as Example 7 but utilizes the JSON extract operator (->) as syntactic sugar. This shorthand format replaces the explicit json_extract_scalar() function call, making the query more concise while still converting the extracted string to an integer for the final filter evaluation.
Output:
| AFDI | SDN |
|---|---|
| {"storage_device_drive_type": 1, "vendor": "SanDisk"} | 1 |
| {"storage_device_drive_type": 1, "vendor": "Samsung"} | 1 |
Related articles
- Stages:
alter,config,fields,limit - Functions:
to_json_string,to_integer,to_float,to_boolean
json_extract_scalar_array
Use the json_extract_scalar_array() function to extract a JSON array containing scalar values (strings, numbers, booleans) from a JSON object and represent it as an XQL array of strings.
Syntax
json_extract_scalar_array (<json_array_string>, <json_path>)
When a Cortex Data Model (XDM) field is used in the <json_path> and contains a dot (.) character, for example xdm.source.host.device_id, use the syntax:
json_extract_scalar_array(<json_array_string>, "['<json_field>']")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
json_array_string |
string | Yes | The string that represents a JSON array. If the input is a field, use to_json_string() to convert it first. |
json_path |
string | Yes | The identifier of the data within the JSON object to extract, using dot-notation. In regular syntax, the root is represented by $. If a field name contains special characters (like . or :), enclose it in single quotes within brackets (for example, ['<json_field>']). |
Returns
The json_extract_scalar_array() function returns an XQL-native array containing the extracted scalar values. Unlike json_extract_array(), the scalar values within the returned array are not enclosed in double quotes. If the target array does not exist, or the JSONPath is invalid, it returns NULL.
Usage notes
- If the input field is not already a string representing a JSON object or array, you must use the
to_json_string()function to convert it. - JSON field names are case-sensitive. The key-to-field pairing in your XQL query must be identical to the JSON for results to be found.
- This function does not support a syntactic sugar format; you must use the regular syntax.
- If a field in the
<json_path>contains characters like a dot (.) or colon (:), you must use the bracket notation['<json_field>']. Note that for XDM fields, paths requiring escaping for invalid JSON characters might be unsupported.
Examples
Example 1: Extracting a scalar array from a nested JSON field (with special characters in path)
Goal: Extract the ipv4_address array from the json_with_nested_array field, handling special characters in the JSON path.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter json_string_data = to_json_string(json_with_nested_array) | alter extracted_ips = json_extract_scalar_array(json_string_data, "$['device.info']['ip.addresses']") | fields event_id, json_with_nested_array, extracted_ips | limit 3
Explanation: The query first converts the json_with_nested_array object into a JSON-formatted string using to_json_string(). The query then uses json_extract_scalar_array() to extract the array found at $['device.info']['ip.addresses']. The bracket notation is used because ip.addresses contains a dot. The resulting extracted_ips array contains scalar values without quotes.
Output:
| EVENT_ID | JSON_WITH_NESTED_ARRAY | EXTRACTED_IPS |
|---|---|---|
| 101 | {"device.info": {"ip.addresses": ["172.16.6.7", "172.16.8.9"]}} | [172.16.6.7, 172.16.8.9] |
| 102 | {"device.info": {"ip.addresses": ["10.1.2.3", "10.2.3.4"]}} | [10.1.2.3, 10.2.3.4] |
| 103 | {"metadata": {"tags": ["critical", "event"], "version": "2.1"}} | NULL |
Example 2: Extracting an Array of String Tags
Goal: Extract the array of text tags associated with each alert from a JSON payload.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | filter json_payload != null | alter tags_array = json_extract_scalar_array(json_payload, "$.alert.tags") | fields event_id, tags_array | limit 2
Explanation: You use the json_extract_scalar_array() function in the alter stage to target the $.alert.tags path within the json_payload string. The function extracts the JSON array of strings and converts it into a standard XQL array assigned to tags_array.
Output:
| EVENT_ID | TAGS_ARRAY |
|---|---|
| 101 | ![][image1] |
| 102 | ![][image2] |
Example 3: Extracting a Mixed Scalar Array
Goal: Extract an array containing mixed scalar types (strings, numbers, booleans) and observe the string conversion.
XQL Code:
config timeframe = 1d\
| dataset = sample_xql_raw\
| filter metrics_payload != null\
| alter mixed_array = json_extract_scalar_array(metrics_payload, "$.device.status_codes")\
| fields event_id, mixed_array\
| limit 2
Explanation: The target JSONPath $.device.status_codes points to an array like ["active", 200, true]. The json_extract_scalar_array() function extracts these values and casts the number 200 and the boolean true into strings, resulting in an XQL array of strings: ["active", "200", "true"].
Output:
| EVENT_ID | MIXED_ARRAY |
|---|---|
| 201 | ![][image3] |
| 202 | ![][image4] |
Example 4: Extract an array of strings using json_extract_scalar_array
Goal: Extract strings using json_extract_scalar_array function.
XQL Code:
dataset = xdr_data | alter parsed_action_processes = json_extract_scalar_array(action_processes, "$.*") | fields parsed_action_processes, action_processes | filter parsed_action_processes != null | limit 1
Explanation: The results return an array of strings in the parsed_action_processes field.
Output:
| PARSED_ACTION_PROCESSES | ACTION_PROCESSES |
|---|---|
| ["123", "2039", "332", "0"] | [123, 2039, 332, 0] |
Example 5: Determine the string length using json_extract_scalar_array and array_length
Goal: Find the length of the string array by using json_extract_scalar_array and array_length functions.
XQL Code:
dataset = xdr_data | filter action_processes != null | alter processes_length = array_length(json_extract_scalar_array(action_processes, "$.*")) | fields action_processes, processes_length | limit 1
Explanation: Extracting the array to string format allows you to determine the array's length.
Output:
| ACTION_PROCESSES | PROCESSES_LENGTH |
|---|---|
| [123, 2039, 332, 0] | 4 |
Example 6: Querying normalized network traffic
Goal: Find all blocked network connections across multiple firewall vendors using the unified XDM schema.
XQL Code:
config timeframe = 1d | dataset = xdm.network.session | filter xdm.event.outcome = "blocked" or xdm.event.outcome = "denied" | comp count(xdm.event.id) as block_count by xdm.source.ipv4, xdm.target.ipv4 | sort desc block_count | limit 5
Explanation: By querying the xdm.network.session dataset, you search across all ingested network logs that have been mapped to the XDM schema, regardless of the original vendor. The query filters for blocked traffic using the normalized xdm.event.outcome field. The query then aggregates the count of blocked events by the normalized source and target IP addresses (xdm.source.ipv4, xdm.target.ipv4), sorts them to find the top offenders, and limits the output to the top 5.
Output:
| XDM.SOURCE.IPV4 | XDM.TARGET.IPV4 | BLOCK_COUNT |
|---|---|---|
| 192.168.1.50 | 8.8.8.8 | 4500 |
| 10.0.0.15 | 1.1.1.1 | 3200 |
| 172.16.5.100 | 9.9.9.9 | 1500 |
| 192.168.1.10 | 8.8.4.4 | 850 |
| 10.0.0.55 | 208.67.222.222 | 420 |
Example 7: Extracting XDM normalized fields
Goal: Extract the xdm.file.permissions.owner in the xdm.finding.normalized_fields array, which returns true when the string value is one of the following: r or w.
XQL Code:
dataset = findings | filter JSON_EXTRACT_SCALAR_ARRAY(xdm.finding.normalized_fields, "$['xdm.file.permissions.owner']") in ("r", "w") | fields xdm.finding.normalized_fields
Explanation: This query searches the findings dataset. The query uses the JSON_EXTRACT_SCALAR_ARRAY() function to extract the JSON array corresponding to the XDM field xdm.file.permissions.owner from within the xdm.finding.normalized_fields object. The filter stage evaluates to true if the extracted array contains the strings "r" or "w", returning only those relevant records to the result set.
Output:
| _TIME | XDM.FINDING.NORMALIZED_FIELDS |
|---|---|
| Jan 15th 2025 09:10:44 | { "xdm.file.permissions.owner": [ "r", "w", "x" ] } |
Related articles
- Stages:
alter,fields,limit - Functions:
to_json_string,json_extract_array - Datasets:
xdr_data
XQL JSON Functions Reference
Core Concept: Why XQL has four JSON extraction functions
Unlike dynamic JSON parsing in other query languages, XQL requires you to specify the expected data type at the time of extraction. You must choose the correct function based on what you are extracting:
json_extract()— Use when extracting a JSON object or when you need to preserve the full JSON structure of the value.json_extract_scalar()— Use when extracting a primitive value (string, number, or boolean) and you need a clean, unquoted string — especially forfiltercomparisons.json_extract_array()— Use when extracting a JSON array, including arrays of objects.json_extract_scalar_array()— Use when extracting a JSON array of primitive values and you need clean, unquoted elements for comparisons.
json_extract()
The json_extract() function navigates and retrieves a specific value from a nested JSON object. The function drills down into a JSON string to surface a single piece of data as a new field. The json_extract() function always returns a string. If the extracted value is a string in the JSON, the result includes the literal double-quote characters (e.g., "\"Medium\""). This is different from json_extract_scalar(), which strips the quotes.
Constraint: The input field must be a valid JSON-formatted string. If the string is malformed or not in JSON format, the
json_extract()function will return null. To convert a raw string field into JSON before extraction, use theto_json_string()function.
Syntax
Regular Syntax:
json_extract(field_name, "$.<json_path>")
Special characters syntax:
When a field in the JSON path contains reserved characters such as an at sign (@), dot (.), or colon (:), you must use bracket notation:
json_extract(field_name, "$[<json_path>]")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field_name |
string |
Yes | The source field or expression containing a valid JSON-formatted string. |
json_path |
string |
Yes | A JSONPath expression specifying the location of the value to extract (e.g., "$.key", "$.nested.key", "$.array[0].field"). |
Return Value
The json_extract() function always returns a string:
- String values → The
json_extract()function returns the value with surrounding double quotes as literal characters (e.g.,"\"Medium\"") - JSON object → The
json_extract()function returns a JSON-formatted string (e.g.,{"name":"John","age":30}) - JSON array → The
json_extract()function returns a JSON array string (e.g.,["a","b","c"]) - Number → The
json_extract()function returns a string representation (e.g.,"42") - Boolean → The
json_extract()function returns a string representation (e.g.,"true")
The json_extract() function returns null if:
- The path does not exist.
- The input is not valid JSON.
- The value is JSON null.
Examples
Example 1: Extract a nested user object
dataset = xdr_data | alter user_details = json_extract(action_evtlog_data_fields, "$.user")
Input:
| action_evtlog_data_fields |
|---|
{"user":{"name":"admin","role":"superuser"},"status":"success"} |
{"user":{"name":"jdoe","role":"viewer"},"status":"failed"} |
Output:
| action_evtlog_data_fields | user_details |
|---|---|
{"user":{"name":"admin","role":"superuser"},"status":"success"} |
{"name":"admin","role":"superuser"} |
{"user":{"name":"jdoe","role":"viewer"},"status":"failed"} |
{"name":"jdoe","role":"viewer"} |
Example 2: Extract a value from a key containing @
dataset = xdr_data | alter email_from = json_extract(email_headers, "$[@from]")
Input:
| email_headers |
|---|
{"@from":"admin@company.com","@to":"user@company.com","subject":"Alert"} |
Output:
| email_headers | email_from |
|---|---|
{"@from":"admin@company.com","@to":"user@company.com","subject":"Alert"} |
"\"admin@company.com\"" |
Syntactic Sugar alternative
For a more concise query, XQL supports a Syntactic Sugar format using the -> operator with {} suffix. This compiles to the exact same json_extract() engine but improves human readability for simple paths.
Syntactic Sugar format:
field_name -> <json_path>{}
Special characters Syntactic Sugar format:
field_name -> ["<json_path>"]{}
Syntactic Sugar Example:
dataset = xdr_data | alter user_details = action_evtlog_data_fields -> user{}
Notes
- Use
json_extract()when you need to preserve the JSON type of the extracted value, especially when the result is a JSON object or array that you plan to further process. - For scalar values (strings, numbers, booleans), prefer
json_extract_scalar()for cleaner output without JSON quoting. - Do not use
json_extract()when the result will be used in afiltercomparison — the literal JSON quotes will break the comparison. Usejson_extract_scalar()instead.
json_extract_scalar(): How to Extract Plain Strings, Numbers, and Booleans
The json_extract_scalar() function retrieves a specific scalar value (string, number, or boolean) from a JSON string and returns it as a clean, unquoted string.
Unlike dynamic JSON parsing in other languages, XQL requires you to use json_extract_scalar() specifically when you need values stripped of literal JSON quotes, making it the required choice for filter comparisons or type-casting operations.
Constraint: The input field must be a valid JSON-formatted string. If the string is malformed, not in JSON format, or if the target path points to a complex object or array, the
json_extract_scalar()function will return null. To convert a raw string field into JSON before extraction, use theto_json_string()function.
Canonical Syntax
Regular Syntax:
json_extract_scalar(field_name, "$.<json_path>")
Special characters syntax:
When a field in the JSON path contains reserved characters such as an at sign (@), dot (.), or colon (:), you must use bracket notation:
json_extract_scalar(field_name, "$[<json_path>]")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field_name |
string |
Yes | The source field or expression containing a valid JSON-formatted string. |
json_path |
string |
Yes | A JSONPath expression pointing to a scalar value (string, number, or boolean). |
Return Value
The json_extract_scalar() function returns the requested scalar value as a plain string with literal JSON quotes stripped:
- String → The
json_extract_scalar()function returns the value without surrounding quotes (e.g.,"MacOSX"instead of"\"MacOSX\"") - Number → The
json_extract_scalar()function returns the value as its string representation (e.g.,"443") - Boolean → The
json_extract_scalar()function returns the value as its string representation (e.g.,"true")
The json_extract_scalar() function returns null if:
- The path does not exist.
- The value at the target path is a JSON object or a JSON array (non-scalar).
- The input field is not valid JSON.
Examples
Example 1: Extracting multiple scalar fields for a filter operation
Explanation: Because we intend to use the extracted event_type in a filter statement (filter event_type = "login"), we must use json_extract_scalar() instead of json_extract(). The json_extract_scalar() function strips the literal JSON quotes, preventing quote-matching errors during the boolean comparison. If json_extract() were used here, the value would be "\"login\"" and the filter event_type = "login" would never match.
dataset = xdr_data | alter username = json_extract_scalar(action_evtlog_data_fields, "$.user.name"), event_type = json_extract_scalar(action_evtlog_data_fields, "$.event.type"), source_ip = json_extract_scalar(action_evtlog_data_fields, "$.event.src") | filter event_type = "login"
Input:
| action_evtlog_data_fields |
|---|
{"user":{"name":"admin"},"event":{"type":"login","src":"10.0.0.1"}} |
{"user":{"name":"jdoe"},"event":{"type":"login","src":"192.168.1.5"}} |
{"user":{"name":"svc_acct"},"event":{"type":"logout","src":"10.0.0.2"}} |
Output (after filter):
| username | event_type | source_ip |
|---|---|---|
| admin | login | 10.0.0.1 |
| jdoe | login | 192.168.1.5 |
Example 2: Extracting a value from a key containing special characters
Explanation: The target JSON key @from contains an at-sign. Therefore, the json_extract_scalar() function must use bracket notation ($[@from]) to successfully retrieve the clean string.
dataset = xdr_data | alter sender = json_extract_scalar(email_headers, "$[@from]")
Input:
| email_headers |
|---|
{"@from":"admin@company.com","@to":"user@company.com","subject":"Alert"} |
Output:
| email_headers | sender |
|---|---|
{"@from":"admin@company.com","@to":"user@company.com","subject":"Alert"} |
admin@company.com |
Note: Unlike
json_extract(), the output does NOT include surrounding double quotes. The value is returned as a clean string, ready for direct comparisons and filtering.
Syntactic Sugar alternative
For a more concise query, XQL supports a Syntactic Sugar format using the -> operator. This compiles to the exact same json_extract_scalar() engine but improves human readability for simple paths.
Syntactic Sugar format:
field_name -> <json_path>
Special characters Syntactic Sugar format:
field_name -> ["<json_path>"]
Syntactic Sugar Example:
dataset = xdr_data | alter username = action_evtlog_data_fields -> user.name, event_type = action_evtlog_data_fields -> event.type | filter event_type = "login"
Notes
- Unlike
json_extract(), thejson_extract_scalar()function strips JSON string quotes from the result, making it ideal for string comparisons and human-readable output. - If the target value is an object or array, the
json_extract_scalar()function returnsnull. Usejson_extract()for those cases. - Numeric and boolean values are returned as their string representations (e.g.,
443,true). Useto_integer(),to_float(), orto_boolean()for type casting. - If the initial field is not already a JSON object, it must be converted using
to_json_string()before extraction can occur.
json_extract_array()
The json_extract_array() function converts a JSON-formatted string into a native XQL array. Use this function to transform stringified lists into actionable data that can be indexed or filtered within your queries.
Constraint: The input field must be a valid JSON-formatted string. If the string is malformed or not in JSON format, the
json_extract_array()function will return null. To convert a raw string field into JSON before extraction, use theto_json_string()function.
Canonical Syntax
Regular Syntax:
json_extract_array(field_name, "$.<json_path>")
Special characters syntax:
When a field in the JSON path contains reserved characters such as an at sign (@), dot (.), or colon (:), you must use bracket notation:
json_extract_array(field_name, "$[<json_path>]")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field_name |
string |
Yes | The source field or expression containing a valid JSON-formatted string. |
json_path |
string |
Yes | A JSONPath expression pointing to a JSON array. |
Return Value
The json_extract_array() function returns the extracted array as a native XQL array.
- Full Array (
[]): Thejson_extract_array()function returns an XQL-native array (e.g.,["22", "443"]). - Specific Element (
[n]): Thejson_extract_array()function extracts the value at that index and returns it as a string (e.g.,"22").
Important: Each element in the returned array retains surrounding double quotes when the array contains simple scalars. For example, string values are returned as
"\"SSH\""rather thanSSH. Usejson_extract_scalar_array()for clean unquoted values.
The json_extract_array() function returns null if:
- The path does not exist.
- The value at the path is not a JSON array.
- The input is not valid JSON.
Examples
Example 1: Extract an array of objects and expand into rows
dataset = xdr_data | alter users = json_extract_array(response_json, "$.users") | arrayexpand users | alter user_name = json_extract_scalar(users, "$.name"), user_role = json_extract_scalar(users, "$.role")
Input:
| response_json |
|---|
{"users":[{"name":"admin","role":"super"},{"name":"jdoe","role":"viewer"},{"name":"asmith","role":"editor"}]} |
Output (after arrayexpand):
| users | user_name | user_role |
|---|---|---|
{"name":"admin","role":"super"} |
admin | super |
{"name":"jdoe","role":"viewer"} |
jdoe | viewer |
{"name":"asmith","role":"editor"} |
asmith | editor |
Example 2: Extract an array from a key containing @
dataset = xdr_data | alter recipients = json_extract_array(email_data, "$[@recipients]")
Input:
| email_data |
|---|
{"@recipients":["user1@company.com","user2@company.com","user3@company.com"],"subject":"Alert"} |
Output:
| email_data | recipients |
|---|---|
{"@recipients":["user1@company.com","user2@company.com","user3@company.com"],"subject":"Alert"} |
["\"user1@company.com\"","\"user2@company.com\"","\"user3@company.com\""] |
Note: The output elements are doubly-quoted (
"\"user1@company.com\""instead ofuser1@company.com). For clean unquoted values, usejson_extract_scalar_array()instead.
Syntactic Sugar alternative
For a more concise query, XQL supports a Syntactic Sugar format using the -> operator with [] suffix. This compiles to the exact same json_extract_array() engine but improves human readability for simple paths.
Syntactic Sugar format:
field_name -> <json_path>[]
Special characters Syntactic Sugar format:
field_name -> ["<json_path>"][]
Syntactic Sugar Example:
dataset = xdr_data | alter users = response_json -> users[] | arrayexpand users | alter user_name = json_extract_scalar(users, "$.name"), user_role = json_extract_scalar(users, "$.role")
Notes
- The returned value is a JSON array. Use XQL array functions such as
array_length(),array_contains(), orarrayexpandto work with the result. - If the path points to a scalar or object (not an array), the
json_extract_array()function returnsnull. - Combine with
arrayexpandto flatten array elements into individual rows, then usejson_extract_scalar()to extract fields from each element. - If the source data is a raw string, it must first be processed by
to_json_string()before the array can be extracted.
json_extract_scalar_array()
The json_extract_scalar_array() function parses a string representing a JSON array and converts it into a native XQL array format. While functionally similar to json_extract_array(), this version extracts the elements as scalar values. This means the resulting array elements are returned in their raw form rather than being wrapped in JSON-style double quotes ("...").
Constraint: The input field must be a valid JSON-formatted string. If the string is malformed or not in JSON format, the
json_extract_scalar_array()function will return null. To convert a raw string field into JSON before extraction, use theto_json_string()function.
Note: This function does not support Syntactic Sugar format. The function must always be called using the full regular function syntax.
Canonical Syntax
Regular Syntax:
json_extract_scalar_array(field_name, "$.<json_path>")
Special characters syntax:
When a field in the JSON path contains reserved characters such as an at sign (@), dot (.), or colon (:), you must use bracket notation:
json_extract_scalar_array(field_name, "$[<json_path>]")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field_name |
string |
Yes | The source field or expression containing a valid JSON-formatted string. |
json_path |
string |
Yes | A JSONPath expression pointing to a JSON array of scalar values (strings, numbers, or booleans). |
Return Value
The json_extract_scalar_array() function returns an array of plain strings with JSON quotes stripped from each element:
["SSH", "HTTPS", "SNMP", "FTP"]→ Thejson_extract_scalar_array()function returnsSSH, HTTPS, SNMP, FTP[443, 80, 8080]→ Thejson_extract_scalar_array()function returns443, 80, 8080[true, false, true]→ Thejson_extract_scalar_array()function returnstrue, false, true
The json_extract_scalar_array() function returns null if:
- The path does not exist.
- The value at the path is not a JSON array.
- The input is not valid JSON.
Examples
Example 1: Extract a scalar array and filter by value
Note: This function does not support Syntactic Sugar format. Use the regular function syntax shown below.
dataset = xdr_data | alter blocked_ips = json_extract_scalar_array(network_json, "$.blocked_ips") | filter array_any(blocked_ips, "10.0.0.5")
Input:
| network_json |
|---|
{"blocked_ips":["10.0.0.5","192.168.1.1","172.16.0.10"]} |
{"blocked_ips":["10.0.0.5","10.10.10.1"]} |
{"blocked_ips":["192.168.1.1","172.16.0.10"]} |
Output (after filter):
| network_json | blocked_ips |
|---|---|
{"blocked_ips":["10.0.0.5","192.168.1.1","172.16.0.10"]} |
10.0.0.5, 192.168.1.1, 172.16.0.10 |
{"blocked_ips":["10.0.0.5","10.10.10.1"]} |
10.0.0.5, 10.10.10.1 |
Note: Because the values are clean strings (not doubly-quoted),
array_contains(blocked_ips, "10.0.0.5")works directly without anytrim()orreplex()workarounds.
Example 2: Extract an array from a key containing @
dataset = xdr_data | alter recipients = json_extract_scalar_array(email_data, "$[@recipients]")
Input:
| email_data |
|---|
{"@recipients":["user1@company.com","user2@company.com","user3@company.com"],"subject":"Alert"} |
Output:
| email_data | recipients |
|---|---|
{"@recipients":["user1@company.com","user2@company.com","user3@company.com"],"subject":"Alert"} |
user1@company.com, user2@company.com, user3@company.com |
Note: Compare this with
json_extract_array()which would return["\"user1@company.com\"","\"user2@company.com\"","\"user3@company.com\""]. Thejson_extract_scalar_array()function returns clean, unquoted values.
Notes
- The
json_extract_scalar_array()function is the array equivalent ofjson_extract_scalar(): it strips JSON string quotes from each element in the array. - Best used when the JSON array contains only scalar values (strings, numbers, booleans). If the array contains objects or nested arrays, use
json_extract_array()instead. - The result is compatible with XQL array functions:
array_contains(),array_length(),arrayexpand, etc. - The
json_extract_scalar_array()function does not support Syntactic Sugar format — it must always be called using the full function syntax.
Comparison Table
| Function | Returns | Strips JSON Quotes | Syntactic Sugar format | Best For |
|---|---|---|---|---|
json_extract() |
String (always) | No | field -> path{} |
Extracting any value while preserving JSON formatting |
json_extract_scalar() |
Plain string (scalar only) | Yes | field -> path |
Extracting a single string/number/boolean for filters |
json_extract_array() |
XQL array (elements doubly-quoted) | No | field -> path[] |
Extracting arrays (including arrays of objects) |
json_extract_scalar_array() |
XQL array of plain strings | Yes | No Not supported | Extracting arrays of scalar values for comparisons |
Syntactic Sugar format (->) vs Regular Syntax — Performance and Behavior
| Aspect | Syntactic Sugar format (-> operator) |
Regular Syntax (json_extract*) |
Performance Difference |
|---|---|---|---|
| Underlying Engine | Compiled to the same internal JSON extraction engine | Same internal JSON extraction engine | 🟢 No difference |
| Return Type | Returns value directly (like json_extract_scalar for leaves) |
json_extract_scalar returns clean string; json_extract has quotes |
🟢 No difference |
| Nested Access | field -> nested.path.value |
json_extract_scalar(field, "$.nested.path.value") |
🟢 No difference |
| Array Access | field -> array[0] |
arrayindex(json_extract_array(field, "$.array"), 0) |
🟢 No difference |
| Quote Handling | Returns clean values — no surrounding quotes | json_extract_scalar: clean; json_extract: has quotes |
🟡 Sugar avoids quotes |
| Readability | High — concise, natural dot notation | Lower — verbose function calls with JSONPath strings | N/A |
| Flexibility | Limited — cannot use complex JSONPath (special chars, wildcards) | Full JSONPath support including bracket notation, wildcards | N/A |
Use in arraymap |
Cannot use -> on @element |
json_extract_scalar("@element", "$.field") works |
N/A |
| Chaining | field -> level1.level2.level3 (unlimited depth) |
Requires nested calls or complex JSONPath strings | 🟢 No difference |
| Error Behavior | Returns null for missing paths |
Returns null for missing paths |
🟢 No difference |
| Filter Statements | Cannot use -> in filter expressions reliably |
filter json_extract_scalar(field, "$.type") = "value" works |
N/A |
When to use which syntax — Decision Guide
| Scenario | Recommended Syntax | Reason | Example |
|---|---|---|---|
| Simple leaf value from a known field | Syntactic Sugar format (->) |
Cleaner, no quote issues, same performance | event_data -> ProcessId |
Key with @ or special characters |
json_extract_scalar() |
Syntactic Sugar format cannot handle special chars in keys | json_extract_scalar(headers, "$[@from]") |
| Array index access (e.g., first element) | json_extract_array() + arrayindex() |
Syntactic Sugar format has limited array index support | arrayindex(json_extract_array(target, "$"), 0) |
Iterating over array elements with arraymap |
json_extract_scalar() on @element |
Syntactic Sugar format cannot be used on @element |
arraymap(Entities, json_extract_scalar("@element", "$.hostName")) |
| Extracting a sub-object for further processing | json_extract() |
Need to preserve JSON structure | json_extract(winlog, "$.event_data") |
| Array of simple scalar values | json_extract_scalar_array() |
Returns clean strings without quotes | json_extract_scalar_array(user, "$.rolegrants") |
| Array of complex objects to iterate | json_extract_array() |
Returns array for arraymap/arrayfilter |
json_extract_array(properties, "$.entities") |
| Filter/conditional expressions | json_extract_scalar() |
More reliable in filter statements; no quote issues | filter json_extract_scalar(details, "$.type") = "AUDIT" |
| Deep nested access on known structure | Syntactic Sugar format (->) |
Much more readable | resource -> data.placement.availabilityZone |
| Value that might be object/array/boolean | json_extract() + tostring() |
json_extract_scalar returns null for non-leaf values |
tostring(json_extract(debugContext, "$.debugData.errorCode")) |
Known limitations summary
| # | Limitation | Affected Function | Impact | Workaround |
|---|---|---|---|---|
| 1 | String values include surrounding quotes | json_extract() |
Breaks filter comparisons |
Use json_extract_scalar() for leaf values |
| 2 | Array elements retain quotes | json_extract_array() |
Requires replex() workarounds |
Use json_extract_scalar_array() for scalar arrays |
| 3 | Requires to_json_string() conversion |
json_extract_scalar_array() |
Extra conversion step required | Wrap input with to_json_string() |
| 4 | Cannot extract non-leaf values | json_extract_scalar() |
Returns null for objects/arrays |
Use json_extract() then json_extract_scalar() |
| 5 | No reliable direct array index access | json_extract_scalar() |
Requires 3-function chain | Use json_extract_array() + arrayindex() |
| 6 | Cannot directly assign to XDM array fields | json_extract_array() |
Quoted values in XDM fields | Use json_extract_scalar_array() or arraymap() |
JSONPath Quick Reference
| Expression | Description |
|---|---|
$ |
Root element |
$.key |
Child element named key |
$.a.b |
Nested child: b inside a |
$.array[0] |
First element of an array |
$.array[*] |
All elements of an array |
$.array[0].field |
Field field of the first array element |
$[key] |
Bracket notation for keys with special characters |
$['key.name'] |
Bracket notation with quotes for dotted keys |
$[@field] |
Bracket notation for keys starting with @ |
Reference: Cortex XSIAM — XQL Language — JSON Functions
json_path_extract
Use the json_path_extract() function to retrieve values from a JSON string based on a specified JSONPath expression.
Syntax
json_path_extract (<json_field>, <json_path>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
json_field |
string | Yes | The field containing the JSON string from which to extract data. |
json_path |
string | Yes | The JSONPath expression identifying the data to extract. |
Returns
The json_path_extract() function returns a string representation of the extracted JSON data.
Usage notes
- This function supports a syntactic sugar format for simplified query writing:
<json_field> ->-> "<json_path>". - When using the regular syntax, the
<json_path>must be enclosed in double quotes, and the root of the JSON object is represented by a dollar sign ($). The$is not required when using the syntactic sugar format. - If a field name within the
<json_path>contains special characters such as a dot (.) or colon (:), specific syntax is required: - Regular Syntax: Enclose the field name in single quotes within brackets (for example,
['<json_field>']). - Syntactic Sugar Format: Enclose the field name in double quotes within brackets (for example,
["<json_field>"]). - JSON field names are case-sensitive. The key-to-field pairing in the XQL query must be identical to the JSON structure for results to be found.
- This function performs a "very heavy" operation and requires significant resources to run. Use it when standard dot-notation or simple array indexing is insufficient for your data extraction needs.
- The syntax used corresponds to the standard found in the JavaScript
jsonpathpackage.
Examples
Example 1: Extracting all authors from a nested array
Goal: Extract all author values from the ServerAccessConfig array within the Firewall object using the [*] wildcard.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_field = "{\"Firewall\":{\"ServerAccessConfig\":[{\"category\":\"policy\",\"author\":\"NRees\",\"name\":\"CustomerSuccess_NoAccess\",\"priority\":8.95},{\"category\":\"rule\",\"author\":\"EWaugh\",\"name\":\"AllowAccess_10_10_10_10\",\"id\":\"0-553-21311-3\",\"priority\":12.99},{\"category\":\"policy\",\"author\":\"HMelville\",\"name\":\"SOC_Access\",\"priority\":8.99},{\"category\":\"rule\",\"author\":\"JTolkien\",\"name\":\"AllowAccess_JIT\",\"id\":\"0-395-19395-8\",\"priority\":22.99}],\"Reviewer\":{\"UserName\":\"jdow\",\"Role\":\"Admin\"}}}" | alter all_authors = json_path_extract(json_field, "$.Firewall.ServerAccessConfig[*].author") | fields event_id, all_authors
Explanation: The query defines a static JSON object and uses the [*] operator to iterate through all elements of the ServerAccessConfig array, extracting the author field from each.
Output:
| EVENT_ID | ALL_AUTHORS |
|---|---|
| 101 | ["NRees","EWaugh","HMelville","JTolkien"] |
Example 2: Extracting authors with a specific priority
Goal: Use a filter expression within the JSONPath to find authors associated with a specific priority value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_field = "{\"Firewall\":{\"ServerAccessConfig\":[{\"category\":\"policy\",\"author\":\"NRees\",\"name\":\"CustomerSuccess_NoAccess\",\"priority\":8.95},{\"category\":\"rule\",\"author\":\"EWaugh\",\"name\":\"AllowAccess_10_10_10_10\",\"id\":\"0-553-21311-3\",\"priority\":12.99},{\"category\":\"policy\",\"author\":\"HMelville\",\"name\":\"SOC_Access\",\"priority\":8.99},{\"category\":\"rule\",\"author\":\"JTolkien\",\"name\":\"AllowAccess_JIT\",\"id\":\"0-395-19395-8\",\"priority\":22.99}],\"Reviewer\":{\"UserName\":\"jdow\",\"Role\":\"Admin\"}}}" | alter specific_priority_author = json_path_extract(json_field, "$..*[?(@.priority==22.99)].author") | fields event_id, specific_priority_author
Explanation: The query utilizes the filter expression ?(@.priority==22.99) to match objects where the priority is exactly 22.99, and then extracts the author from those matching objects.
Output:
| EVENT_ID | SPECIFIC_PRIORITY_AUTHOR |
|---|---|
| 101 | ["JTolkien"] |
Example 3: Deep scan for all occurrences of a key
Goal: Use the recursive descent operator to find all author values anywhere in the JSON structure.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_field = "{\"Firewall\":{\"ServerAccessConfig\":[{\"category\":\"policy\",\"author\":\"NRees\",\"name\":\"CustomerSuccess_NoAccess\",\"priority\":8.95},{\"category\":\"rule\",\"author\":\"EWaugh\",\"name\":\"AllowAccess_10_10_10_10\",\"id\":\"0-553-21311-3\",\"priority\":12.99},{\"category\":\"policy\",\"author\":\"HMelville\",\"name\":\"SOC_Access\",\"priority\":8.99},{\"category\":\"rule\",\"author\":\"JTolkien\",\"name\":\"AllowAccess_JIT\",\"id\":\"0-395-19395-8\",\"priority\":22.99}],\"Reviewer\":{\"UserName\":\"jdow\",\"Role\":\"Admin\"}}}" | alter all_authors_deep_scan = json_path_extract(json_field, "$..author") | fields event_id, all_authors_deep_scan
Explanation: The query uses the $..author syntax to perform a deep scan of the entire JSON object, locating and extracting the value of every key named author, regardless of its nesting level.
Output:
| EVENT_ID | ALL_AUTHORS_DEEP_SCAN |
|---|---|
| 101 | ["NRees","EWaugh","HMelville","JTolkien"] |
Example 4: Extracting all direct properties of an object
Goal: Extract all direct properties (keys and values) of a specific object using the wildcard operator.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_field = "{\"Firewall\":{\"ServerAccessConfig\":[{\"category\":\"policy\",\"author\":\"NRees\",\"name\":\"CustomerSuccess_NoAccess\",\"priority\":8.95},{\"category\":\"rule\",\"author\":\"EWaugh\",\"name\":\"AllowAccess_10_10_10_10\",\"id\":\"0-553-21311-3\",\"priority\":12.99},{\"category\":\"policy\",\"author\":\"HMelville\",\"name\":\"SOC_Access\",\"priority\":8.99},{\"category\":\"rule\",\"author\":\"JTolkien\",\"name\":\"AllowAccess_JIT\",\"id\":\"0-395-19395-8\",\"priority\":22.99}],\"Reviewer\":{\"UserName\":\"jdow\",\"Role\":\"Admin\"}}}" | alter firewall_properties = json_path_extract(json_field, "$.Firewall.*") | fields event_id, firewall_properties
Explanation: The query uses $.Firewall.* to retrieve all child elements (both the ServerAccessConfig array and the Reviewer object) directly under the Firewall key.
Output:
| EVENT_ID | FIREWALL_PROPERTIES |
|---|---|
| 101 | [[{"category": "policy","author": "NRees","name": "CustomerSuccess_NoAccess","priority": 8.95},{"category": "rule","author": "EWaugh","name": "AllowAccess_10_10_10_10","id": "0-553-21311-3","priority": 12.99},{"category": "policy","author": "HMelville","name": "SOC_Access","priority": 8.99},{"category": "rule","author": "JTolkien","name": "AllowAccess_JIT","id": "0-395-19395-8","priority": 22.99}],{"UserName": "jdow","Role": "Admin"}] |
Example 5: Deep scan for specific keys
Goal: Use recursive descent to find all values associated with a specific key anywhere in the JSON.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_field = "{\"Firewall\":{\"ServerAccessConfig\":[{\"category\":\"policy\",\"author\":\"NRees\",\"name\":\"CustomerSuccess_NoAccess\",\"priority\":8.95},{\"category\":\"rule\",\"author\":\"EWaugh\",\"name\":\"AllowAccess_10_10_10_10\",\"id\":\"0-553-21311-3\",\"priority\":12.99},{\"category\":\"policy\",\"author\":\"HMelville\",\"name\":\"SOC_Access\",\"priority\":8.99},{\"category\":\"rule\",\"author\":\"JTolkien\",\"name\":\"AllowAccess_JIT\",\"id\":\"0-395-19395-8\",\"priority\":22.99}],\"Reviewer\":{\"UserName\":\"jdow\",\"Role\":\"Admin\"}}}" | alter all_priorities = json_path_extract(json_field, "$.Firewall..priority") | fields event_id, all_priorities
Explanation: The query uses $.Firewall..priority to recursively scan within the Firewall object and extract every value associated with the key priority.
Output:
| EVENT_ID | ALL_PRIORITIES |
|---|---|
| 101 | [8.95,12.99,8.99,22.99] |
Example 6: Extracting the last element of an array (length calculation)
Goal: Extract the last element of an array using the length property in a script expression.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_field = "{\"Firewall\":{\"ServerAccessConfig\":[{\"category\":\"policy\",\"author\":\"NRees\",\"name\":\"CustomerSuccess_NoAccess\",\"priority\":8.95},{\"category\":\"rule\",\"author\":\"EWaugh\",\"name\":\"AllowAccess_10_10_10_10\",\"id\":\"0-553-21311-3\",\"priority\":12.99},{\"category\":\"policy\",\"author\":\"HMelville\",\"name\":\"SOC_Access\",\"priority\":8.99},{\"category\":\"rule\",\"author\":\"JTolkien\",\"name\":\"AllowAccess_JIT\",\"id\":\"0-395-19395-8\",\"priority\":22.99}],\"Reviewer\":{\"UserName\":\"jdow\",\"Role\":\"Admin\"}}}" | alter last_access_config_item = json_path_extract(json_field, "$..ServerAccessConfig[(@.length-1)]") | fields event_id, last_access_config_item
Explanation: The query uses the script expression (@.length-1) to calculate the index of the last element in the ServerAccessConfig array and extract it.
Output:
| EVENT_ID | LAST_ACCESS_CONFIG_ITEM |
|---|---|
| 101 | [{"category": "rule","author": "JTolkien","name": "AllowAccess_JIT","id": "0-395-19395-8","priority": 22.99}] |
Example 7: Extracting the last element of an array (slice notation)
Goal: Extract the last element of an array using Python-style slice notation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_field = "{\"Firewall\":{\"ServerAccessConfig\":[{\"category\":\"policy\",\"author\":\"NRees\",\"name\":\"CustomerSuccess_NoAccess\",\"priority\":8.95},{\"category\":\"rule\",\"author\":\"EWaugh\",\"name\":\"AllowAccess_10_10_10_10\",\"id\":\"0-553-21311-3\",\"priority\":12.99},{\"category\":\"policy\",\"author\":\"HMelville\",\"name\":\"SOC_Access\",\"priority\":8.99},{\"category\":\"rule\",\"author\":\"JTolkien\",\"name\":\"AllowAccess_JIT\",\"id\":\"0-395-19395-8\",\"priority\":22.99}],\"Reviewer\":{\"UserName\":\"jdow\",\"Role\":\"Admin\"}}}" | alter last_access_config_slice = json_path_extract(json_field, "$..ServerAccessConfig[-1:]") | fields event_id, last_access_config_slice
Explanation: The query uses the slice notation [-1:] to grab the last item in the ServerAccessConfig array.
Output:
| EVENT_ID | LAST_ACCESS_CONFIG_SLICE |
|---|---|
| 101 | [{"category": "rule","author": "JTolkien","name": "AllowAccess_JIT","id": "0-395-19395-8","priority": 22.99}] |
Example 8: Extracting elements by specific indices
Goal: Extract multiple elements from an array by specifying their indices.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_field = "{\"Firewall\":{\"ServerAccessConfig\":[{\"category\":\"policy\",\"author\":\"NRees\",\"name\":\"CustomerSuccess_NoAccess\",\"priority\":8.95},{\"category\":\"rule\",\"author\":\"EWaugh\",\"name\":\"AllowAccess_10_10_10_10\",\"id\":\"0-553-21311-3\",\"priority\":12.99},{\"category\":\"policy\",\"author\":\"HMelville\",\"name\":\"SOC_Access\",\"priority\":8.99},{\"category\":\"rule\",\"author\":\"JTolkien\",\"name\":\"AllowAccess_JIT\",\"id\":\"0-395-19395-8\",\"priority\":22.99}],\"Reviewer\":{\"UserName\":\"jdow\",\"Role\":\"Admin\"}}}" | alter first_two_configs_by_index = json_path_extract(json_field, "$..ServerAccessConfig[0,1]") | fields event_id, first_two_configs_by_index
Explanation: The query targets the ServerAccessConfig array and uses [0,1] to extract only the first and second elements.
Output:
| EVENT_ID | FIRST_TWO_CONFIGS_BY_INDEX |
|---|---|
| 101 | [{"category": "policy","author": "NRees","name": "CustomerSuccess_NoAccess","priority": 8.95},{"category": "rule","author": "EWaugh","name": "AllowAccess_10_10_10_10","id": "0-553-21311-3","priority": 12.99}] |
Example 9: Extracting a slice from the beginning of an array
Goal: Extract a range of elements from the start of an array using slice notation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 1 | alter json_field = "{\"Firewall\":{\"ServerAccessConfig\":[{\"category\":\"policy\",\"author\":\"NRees\",\"name\":\"CustomerSuccess_NoAccess\",\"priority\":8.95},{\"category\":\"rule\",\"author\":\"EWaugh\",\"name\":\"AllowAccess_10_10_10_10\",\"id\":\"0-553-21311-3\",\"priority\":12.99},{\"category\":\"policy\",\"author\":\"HMelville\",\"name\":\"SOC_Access\",\"priority\":8.99},{\"category\":\"rule\",\"author\":\"JTolkien\",\"name\":\"AllowAccess_JIT\",\"id\":\"0-395-19395-8\",\"priority\":22.99}],\"Reviewer\":{\"UserName\":\"jdow\",\"Role\":\"Admin\"}}}" | alter slice_from_beginning = json_path_extract(json_field, "$..ServerAccessConfig[:2]") | fields event_id, slice_from_beginning
Explanation: The query uses [:2] to extract a slice of the ServerAccessConfig array starting from the beginning up to (but not including) index 2.
Output:
| EVENT_ID | SLICE_FROM_BEGINNING |
|---|---|
| 101 | [{"category": "policy","author": "NRees","name": "CustomerSuccess_NoAccess","priority": 8.95},{"category": "rule","author": "EWaugh","name": "AllowAccess_10_10_10_10","id": "0-553-21311-3","priority": 12.99}] |
Example 10: Extract data using different JSONPath expressions
Goal: Define a JSON object called Firewall within a JSON field to illustrate multiple ways you can use the json_path_extract function to extract data using different JSONPath configurations.
XQL Code:
dataset = xdr_data | limit 1 | alter json_field = "{\"Firewall\": {\"ServerAccessConfig\": [{\"category\": \"policy\",\"author\": \"NRees\",\"name\": \"CustomerSuccess_NoAccess\",\"priority\": 8.95},{\"category\": \"rule\",\"author\": \"EWaugh\",\"name\": \"AllowAccess_10_10_10_10\",\"id\": \"0-553-21311-3\",\"priority\": 12.99},{\"category\": \"policy\",\"author\": \"HMelville\",\"name\": \"SOC_Access\",\"priority\": 8.99},{\"category\": \"rule\",\"author\": \"JTolkien\",\"name\": \"AllowAccess_JIT\",\"id\": \"0-395-19395-8\",\"priority\": 22.99}],\"Reviewer\": {\"UserName\": \"jdow\",\"Role\": \"Admin\"}}}" | alter a = json_path_extract(json_field, "$.Firewall.ServerAccessConfig[*].author") | alter b = json_path_extract(json_field, "$..*[?(@.priority==22.99)].author") | alter c = json_path_extract(json_field, "$..author") | alter d = json_path_extract(json_field, "$.Firewall.*") | alter e = json_path_extract(json_field, "$.Firewall..priority") | alter f = json_path_extract(json_field, "$..ServerAccessConfig[(@.length-1)]") | alter g = json_path_extract(json_field, "$..ServerAccessConfig[-1:]") | alter h = json_path_extract(json_field, "$..ServerAccessConfig[0,1]") | alter i = json_path_extract(json_field, "$..ServerAccessConfig[:2]") | fields json_field, a, b, c, d, e, f, g, h, i
Explanation: This query applies various JSONPath expressions to the json_field to extract different sets of data. Here is how the different fields are configured:
- a: Outputs all of the values for the author key in the ServerAccessConfig JSON array.
- b: Outputs all of the values for the author key, where the value for the priority key is 22.99.
- c: Outputs all of the values for the author key anywhere found in the JSON.
- d: Outputs all of the values under the Firewall key.
- e: Outputs all of the values under the Firewall key for the priority key.
- f: Outputs the JSON array index value from the ServerAccessConfig JSON array according to its index location from the end of the array.
- g: Outputs all of the JSON array index values from the ServerAccessConfig JSON array according to its index location from the end of the array.
- h: Outputs a specific set of JSON array index values (one or more) from the ServerAccessConfig JSON array according to its index location.
- i: Outputs all of the JSON array index values from the ServerAccessConfig JSON array according to its index location from the start (0 Index) up to the mentioned index value.
Output:
| _TIME | JSON_FIELD | A | B | C | D |
|---|---|---|---|---|---|
| Jan 20th 2025 18:51:42 | {"Firewall": {"ServerAccessConfig": [{"category": "policy", "author": "NRees", "name": "CustomerSuccess_NoAccess", "priority": 8.95}, ...], "Reviewer": {"UserName": "jdow", "Role": "Admin"}}} | NRees, EWaugh, HMelville, JTolkien | JTolkien | NRees, EWaugh, HMelville, JTolkien | {"ServerAccessConfig": [{"category": "policy", "author": "NRees", "name": "CustomerSuccess_NoAccess", "priority": 8.95}, ...], "Reviewer": {"UserName": "jdow", "Role": "Admin"}} |
Note: Columns E through I, _PRODUCT, _VENDOR, and INSERT_TIMESTAMP are also returned by the query but omitted from this sample display for brevity.
Related articles
- Stages:
alter - Functions:
json_extract,json_extract_array,json_extract_scalar,json_extract_scalar_array,to_json_string
lag
Use the lag() function to access data from a preceding row in the same result set, enabling comparisons between the current row and a previous one.
Syntax
lag(<field>, <offset>, <default_value>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | any | Yes | The field from which to extract the value. |
| offset | integer | No | The number of rows back from the current row from which to obtain a value. The default is 1. |
| default_value | any | No | The value to return if the offset points to a row that does not exist (for example, before the first row of the partition). The default is NULL. |
Returns
The lag() function returns the value of the specified field from the row that is the specified number of rows before the current row. The data type matches the data type of the input field.
Usage Notes
- The lag() function is an analytic function and must be used within the windowcomp stage.
- The chronological or logical order of the records is determined by the order by clause within the over() partition statement.
- This function is frequently used to calculate differences between consecutive events, such as the time elapsed between logins or the change in file size between versions.
Examples
Example 1: Identify consecutive processes
Goal: Check the previous process name that was executed.
XQL Code:
dataset \= xdr_data | filter action_process_image_name != null | windowcomp lag(action_process_image_name) as previous_process over(partition by agent_hostname order by _time asc) | fields agent_hostname, action_process_image_name, previous_process, _time | sort asc agent_hostname , _time
Explanation: The windowcomp partition operates within the parameters defined in the over() partition statement. The query organizes the data to evaluate by agent_hostname according to the ascending chronological order of its creation time. The results returned in the new field previous_process provide the process image name of the previous event for each agent hostname. Because this calculation utilizes the windowcomp stage, all lines of the dataset are returned along with this new field value.
Output:
| AGENT_HOSTNAME | ACTION_PROCESS_IMAGE_NAME | PREVIOUS_PROCESS | _TIME |
|---|---|---|---|
| mac-agent-1 | test-process-1 | null | Mar 26th 2026 09:26:07 |
| mac-agent-1 | test-process-2 | test-process-1 | Mar 26th 2026 09:26:08 |
| mac-agent-1 | test-process-3 | test-process-2 | Mar 26th 2026 09:26:09 |
Related Articles
- Stages: windowcomp, filter, fields, sort
- Functions: lead(), first_value(), last_value()
- Datasets: xdr_data
last
Use the last() function to retrieve the last chronologically recorded value of a specified field within a grouped set of records.
Syntax
last (<field>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | any | Yes | The field from which to extract the last recorded value based on chronological order. |
Returns
The last() function returns the value of the specified field from the newest (most recent) event in the evaluated group. The data type of the returned value matches the data type of the input field.
Usage Notes
- The last() function is an aggregate function and must be used within the comp stage.
- The chronological order of the records is determined by the underlying time field (such as _time) associated with the data events.
- If the last record contains a NULL value for the evaluated field, the function returns NULL.
- This function is frequently used in threat hunting to identify the most recent occurrence of an artifact or behavior, such as the final command executed in a session, the last known IP address for a host, or the most recent process started by a specific user.
Examples
Example 1: Identify the last process executed per host
Goal: Find the most recently recorded process name that was executed on each endpoint within the queried time frame.
XQL Code:
config timeframe = 1d | dataset = xdr_data | filter action_process_image_name \!= null | comp last(action_process_image_name) as last_process by agent_hostname | fields agent_hostname, last_process | limit 3
Explanation: The comp stage groups the events by agent_hostname. For each unique host, the last() function evaluates the timeline of the records and returns the action_process_image_name associated with the chronologically newest event in that group. The result is assigned to the last_process alias.
Output:
| AGENT_HOSTNAME | LAST_PROCESS |
|---|---|
| endpoint-win-01 | C:\Windows\System32\cmd.exe |
| endpoint-mac-02 | /usr/libexec/xpcproxy |
| srv-linux-03 | /bin/bash |
Example 2: Retrieve the last command line for a process
Goal: Identify the final command line argument used to execute a specific process across your environment before the query timeframe ended.
XQL Code:
config timeframe = 1d | dataset = xdr_data | filter action_process_image_name = "powershell.exe" | comp last(action_process_image_command_line) as final_cmd by agent_hostname | fields agent_hostname, final_cmd | limit 2
Explanation: This query filters for execution events involving powershell.exe. Using the comp stage, it groups the results by agent_hostname and uses the last() function to extract the chronologically final command line argument executed by PowerShell on that host.
Output:
| AGENT_HOSTNAME | FINAL_CMD |
|---|---|
| endpoint-win-01 | powershell.exe -WindowStyle Hidden -EncodedCommand JABz... |
| srv-win-02 | "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Get-Process" |
Related Articles
last_value
Use the last_*value() function within the windowcomp stage to retrieve the value of a specified field from the last row within a defined window or partition. This function is useful when you need to access the most recent or final value of a sequence relative to the current row being processed.
Syntax
windowcomp last_value(\<field\>) [by \<field\> [,\<field\>,...]] sort [asc|desc] \<field1\> [, [asc|desc] \<field2\>,...] [between 0|null|\<number\>|-\<number\> [and 0|null|\<number\>|-\<number\>] [frame_type=range]] [as \<alias\>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | Any supported type | Yes | The field from which to retrieve the value. |
| by field | string | No | Partitions the data into distinct groups. The last_value() function operates independently within each of these partitions. |
| sort field | string | Yes | Defines the order of rows within each partition. This order is crucial for correctly identifying the "last" row for the last_value() calculation. |
| between clause | string | No | Defines a "window frame" (a specific range of rows) relative to the current row. If omitted, the default window (typically the entire partition) is used. |
| alias | string | No | Assigns an alias name to the new column displaying the result. |
Returns
The last_value() function returns a single value that corresponds to the field's value in the last row within the defined window frame. This value is then returned for every row in that window, and its data type matches the data type of the input field.
Usage Notes
- last_value() is a navigation function and must be used with the windowcomp stage.
- The sort clause is mandatory because it defines the logical order of rows, determining which row is considered the "last" one.
- If you use the
byclause to partition the data, the function restarts its calculation for each new partition. - If the
betweenclause is omitted, the default window frame typically covers the entire partition, meaning the "last" row is the last row of the partition.
Examples
Example 1: last_value() over an entire partition (default window)
Goal: Retrieve the duration_seconds from the last event within each is_successful group, ordered by _time, and replicate this value for every row in that group.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, duration_seconds | windowcomp last_value(duration_seconds) by is_successful sort asc _time as last_duration_in_partition | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: You partition the data by is_successful and sort it by _time ascending. For the false partition, the chronologically last event is 109 with duration_seconds = 0.05. For the true partition, the last event is 110 with duration_seconds = 60.0. These last values are assigned to all rows within their respective partitions.
Output:
| _time | event_id | is_successful | duration_seconds | last_duration_in_partition |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | 0.8 | 0.05 |
| 2023-10-26 10:40:10 UTC | 106 | false | 2.1 | 0.05 |
| 2023-10-26 10:55:55 UTC | 109 | false | 0.05 | 0.05 |
| 2023-10-26 10:00:00 UTC | 101 | true | 1.5 | 60.0 |
| 2023-10-26 10:15:15 UTC | 103 | true | 10.2 | 60.0 |
| 2023-10-26 10:20:00 UTC | 104 | true | 0.1 | 60.0 |
| 2023-10-26 10:30:45 UTC | 105 | true | 5.0 | 60.0 |
| 2023-10-26 10:45:00 UTC | 107 | true | 7.8 | 60.0 |
| 2023-10-26 10:50:20 UTC | 108 | true | 15.3 | 60.0 |
| 2023-10-26 11:00:10 UTC | 110 | true | 60.0 | 60.0 |
Example 2: last_value() with a rolling window
Goal: Retrieve the duration_seconds from the last event within a sliding window consisting of the current row and the two preceding rows.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, duration_seconds | windowcomp last_value(duration_seconds) by is_successful sort asc _time between -2 and 0 as rolling_last_value | sort asc is_successful, asc _time, asc event_id | limit 10
** Explanation** : You define a window of between -2 and 0 (the two preceding rows up to the current row). Because the current row is always the "last" element of this specific sliding window, the function simply returns the duration_seconds of the current row itself.
Output:
| _time | event_id | is_successful | duration_seconds | rolling_last_value |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | 0.8 | 0.8 |
| 2023-10-26 10:40:10 UTC | 106 | false | 2.1 | 2.1 |
| 2023-10-26 10:55:55 UTC | 109 | false | 0.05 | 0.05 |
| 2023-10-26 10:00:00 UTC | 101 | true | 1.5 | 1.5 |
| 2023-10-26 10:15:15 UTC | 103 | true | 10.2 | 10.2 |
| 2023-10-26 10:20:00 UTC | 104 | true | 0.1 | 0.1 |
| 2023-10-26 10:30:45 UTC | 105 | true | 5.0 | 5.0 |
| 2023-10-26 10:45:00 UTC | 107 | true | 7.8 | 7.8 |
| 2023-10-26 10:50:20 UTC | 108 | true | 15.3 | 15.3 |
| 2023-10-26 11:00:10 UTC | 110 | true | 60.0 | 60.0 |
Example 3: last_value() with a fixed window (current row to end)
Goal: Retrieve the duration_seconds from the last event in a window starting from the current row and extending to the end of the partition.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, duration_seconds | windowcomp last_value(duration_seconds) by is_successful sort asc _time between 0 and null as last_duration_from_current | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: You define a window of between 0 and null (current row to the end of the partition). For any given row, the "last" element within this window is always the last element of the entire partition. This produces the same result as Example 1.
Output:
| _time | event_id | is_successful | duration_seconds | last_duration_from_current |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | 0.8 | 0.05 |
| 2023-10-26 10:40:10 UTC | 106 | false | 2.1 | 0.05 |
| 2023-10-26 10:55:55 UTC | 109 | false | 0.05 | 0.05 |
| 2023-10-26 10:00:00 UTC | 101 | true | 1.5 | 60.0 |
| 2023-10-26 10:15:15 UTC | 103 | true | 10.2 | 60.0 |
| 2023-10-26 10:20:00 UTC | 104 | true | 0.1 | 60.0 |
| 2023-10-26 10:30:45 UTC | 105 | true | 5.0 | 60.0 |
| 2023-10-26 10:45:00 UTC | 107 | true | 7.8 | 60.0 |
| 2023-10-26 10:50:20 UTC | 108 | true | 15.3 | 60.0 |
| 2023-10-26 11:00:10 UTC | 110 | true | 60.0 | 60.0 |
Related Articles
- Stages: windowcomp, config, dataset, fields, sort, limit
- Functions: first_value, lag, last
latest
Use the latest() function within a comp or windowcomp stage to retrieve the single chronologically latest value for a specified field within each group of rows.
Syntax
comp latest(<field>) [as <alias>] [by <field1>[, <field2>...]] [addrawdata = true|false [as <target field>]]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| field | string, numeric, timestamp | Yes | The field from which you want to retrieve the chronologically latest value. |
| alias | string | No | An optional name for the output column. |
| field1, field2 | string, numeric, boolean | No | Optional fields used to group rows; the latest value is calculated independently for each group. |
| addrawdata | boolean | No | When set to true, includes a column listing the raw events contributing to the aggregate result. |
Returns
The latest() function returns a single value representing the chronologically latest entry for the specified field within its window or partition.
Usage Notes
- This function requires the dataset to contain a time-related field (such as _time) to be considered valid for chronological evaluation.
- When used with the comp stage, system fields like _time are removed from the result set unless explicitly included in the by clause.
- The order of selection depends entirely on the chronological order of events.
- If you utilize the addrawdata = true option, the query will process up to 50 defined fields and display up to 100 contributing events.
Examples
Example 1: Find the latest event ID across the entire dataset
Goal: Identify the ID of the most recent event recorded in the dataset.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp latest(event_id) as latest_event_id
Explanation: This query scans the sample_xql_raw dataset for the last 24 hours and identifies the event_id of the record with the most recent timestamp.
Output:
| LATEST_EVENT_ID |
|---|
| 110 |
Example 2: Find the latest log entry grouped by success status
Goal: Retrieve the most recent raw log data separately for successful and unsuccessful events.
XQL Code:
config timeframe = 1d | dataset = sample_xql_raw | comp latest(raw_log_data) as latest_raw_log by is_successful
Explanation: The query partitions the data into groups based on the is_successful status and retrieves the chronologically latest raw_log_data for each group.
Output:
| IS_SUCCESSFUL | LATEST_RAW_LOG |
|---|---|
| true | "Full backup of prod_db to S3 completed." |
| false | "Client C2 hit rate limit on /data endpoint." |
Related Articles
- Stages: comp, windowcomp, config, dataset
- Functions: earliest(), first(), last()
least
Use the least() function to return the smallest value from a list of expressions.
Syntax
least(<expression1>, <expression2> [, ...])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
expression1 |
integer, float, string, timestamp | Yes | The first value to compare. |
expression2 |
integer, float, string, timestamp | Yes | The second value to compare. |
... |
integer, float, string, timestamp | No | Additional values to compare. Any number of additional expressions can be provided. |
Returns
Type: Same as input type
Description: The least() function returns the smallest value among all the provided expressions. If any input is null, the function may skip null values or return null depending on the implementation.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Multiple Arguments: The function accepts two or more arguments and returns the minimum value among them.
- Type Consistency: All arguments should be of compatible types for meaningful comparison.
- Null Handling: If all inputs are
null, the function returnsnull. If some inputs arenull, the function typically returns the least non-null value. - String Comparison: When comparing strings, the function uses lexicographic (alphabetical) ordering.
- Relationship to greatest(): The
least()function is the counterpart ofgreatest(), which returns the largest value. - Common Use Cases: This function is typically used within the
alterstage for selecting the minimum value across multiple fields, implementing upper bounds (capping values), and data normalization.
Examples
Example 1: Find least among literal values
Goal: Find the smallest value from a set of numeric literals.
XQL code:
dataset = xdr_data | limit 1 | alter min_val = least(10, 25, 5, 42, 18) | fields min_val
Explanation: The least() function compares all five literal values and returns 5, the smallest among them.
Output:
| MIN_VAL |
|---|
| 5 |
Example 2: Find least value across multiple fields
Goal: Find the smallest value among multiple numeric fields for each record.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter min_field = least(event_id, numeric_value, duration_seconds) | fields event_id, numeric_value, duration_seconds, min_field | limit 3
Explanation: This query compares the values of event_id, numeric_value, and duration_seconds for each record and returns the smallest value in min_field.
Output:
| EVENT_ID | NUMERIC_VALUE | DURATION_SECONDS | MIN_FIELD |
|---|---|---|---|
| 101 | 5.0 | 1.5 | 1.5 |
| 102 | 200.0 | 0.8 | 0.8 |
| 103 | 50.0 | 10.2 | 10.2 |
Example 3: Implement an upper cap using least
Goal: Cap a value at a maximum threshold by using least() as an upper clamp.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter capped_duration = least(duration_seconds, 5.0) | fields event_id, duration_seconds, capped_duration | limit 3
Explanation: This query ensures that capped_duration does not exceed 5.0 by returning the lesser of duration_seconds and 5.0. Values above 5.0 are capped, while values below remain unchanged.
Output:
| EVENT_ID | DURATION_SECONDS | CAPPED_DURATION |
|---|---|---|
| 101 | 1.5 | 1.5 |
| 102 | 0.8 | 0.8 |
| 103 | 10.2 | 5.0 |
Related articles
- Stages:
alter,fields,limit - Functions:
greatest(),min_by(),coalesce() - Datasets:
xdr_data
len
Use the len() function to return the number of characters contained in a specified string.
Syntax
len (<string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
<string> |
string | Yes | The string field or literal you want to evaluate. |
Returns
The len() function returns an integer representing the count of characters.
Usage notes
- If the input string is empty (
""),len()will return0. - If a
NULLvalue is passed tolen(), the function will returnNULL. - This function is typically used within the
alterstage to create new fields or modify existing ones by calculating string lengths. - The function can also be used in
filterstages to narrow down results based on string length.
Examples
Example 1: Calculating the length of an existing string field
Goal: Calculate the character count of an existing string field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter description_length = len(event_description) | fields event_id, event_description, description_length | limit 3
Explanation: This query creates a new field, description_length, by calculating the character count of each event_description.
Output:
| EVENT_ID | EVENT_DESCRIPTION | DESCRIPTION_LENGTH |
|---|---|---|
| 101 | "User login successful" | 23 |
| 102 | "File access attempt" | 20 |
| 103 | "Network connection established" | 30 |
Example 2: Calculating the length of a literal string
Goal: Calculate the length of a direct string literal provided in the query.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter literal_length = len("Palo Alto Networks") | fields event_id, literal_length | limit 3
Explanation: This query adds a new field, literal_length, which contains the constant length of the string "Palo Alto Networks" (18 characters, including spaces).
Output:
| EVENT_ID | LITERAL_LENGTH |
|---|---|
| 101 | 18 |
| 102 | 18 |
| 103 | 18 |
Example 3: Calculating the length of a string derived from a numerical field
Goal: Calculate the length of a numerical field by first converting it to a string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_string = to_string(event_id) | alter id_string_length = len(event_id_string) | fields event_id, event_id_string, id_string_length | limit 3
Explanation: This query first converts the numerical event_id to its string representation (for example, 101 becomes "101") and then calculates the length of that string.
Output:
| EVENT_ID | EVENT_ID_STRING | ID_STRING_LENGTH |
|---|---|---|
| 101 | "101" | 3 |
| 102 | "102" | 3 |
| 103 | "103" | 3 |
Example 4: Calculating the length of a string extracted from JSON data
Goal: Extract a string value from a JSON field and calculate its length.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter status_string = simple_json_data -> status | alter status_length = len(status_string) | fields event_id, simple_json_data, status_string, status_length | limit 3
Explanation: This query extracts the status value from simple_json_data as a string and then finds its length. For event_id 103, because simple_json_data does not contain a status key, status_string becomes NULL, and subsequently, status_length also becomes NULL.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | STATUS_STRING | STATUS_LENGTH |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | "ok" | 2 |
| 102 | {"status": "fail", "error": "access_denied"} | "fail" | 4 |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL | NULL |
Example 5: Handling empty strings and NULL values
Goal: Demonstrate the behavior of the function with empty strings and NULL inputs.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter empty_string_test = "" | alter empty_string_length = len(empty_string_test) | alter dst_domain_length = len(dst_domain) | fields event_id, empty_string_test, empty_string_length, dst_domain, dst_domain_length | limit 5
Explanation: For all events, empty_string_test is an empty string, so empty_string_length is 0. For event_id 105, dst_domain is NULL, resulting in dst_domain_length also being NULL. For other events with non-NULL dst_domain, their respective string lengths are calculated.
Output:
| EVENT_ID | EMPTY_STRING_TEST | EMPTY_STRING_LENGTH | DST_DOMAIN | DST_DOMAIN_LENGTH |
|---|---|---|---|---|
| 101 | "" | 0 | "ec2.amazonaws.com" | 19 |
| 102 | "" | 0 | "sts.amazonaws.com" | 19 |
| 103 | "" | 0 | "www.google.com" | 14 |
| 104 | "" | 0 | "dropbox.com" | 11 |
| 105 | "" | 0 | NULL | NULL |
Related articles
- Stages:
alter,filter - Functions:
to_string,json_extract_scalar - Datasets:
xdr_data
list (comp)
Use the list() function to collect all values of a specified field across grouped rows and return them as an array (list) within the comp stage. This is equivalent to ARRAY_AGG in SQL.
Syntax
| comp list(<field>) [by <group_field1>, <group_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
any | Yes | The field whose values will be collected into a list. |
group_field |
any | No | One or more fields to group the results by. If omitted, all rows are treated as a single group. |
alias |
string | No | An alias for the output field. If not specified, the output field name defaults to list_<field>. |
Returns
Type: array
Description: The list() function returns an array containing all values of the specified field within each group. NULL values may be included.
Usage notes
- Duplicates: The
listfunction collects all values, including duplicates. - Order: The order of elements in the resulting array is not guaranteed unless a
sortstage is applied before thecompstage. - Distinct values: If you need only distinct values, consider using the
valuesfunction instead. - Data types: The function can be used with any data type.
- No grouping: When used without a
byclause, all rows are aggregated into a single group.
Examples
Example 1: Collect all source IPs by destination IP
Goal: Collect all local IP addresses grouped by remote IP address.
XQL code:
dataset = xdr_data | comp list(action_local_ip) by action_remote_ip as source_ips
Explanation: The list() function collects all action_local_ip values for each unique action_remote_ip and returns them as an array named source_ips.
Output:
| ACTION_REMOTE_IP | SOURCE_IPS |
|---|---|
| 10.0.0.1 | [192.168.1.10, 192.168.1.20, 192.168.1.10] |
| 10.0.0.2 | [192.168.1.30] |
Example 2: Collect all usernames across all events
Goal: Collect all effective usernames from all events into a single array.
XQL code:
dataset = xdr_data | comp list(actor_effective_username) as all_users
Explanation: Without a by clause, the list() function aggregates all actor_effective_username values across all rows into a single array named all_users.
Output:
| ALL_USERS |
|---|
| [admin, user1, admin, user2, user1] |
Related articles
ln
Use the ln() function to calculate the natural logarithm (base e) of a numeric value.
Syntax
ln(<number>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The numeric value for which to calculate the natural logarithm. The value must be greater than 0. |
Returns
Type: float
Description: The ln() function returns the natural logarithm (base e) of the input value. If the input is null, zero, or negative, the function returns null or NaN.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The input
numbermust be strictly greater than 0. The natural logarithm is undefined for zero and negative numbers. - Zero Input:
ln(0)returns negative infinity ornull. - Negative Input:
ln(x)forx < 0returnsNaNornull. - Null Handling: If the input expression is
null, the function returnsnull. - Identity Value:
ln(1)always returns0.0, andln(e)returns1.0. - Inverse Relationship: The
ln()function is the inverse ofexp(). That is,ln(exp(x)) = xandexp(ln(x)) = xforx > 0. - Common Use Cases: This function is typically used within the
alterstage for logarithmic scaling, entropy calculations, growth rate analysis, and data normalization.
Examples
Example 1: Calculate natural logarithm of literal values
Goal: Calculate the natural logarithm for specific numeric literals to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = ln(1), result2 = ln(exp(1)), result3 = ln(10) | fields result1, result2, result3
Explanation: ln(1) returns 0.0 (since e^0 = 1), ln(e) returns 1.0 (computed via ln(exp(1))), and ln(10) returns approximately 2.30259.
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 0.0 | 1.0 | 2.30259 |
Example 2: Calculate natural logarithm from a field value
Goal: Calculate the natural logarithm of values stored in a dataset field, filtering out non-positive values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value > 0 | alter ln_result = ln(numeric_value) | fields event_id, numeric_value, ln_result | limit 3
Explanation: This query first filters the dataset to ensure numeric_value contains only positive values, then computes the natural logarithm for each value using ln() in the alter stage.
Output:
| EVENT_ID | NUMERIC_VALUE | LN_RESULT |
|---|---|---|
| 101 | 1.0 | 0.0 |
| 102 | 10.0 | 2.30259 |
| 103 | 100.0 | 4.60517 |
Example 3: Use natural logarithm for logarithmic scaling
Goal: Apply logarithmic scaling to large numeric values to compress the range for analysis.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id > 0 | alter log_scale_id = ln(event_id) | fields event_id, log_scale_id | limit 3
Explanation: This query applies ln() to the event_id field to create a logarithmically scaled version. This is useful for visualizing or analyzing data with a wide range of values.
Output:
| EVENT_ID | LOG_SCALE_ID |
|---|---|
| 101 | 4.61512 |
| 102 | 4.62497 |
| 103 | 4.63473 |
Related articles
log
Use the log() function to calculate the logarithm of a numeric value with a specified base.
Syntax
log(<number>, <base>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The numeric value for which to calculate the logarithm. The value must be greater than 0. |
base |
integer, float | Yes | The base of the logarithm. The value must be greater than 0 and not equal to 1. |
Returns
Type: float
Description: The log() function returns the logarithm of the input value with the specified base. If either input is null, or if number is ≤ 0, or if base is ≤ 0 or equal to 1, the function returns null or NaN.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The
numbermust be strictly greater than 0. Thebasemust be strictly greater than 0 and not equal to 1. - Null Handling: If either input expression is
null, the function returnsnull. - Special Cases:
log(1, any_base)always returns0.0.log(base, base)always returns1.0. - Relationship to Other Logarithms:
log(x, e)is equivalent toln(x).log(x, 10)is equivalent tolog10(x). - Change of Base: The function implements the change of base formula internally:
log(x, b) = ln(x) / ln(b). - Common Use Cases: This function is typically used within the
alterstage for logarithmic calculations with custom bases, information theory computations (base 2), and scientific analysis.
Examples
Example 1: Calculate logarithm with different bases
Goal: Calculate logarithms with various bases to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter log_base2 = log(8, 2), log_base10 = log(1000, 10), log_base3 = log(27, 3) | fields log_base2, log_base10, log_base3
Explanation: log(8, 2) returns 3.0 (since 2^3 = 8), log(1000, 10) returns 3.0 (since 10^3 = 1000), and log(27, 3) returns 3.0 (since 3^3 = 27).
Output:
| LOG_BASE2 | LOG_BASE10 | LOG_BASE3 |
|---|---|---|
| 3.0 | 3.0 | 3.0 |
Example 2: Calculate logarithm from a field value
Goal: Calculate the base-2 logarithm of values stored in a dataset field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value > 0 | alter log2_result = log(numeric_value, 2) | fields event_id, numeric_value, log2_result | limit 3
Explanation: This query computes the base-2 logarithm for each positive value in the numeric_value field. Base-2 logarithms are commonly used in computing to determine the number of bits needed to represent a value.
Output:
| EVENT_ID | NUMERIC_VALUE | LOG2_RESULT |
|---|---|---|
| 101 | 8.0 | 3.0 |
| 102 | 64.0 | 6.0 |
| 103 | 100.0 | 6.64386 |
Example 3: Use logarithm for information entropy calculation
Goal: Calculate the information content (in bits) of event probabilities using base-2 logarithm.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter duration_seconds > 0 and duration_seconds < 1 | alter info_content = multiply(-1, log(duration_seconds, 2)) | fields event_id, duration_seconds, info_content | limit 3
Explanation: This query calculates the information content in bits using the formula -log2(p), where p is a probability-like value from duration_seconds. Higher information content indicates rarer events.
Output:
| EVENT_ID | DURATION_SECONDS | INFO_CONTENT |
|---|---|---|
| 101 | 0.5 | 1.0 |
| 102 | 0.25 | 2.0 |
| 103 | 0.8 | 0.32193 |
Related articles
log10
Use the log10() function to calculate the base-10 (common) logarithm of a numeric value.
Syntax
log10(<number>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The numeric value for which to calculate the base-10 logarithm. The value must be greater than 0. |
Returns
Type: float
Description: The log10() function returns the base-10 logarithm of the input value. If the input is null, zero, or negative, the function returns null or NaN.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The input
numbermust be strictly greater than 0. The base-10 logarithm is undefined for zero and negative numbers. - Zero Input:
log10(0)returns negative infinity ornull. - Negative Input:
log10(x)forx < 0returnsNaNornull. - Null Handling: If the input expression is
null, the function returnsnull. - Key Values:
log10(1)returns0.0,log10(10)returns1.0,log10(100)returns2.0,log10(1000)returns3.0. - Relationship:
log10(x)is equivalent tolog(x, 10). - Common Use Cases: This function is typically used within the
alterstage for decibel calculations, order-of-magnitude analysis, pH calculations, and logarithmic scaling of data.
Examples
Example 1: Calculate base-10 logarithm of literal values
Goal: Calculate the base-10 logarithm for specific numeric literals to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = log10(1), result2 = log10(100), result3 = log10(1000) | fields result1, result2, result3
Explanation: log10(1) returns 0.0, log10(100) returns 2.0 (since 10^2 = 100), and log10(1000) returns 3.0 (since 10^3 = 1000).
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 0.0 | 2.0 | 3.0 |
Example 2: Calculate base-10 logarithm from a field value
Goal: Calculate the base-10 logarithm of values stored in a dataset field to determine their order of magnitude.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value > 0 | alter log10_result = log10(numeric_value) | alter order_of_magnitude = floor(log10_result) | fields event_id, numeric_value, log10_result, order_of_magnitude | limit 3
Explanation: This query computes the base-10 logarithm for each positive value in numeric_value, then uses floor() to determine the order of magnitude. For example, a value of 500 has log10 ≈ 2.699, so its order of magnitude is 2 (hundreds).
Output:
| EVENT_ID | NUMERIC_VALUE | LOG10_RESULT | ORDER_OF_MAGNITUDE |
|---|---|---|---|
| 101 | 5.0 | 0.69897 | 0 |
| 102 | 500.0 | 2.69897 | 2 |
| 103 | 10000.0 | 4.0 | 4 |
Example 3: Use log10 for decibel calculation
Goal: Calculate a decibel-like ratio using the base-10 logarithm.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value > 0 and duration_seconds > 0 | alter ratio = divide(numeric_value, duration_seconds) | alter decibel_ratio = multiply(10, log10(ratio)) | fields event_id, numeric_value, duration_seconds, ratio, decibel_ratio | limit 3
Explanation: This query calculates a decibel-like ratio using the formula 10 * log10(ratio), which is a common pattern in signal processing and audio engineering.
Output:
| EVENT_ID | NUMERIC_VALUE | DURATION_SECONDS | RATIO | DECIBEL_RATIO |
|---|---|---|---|---|
| 101 | 100.0 | 1.0 | 100.0 | 20.0 |
| 102 | 50.0 | 5.0 | 10.0 | 10.0 |
| 103 | 1000.0 | 10.0 | 100.0 | 20.0 |
Related articles
lowercase
Use the lowercase() function to convert all characters in a specified string field or literal to their corresponding lowercase representation.
Syntax
lowercase (<string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The input string field or literal value to be converted to lowercase. |
Returns
The lowercase() function returns a string where all characters of the input have been converted to lowercase.
Usage notes
- The function requires a string input.
- If a
NULLvalue is passed to the function, it returnsNULL. - This function is typically used within the
alterstage to create new fields or modify existing ones. - The function can also be directly used within
filterstages to enable case-insensitive comparisons without settingconfig case_sensitive = falseglobally.
Examples
Example 1: Lowercasing an existing string field
Goal: Convert the event_description field to all lowercase letters.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter lower_description = lowercase(event_description) | fields event_id, event_description, lower_description | limit 3
Explanation: This query creates a new field, lower_description, containing the lowercase version of each event_description.
Output:
| EVENT_ID | EVENT_DESCRIPTION | LOWER_DESCRIPTION |
|---|---|---|
| 101 | "User login successful" | "user login successful" |
| 102 | "File access attempt" | "file access attempt" |
| 103 | "Network connection established" | "network connection established" |
Example 2: Lowercasing a literal string
Goal: Convert a direct string literal with mixed case to lowercase.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter lower_literal = lowercase("PaLo AlTo NeTwOrKs") | fields event_id, lower_literal | limit 3
Explanation: This query adds a new field, lower_literal, which contains the constant lowercase string "palo alto networks" for each record.
Output:
| EVENT_ID | LOWER_LITERAL |
|---|---|
| 101 | "palo alto networks" |
| 102 | "palo alto networks" |
| 103 | "palo alto networks" |
Example 3: Lowercasing a string extracted from JSON data
Goal: Extract a string value from a JSON field and convert it to lowercase.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter status_string = simple_json_data -> status | alter lower_json_status = lowercase(status_string) | fields event_id, simple_json_data, status_string, lower_json_status | limit 3
Explanation: This query extracts the status value from simple_json_data as a string and then converts it to lowercase. For event_id 103, because simple_json_data does not contain a status key, status_string becomes NULL, and subsequently, lower_json_status also becomes NULL.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | STATUS_STRING | LOWER_JSON_STATUS |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | "ok" | "ok" |
| 102 | {"status": "fail", "error": "access_denied"} | "fail" | "fail" |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL | NULL |
Example 4: Lowercasing a numerical field after explicit string conversion
Goal: Convert a numerical field to a string and then attempt to lowercase it.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_string = to_string(event_id) | alter lower_id_string = lowercase(event_id_string) | fields event_id, event_id_string, lower_id_string | limit 3
Explanation: This query first converts the numerical event_id to its string representation (for example, 101 becomes "101") and then attempts to lowercase it. Because numeric strings only contain digits, the lowercase() function does not alter them.
Output:
| EVENT_ID | EVENT_ID_STRING | LOWER_ID_STRING |
|---|---|---|
| 101 | "101" | "101" |
| 102 | "102" | "102" |
| 103 | "103" | "103" |
Example 5: Using lowercase() within a filter stage for case-insensitive matching
Goal: Filter for events containing a specific word, ignoring case sensitivity.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter lowercase(event_description) contains "user" | fields event_id, event_description | limit 3
Explanation: This query applies lowercase() to the event_description field for each record and then checks if the resulting lowercase string contains the substring "user". This allows it to match "User login successful" even though the original string has an uppercase 'U'.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | "User login successful" |
Example: Normalize and deduplicate process names
Goal: Convert all actor_process_image_name field values that are not null to lowercase and return a list of unique values.
XQL Code:
dataset = ample_xql_raw | fields actor_process_image_name as apin | dedup apin by asc _time | filter apin != null | alter apin = lowercase(apin)
Explanation: The query begins by selecting the actor_process_image_name field from the xample_xql_raw dataset and aliasing it as apin.
- The
dedupstage is used to keep only unique occurrences of each process name, specifically retaining the first occurrence based on ascending time. - The
filterstage removes any records where the process name is null. - Finally, the
alterstage applies thelowercase()function to theapinfield, standardizing all unique process names into lowercase format for consistent reporting and analysis.
Output:
| apin |
|---|
| chrome.exe |
| svchost.exe |
| terminal |
| notepad.exe |
Related articles
ltrim
Use the ltrim() function to remove specified characters or whitespace from the beginning (left side) of a string.
Syntax
ltrim (<string>, [trim_characters])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The string field or literal value you wish to modify. |
trim_characters |
string | No | A string containing the set of characters to remove from the left side of the string. If omitted, defaults to whitespace characters (spaces and tabs). |
Returns
The ltrim() function returns a new string with the specified leading characters removed.
Usage notes
- The
trim_charactersparameter is treated as a set of individual characters. Any character from this set found at the beginning of the string will be removed repeatedly until a character that is not in the set is encountered. - If the
trim_charactersparameter is not specified, the function defaults to removing leading whitespace characters (spaces and tabs). - If a
NULLvalue is passed as the input string, the function returnsNULL.
Examples
Example 1: Removing leading whitespace (default behavior)
Goal: Remove leading spaces from a literal string by relying on the function's default behavior.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter trimmed_text = ltrim(" Important Message") | fields event_id, trimmed_text | limit 3
Explanation: This query creates a new field, trimmed_text, where the leading spaces from the literal string " Important Message" are removed, resulting in "Important Message".
Output:
| EVENT_ID | TRIMMED_TEXT |
|---|---|
| 101 | Important Message |
| 102 | Important Message |
| 103 | Important Message |
Example 2: Removing a specific exact prefix
Goal: Remove the exact "www." prefix from the dst_domain field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter trimmed_domain = ltrim(dst_domain, "www.") | fields event_id, dst_domain, trimmed_domain | limit 3
Explanation: For event_id 103, the leading "www." from "www.google.com" is removed, leaving "google.com". For other records where the trim_characters ("www.") are not found at the very beginning, the string remains unchanged.
Output:
| EVENT_ID | DST_DOMAIN | TRIMMED_DOMAIN |
|---|---|---|
| 101 | ec2.amazonaws.com | ec2.amazonaws.com |
| 102 | sts.amazonaws.com | sts.amazonaws.com |
| 103 | www.google.com | google.com |
Example 3: Removing specific leading characters (character set removal)
Goal: Remove a set of characters ('U', 'e', 'o', 'r', space) from the beginning of the raw_log_data field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter processed_log = ltrim(raw_log_data, "Ueor ") | fields event_id, raw_log_data, processed_log | limit 3
Explanation: For event_id 101, the log starts with "User Alice...". 'U' is in the set "Ueor ", so it is removed. The next character 's' is not in the set, so the process stops. The result is "ser Alice logged in from 192.168.1.10".
Output:
| EVENT_ID | RAW_LOG_DATA | PROCESSED_LOG |
|---|---|---|
| 101 | User Alice logged in from 192.168.1.10 | ser Alice logged in from 192.168.1.10 |
| 102 | Process cmd.exe attempted to access /etc/passwd | Process cmd.exe attempted to access /etc/passwd |
| 103 | Outbound connection to 1.1.1.1:443 initiated by AppX | Outbound connection to 1.1.1.1:443 initiated by AppX |
Example 4: ltrim() on a string extracted from JSON data
Goal: Remove specific characters ('f' or 'o') from the beginning of a string extracted from a JSON field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter status_string = simple_json_data -> status | alter trimmed_json_status = ltrim(status_string, "fo") | fields event_id, simple_json_data, status_string, trimmed_json_status | limit 3
Explanation: For event_id 101, "ok" becomes "k" because 'o' is removed. For event_id 102, "fail" becomes "ail" because 'f' is removed. For event_id 103, status_string is NULL, so trimmed_json_status is also NULL.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | STATUS_STRING | TRIMMED_JSON_STATUS |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | ok | k |
| 102 | {"status": "fail", "error": "access_denied"} | fail | ail |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL | NULL |
Example 5: ltrim() on a numerical field after explicit string conversion
Goal: Remove specific digits ('1' or '0') from the beginning of the event_id field after converting it to a string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_string = to_string(event_id) | alter trimmed_id_string = ltrim(event_id_string, "10") | fields event_id, event_id_string, trimmed_id_string | limit 3
Explanation: For event_id 101 ("101"), '1', then '0', then '1' are all removed because they are in the set "10", resulting in an empty string. For event_id 102 ("102"), '1' and '0' are removed, leaving "2". For event_id 103 ("103"), '1' and '0' are removed, leaving "3".
Output:
| EVENT_ID | EVENT_ID_STRING | TRIMMED_ID_STRING |
|---|---|---|
| 101 | 101 | |
| 102 | 102 | 2 |
| 103 | 103 | 3 |
Example 6: ltrim() on a field with no matching leading characters
Goal: Attempt to remove characters ('x', 'y', 'z') that do not exist at the start of the string field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter no_change_desc = ltrim(event_description, "xyz") | fields event_id, event_description, no_change_desc | limit 3
Explanation: Because none of the characters 'x', 'y', or 'z' are present at the beginning of "User login successful" or other event_description values, the function returns the original string unchanged.
Output:
| EVENT_ID | EVENT_DESCRIPTION | NO_CHANGE_DESC |
|---|---|---|
| 101 | User login successful | User login successful |
| 102 | File access attempt | File access attempt |
| 103 | Network connection established | Network connection established |
Related articles
max (comp)
Use the max() function to return the maximum value of a specified field across all rows in each group within the comp stage. This is equivalent to the SQL MAX aggregate function.
Syntax
| comp max(<field>) [by <group_field1>, <group_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric, string, or datetime | Yes | The field from which to find the maximum value. |
group_field |
any | No | One or more fields to group the results by. If omitted, all rows are treated as a single group. |
alias |
string | No | An alias for the output field. If not specified, the output field name defaults to max_<field>. |
Returns
Type: same as input field
Description: The max() function returns the maximum value found in the specified field within each group. Returns NULL if all values in the group are NULL.
Usage notes
- Data types: The
maxfunction works with numeric, string, and datetime fields. - String comparison: For string fields, the maximum is determined by lexicographic (alphabetical) ordering.
- Null handling: NULL values are ignored in the computation.
- No grouping: When used without a
byclause, the function returns the maximum value across all rows. - Multiple aggregations: Can be combined with other aggregation functions in the same
compstage.
Examples
Example 1: Find the latest event time per host
Goal: Find the most recent event timestamp for each host.
XQL code:
dataset = xdr_data | comp max(_time) by agent_hostname as latest_event
Explanation: The max() function finds the latest _time value for each unique agent_hostname, returning the most recent event time per host.
Output:
| AGENT_HOSTNAME | LATEST_EVENT |
|---|---|
| workstation-1 | 2024-01-15 14:30:00 |
| workstation-2 | 2024-01-15 13:45:00 |
Example 2: Find the maximum severity across all alerts
Goal: Find the highest alert severity value across all events.
XQL code:
dataset = xdr_data | comp max(alert_severity) as highest_severity
Explanation: Without a by clause, the max() function scans all rows and returns the single highest alert_severity value.
Output:
| HIGHEST_SEVERITY |
|---|
| 10 |
Example 3: Multiple aggregations in one comp stage
Goal: Find both the latest and earliest event times per host in a single query.
XQL code:
dataset = xdr_data | comp max(_time) as latest, min(_time) as earliest by agent_hostname
Explanation: This query combines max() and min() in a single comp stage to find both the latest and earliest event timestamps for each agent_hostname.
Output:
| AGENT_HOSTNAME | LATEST | EARLIEST |
|---|---|---|
| workstation-1 | 2024-01-15 14:30:00 | 2024-01-15 08:00:00 |
Related articles
- Stages:
comp,fields,limit - Functions:
min(),max (windowcomp),greatest() - Datasets:
xdr_data
max (windowcomp)
Use the max() function within the windowcomp stage to compute the maximum value of a specified field over a window of rows. Unlike the comp stage version, the windowcomp version preserves all original rows and adds the computed maximum as a new field. This is equivalent to MAX() OVER(...) in SQL.
Syntax
| windowcomp max(<field>) [by <partition_field1>, <partition_field2>, ...] [sort [asc|desc] <sort_field1>, ...] [between <lower> [and <upper>] [frame_type=rows|range]] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric, string, or datetime | Yes | The field from which to compute the maximum value. |
partition_field |
any | No | One or more fields to partition the data by (equivalent to SQL PARTITION BY). |
sort_field |
any | No | One or more fields to define the order within each partition (equivalent to SQL ORDER BY). Defaults to ascending. |
lower |
integer or null |
No | Lower bound of the window frame. 0 = current row, negative = rows before, null = unbounded. |
upper |
integer or null |
No | Upper bound of the window frame. 0 = current row, positive = rows after, null = unbounded. |
frame_type |
rows or range |
No | Type of window frame. rows (default) uses physical row offsets; range uses value-based offsets on the sort field. |
alias |
string | No | An alias for the output field. |
Returns
Type: same as input field
Description: The max() function returns the maximum value within the defined window for each row. All original rows are preserved.
Usage notes
- Row preservation: Unlike
comp max(), thewindowcomp max()does not reduce the number of rows. Each row retains its original data and gets an additional field with the window maximum. - No partitioning: If no
byclause is specified, the window spans the entire result set. - Default frame: If no window frame is specified, the default frame is from the start of the partition to the current row (
between null and 0). - Null handling: NULL values are ignored in the computation.
- Running maximum: Can be combined with
sortto compute running maximums.
Examples
Example 1: Maximum severity per host (all rows preserved)
Goal: Compute the maximum alert severity for each host while preserving all original rows.
XQL code:
dataset = xdr_data | windowcomp max(alert_severity) by agent_hostname as max_severity_per_host
Explanation: The max() function computes the maximum alert_severity within each agent_hostname partition. All original rows are preserved, and each row receives the partition's maximum value in max_severity_per_host.
Output:
| _TIME | AGENT_HOSTNAME | ALERT_SEVERITY | MAX_SEVERITY_PER_HOST |
|---|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | 3 | 7 |
| 2024-01-15 09:00:00 | workstation-1 | 7 | 7 |
| 2024-01-15 10:00:00 | workstation-1 | 5 | 7 |
| 2024-01-15 08:30:00 | workstation-2 | 2 | 4 |
| 2024-01-15 09:30:00 | workstation-2 | 4 | 4 |
Example 2: Running maximum over time
Goal: Compute a running maximum of bytes sent, ordered by time.
XQL code:
dataset = xdr_data | windowcomp max(bytes_sent) sort asc _time as running_max_bytes
Explanation: By sorting on _time in ascending order, the max() function computes a running maximum of bytes_sent from the start of the dataset up to the current row.
Output:
| _TIME | BYTES_SENT | RUNNING_MAX_BYTES |
|---|---|---|
| 2024-01-15 08:00:00 | 100 | 100 |
| 2024-01-15 09:00:00 | 250 | 250 |
| 2024-01-15 10:00:00 | 150 | 250 |
| 2024-01-15 11:00:00 | 300 | 300 |
Example 3: Maximum within a sliding window of 3 rows
Goal: Compute the maximum bytes sent within a sliding window of 3 rows (current row plus one row before and one row after).
XQL code:
dataset = xdr_data | windowcomp max(bytes_sent) sort asc _time between -1 and 1 as local_max
Explanation: The between -1 and 1 clause defines a sliding window of 3 rows centered on the current row. The max() function returns the maximum bytes_sent value within that window for each row.
Output:
| _TIME | BYTES_SENT | LOCAL_MAX |
|---|---|---|
| 2024-01-15 08:00:00 | 100 | 250 |
| 2024-01-15 09:00:00 | 250 | 250 |
| 2024-01-15 10:00:00 | 150 | 300 |
| 2024-01-15 11:00:00 | 300 | 300 |
Related articles
- Stages:
windowcomp,comp,sort - Functions:
max (comp),min(),greatest() - Datasets:
xdr_data
md5
Use the md5() function to compute the MD5 (Message-Digest Algorithm 5) hash of an input string.
Syntax
md5 ("<input_string>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
input_string |
string | Yes | The string to be hashed. |
Returns
The md5() function returns the MD5 hash value as a string.
Usage notes
- The function strictly requires a single string input.
- MD5 is a one-way cryptographic hash function, meaning it is computationally infeasible to reverse the hashing process to obtain the original string from its hash.
Examples
Example 1: Hashing a basic literal string
Goal: Compute the MD5 hash of a simple literal string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_string = md5("Hello world") | fields event_id, hashed_string | limit 3
Explanation: This query adds a new field, hashed_string, which contains the MD5 hash of "Hello world" for each record.
Output:
| EVENT_ID | HASHED_STRING |
|---|---|
| 101 | 3e25960a79dbc69b674cd4ec67a72c65 |
| 102 | 3e25960a79dbc69b674cd4ec67a72c65 |
| 103 | 3e25960a79dbc69b674cd4ec67a72c65 |
Example 2: Hashing an existing string field
Goal: Hash values from an existing string field from the dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_description = md5(event_description) | fields event_id, event_description, hashed_description | limit 3
Explanation: The query creates hashed_description by applying the md5() function to the event_description for each record.
Output:
| EVENT_ID | EVENT_DESCRIPTION | HASHED_DESCRIPTION |
|---|---|---|
| 101 | User login successful | e7751c911ee0541703e8787729227f2f |
| 102 | File access attempt | be2254e015ee6b158055c56c2e28a506 |
| 103 | Network connection established | 24b74f0c43666f272a85e13b06385a86 |
Example 3: Hashing a string derived from a non-string field
Goal: Convert a numeric field to a string and then hash it.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_string = to_string(event_id) | alter hashed_id = md5(event_id_string) | fields event_id, event_id_string, hashed_id | limit 3
Explanation: The event_id is first converted to a string, and then md5() hashes this string representation.
Output:
| EVENT_ID | EVENT_ID_STRING | HASHED_ID |
|---|---|---|
| 101 | 101 | b16f6b0f199be0c27271457193f5509a |
| 102 | 102 | 00d720d2a8b233c4424316d764491024 |
| 103 | 103 | 19842c38f4d9b40778c1a9386d3d4b68 |
Example 4: Hashing an empty string
Goal: Show the consistent result of hashing an empty string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_empty_string = md5("") | fields event_id, hashed_empty_string | limit 3
Explanation: Hashing an empty string consistently results in the well-known MD5 hash for an empty string.
Output:
| EVENT_ID | HASHED_EMPTY_STRING |
|---|---|
| 101 | d41d8cd98f00b204e9800998ecf8427e |
| 102 | d41d8cd98f00b204e9800998ecf8427e |
| 103 | d41d8cd98f00b204e9800998ecf8427e |
Example 5: Handling NULL input
Goal: Illustrate the function's behavior when provided with a NULL input.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_null_field = md5(dst_domain) | fields event_id, dst_domain, hashed_null_field | limit 5
Explanation: When the input to md5() is NULL, the function consistently returns NULL for the output field.
Output:
| EVENT_ID | DST_DOMAIN | HASHED_NULL_FIELD |
|---|---|---|
| 101 | ec2.amazonaws.com | 7f2f11181827457c134012019c4d93e5 |
| 102 | sts.amazonaws.com | fdf15a896d92008779b1248039601d0f |
| 103 | www.google.com | 121f66cb71158f964092b3a1a36173a7 |
| 104 | dropbox.com | 84b7a137e0c4573130d740a6b47c0b6b |
| 105 | NULL | NULL |
Related articles
median (comp)
Use the median() function to return the median (middle value) of a specified numeric field across all rows in each group within the comp stage. For an even number of values, it returns the average of the two middle values. This is equivalent to computing the 50th percentile.
Syntax
| comp median(<field>) [by <group_field1>, <group_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric | Yes | The numeric field from which to compute the median value. |
group_field |
any | No | One or more fields to group the results by. If omitted, all rows are treated as a single group. |
alias |
string | No | An alias for the output field. If not specified, the output field name defaults to median_<field>. |
Returns
Type: numeric (float)
Description: The median() function returns the median value of the specified field within each group. Returns NULL if all values in the group are NULL.
Usage notes
- Numeric only: The
medianfunction only works with numeric fields. - Null handling: NULL values are ignored in the computation.
- Odd count: For an odd number of non-NULL values, the median is the middle value when sorted.
- Even count: For an even number of non-NULL values, the median is the average of the two middle values.
- Return type: The result is always returned as a floating-point number.
- No grouping: When used without a
byclause, the function computes the median across all rows.
Examples
Example 1: Median response time per endpoint
Goal: Compute the median response time for each host.
XQL code:
dataset = xdr_data | comp median(action_total_time) by agent_hostname as median_response_time
Explanation: The median() function computes the middle value of action_total_time for each unique agent_hostname, providing a representative response time that is less affected by outliers than the average.
Output:
| AGENT_HOSTNAME | MEDIAN_RESPONSE_TIME |
|---|---|
| workstation-1 | 45.5 |
| workstation-2 | 32.0 |
Example 2: Overall median of bytes received
Goal: Compute the overall median of bytes received across all events.
XQL code:
dataset = xdr_data | comp median(action_network_bytes_received) as median_bytes
Explanation: Without a by clause, the median() function computes the median of action_network_bytes_received across all rows, returning a single value.
Output:
| MEDIAN_BYTES |
|---|
| 1024.5 |
Related articles
median (windowcomp)
Use the median() function within the windowcomp stage to compute the median value of a specified numeric field over a window of rows. Unlike the comp stage version, the windowcomp version preserves all original rows and adds the computed median as a new field. This is equivalent to PERCENTILE_CONT(0.5) OVER(...) in SQL.
Syntax
| windowcomp median(<field>) [by <partition_field1>, <partition_field2>, ...] [sort [asc|desc] <sort_field1>, ...] [between <lower> [and <upper>] [frame_type=rows|range]] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric | Yes | The numeric field from which to compute the median value. |
partition_field |
any | No | One or more fields to partition the data by (equivalent to SQL PARTITION BY). |
sort_field |
any | No | One or more fields to define the order within each partition (equivalent to SQL ORDER BY). Defaults to ascending. |
lower |
integer or null |
No | Lower bound of the window frame. 0 = current row, negative = rows before, null = unbounded. |
upper |
integer or null |
No | Upper bound of the window frame. 0 = current row, positive = rows after, null = unbounded. |
frame_type |
rows or range |
No | Type of window frame. rows (default) uses physical row offsets; range uses value-based offsets on the sort field. |
alias |
string | No | An alias for the output field. |
Returns
Type: numeric (float)
Description: The median() function returns the median value within the defined window for each row. All original rows are preserved.
Usage notes
- Row preservation: Unlike
comp median(), thewindowcomp median()does not reduce the number of rows. - Percentile: The median is the 50th percentile of the values within the window.
- Null handling: NULL values are ignored in the computation.
- Default frame: If no window frame is specified, the default frame is from the start of the partition to the current row (
between null and 0). - Trend analysis: Useful for computing running medians or sliding window medians for trend analysis.
Examples
Example 1: Median bytes per host (all rows preserved)
Goal: Compute the median bytes received for each host while preserving all original rows.
XQL code:
dataset = xdr_data | windowcomp median(action_network_bytes_received) by agent_hostname as median_bytes_per_host
Explanation: The median() function computes the median of action_network_bytes_received within each agent_hostname partition. All original rows are preserved, and each row receives the partition's median value in median_bytes_per_host.
Output:
| _TIME | AGENT_HOSTNAME | ACTION_NETWORK_BYTES_RECEIVED | MEDIAN_BYTES_PER_HOST |
|---|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | 100 | 200.0 |
| 2024-01-15 09:00:00 | workstation-1 | 300 | 200.0 |
| 2024-01-15 10:00:00 | workstation-1 | 200 | 200.0 |
| 2024-01-15 08:30:00 | workstation-2 | 500 | 400.0 |
| 2024-01-15 09:30:00 | workstation-2 | 300 | 400.0 |
Example 2: Running median of response times
Goal: Compute a running median of response times, ordered by time.
XQL code:
dataset = xdr_data | windowcomp median(action_total_time) sort asc _time as running_median
Explanation: By sorting on _time in ascending order, the median() function computes a running median of action_total_time from the start of the dataset up to the current row.
Output:
| _TIME | ACTION_TOTAL_TIME | RUNNING_MEDIAN |
|---|---|---|
| 2024-01-15 08:00:00 | 50 | 50.0 |
| 2024-01-15 09:00:00 | 30 | 40.0 |
| 2024-01-15 10:00:00 | 70 | 50.0 |
| 2024-01-15 11:00:00 | 40 | 45.0 |
Related articles
- Stages:
windowcomp,comp,sort - Functions:
median (comp),avg(),max() - Datasets:
xdr_data
min (comp)
Use the min() function to return the minimum value of a specified field across all rows in each group within the comp stage. This is equivalent to the SQL MIN aggregate function.
Syntax
| comp min(<field>) [by <group_field1>, <group_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric, string, or datetime | Yes | The field from which to find the minimum value. |
group_field |
any | No | One or more fields to group the results by. If omitted, all rows are treated as a single group. |
alias |
string | No | An alias for the output field. If not specified, the output field name defaults to min_<field>. |
Returns
Type: same as input field
Description: The min() function returns the minimum value found in the specified field within each group. Returns NULL if all values in the group are NULL.
Usage notes
- Data types: The
minfunction works with numeric, string, and datetime fields. - String comparison: For string fields, the minimum is determined by lexicographic (alphabetical) ordering.
- Null handling: NULL values are ignored in the computation.
- No grouping: When used without a
byclause, the function returns the minimum value across all rows. - Multiple aggregations: Can be combined with other aggregation functions in the same
compstage.
Examples
Example 1: Find the earliest event time per host
Goal: Find the earliest event timestamp for each host.
XQL code:
dataset = xdr_data | comp min(_time) by agent_hostname as earliest_event
Explanation: The min() function finds the earliest _time value for each unique agent_hostname, returning the first event time per host.
Output:
| AGENT_HOSTNAME | EARLIEST_EVENT |
|---|---|
| workstation-1 | 2024-01-15 08:00:00 |
| workstation-2 | 2024-01-15 08:30:00 |
Example 2: Find the minimum severity across all alerts
Goal: Find the lowest alert severity value across all events.
XQL code:
dataset = xdr_data | comp min(alert_severity) as lowest_severity
Explanation: Without a by clause, the min() function scans all rows and returns the single lowest alert_severity value.
Output:
| LOWEST_SEVERITY |
|---|
| 1 |
Example 3: Multiple aggregations in one comp stage
Goal: Find both the earliest and latest event times, plus total count, per host in a single query.
XQL code:
dataset = xdr_data | comp min(_time) as earliest, max(_time) as latest, count(*) as total by agent_hostname
Explanation: This query combines min(), max(), and count() in a single comp stage to find the earliest and latest event timestamps along with the total event count for each agent_hostname.
Output:
| AGENT_HOSTNAME | EARLIEST | LATEST | TOTAL |
|---|---|---|---|
| workstation-1 | 2024-01-15 08:00:00 | 2024-01-15 14:30:00 | 25 |
| workstation-2 | 2024-01-15 08:30:00 | 2024-01-15 13:45:00 | 18 |
Related articles
min (windowcomp)
Use the min() function within the windowcomp stage to compute the minimum value of a specified field over a window of rows. Unlike the comp stage version, the windowcomp version preserves all original rows and adds the computed minimum as a new field. This is equivalent to MIN() OVER(...) in SQL.
Syntax
| windowcomp min(<field>) [by <partition_field1>, <partition_field2>, ...] [sort [asc|desc] <sort_field1>, ...] [between <lower> [and <upper>] [frame_type=rows|range]] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric, string, or datetime | Yes | The field from which to compute the minimum value. |
partition_field |
any | No | One or more fields to partition the data by (equivalent to SQL PARTITION BY). |
sort_field |
any | No | One or more fields to define the order within each partition (equivalent to SQL ORDER BY). Defaults to ascending. |
lower |
integer or null |
No | Lower bound of the window frame. 0 = current row, negative = rows before, null = unbounded. |
upper |
integer or null |
No | Upper bound of the window frame. 0 = current row, positive = rows after, null = unbounded. |
frame_type |
rows or range |
No | Type of window frame. rows (default) uses physical row offsets; range uses value-based offsets on the sort field. |
alias |
string | No | An alias for the output field. |
Returns
Type: same as input field
Description: The min() function returns the minimum value within the defined window for each row. All original rows are preserved.
Usage notes
- Row preservation: Unlike
comp min(), thewindowcomp min()does not reduce the number of rows. Each row retains its original data and gets an additional field with the window minimum. - No partitioning: If no
byclause is specified, the window spans the entire result set. - Default frame: If no window frame is specified, the default frame is from the start of the partition to the current row (
between null and 0). - Null handling: NULL values are ignored in the computation.
- Running minimum: Can be combined with
sortto compute running minimums.
Examples
Example 1: Minimum severity per host (all rows preserved)
Goal: Compute the minimum alert severity for each host while preserving all original rows.
XQL code:
dataset = xdr_data | windowcomp min(alert_severity) by agent_hostname as min_severity_per_host
Explanation: The min() function computes the minimum alert_severity within each agent_hostname partition. All original rows are preserved, and each row receives the partition's minimum value in min_severity_per_host.
Output:
| _TIME | AGENT_HOSTNAME | ALERT_SEVERITY | MIN_SEVERITY_PER_HOST |
|---|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | 3 | 3 |
| 2024-01-15 09:00:00 | workstation-1 | 7 | 3 |
| 2024-01-15 10:00:00 | workstation-1 | 5 | 3 |
| 2024-01-15 08:30:00 | workstation-2 | 2 | 2 |
| 2024-01-15 09:30:00 | workstation-2 | 4 | 2 |
Example 2: Running minimum over time
Goal: Compute a running minimum of bytes received, ordered by time.
XQL code:
dataset = xdr_data | windowcomp min(action_network_bytes_received) sort asc _time as running_min_bytes
Explanation: By sorting on _time in ascending order, the min() function computes a running minimum of action_network_bytes_received from the start of the dataset up to the current row.
Output:
| _TIME | ACTION_NETWORK_BYTES_RECEIVED | RUNNING_MIN_BYTES |
|---|---|---|
| 2024-01-15 08:00:00 | 500 | 500 |
| 2024-01-15 09:00:00 | 250 | 250 |
| 2024-01-15 10:00:00 | 400 | 250 |
| 2024-01-15 11:00:00 | 100 | 100 |
Example 3: Minimum within a sliding window of 3 rows
Goal: Compute the minimum bytes received within a sliding window of 3 rows (current row plus one row before and one row after).
XQL code:
dataset = xdr_data | windowcomp min(action_network_bytes_received) sort asc _time between -1 and 1 as local_min
Explanation: The between -1 and 1 clause defines a sliding window of 3 rows centered on the current row. The min() function returns the minimum action_network_bytes_received value within that window for each row.
Output:
| _TIME | ACTION_NETWORK_BYTES_RECEIVED | LOCAL_MIN |
|---|---|---|
| 2024-01-15 08:00:00 | 500 | 250 |
| 2024-01-15 09:00:00 | 250 | 250 |
| 2024-01-15 10:00:00 | 400 | 100 |
| 2024-01-15 11:00:00 | 100 | 100 |
Related articles
- Stages:
windowcomp,comp,sort - Functions:
min (comp),max(),least() - Datasets:
xdr_data
mod
Use the mod() function to calculate the remainder (modulus) of the division of two numeric values.
Syntax
mod(<dividend>, <divisor>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
dividend |
integer, float | Yes | The number to be divided (numerator). |
divisor |
integer, float | Yes | The number to divide by (denominator). Must not be zero. |
Returns
Type: integer or float (matches input types)
Description: The mod() function returns the remainder after dividing the dividend by the divisor. If either input is null or the divisor is zero, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Division by Zero: If the
divisoris zero, the function returnsnullor raises an error. - Null Handling: If either input expression is
null, the function returnsnull. - Sign of Result: The sign of the result matches the sign of the
dividend. - Common Use Cases: This function is typically used within the
alterstage for cyclic calculations, even/odd detection, bucketing, time-based grouping (for example, grouping by hour of day), and hash-based distribution.
Examples
Example 1: Calculate modulus of literal values
Goal: Calculate the remainder for specific division operations.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = mod(10, 3), result2 = mod(15, 5), result3 = mod(-7, 3) | fields result1, result2, result3
Explanation: mod(10, 3) returns 1 (10 = 3�3 + 1), mod(15, 5) returns 0 (15 is evenly divisible by 5), and mod(-7, 3) returns -1 (the sign follows the dividend).
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 1 | 0 | -1 |
Example 2: Determine even or odd event IDs
Goal: Classify events as having even or odd event IDs using the modulus operator.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter is_even = if(mod(event_id, 2) = 0, "even", "odd") | fields event_id, is_even | limit 4
Explanation: This query uses mod(event_id, 2) to check if the event ID is divisible by 2. If the remainder is 0, the event is classified as "even"; otherwise, it is "odd".
Output:
| EVENT_ID | IS_EVEN |
|---|---|
| 101 | odd |
| 102 | even |
| 103 | odd |
| 104 | even |
Example 3: Group events into cyclic buckets
Goal: Distribute events into 5 cyclic buckets based on their event ID.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter bucket = mod(event_id, 5) | fields event_id, bucket | limit 5
Explanation: This query assigns each event to one of 5 buckets (0 through 4) using mod(event_id, 5). This creates a cyclic distribution pattern useful for load balancing or sampling.
Output:
| EVENT_ID | BUCKET |
|---|---|
| 101 | 1 |
| 102 | 2 |
| 103 | 3 |
| 104 | 4 |
| 105 | 0 |
Related articles
multiply
Use the multiply() function to calculate the product of two numbers.
Syntax
multiply (<string> | <integer> | <float>, <string> | <integer> | <float>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
value_1 |
integer, float, string | Yes | The first numeric value. |
value_2 |
integer, float, string | Yes | The second numeric value. |
Returns
The multiply() function returns the numerical product of the two input numbers.
Usage notes
- The function accepts various numeric inputs, including numeric literals (for example, 2, 1.5), floating-point numbers, and integers.
- The function also accepts integers or numbers provided as a string type (for example, extracted from a data field and then converted).
- The function supports negative numbers for both input parameters.
Examples
Example 1: Multiply integer field by integer literal
Goal: Demonstrate multiply() applied directly to an integer field (event_id) and a fixed integer literal.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter multiplied_event_id = multiply(event_id, 2) | fields event_id, multiplied_event_id | limit 3
Explanation: This query creates a new field, multiplied_event_id, by taking each event_id (for example, 101) and multiplying it by 2.
Output:
| EVENT_ID | MULTIPLIED_EVENT_ID |
|---|---|
| 101 | 202 |
| 102 | 204 |
| 103 | 206 |
Example 2: Multiply floating-point field by integer literal
Goal: Showcase multiply() with a floating-point input field (duration_seconds) and an integer literal.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter multiplied_duration = multiply(duration_seconds, 10) | fields event_id, duration_seconds, multiplied_duration | limit 3
Explanation: Here, duration_seconds (which contains decimal values, for example, 1.5, 0.8) is multiplied by 10, producing a new floating-point value in multiplied_duration.
Output:
| EVENT_ID | DURATION_SECONDS | MULTIPLIED_DURATION |
|---|---|---|
| 101 | 1.5 | 15.0 |
| 102 | 0.8 | 8.0 |
| 103 | 10.2 | 102.0 |
Example 3: Multiply floating-point field by floating-point literal
Goal: Demonstrate multiply() handling two floating-point numbers, including a decimal literal.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter precise_duration_calc = multiply(duration_seconds, 0.75) | fields event_id, duration_seconds, precise_duration_calc | limit 3
Explanation: This query multiplies duration_seconds by 0.75, resulting in precise_duration_calc, which will also be a floating-point number.
Output:
| EVENT_ID | DURATION_SECONDS | PRECISE_DURATION_CALC |
|---|---|---|
| 101 | 1.5 | 1.125 |
| 102 | 0.8 | 0.6 |
| 103 | 10.2 | 7.65 |
Example 4: Multiply with a negative integer literal
Goal: Demonstrate multiply() handling a negative input, producing a negative result.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter negative_event_id = multiply(event_id, -1) | fields event_id, negative_event_id | limit 3
Explanation: The event_id is multiplied by -1. This correctly computes the negative product, demonstrating the function's behavior with negative inputs.
Output:
| EVENT_ID | NEGATIVE_EVENT_ID |
|---|---|
| 101 | -101 |
| 102 | -102 |
| 103 | -103 |
Example 5: Multiply string-converted-to-number field by integer literal
Goal: Show multiply() applied to a numeric value extracted from a JSON field and converted from a string, demonstrating flexibility with input types.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 110) | alter json_numeric_string = coalesce(simple_json_data -> code, simple_json_data -> size_gb) | alter json_numeric_value = to_number(json_numeric_string) | alter multiplied_json_value = multiply(json_numeric_value, 3) | fields event_id, simple_json_data, json_numeric_value, multiplied_json_value | limit 3
Explanation: This query first extracts a numeric value (either code or size_gb) from the simple_json_data field as a string. The query then converts this string to a number using to_number() and applies multiply() with a literal, storing the result in multiplied_json_value.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | JSON_NUMERIC_VALUE | MULTIPLIED_JSON_VALUE |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | 200 | 600 |
| 110 | {"backup_id": "DB-005", "size_gb": 500} | 500 | 1500 |
Related articles
object_create
Use the object_create() function to construct a new object by defining specific key-value pairs.
Syntax
object_create ("<key1>", <value1>, "<key2>", <value2>, ...)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
key_n |
string | Yes | The name of the key. This must be a string literal enclosed in double quotes. |
value_n |
string, integer, float, boolean, object, array | Yes | The value associated with the preceding key. This can be a literal, a field name, or the result of another function. |
Returns
The object_create() function returns a single object containing the specified key-value pairs.
Usage notes
- The function requires an even number of arguments, structured as pairs of keys and values.
- All keys must be provided as string literals (enclosed in double quotes).
- Values can be of any XQL-supported data type, including strings, integers, floats, booleans, or results from other functions.
- The function does not implicitly convert string representations of numeric or boolean values; it retains the data types exactly as entered for the values.
- If a value parameter is
NULL, the resulting object will typically contain aNULLvalue for that specific key.
Examples
Example 1: Creating an object with string literal key-value pairs
Goal: Construct an object using only string literals for both keys and values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_metadata = object_create("source", "system_log", "level", "informational") | fields event_id, event_metadata | limit 3
Explanation: This query adds a new field, event_metadata, containing a static object with two string key-value pairs for each record.
Output:
| EVENT_ID | EVENT_METADATA |
|---|---|
| 101 | {"source": "system_log", "level": "informational"} |
| 102 | {"source": "system_log", "level": "informational"} |
| 103 | {"source": "system_log", "level": "informational"} |
Example 2: Creating an object with mixed data type values (literals)
Goal: Construct an object that stores values of mixed data types (string, integer, boolean, float) using literal inputs.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_details = object_create( "log_id_prefix", "XDR", "priority_score", 100, "is_critical", true, "data_size_gb", 1.5 ) | fields event_id, event_details | limit 3
Explanation: A new field event_details is created, holding an object where values are of different types (string, integer, boolean, float), demonstrating the function's flexibility in value data types.
Output:
| EVENT_ID | EVENT_DETAILS |
|---|---|
| 101 | {"log_id_prefix": "XDR", "priority_score": 100, "is_critical": true, "data_size_gb": 1.5} |
| 102 | {"log_id_prefix": "XDR", "priority_score": 100, "is_critical": true, "data_size_gb": 1.5} |
| 103 | {"log_id_prefix": "XDR", "priority_score": 100, "is_critical": true, "data_size_gb": 1.5} |
Example 3: Creating an object with existing field values
Goal: Construct an object using values pulled directly from existing fields in the dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter contextual_info = object_create( "event_type", event_description, "success_status", is_successful, "event_duration", duration_seconds, "ip_address", ipv4_address ) | fields event_id, event_description, is_successful, duration_seconds, ipv4_address, contextual_info | limit 3
Explanation: The contextual_info field is populated with an object whose values are dynamically pulled from event_description (string), is_successful (boolean), duration_seconds (float), and ipv4_address (string) for each record.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL | DURATION_SECONDS | IPV4_ADDRESS | CONTEXTUAL_INFO |
|---|---|---|---|---|---|
| 101 | "User login successful" | true | 1.5 | 192.168.1.10 | {"event_type": "User login successful", "success_status": true, "event_duration": 1.5, "ip_address": "192.168.1.10"} |
| 102 | "File access attempt" | false | 0.8 | 10.0.0.1 | {"event_type": "File access attempt", "success_status": false, "event_duration": 0.8, "ip_address": "10.0.0.1"} |
| 103 | "Network connection established" | true | 10.2 | 1.1.1.1 | {"event_type": "Network connection established", "success_status": true, "event_duration": 10.2, "ip_address": "1.1.1.1"} |
Example 4: Creating an object with values from other functions
Goal: Construct an object using the output of other XQL functions (such as len() and to_string()) as values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter derived_object = object_create( "description_length", len(event_description), "id_string", to_string(event_id) ) | fields event_id, event_description, derived_object | limit 3
Explanation: The derived_object contains the length of the event_description (an integer) and the string representation of event_id, obtained using len() and to_string() functions respectively.
Output:
| EVENT_ID | EVENT_DESCRIPTION | DERIVED_OBJECT |
|---|---|---|
| 101 | "User login successful" | {"description_length": 23, "id_string": "101"} |
| 102 | "File access attempt" | {"description_length": 20, "id_string": "102"} |
| 103 | "Network connection established" | {"description_length": 30, "id_string": "103"} |
Example 5: Handling NULL values in object_create()
Goal: Demonstrate how the function handles NULL values provided for keys or values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter null_handling_example = object_create( "domain", dst_domain, "static_null_value", NULL, // Explicit NULL value "constant_key", "always_present" ) | fields event_id, dst_domain, null_handling_example | limit 5
Explanation: When dst_domain is NULL (as for event_id 105), the "domain" key in the null_handling_example object also holds NULL. The "static_null_value" key consistently holds NULL due to its explicit NULL input. This demonstrates that object_create() will include NULL values for corresponding keys if the input value is NULL.
Output:
| EVENT_ID | DST_DOMAIN | NULL_HANDLING_EXAMPLE |
|---|---|---|
| 101 | "ec2.amazonaws.com" | {"domain": "ec2.amazonaws.com", "static_null_value": NULL, "constant_key": "always_present"} |
| 102 | "sts.amazonaws.com" | {"domain": "sts.amazonaws.com", "static_null_value": NULL, "constant_key": "always_present"} |
| 103 | "www.google.com" | {"domain": "www.google.com", "static_null_value": NULL, "constant_key": "always_present"} |
| 104 | "dropbox.com" | {"domain": "dropbox.com", "static_null_value": NULL, "constant_key": "always_present"} |
| 105 | NULL | {"domain": NULL, "static_null_value": NULL, "constant_key": "always_present"} |
Related articles
- Stages:
alter - Functions:
object_merge - Datasets:
xdr_data
object_merge
Use the object_merge() function to construct a new object by merging the key-value pairs from two or more existing objects.
Syntax
object_merge (<obj1>, <obj2>, <obj3>, ...)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
obj_n |
object | Yes | Two or more object parameters to be merged. |
Returns
The object_merge() function returns a single, new object containing the combined key-value pairs from the input objects.
Usage notes
- When a key name is duplicated across multiple input objects, the value associated with that key in the new, merged object is determined by the value from the latter (rightmost) argument in the function call.
- If an entire object parameter provided to the function is
NULL, the function effectively ignores thatNULLinput object and proceeds to merge the non-NULLobjects. - If a key within an input object has a
NULLvalue, thatNULLvalue is carried over into the merged object unless it is overridden by a subsequent object in the merge sequence that defines the same key.
Examples
Example 1: Merging two simple literal objects
Goal: Combine two objects created directly from literal key-value pairs to demonstrate basic merging and key override behavior.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter obj1 = object_create("name", "jane", "last_name", "doe", "age", 33), obj2 = object_create("name", "jane", "last_name", "simon", "age", 34, "city", "new-york") | alter result = object_merge(obj1, obj2) | fields event_id, result | limit 3
Explanation: The result object contains all unique keys from obj1 and obj2. For last_name and age, the values from obj2 ("simon", 34) overwrite those from obj1 ("doe", 33) because obj2 is the latter argument in the function.
Output:
| EVENT_ID | RESULT |
|---|---|
| 101 | {"name": "jane", "last_name": "simon", "age": 34, "city": "new-york"} |
| 102 | {"name": "jane", "last_name": "simon", "age": 34, "city": "new-york"} |
| 103 | {"name": "jane", "last_name": "simon", "age": 34, "city": "new-york"} |
Example 2: Merging objects with overlapping keys and new keys
Goal: Demonstrate the "latter argument wins" rule for overlapping keys and the addition of new keys when merging three objects.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter initial_security_status = object_create("alert_id", "A123", "status", "new", "severity", "medium"), update_details = object_create("status", "in_progress", "analyst", "JohnDoe"), final_disposition = object_create("status", "closed", "resolution", "false_positive") | alter combined_security_info = object_merge(initial_security_status, update_details, final_disposition) | fields event_id, combined_security_info | limit 3
Explanation: The combined_security_info object incorporates keys from all three input objects. The status key's value is "closed" from final_disposition because it is the latest object in the sequence to define that key. New keys like analyst and resolution are added without conflict.
Output:
| EVENT_ID | COMBINED_SECURITY_INFO |
|---|---|
| 101 | {"alert_id": "A123", "status": "closed", "severity": "medium", "analyst": "JohnDoe", "resolution": "false_positive"} |
| 102 | {"alert_id": "A123", "status": "closed", "severity": "medium", "analyst": "JohnDoe", "resolution": "false_positive"} |
| 103 | {"alert_id": "A123", "status": "closed", "severity": "medium", "analyst": "JohnDoe", "resolution": "false_positive"} |
Example 3: Merging objects with values from existing dataset fields
Goal: Construct and merge objects using values pulled directly from existing fields in the dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_summary_obj = object_create( "description", event_description, "successful", is_successful ) | alter network_details_obj = object_create( "ip_address", ipv4_address, "domain", dst_domain ) | alter full_event_context = object_merge(event_summary_obj, network_details_obj) | fields event_id, full_event_context | limit 3
Explanation: For each record, event_summary_obj captures the event's description and success status, while network_details_obj captures network-related fields. The function then combines these dynamically created objects into full_event_context.
Output:
| EVENT_ID | FULL_EVENT_CONTEXT |
|---|---|
| 101 | {"description": "User login successful", "successful": true, "ip_address": "192.168.1.10", "domain": "ec2.amazonaws.com"} |
| 102 | {"description": "File access attempt", "successful": false, "ip_address": "10.0.0.1", "domain": "sts.amazonaws.com"} |
| 103 | {"description": "Network connection established", "successful": true, "ip_address": "1.1.1.1", "domain": "www.google.com"} |
Example 4: Merging objects with values derived from other functions
Goal: Use object_merge() where some of the object's key-value pairs are results of other XQL functions (for example, to_string(), len()).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_ids_obj = object_create("event_id_str", to_string(event_id), "event_id_len", len(to_string(event_id))), event_desc_obj = object_create("description_len", len(event_description)) | alter derived_and_merged_obj = object_merge(event_ids_obj, event_desc_obj) | fields event_id, derived_and_merged_obj | limit 3
Explanation: The event_ids_obj contains string and length properties derived from event_id. event_desc_obj contains the length of event_description. The function combines these, showcasing the ability to merge objects containing function-derived values.
Output:
| EVENT_ID | DERIVED_AND_MERGED_OBJ |
|---|---|
| 101 | {"event_id_str": "101", "event_id_len": 3, "description_len": 23} |
| 102 | {"event_id_str": "102", "event_id_len": 3, "description_len": 20} |
| 103 | {"event_id_str": "103", "event_id_len": 3, "description_len": 30} |
Example 5: Handling NULL object inputs during merge
Goal: Illustrate behavior when one of the input objects is NULL, demonstrating that NULL input objects are effectively ignored during the merge operation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter base_info = object_create("source_product", "Cortex XDR"), // Conditional creation of 'dynamic_tag': // If event_id / 2 equals its floor (i.e., event_id is even), create the object; otherwise, it is NULL. conditional_info = if(divide(event_id, 2) = floor(divide(event_id, 2)), object_create("dynamic_tag", "processed"), NULL), static_additional_info = object_create("processing_status", "completed") | alter merged_data_with_null = object_merge(base_info, conditional_info, static_additional_info) | fields event_id, merged_data_with_null | limit 5
Explanation: The conditional_info object is created only for records where event_id is even. For odd event_ids, conditional_info is NULL. In these instances, the function merges base_info and static_additional_info, skipping the NULL object. For even IDs, conditional_info is a valid object and its keys are included.
Output:
| EVENT_ID | MERGED_DATA_WITH_NULL |
|---|---|
| 101 | {"source_product": "Cortex XDR", "processing_status": "completed"} |
| 102 | {"source_product": "Cortex XDR", "dynamic_tag": "processed", "processing_status": "completed"} |
| 103 | {"source_product": "Cortex XDR", "processing_status": "completed"} |
| 104 | {"source_product": "Cortex XDR", "dynamic_tag": "processed", "processing_status": "completed"} |
| 105 | {"source_product": "Cortex XDR", "processing_status": "completed"} |
Related articles
- Stages:
alter - Functions:
object_create - Datasets:
xdr_data
parse_epoch
Use the parse_epoch() function to return a Unix epoch integer value by converting a string representation of a timestamp.
Syntax
parse_epoch ("<format_string>", <timestamp field>)
parse_epoch ("<format_string>", <timestamp field>, "<time_zone>")
parse_epoch ("<format_string>", <timestamp field>, "<time_zone>", "<time_unit>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
format_string |
string | Yes | Defines the layout of the input timestamp string (for example, %Y-%m-%d %H:%M:%S). |
timestamp_field |
string | Yes | The string containing the timestamp to be parsed. |
time_zone |
string | No | An optional time zone specified by hours offset (for example, +08:00) or name (for example, America/Chicago). The default is UTC. |
time_unit |
string | No | Specifies the granularity of the returned integer (SECONDS, MILLIS, MICROS). The default is SECONDS. |
Returns
The parse_epoch() function returns a Unix epoch integer value.
Usage notes
- The order of
time_zoneandtime unitis important. - If you're using the
time_zoneargument, you must define it immediately before thetime_unitargument. - If you use
time_zoneaftertime_unit, the default time zone (UTC) is used, and the configured value is ignored. - To display the returned integer as a human-readable timestamp, it is typically passed to the
to_timestamp()function.
Examples
Example 1: Without a time zone or time unit configured (implicit UTC, seconds)
Goal: Convert a timestamp string into an epoch integer using the default UTC time zone and SECONDS unit, then display it as a timestamp.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_time = to_timestamp(parse_epoch("%Y-%m-%d %H:%M:%S", "2023-10-26 10:00:00")) | fields event_id, new_time | limit 3
Explanation: The input string "2023-10-26 10:00:00" is parsed using the format "%Y-%m-%d %H:%M:%S". Because no time zone is specified, parse_epoch() interprets it as a UTC timestamp. to_timestamp() then converts the resulting epoch seconds back to a TIMESTAMP object for display.
Output:
| EVENT_ID | NEW_TIME |
|---|---|
| 101 | Oct 26th 2023 10:00:00 |
| 102 | Oct 26th 2023 10:00:00 |
| 103 | Oct 26th 2023 10:00:00 |
Example 2: With a time zone configured using an hours offset
Goal: Convert a timestamp string interpreting it relative to a +03:00 hours offset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_time = to_timestamp(parse_epoch("%Y-%m-%d %H:%M:%S", "2023-10-26 10:00:00", "+03:00")) | fields event_id, new_time | limit 3
Explanation: The input string 10:00:00 is interpreted as being in a +03:00 time zone. When converted to UTC (which epoch time is based on), it becomes 07:00:00 UTC. This UTC time is then returned as the TIMESTAMP object.
Output:
| EVENT_ID | NEW_TIME |
|---|---|
| 101 | Oct 26th 2023 07:00:00 |
| 102 | Oct 26th 2023 07:00:00 |
| 103 | Oct 26th 2023 07:00:00 |
Example 3: With a time zone name configured
Goal: Convert a timestamp string interpreting it relative to the "America/Chicago" time zone.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_time = to_timestamp(parse_epoch("%Y-%m-%d %H:%M:%S", "2023-10-26 10:00:00", "America/Chicago")) | fields event_id, new_time | limit 3
Explanation: The input string 10:00:00 is interpreted as being in the "America/Chicago" time zone (UTC-5 for this date). To convert to UTC, 5 hours are added, resulting in 15:00:00 UTC.
Output:
| EVENT_ID | NEW_TIME |
|---|---|
| 101 | Oct 26th 2023 15:00:00 |
| 102 | Oct 26th 2023 15:00:00 |
| 103 | Oct 26th 2023 15:00:00 |
Example 4: With both time zone and time unit configured
Goal: Convert a timestamp string using a +03:00 hours offset and explicitly return the epoch in MILLIS (milliseconds).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_time = to_timestamp(parse_epoch("%Y-%m-%d %H:%M:%S", "2023-10-26 10:00:00", "+03:00", "MILLIS"), "MILLIS") | fields event_id, new_time | limit 3
Explanation: The input string is interpreted within the +03:00 time zone (converting 10:00:00 to 07:00:00 UTC). parse_epoch() generates the epoch value in milliseconds. This integer is then converted to a TIMESTAMP object using to_timestamp() with the "MILLIS" unit.
Output:
| EVENT_ID | NEW_TIME |
|---|---|
| 101 | Oct 26th 2023 07:00:00 |
| 102 | Oct 26th 2023 07:00:00 |
| 103 | Oct 26th 2023 07:00:00 |
Related articles
- Stages:
alter - Functions:
to_timestamp - Datasets:
xdr_data
parse_timestamp
Use the parse_timestamp() function to convert a string representation of a timestamp into a TIMESTAMP object.
Syntax
parse_timestamp ("<format_time_string>", "<time_string>" | format_string(<time field>) | <time string field> [, "<time zone>"])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
<format_time_string> |
string | Yes | A format string that defines the layout of the input timestamp string (for example, %Y-%m-%d %H:%M:%S). |
<time_string> |
<time_string_field> |
string | Yes |
<time_zone> |
string | No | An optional time zone specified as an hours offset (for example, +08:00) or a time zone name (for example, America/Chicago). If omitted, the default is UTC. |
Returns
The parse_timestamp() function returns a TIMESTAMP object.
Usage notes
- The
<format_time_string>parameter must define the format elements that match how the input string is formatted. Every element in the input string must have a corresponding element in the format string, and their positions must match. - If no time zone is configured via the optional parameter, the function defaults to using the UTC time zone.
- This function is vital for transforming human-readable date-time strings into a structured timestamp format that can be used for time-based analysis, filtering, or display.
parse_timestamp()can be used within analterstage to create new timestamp fields, or within afilterstage for time-based comparisons.
Examples
Example 1: Without a time zone configured (implicit UTC)
Goal: Convert a timestamp string into a TIMESTAMP object, relying on the default UTC time zone for interpretation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_time_field = parse_timestamp("%Y-%m-%d %H:%M:%S", "2023-10-26 10:00:00") | fields event_id, new_time_field | limit 3
Explanation: The input string "2023-10-26 10:00:00" is parsed using the format "%Y-%m-%d %H:%M:%S". Because no time zone is specified, parse_timestamp() interprets it as a UTC timestamp, which is then displayed in the specified output format.
Output:
| event_id | new_time_field |
|---|---|
| 101 | Oct 26th 2023 10:00:00 |
| 102 | Oct 26th 2023 10:00:00 |
| 103 | Oct 26th 2023 10:00:00 |
Example 2: With a time zone configured using an hours offset
Goal: Convert a timestamp string, interpreting it relative to a +03:00 hours offset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_time_field = parse_timestamp("%Y-%m-%d %H:%M:%S", "2023-10-26 10:00:00", "+03:00") | fields event_id, new_time_field | limit 3
Explanation: The input string 10:00:00 is interpreted as being in a +03:00 time zone. When converted to UTC (which all timestamps are internally based on), it effectively becomes 10:00:00 - 03:00 = 07:00:00 UTC. This UTC time is then returned as the TIMESTAMP object, displayed in the specified format.
Output:
| event_id | new_time_field |
|---|---|
| 101 | Oct 26th 2023 07:00:00 |
| 102 | Oct 26th 2023 07:00:00 |
| 103 | Oct 26th 2023 07:00:00 |
Example 3: With a time zone name configured
Goal: Convert a timestamp string, interpreting it relative to the "America/Chicago" time zone.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter new_time_field = parse_timestamp("%Y-%m-%d %H:%M:%S", "2023-10-26 10:00:00", "America/Chicago") | fields event_id, new_time_field | limit 3
Explanation: The input string 10:00:00 is interpreted as being in the "America/Chicago" time zone. To convert this local time to UTC, you add the offset. If Chicago is UTC-5 (CDT), then 10:00:00 + 05:00 = 15:00:00 UTC. This UTC time is then returned as the TIMESTAMP object, displayed in the specified format.
Output:
| event_id | new_time_field |
|---|---|
| 101 | Oct 26th 2023 15:00:00 |
| 102 | Oct 26th 2023 15:00:00 |
| 103 | Oct 26th 2023 15:00:00 |
Example 4: Converting a time string that contains milliseconds
Goal: Convert a time string that includes fractional seconds (milliseconds) using specific format elements.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw // Use %E3S to capture 3 digits of fractional seconds, commonly used for milliseconds | alter time_string_with_millis = "2023-10-26 10:00:00.723" // Example string with milliseconds | alter new_time_field = parse_timestamp("%Y-%m-%d %H:%M:%E3S", time_string_with_millis) //"%H:%M:%E3S" is also equivalent to "%R:%E3S", both matching "10:00:00.723" | fields event_id, time_string_with_millis, new_time_field | limit 3
Explanation: The parse_timestamp() function successfully processes the input string time_string_with_millis using the format string that includes %E3S to account for seconds and three digits of fractional seconds. Although the internal TIMESTAMP object will store the milliseconds, the final displayed new_time_field conforms to the default format, truncating the fractional part in the output.
Output:
| event_id | time_string_with_millis | new_time_field |
|---|---|---|
| 101 | 2023-10-26 10:00:00.723 | Oct 26th 2023 10:00:00 |
| 102 | 2023-10-26 10:00:00.723 | Oct 26th 2023 10:00:00 |
| 103 | 2023-10-26 10:00:00.723 | Oct 26th 2023 10:00:00 |
Related articles
- Stages:
alter,config,fields,limit - Functions:
to_timestamp,format_string
pow
Use the pow() function to calculate the value of a number raised to the power of another number.
Syntax
pow (<base>, <exponent>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
base |
integer, float, string | Yes | The base number to be raised. |
exponent |
integer, float, string | Yes | The exponent to which the base is raised. |
Returns
The pow() function returns the numerical result of the base raised to the power of the exponent.
Usage notes
- The function accepts numeric literals (for example, 2, 1.5), floating-point numbers, and integers as input.
- Input values can also be provided as strings representing numbers (for example, extracted from a data field), which the function will convert for calculation.
- The function supports negative numbers for both the base and the exponent.
Examples
Example 1: Literal base and literal integer exponent (calculating 1 MB and 1 GB)
Goal: Calculate common byte sizes (Megabytes and Gigabytes) using integer literals, where 1MB is 2^20 bytes and 1GB is 2^30 bytes.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter mega_bytes = pow(2, 20) | alter giga_bytes = pow(2, 30) | fields event_id, mega_bytes, giga_bytes | limit 3
Explanation: This query creates two new fields, mega_bytes and giga_bytes, by raising the literal 2 to the powers of 20 and 30 respectively. The result, 1048576 for 1MB and 1073741824 for 1GB, is a constant numerical value for each record.
Output:
| EVENT_ID | MEGA_BYTES | GIGA_BYTES |
|---|---|---|
| 101 | 1048576 | 1073741824 |
| 102 | 1048576 | 1073741824 |
| 103 | 1048576 | 1073741824 |
Example 2: Field base and literal integer exponent
Goal: Use a floating-point field as the base for a power calculation to square the value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter duration_squared = pow(duration_seconds, 2) | fields event_id, duration_seconds, duration_squared | limit 3
Explanation: The duration_seconds field (for example, 1.5, 0.8, 10.2) is raised to the power of 2 (squared). For instance, 1.5 becomes 2.25, and 0.8 becomes 0.64, demonstrating the function's precision with floating-point numbers.
Output:
| EVENT_ID | DURATION_SECONDS | DURATION_SQUARED |
|---|---|---|
| 101 | 1.5 | 2.25 |
| 102 | 0.8 | 0.64 |
| 103 | 10.2 | 104.04 |
Example 3: Field base from array and literal integer exponent
Goal: Use an element extracted from an array field as the base for a power calculation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_numeric_code = arrayindex(numeric_codes, 0) | alter code_cubed = pow(first_numeric_code, 3) | fields event_id, numeric_codes, first_numeric_code, code_cubed | limit 3
Explanation: This query extracts the first element (index 0) from the numeric_codes array for each record. The query then raises this extracted integer to the power of 3 (cubed), storing the result in code_cubed.
Output:
| EVENT_ID | NUMERIC_CODES | FIRST_NUMERIC_CODE | CODE_CUBED |
|---|---|---|---|
| 101 | [13, -47, 29, 82, -15] | 13 | 2197 |
| 102 | [-21, 56, 13, -88, 42] | -21 | -9261 |
| 103 | [90, -33, 7, 51, -62, 18] | 90 | 729000 |
Example 4: Literal base and negative integer exponent from array
Goal: Raise a literal base to the power of a negative exponent extracted from an array field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter second_numeric_code = arrayindex(numeric_codes, 1) | alter base_powered_by_code = pow(10, second_numeric_code) | fields event_id, numeric_codes, second_numeric_code, base_powered_by_code | limit 3
Explanation: For event_id 101, second_numeric_code is -47. The calculation becomes 10^-47, resulting in a very small floating-point number (scientific notation 1e-47). This illustrates how pow() correctly handles negative exponents, producing decimal results.
Output:
| EVENT_ID | NUMERIC_CODES | SECOND_NUMERIC_CODE | BASE_POWERED_BY_CODE |
|---|---|---|---|
| 101 | [13, -47, 29, 82, -15] | -47 | 1e-47 |
| 102 | [-21, 56, 13, -88, 42] | 56 | 1e+56 |
| 103 | [90, -33, 7, 51, -62, 18] | -33 | 1e-33 |
Example 5: Negative base and literal integer exponent
Goal: Calculate the power of a negative base number.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter pow_negative_base = pow(-5, 3) | fields event_id, pow_negative_base | limit 3
Explanation: This calculates -5 multiplied by itself three times (-5 -5 -5), resulting in -125. The result is consistently -125 across records as the inputs are literals.
Output:
| EVENT_ID | POW_NEGATIVE_BASE |
|---|---|
| 101 | -125 |
| 102 | -125 |
| 103 | -125 |
Example 6: Field base and zero exponent
Goal: Demonstrate the mathematical rule that any non-zero number raised to the power of zero equals one.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter zero_exponent_result = pow(event_id, 0) | fields event_id, zero_exponent_result | limit 3
Explanation: Regardless of the event_id value (as long as it's non-zero), pow(<number>, 0) will always return 1, following standard mathematical rules.
Output:
| EVENT_ID | ZERO_EXPONENT_RESULT |
|---|---|
| 101 | 1 |
| 102 | 1 |
| 103 | 1 |
Example 7: Extracting from JSON and applying pow
Goal: Extract a numeric value from JSON data and use it as the base for a power calculation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter simple_json_data != null | alter json_code_string = simple_json_data -> code | alter json_numeric_value = to_number(json_code_string) | alter code_to_power_of_two = pow(json_numeric_value, 2) | fields event_id, simple_json_data, json_numeric_value, code_to_power_of_two | limit 3
Explanation: This query first extracts the code value (for example, "200") from the simple_json_data field as a string. The query then converts this string to a number using to_number() and applies pow() with a literal exponent, storing the result in code_to_power_of_two.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | JSON_NUMERIC_VALUE | CODE_TO_POWER_OF_TWO |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | 200 | 40000 |
Related articles
power
Use the power() function to calculate the value of a number raised to the power of another number. This function is an alias for pow().
Syntax
power(<base>, <exponent>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
base |
integer, float | Yes | The base number to be raised. |
exponent |
integer, float | Yes | The exponent to which the base is raised. |
Returns
Type: float
Description: The power() function returns the numerical result of the base raised to the power of the exponent. If either input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Alias:
power()is functionally identical topow(). Both functions can be used interchangeably. - Valid Input Range: The function accepts any numeric values for both base and exponent, including negative numbers and zero.
- Null Handling: If either input expression is
null, the function returnsnull. - Special Cases:
power(x, 0)returns1.0for any non-zerox.power(0, 0)returns1.0.power(0, n)returns0.0forn > 0. - Negative Base: When the base is negative and the exponent is not an integer, the result may be
NaN. - Common Use Cases: This function is typically used within the
alterstage for exponential calculations, area/volume computations, and scientific formulas.
Examples
Example 1: Calculate power of literal values
Goal: Calculate specific power operations to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = power(2, 10), result2 = power(3, 3), result3 = power(10, -2) | fields result1, result2, result3
Explanation: power(2, 10) returns 1024 (2^10), power(3, 3) returns 27 (3^3), and power(10, -2) returns 0.01 (10^-2 = 1/100).
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 1024 | 27 | 0.01 |
Example 2: Square field values using power
Goal: Calculate the square of values stored in a dataset field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter squared_value = power(duration_seconds, 2) | fields event_id, duration_seconds, squared_value | limit 3
Explanation: This query squares each value in the duration_seconds field using power() with an exponent of 2. For example, 1.5 squared is 2.25.
Output:
| EVENT_ID | DURATION_SECONDS | SQUARED_VALUE |
|---|---|---|
| 101 | 1.5 | 2.25 |
| 102 | 0.8 | 0.64 |
| 103 | 10.2 | 104.04 |
Example 3: Calculate square root using power with fractional exponent
Goal: Demonstrate that power(x, 0.5) is equivalent to the square root.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value > 0 | alter sqrt_via_power = power(numeric_value, 0.5) | alter sqrt_direct = sqrt(numeric_value) | fields event_id, numeric_value, sqrt_via_power, sqrt_direct | limit 3
Explanation: This query demonstrates that raising a number to the power of 0.5 is equivalent to taking its square root. Both power(x, 0.5) and sqrt(x) produce the same result.
Output:
| EVENT_ID | NUMERIC_VALUE | SQRT_VIA_POWER | SQRT_DIRECT |
|---|---|---|---|
| 101 | 4.0 | 2.0 | 2.0 |
| 102 | 9.0 | 3.0 | 3.0 |
| 103 | 16.0 | 4.0 | 4.0 |
Related articles
rand
Use the rand() function to generate a pseudo-random floating-point number between 0 (inclusive) and 1 (exclusive).
Syntax
rand()
Parameters
This function takes no parameters.
Returns
Type: float
Description: The rand() function returns a pseudo-random floating-point number in the range 0, 1). Each invocation produces a different random value.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- No Arguments: The
rand()function takes no parameters and generates a new random value each time it is called. - Range: The returned value is always ≥ 0.0 and < 1.0.
- Non-Deterministic: Each call to
rand()produces a different value. Results are not reproducible across query executions. - Scaling: To generate random numbers in a different range, multiply the result by the desired range and add an offset. For example,
add(multiply(rand(), 100), 1)generates a random number between 1 and 101. - Common Use Cases: This function is typically used within the
alterstage for random sampling, generating test data, randomized ordering, and probabilistic analysis.
Examples
Example 1: Generate random values for each record
Goal: Add a random value to each record in the dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter random_val = rand() | fields event_id, random_val | limit 3
Explanation: This query generates a random floating-point number between 0 and 1 for each record and stores it in random_val. Each record receives a different random value.
Output:
| EVENT_ID | RANDOM_VAL |
|---|---|
| 101 | 0.73214 |
| 102 | 0.15892 |
| 103 | 0.94501 |
Example 2: Random sampling of records
Goal: Randomly sample approximately 50% of records from the dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter sample_flag = rand() | filter sample_flag < 0.5 | fields event_id, source_name | limit 5
Explanation: This query assigns a random value to each record, then filters to keep only records where the random value is less than 0.5, effectively sampling approximately 50% of the data.
Output:
| EVENT_ID | SOURCE_NAME |
|---|---|
| 102 | server-01 |
| 104 | server-03 |
| 107 | server-02 |
| 109 | server-01 |
| 111 | server-03 |
Example 3: Generate random integers in a specific range
Goal: Generate random integers between 1 and 100 for each record.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter random_int = to_integer(add(multiply(rand(), 100), 1)) | fields event_id, random_int | limit 3
Explanation: This query scales the random value from [0, 1) to [1, 101) by multiplying by 100 and adding 1, then converts to an integer using to_integer() to produce whole numbers between 1 and 100.
Output:
| EVENT_ID | RANDOM_INT |
|---|---|
| 101 | 47 |
| 102 | 83 |
| 103 | 12 |
Related articles
- Stages: [
alter,filter,fields,limit - Functions:
multiply(),add(),to_integer(),floor()
range_bucket
Use the range_bucket() function to determine which bucket a numeric value falls into, given an array of bucket boundaries. The function returns the index of the bucket (0-based) that contains the value.
Syntax
range_bucket(<value>, <boundaries>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
value |
integer, float | Yes | The numeric value to classify into a bucket. |
boundaries |
array of integers or floats | Yes | A sorted array of boundary values that define the bucket edges. Must be in ascending order. |
Returns
Type: integer
Description: The range_bucket() function returns a 0-based integer index indicating which bucket the value falls into. If the value is less than the first boundary, it returns 0. If the value is greater than or equal to the last boundary, it returns the number of boundaries. If the input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Sorted Boundaries: The
boundariesarray must be sorted in ascending order. Unsorted boundaries produce undefined results. - Bucket Ranges: For boundaries
[b1, b2, b3], the buckets are: bucket 0 =(-∞, b1), bucket 1 =[b1, b2), bucket 2 =[b2, b3), bucket 3 =[b3, +∞). - Null Handling: If the
valueisnull, the function returnsnull. - Common Use Cases: This function is typically used within the
alterstage for data binning, histogram creation, severity classification, and score grading.
Examples
Example 1: Classify values into predefined buckets
Goal: Classify numeric values into severity levels using predefined boundaries.
XQL code:
dataset = xdr_data | limit 1 | alter bucket1 = range_bucket(5, arraycreate(0, 10, 50, 100)) | alter bucket2 = range_bucket(25, arraycreate(0, 10, 50, 100)) | alter bucket3 = range_bucket(75, arraycreate(0, 10, 50, 100)) | fields bucket1, bucket2, bucket3
Explanation: With boundaries [0, 10, 50, 100], the value 5 falls in bucket 1 (between 0 and 10), 25 falls in bucket 2 (between 10 and 50), and 75 falls in bucket 3 (between 50 and 100).
Output:
| BUCKET1 | BUCKET2 | BUCKET3 |
|---|---|---|
| 1 | 2 | 3 |
Example 2: Classify field values into risk levels
Goal: Assign risk levels to events based on their numeric value using bucket boundaries.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter risk_bucket = range_bucket(numeric_value, arraycreate(0, 25, 50, 75, 100)) | alter risk_level = if(risk_bucket = 0, "none", risk_bucket = 1, "low", risk_bucket = 2, "medium", risk_bucket = 3, "high", "critical") | fields event_id, numeric_value, risk_bucket, risk_level | limit 3
Explanation: This query classifies each numeric_value into a risk bucket using boundaries [0, 25, 50, 75, 100], then maps each bucket to a human-readable risk level label.
Output:
| EVENT_ID | NUMERIC_VALUE | RISK_BUCKET | RISK_LEVEL |
|---|---|---|---|
| 101 | 5.0 | 1 | low |
| 102 | 60.0 | 3 | high |
| 103 | 30.0 | 2 | medium |
Example 3: Create histogram buckets for duration values
Goal: Distribute duration values into histogram buckets for analysis.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter duration_bucket = range_bucket(duration_seconds, arraycreate(1, 5, 10, 30, 60)) | comp count(event_id) as event_count by duration_bucket | fields duration_bucket, event_count | sort asc duration_bucket
Explanation: This query assigns each event to a duration bucket based on duration_seconds, then counts the number of events in each bucket. This creates a histogram-like distribution of event durations.
Output:
| DURATION_BUCKET | EVENT_COUNT |
|---|---|
| 0 | 3 |
| 1 | 5 |
| 2 | 4 |
| 3 | 2 |
| 4 | 1 |
Related articles
rank (windowcomp)
Use the rank() function within the windowcomp stage to assign a rank to each row within a partition based on the specified sort order. Rows with equal values in the sort field receive the same rank, and the next rank is incremented by the number of tied rows (i.e., ranks may have gaps). This is equivalent to RANK() OVER(...) in SQL.
Syntax
| windowcomp rank() [by <partition_field1>, <partition_field2>, ...] sort [asc|desc] <sort_field1> [, [asc|desc] <sort_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
partition_field |
any | No | One or more fields to partition the data by (equivalent to SQL PARTITION BY). |
sort_field |
any | Yes | One or more fields to define the order within each partition (equivalent to SQL ORDER BY). Required for numbering functions. Defaults to ascending. |
alias |
string | No | An alias for the output field. |
Returns
Type: integer
Description: The rank() function returns an integer rank for each row within its partition. Rows with identical sort values receive the same rank, and subsequent ranks skip accordingly (for example, 1, 2, 2, 4).
Usage notes
- Sort required: The
sortclause is mandatory for therank()function. - Numbering function:
rank()is a numbering function and cannot be used with window frames (betweenclause). - Tied values: When multiple rows have the same value in the sort field, they receive the same rank. The next rank after a tie skips the number of tied rows.
- Difference from row_number: Unlike
row_number(), which always assigns unique sequential numbers,rank()assigns the same number to tied rows and leaves gaps. - Difference from dense_rank: Unlike
dense_rank(), which does not leave gaps after ties,rank()leaves gaps (for example, 1, 2, 2, 4 instead of 1, 2, 2, 3).
Examples
Example 1: Rank alerts by severity within each host
Goal: Rank alerts by severity (highest first) for each host.
XQL code:
dataset = xdr_data | windowcomp rank() by agent_hostname sort desc alert_severity as severity_rank
Explanation: The rank() function assigns a rank to each row within each agent_hostname partition, ordered by alert_severity in descending order. Alerts with the same severity receive the same rank.
Output:
| _TIME | AGENT_HOSTNAME | ALERT_SEVERITY | SEVERITY_RANK |
|---|---|---|---|
| 2024-01-15 09:00:00 | workstation-1 | 7 | 1 |
| 2024-01-15 10:00:00 | workstation-1 | 5 | 2 |
| 2024-01-15 11:00:00 | workstation-1 | 5 | 2 |
| 2024-01-15 08:00:00 | workstation-1 | 3 | 4 |
Example 2: Rank events by time globally
Goal: Rank all events by time in ascending order without partitioning.
XQL code:
dataset = xdr_data | windowcomp rank() sort asc _time as time_rank
Explanation: Without a by clause, the rank() function ranks all rows across the entire result set by _time in ascending order.
Output:
| _TIME | AGENT_HOSTNAME | TIME_RANK |
|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | 1 |
| 2024-01-15 08:00:00 | workstation-2 | 1 |
| 2024-01-15 09:00:00 | workstation-1 | 3 |
| 2024-01-15 10:00:00 | workstation-2 | 4 |
Example 3: Find top-ranked events per category
Goal: Rank events by bytes sent within each event category and filter for the top 3.
XQL code:
dataset = xdr_data | windowcomp rank() by event_type sort desc bytes_sent as bytes_rank | filter bytes_rank <= 3
Explanation: The rank() function assigns ranks within each event_type partition based on bytes_sent in descending order. The subsequent filter stage keeps only the top 3 ranked rows per category.
Output:
| _TIME | EVENT_TYPE | BYTES_SENT | BYTES_RANK |
|---|---|---|---|
| 2024-01-15 09:00:00 | NETWORK | 5000 | 1 |
| 2024-01-15 10:00:00 | NETWORK | 4500 | 2 |
| 2024-01-15 11:00:00 | NETWORK | 3000 | 3 |
| 2024-01-15 08:00:00 | PROCESS | 2000 | 1 |
| 2024-01-15 12:00:00 | PROCESS | 1500 | 2 |
| 2024-01-15 13:00:00 | PROCESS | 1000 | 3 |
Related articles
- Stages:
windowcomp,comp,sort - Functions:
row_number(),dense_rank() - Datasets:
xdr_data
regexcapture
Use the regexcapture() function to extract from a string substrings that match specified named regular expression groups and return them as a JSON object.
Syntax
regexcapture (<field>, "<pattern>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
string | Yes | The string field (typically _raw_log) or literal to apply the regex to. |
pattern |
string | Yes | The regular expression string, enclosed in double quotes, containing named capture groups ((?P<name>...)). |
Returns
The regexcapture() function returns a JSON object where the keys correspond to the named capture groups defined in the regex pattern, and the values are the extracted substrings.
Usage notes
- The
regexcapture()function is only supported in the XQL syntax for parsing rules. The function cannot be used directly in analterorfilterstage within an interactive XQL query submitted via the Query Builder. - XQL utilizes the RE2 regular expression implementation.
- For case-insensitive matching, you can include
(?i)at the beginning of your regular expression pattern. This syntax must be added only once at the beginning of the inline regular expression. - Unlike the
regextract()function, which typically supports only one capturing group in queries,regexcapture()is designed for capturing multiple named groups within a single pattern. - The function is ideal for scenarios where the exact regex pattern might vary across logs, offering flexible extraction into structured JSON.
Examples
Example 1: Extracting user and IP address from a login log
Goal: Extract the username and source IP address from a raw log using named capture groups.
XQL code:
// This example demonstrates how regexcapture() is defined in a Parsing Rule // and simulates the output using standard XQL functions for display purposes. // Parsing Rule Syntax: // alter captured_details = regexcapture(_raw_log, "User (?P<username>\w+) logged in from (?P<source_ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"); // Simulated Query to visualize the result: config timeframe = 1d | dataset = sample_xql_raw | alter log_entry = raw_log_data | alter extracted_info = if(event_id = 101, object_create( "username", "Alice", "source_ip", "192.168.1.10" ), NULL ) | fields event_id, log_entry, extracted_info | limit 1
Explanation: A conceptual Parsing Rule would apply the regex pattern to the raw log. The named groups username and source_ip would capture "Alice" and "192.168.1.10" respectively, forming the JSON object {"username": "Alice", "source_ip": "192.168.1.10"} in the extracted_info field.
Output:
| EVENT_ID | LOG_ENTRY | EXTRACTED_INFO |
|---|---|---|
| 101 | "User Alice logged in from 192.168.1.10" | {"username": "Alice", "source_ip": "192.168.1.10"} |
Example 2: Extracting process name and file path from an access log
Goal: Extract a process name and a file path from a system log entry.
XQL code:
// This example demonstrates how regexcapture() is defined in a Parsing Rule // and simulates the output using standard XQL functions for display purposes. // Parsing Rule Syntax: // alter captured_process_data = regexcapture(_raw_log, "Process (?P<process_name>[a-zA-Z0-9.]+?) attempted to access (?P<file_path>.*)"); // Simulated Query to visualize the result: config timeframe = 1d | dataset = sample_xql_raw | alter log_entry = raw_log_data | alter extracted_info = if(event_id = 102, object_create( "process_name", "cmd.exe", "file_path", "/etc/passwd" ), NULL ) | fields event_id, log_entry, extracted_info | limit 1
Explanation: The conceptual Parsing Rule extracts "cmd.exe" into process_name and "/etc/passwd" into file_path, creating the corresponding JSON object.
Output:
| EVENT_ID | LOG_ENTRY | EXTRACTED_INFO |
|---|---|---|
| 102 | "Process cmd.exe attempted to access /etc/passwd" | {"process_name": "cmd.exe", "file_path": "/etc/passwd"} |
Example 3: Extracting destination IP address, port, and application ID (with case-insensitive matching)
Goal: Extract network details and an application ID from a network connection log using case-insensitive matching.
XQL code:
// This example demonstrates how regexcapture() is defined in a Parsing Rule // and simulates the output using standard XQL functions for display purposes. // Parsing Rule Syntax: // alter captured_network_details = regexcapture(_raw_log, "(?i)connection to (?P<dest_ip>\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}):(?P<port>\d+) initiated by (?P<app_id>[^ ]+)"); // Simulated Query to visualize the result: config timeframe = 1d | dataset = sample_xql_raw | alter log_entry = raw_log_data | alter extracted_info = if(event_id = 103, object_create( "dest_ip", "1.1.1.1", "port", "443", "app_id", "AppX" ), NULL ) | fields event_id, log_entry, extracted_info | limit 1
Explanation: The conceptual Parsing Rule uses (?i) for case-insensitivity and extracts the destination IP, port, and application ID, demonstrating the capability to parse varied log structures into structured JSON objects.
Output:
| EVENT_ID | LOG_ENTRY | EXTRACTED_INFO |
|---|---|---|
| 103 | "Outbound connection to 1.1.1.1:443 initiated by AppX" | {"dest_ip": "1.1.1.1", "port": "443", "app_id": "AppX"} |
Related articles
- Stages:
alter - Functions:
regextract,json_extract,object_create - Datasets:
xdr_data
regextract
Use the regextract() function to extract a substring from a field value using a regular expression pattern. The function returns the first captured group from the regex match. This is a scalar function used within the alter stage.
Syntax
| alter <output_field> = regextract(<field>, "<regex_pattern>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
string | Yes | The string field from which to extract a substring. |
regex_pattern |
string (regex) | Yes | A regular expression pattern with at least one capture group (). The function returns the content matched by the first capture group. |
Returns
Type: string
Description: The regextract() function returns the substring matched by the first capture group in the regular expression. Returns NULL if the pattern does not match the input string or if the input field is NULL.
Usage notes
- Capture groups: The regex pattern must contain at least one capture group defined by parentheses
(). Only the first capture group is returned. - No match: If the regex does not match the input string, the function returns NULL.
- Case sensitivity: Regular expression matching is case-sensitive by default.
- Escape characters: Special regex characters must be escaped with a backslash
\(for example,\.to match a literal dot). - Scalar function:
regextract()is a scalar function used in thealterstage, not an aggregation function. The function operates on each row individually. - Multiple extractions: To extract multiple parts from a string, use multiple
alterstatements with different capture groups.
Examples
Example 1: Extract domain from email address
Goal: Extract the domain portion from an email address field.
XQL code:
dataset = xdr_data | alter domain = regextract(actor_effective_username, "@(.+)$")
Explanation: The regex @(.+)$ matches the @ symbol followed by one or more characters until the end of the string. The capture group (.+) captures the domain portion.
Output:
| ACTOR_EFFECTIVE_USERNAME | DOMAIN |
|---|---|
| admin@example.com | example.com |
| user1@corp.local | corp.local |
| svc_account@internal.net | internal.net |
Example 2: Extract IP address from a log message
Goal: Extract an IPv4 address from a free-text log message.
XQL code:
dataset = xdr_data | alter extracted_ip = regextract(action_file_path, "(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})")
Explanation: The regex pattern (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) matches an IPv4 address pattern. The entire match is captured by the outer parentheses.
Output:
| ACTION_FILE_PATH | EXTRACTED_IP |
|---|---|
| Connection from 192.168.1.100 on port 443 | 192.168.1.100 |
| Failed login attempt from 10.0.0.5 | 10.0.0.5 |
| No IP in this entry | null |
Example 3: Extract file extension from file path
Goal: Extract the file extension from a file path.
XQL code:
dataset = xdr_data | alter file_ext = regextract(action_file_path, "\.([^.]+)$")
Explanation: The regex \.([^.]+)$ matches a literal dot followed by one or more non-dot characters at the end of the string. The capture group ([^.]+) captures the file extension without the dot.
Output:
| ACTION_FILE_PATH | FILE_EXT |
|---|---|
| C:\Windows\System32\cmd.exe | exe |
| /var/log/syslog.log | log |
| /tmp/archive.tar.gz | gz |
Related articles
replace
Use the replace() function to substitute all occurrences of a specified substring within a string field with a new replacement string.
Syntax
replace (<field>, "<old_substring>", "<new_string>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
string | Yes | The string field or literal value you wish to modify. |
old_substring |
string | Yes | The specific substring to be found and replaced. This must be enclosed in double quotes. |
new_string |
string | Yes | The string that will replace all occurrences of the old_substring. This must also be enclosed in double quotes. |
Returns
The replace() function returns a new string with the replacements made. If the old_substring is not found, the original string is returned unchanged.
Usage notes
- The
replace()function operates exclusively on string inputs. - The function replaces all occurrences of the specified
old_substringwithin the input field. - By default,
replace()is case-sensitive. "user" will not replace "User" unless explicitly handled (for example, by combining withlowercase()). replace()is typically used within thealterstage to create new fields or modify existing ones.
Examples
Example 1: Simple replacement of a literal substring
Goal: Replace a specific word ("User") in raw_log_data with a new word ("Client").
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter raw_log_data contains "User" | alter modified_log = replace(raw_log_data, "User", "Client") | fields event_id, raw_log_data, modified_log
Explanation: The query finds the literal string "User" in the raw_log_data for event_id 101 and replaces it with "Client", creating the modified_log field.
Output:
| EVENT_ID | RAW_LOG_DATA | MODIFIED_LOG |
|---|---|---|
| 101 | "User Alice logged in from 192.168.1.10" | "Client Alice logged in from 192.168.1.10" |
Example 2: Replacing with an empty string (removal)
Goal: Remove a specific phrase (" attempted to access") from raw_log_data by replacing it with an empty string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter raw_log_data contains "attempted to access" | alter cleaned_log = replace(raw_log_data, " attempted to access", "") | fields event_id, raw_log_data, cleaned_log
Explanation: The specified phrase is entirely removed from the raw_log_data, resulting in a more concise cleaned_log.
Output:
| EVENT_ID | RAW_LOG_DATA | CLEANED_LOG |
|---|---|---|
| 102 | "Process cmd.exe attempted to access /etc/passwd" | "Process cmd.exe /etc/passwd" |
Example 3: Case-sensitive replacement
Goal: Demonstrate that replace() is case-sensitive by attempting to replace "user login" with "user logon" in event_description where "User login" is present.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_description contains "login" | alter case_sensitive_change = replace(event_description, "user login", "user logon") | fields event_id, event_description, case_sensitive_change
Explanation: Since replace() is case-sensitive, and "user login" (lowercase) does not exactly match "User login" (as it appears in "User login successful" which has an uppercase 'U'), no replacement occurs.
Output:
| EVENT_ID | EVENT_DESCRIPTION | CASE_SENSITIVE_CHANGE |
|---|---|---|
| 101 | "User login successful" | "User login successful" |
Example 4: Combining with lowercase() for case-insensitive replacement logic
Goal: Use lowercase() to standardize the input string before applying replace(), achieving a conceptual case-insensitive replacement.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_description contains "connection" | alter lower_event_desc = lowercase(event_description) | alter case_insensitive_replace = replace(lower_event_desc, "network", "link") | fields event_id, event_description, lower_event_desc, case_insensitive_replace
Explanation: By first converting event_description to lowercase, replace() successfully finds and replaces "network" with "link", demonstrating how to implement case-insensitive logic.
Output:
| EVENT_ID | EVENT_DESCRIPTION | LOWER_EVENT_DESC | CASE_INSENSITIVE_REPLACE |
|---|---|---|---|
| 103 | "Network connection established" | "network connection established" | "link connection established" |
Example 5: Replacing a character with another character
Goal: Replace all spaces in event_description with underscores for a specific event.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 104 | alter underscored_description = replace(event_description, " ", "_") | fields event_id, event_description, underscored_description
Explanation: All spaces within the event_description are replaced by underscores.
Output:
| EVENT_ID | EVENT_DESCRIPTION | UNDERSCORED_DESCRIPTION |
|---|---|---|
| 104 | "System heartbeat" | "System_heartbeat" |
Example 6: Handling non-existent substrings
Goal: Demonstrate that if the old_substring is not found, the original string is returned unmodified.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter no_change_log = replace(raw_log_data, "NonExistentPhrase", "NewPhrase") | fields event_id, raw_log_data, no_change_log
Explanation: Since "NonExistentPhrase" is not present in raw_log_data, the no_change_log field retains the original value of raw_log_data.
Output:
| EVENT_ID | RAW_LOG_DATA | NO_CHANGE_LOG |
|---|---|---|
| 101 | "User Alice logged in from 192.168.1.10" | "User Alice logged in from 192.168.1.10" |
Related articles
replex
Use the replex() function to identify a substring (pattern) and replace it with a new string.
Syntax
replex (<string>, <pattern>, <new_string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The string field or literal value you want to modify. |
pattern |
string | Yes | The regular expression pattern to find and replace. The pattern must be enclosed in double quotes. |
new_string |
string | Yes | The string that will replace all occurrences of the matched pattern. This string must also be enclosed in double quotes. |
Returns
The replex() function returns a new string with the replacements made. If the pattern is not found, the original string is returned unchanged.
Usage notes
- The
replex()function operates exclusively on string inputs. - The function replaces all occurrences of the specified regular expression pattern within the input field.
- XQL uses the RE2 regular expression implementation.
- By default, regex patterns are case-sensitive. To achieve case-insensitive matching, the
(?i)syntax should be added once at the beginning of the inline regular expression within the pattern string. - The
replex()function is typically used within thealterstage to create new fields or modify existing ones.
Examples
Example 1: Simple pattern replacement (masking a specific IP address)
Goal: Replace a specific IP address (192.168.1.10) in the raw_log_data field with a placeholder INTERNAL_IP.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter masked_log = replex(raw_log_data, "192\.168\.1\.10", "INTERNAL_IP") | fields event_id, raw_log_data, masked_log
Explanation: The query finds the literal IP "192.168.1.10" (escaped dots for regex literal match) in raw_log_data for event_id 101 and replaces it with "INTERNAL_IP", creating the masked_log field.
Output:
| EVENT_ID | RAW_LOG_DATA | MASKED_LOG |
|---|---|---|
| 101 | "User Alice logged in from 192.168.1.10" | "User Alice logged in from INTERNAL_IP" |
Example 2: Using regex character classes for general IP address masking
Goal: Use a regular expression to find and mask any standard IPv4 address pattern in the raw_log_data or ipv4_address fields.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 103) | alter masked_ipv4 = replex(ipv4_address, "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", "MASKED_ADDR") | alter masked_raw_log = replex(raw_log_data, "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", "MASKED_IP") | fields event_id, ipv4_address, masked_ipv4, raw_log_data, masked_raw_log
Explanation: The query uses the regex \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} to identify and replace dotted-decimal IPv4 addresses. For event 101, ipv4_address is masked. For event 103, the IP in raw_log_data is masked.
Output:
| EVENT_ID | IPV4_ADDRESS | MASKED_IPV4 | RAW_LOG_DATA | MASKED_RAW_LOG |
|---|---|---|---|---|
| 101 | "192.168.1.10" | "MASKED_ADDR" | "User Alice logged in from 192.168.1.10" | "User Alice logged in from MASKED_IP" |
| 103 | NULL | NULL | "Outbound connection to 1.1.1.1:443 initiated by AppX" | "Outbound connection to MASKED_IP:443 initiated by AppX" |
Example 3: Replacing multiple occurrences of a word
Goal: Target raw_log_data and replace multiple instances of whitespace characters with "_".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 103 | alter updated_log = replex(raw_log_data, "\s", "_") | fields event_id, raw_log_data, updated_log
Explanation: The replex() function finds all instances of the whitespace character " " and replaces them with "_".
Output:
| EVENT_ID | RAW_LOG_DATA | UPDATED_LOG |
|---|---|---|
| 103 | "Outbound connection to 1.1.1.1:443 initiated by AppX" | "Outbound_connection_to_1.1.1.1:443_initiated_by_AppX" |
Example 4: Case-insensitive replacement using (?i)
Goal: Perform a case-insensitive replacement by using the (?i) flag to match "User" or "user" regardless of capitalization, replacing it with "ACCOUNT_HOLDER" in event_description.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter anonymized_desc = replex(event_description, "(?i)user", "ACCOUNT_HOLDER") | fields event_id, event_description, anonymized_desc
Explanation: By prefixing the regex with (?i), replex() ignores case, successfully replacing "User" (with a capital 'U') in event_description with "ACCOUNT_HOLDER".
Output:
| EVENT_ID | EVENT_DESCRIPTION | ANONYMIZED_DESC |
|---|---|---|
| 101 | "User login successful" | "ACCOUNT_HOLDER login successful" |
Example 5: Removing a pattern (replacing with an empty string)
Goal: Remove the " from " followed by an IP address from raw_log_data by replacing the pattern with an empty string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter cleaned_log = replex(raw_log_data, " from \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", "") | fields event_id, raw_log_data, cleaned_log | filter event_id = 101
Explanation: The regex matches " from " followed by any IPv4 pattern. replex() then replaces this entire matched substring with an empty string, effectively removing it and cleaning the raw_log_data entry.
Output:
| EVENT_ID | RAW_LOG_DATA | CLEANED_LOG |
|---|---|---|
| 101 | "User Alice logged in from 192.168.1.10" | "User Alice logged in" |
Related articles
- Stages:
alter - Functions:
replace,regextract,regexcapture - Datasets:
xdr_data
round
Use the round() function to take a numeric input (either a float or an integer) and return the value rounded to the nearest whole integer.
Syntax
round (<float> | <integer>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
value |
float, integer | Yes | The numeric value to be rounded. |
Returns
The round() function returns an integer representing the input value rounded to the nearest whole number. Standard mathematical rounding rules apply, where values exactly at .5 typically round up.
Usage notes
- The function accepts either a floating-point number or an integer as its input.
- If the input is already an integer, the value remains unchanged.
- For positive numbers, a fractional part of .5 or greater rounds up to the next higher integer.
- For negative numbers, the function rounds to the nearest integer, adhering to standard mathematical rounding for negative values.
Examples
Example 1: Round on a positive floating-point field
Goal: Round a positive floating-point field to the nearest integer, demonstrating rounding up and rounding down.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter rounded_duration_up = round(duration_seconds) | alter example_duration = 1.4 | alter rounded_duration_down = round(example_duration) | fields event_id, duration_seconds, rounded_duration_up, example_duration, rounded_duration_down | limit 3
Explanation: This query calculates rounded_duration_up by rounding duration_seconds. For event_id 101 (duration_seconds of 1.5), it rounds to 2. For event_id 102 (duration_seconds of 0.8), it rounds to 1. A literal 1.4 is introduced to show it rounds down to 1.
Output:
| EVENT_ID | DURATION_SECONDS | ROUNDED_DURATION_UP | EXAMPLE_DURATION | ROUNDED_DURATION_DOWN |
|---|---|---|---|---|
| 101 | 1.5 | 2 | 1.4 | 1 |
| 102 | 0.8 | 1 | 1.4 | 1 |
| 103 | 10.2 | 10 | 1.4 | 1 |
Example 2: Round on a calculated floating-point value (from an integer field)
Goal: Round a calculated floating-point number derived from an integer field after a division operation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter divided_event_id = divide(event_id, 3) | alter rounded_divided_id = round(divided_event_id) | fields event_id, divided_event_id, rounded_divided_id | limit 3
Explanation: Here, event_id (for example, 101) is divided by 3, resulting in approximately 33.666. The round() function then rounds this to 34. For event_id 102, 102/3 = 34, so round() returns 34.
Output:
| EVENT_ID | DIVIDED_EVENT_ID | ROUNDED_DIVIDED_ID |
|---|---|---|
| 101 | 33.666666666666664 | 34 |
| 102 | 34 | 34 |
| 103 | 34 | 34 |
Example 3: Round on a negative floating-point value (from an array field)
Goal: Round a negative floating-point number derived from an array element.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter second_numeric_code = arrayindex(numeric_codes, 1) | alter negative_float_example = divide(second_numeric_code, 10.0) | alter rounded_negative_float = round(negative_float_example) | fields event_id, numeric_codes, negative_float_example, rounded_negative_float | limit 3
Explanation: For event_id 101, second_numeric_code is -47. Dividing by 10.0 results in -4.7. round() then converts -4.7 to -5. For event_id 102, the code is 56, resulting in 5.6, which round() converts to 6.
Output:
| EVENT_ID | NUMERIC_CODES | NEGATIVE_FLOAT_EXAMPLE | ROUNDED_NEGATIVE_FLOAT |
|---|---|---|---|
| 101 | [13, -47, 29,...] | -4.7 | -5 |
| 102 | [-21, 56, 13,...] | 5.6 | 6 |
| 103 | [90, -33, 7,...] | -3.3 | -3 |
Example 4: Round on an integer field (no change)
Goal: Apply the function to an integer field to confirm that whole numbers remain unchanged.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter rounded_event_id = round(event_id) | fields event_id, rounded_event_id | limit 3
Explanation: The event_id field contains integers (for example, 101, 102). When round() is applied, these values remain 101, 102, etc., demonstrating no change for whole numbers.
Output:
| EVENT_ID | ROUNDED_EVENT_ID |
|---|---|
| 101 | 101 |
| 102 | 102 |
| 103 | 103 |
Example 5: Round on a numeric value extracted from JSON data
Goal: Round a number extracted from a JSON field after converting it and performing a calculation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter simple_json_data != null | alter json_code_string = simple_json_data -> code | alter json_numeric_value = to_number(json_code_string) | alter calc_json_value = divide(json_numeric_value, 1.5) | alter rounded_json_value = round(calc_json_value) | fields event_id, simple_json_data, json_numeric_value, calc_json_value, rounded_json_value | limit 1
Explanation: This query extracts the code value (for example, "200") from the simple_json_data field as a string, converts it to a number using to_number(), divides it by 1.5 to introduce a decimal, and then applies round() to get the nearest whole integer. Note that only event_id 101 has a "code" field in simple_json_data in the sample_xql_raw dataset, hence only one result is displayed.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | JSON_NUMERIC_VALUE | CALC_JSON_VALUE | ROUNDED_JSON_VALUE |
|---|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | 200 | 133.33333333333334 | 133 |
Related articles
row_number (windowcomp)
Use the row_number() function within the windowcomp stage to assign a unique sequential integer to each row within a partition, based on the specified sort order. The numbering starts at 1 for the first row in each partition. This is equivalent to ROW_NUMBER() OVER(...) in SQL.
Syntax
| windowcomp row_number() [by <partition_field1>, <partition_field2>, ...] sort [asc|desc] <sort_field1> [, [asc|desc] <sort_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
partition_field |
any | No | One or more fields to partition the data by (equivalent to SQL PARTITION BY). |
sort_field |
any | Yes | One or more fields to define the order within each partition (equivalent to SQL ORDER BY). Required for numbering functions. Defaults to ascending. |
alias |
string | No | An alias for the output field. |
Returns
Type: integer
Description: The row_number() function returns a unique sequential integer (starting at 1) for each row within its partition, based on the sort order. Unlike rank(), every row receives a distinct number even when sort values are tied.
Usage notes
- Sort required: The
sortclause is mandatory for therow_number()function. - Numbering function:
row_number()is a numbering function and cannot be used with window frames (betweenclause). - Unique values: Unlike
rank(),row_number()always assigns unique sequential numbers. When rows have identical sort values, the assignment among tied rows is non-deterministic. - Deduplication:
row_number()is commonly used for deduplication by assigning row numbers within groups and then filtering forrow_number = 1. - 1-based indexing: Row numbering starts at 1, not 0.
Examples
Example 1: Number events chronologically per host
Goal: Assign a sequential number to each event per host, ordered by time.
XQL code:
dataset = xdr_data | windowcomp row_number() by agent_hostname sort asc _time as event_seq
Explanation: The row_number() function assigns a sequential number to each row within each agent_hostname partition, ordered by _time in ascending order.
Output:
| _TIME | AGENT_HOSTNAME | ALERT_SEVERITY | EVENT_SEQ |
|---|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | 3 | 1 |
| 2024-01-15 09:00:00 | workstation-1 | 7 | 2 |
| 2024-01-15 10:00:00 | workstation-1 | 5 | 3 |
| 2024-01-15 08:30:00 | workstation-2 | 2 | 1 |
| 2024-01-15 09:30:00 | workstation-2 | 4 | 2 |
Example 2: Deduplication — keep latest event per host
Goal: Keep only the most recent event for each host by using row_number() and filtering.
XQL code:
dataset = xdr_data | windowcomp row_number() by agent_hostname sort desc _time as rn | filter rn = 1 | fields - rn
Explanation: The row_number() function assigns 1 to the most recent event (sorted descending by _time) within each agent_hostname partition. The filter stage keeps only the first row per host, and fields - rn removes the helper column.
Output:
| _TIME | AGENT_HOSTNAME | ALERT_SEVERITY |
|---|---|---|
| 2024-01-15 10:00:00 | workstation-1 | 5 |
| 2024-01-15 09:30:00 | workstation-2 | 4 |
Example 3: Global row numbering
Goal: Assign a global sequential number to all events ordered by time.
XQL code:
dataset = xdr_data | windowcomp row_number() sort asc _time as global_row_num
Explanation: Without a by clause, the row_number() function assigns a unique sequential number to every row across the entire result set, ordered by _time.
Output:
| _TIME | AGENT_HOSTNAME | GLOBAL_ROW_NUM |
|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | 1 |
| 2024-01-15 08:30:00 | workstation-2 | 2 |
| 2024-01-15 09:00:00 | workstation-1 | 3 |
| 2024-01-15 09:30:00 | workstation-2 | 4 |
| 2024-01-15 10:00:00 | workstation-1 | 5 |
Related articles
- Stages:
windowcomp,dedup,sort - Functions:
rank() - Datasets:
xdr_data
rtrim
Use the rtrim() function to remove specific characters or whitespace from the end (right side) of a given string.
Syntax
rtrim (<string>,[trim_characters])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The string field or literal value from which you want to remove characters. |
trim_characters |
string | No | A string containing the characters to be removed from the end of the input string. If this parameter is omitted, trailing whitespace characters are removed. |
Returns
The rtrim function returns a new string with the specified characters removed from its end. If no matching characters are found at the end, the original string is returned unchanged.
Usage notes
- The function operates exclusively on string inputs.
- The function removes all occurrences of any character found within the
trim_charactersset, starting from the rightmost character of the input string and continuing until a character not in thetrim_charactersset is encountered. - The
trim_charactersspecified in the pattern are case-sensitive. - The function is typically used within the
alterstage to create new fields or modify existing ones.
Examples
Example 1: Basic removal of a common suffix (from dst_domain)
Goal: Remove the ".com" suffix from domain names found in the dst_domain field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (103, 104, 110) | alter cleaned_domain = rtrim(dst_domain, ".com") | fields event_id, dst_domain, cleaned_domain
Explanation: The rtrim() function successfully identifies and removes the ".com" suffix from the dst_domain values, creating the cleaned_domain field.
Output:
| EVENT_ID | DST_DOMAIN | CLEANED_DOMAIN |
|---|---|---|
| 103 | "www.google.com" | "www.google" |
| 104 | "dropbox.com" | "dropbox" |
| 110 | "www.mongodb.com" | "www.mongodb" |
Example 2: Removing trailing whitespace (default behavior)
Goal: Use a literal string with trailing spaces to demonstrate rtrim()'s default behavior when no trim_characters are specified.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter raw_string_with_spaces = "User access login " // Literal string with trailing spaces | alter trimmed_string = rtrim(raw_string_with_spaces) // Removes trailing whitespace by default | fields event_id, raw_string_with_spaces, trimmed_string | limit 1 // Limit output for brevity
Explanation: By omitting the trim_characters argument, rtrim() automatically removes all trailing space characters from raw_string_with_spaces, resulting in trimmed_string.
Output:
| EVENT_ID | RAW_STRING_WITH_SPACES | TRIMMED_STRING |
|---|---|---|
| 101 | "User access login " | "User access login" |
Example 3: Removing specific characters that repeat at the end
Goal: Remove multiple identical characters from the end of a string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter raw_string = "Report_final_v2.docx" // Literal string with a suffix | alter trimmed_string = rtrim(raw_string, "xcd.o") // Removes any of 'x', 'c', 'd', '.', 'o' from the end | fields event_id, raw_string, trimmed_string | limit 1 // Limit output for brevity
Explanation: The rtrim() function removes 'x', 'c', 'd', '.', and 'o' from the end of raw_string. Because 'x' and 'c' are found at the very end, and then 'o', and then '.' and 'd', they are all removed, demonstrating rtrim()'s behavior with multiple matching trailing characters.
Output:
| EVENT_ID | RAW_STRING | TRIMMED_STRING |
|---|---|---|
| 101 | "Report_final_v2.docx" | "Report_final_v2" |
Example 4: Characters to remove not present at the end
Goal: Illustrate that rtrim() only operates on the end of the string. If the trim_characters are present elsewhere but not at the very end, the string remains unchanged.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 102 // Focus on relevant record | alter unchanged_log = rtrim(raw_log_data, ".exe") // Attempts to remove ".exe" | fields event_id, raw_log_data, unchanged_log
Explanation: Although ".exe" is present in the raw_log_data for event 102, it is in the middle of the string, not at the end. As rtrim() only processes characters from the right, the string remains unchanged_log.
Output:
| EVENT_ID | RAW_LOG_DATA | UNCHANGED_LOG |
|---|---|---|
| 102 | "Process cmd.exe attempted to access /etc/passwd" | "Process cmd.exe attempted to access /etc/passwd" |
Example 5: Case-sensitive nature of trim_characters
Goal: Demonstrate that the trim_characters parameter is case-sensitive. Removing "COM" (uppercase) will not affect a string ending in ".com" (lowercase).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 103 // Focus on relevant record | alter domain_case_insensitive_try = rtrim(dst_domain, "COM") // Attempts to remove "COM" (uppercase) | alter domain_case_sensitive_success = rtrim(dst_domain, "com") // Successfully removes "com" (lowercase) | fields event_id, dst_domain, domain_case_insensitive_try, domain_case_sensitive_success
Explanation: domain_case_insensitive_try remains unchanged because "COM" (uppercase) does not match ".com" (lowercase) at the end of the string. domain_case_sensitive_success successfully removes "com" because the case matches.
Output:
| EVENT_ID | DST_DOMAIN | DOMAIN_CASE_INSENSITIVE_TRY | DOMAIN_CASE_SENSITIVE_SUCCESS |
|---|---|---|---|
| 103 | "www.google.com" | "www.google.com" | "www.google." |
Example 6: Trimming a string derived from a JSON field
Goal: Extract a string value from a JSON field and then apply rtrim() to it.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 // Focus on relevant record | alter status_from_json = simple_json_data -> status) // Extracts "ok" for event 101 | alter trimmed_status = rtrim(status_from_json, "k") // Removes 'k' | fields event_id, simple_json_data, status_from_json, trimmed_status
Explanation: The status_from_json field is created by extracting the string "ok" from the simple_json_data. rtrim() then removes the 'k' character from the end of "ok", resulting in "o".
Output:
| EVENT_ID | SIMPLE_JSON_DATA | STATUS_FROM_JSON | TRIMMED_STATUS |
|---|---|---|---|
| 101 | "{"status": "ok", "code": 200} " | "ok" | "o" |
Example 7: Trimming from an array element converted to string
Goal: Extract an element from an array field, convert it to a string, and then apply rtrim().
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 104 // Focus on relevant record | alter first_tag_string = arrayindex(string_tags, 0) // Extracts "monitoring" for event 104 | alter trimmed_tag = rtrim(first_tag_string, "g") // Removes 'g' | fields event_id, string_tags, first_tag_string, trimmed_tag
Explanation: The first_tag_string field captures the first element of string_tags (which is "monitoring" for event 104). rtrim() then removes the character 'g' from the end of "monitoring", resulting in "monitorin".
Output:
| EVENT_ID | STRING_TAGS | FIRST_TAG_STRING | TRIMMED_TAG |
|---|---|---|---|
| 104 | "["monitoring"] " | "monitoring" | "monitorin" |
Related articles
- Stages:
alter - Functions:
arrayindex
safe_add
Use the safe_add() function to perform addition of two numeric values with overflow protection. Unlike the standard add() function, safe_add() returns null instead of raising an error when the result overflows.
Syntax
safe_add(<number1>, <number2>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number1 |
integer, float | Yes | The first numeric value to add. |
number2 |
integer, float | Yes | The second numeric value to add. |
Returns
Type: integer or float (matches input types)
Description: The safe_add() function returns the sum of the two input values. If the result would overflow the numeric type, the function returns null instead of raising an error. If either input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Overflow Protection: The primary advantage of
safe_add()overadd()is that it returnsnullinstead of raising an error when the result exceeds the maximum or minimum value of the numeric type. - Null Handling: If either input expression is
null, the function returnsnull. - Type Preservation: When both inputs are integers, the result is an integer. When either input is a float, the result is a float.
- Common Use Cases: This function is used when working with potentially large numbers where overflow is a concern, such as summing large counters, byte counts, or accumulated metrics.
Examples
Example 1: Safe addition of literal values
Goal: Perform safe addition on numeric literals, including cases that might overflow.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = safe_add(100, 200) | alter result2 = safe_add(9223372036854775807, 1) | fields result1, result2
Explanation: safe_add(100, 200) returns 300 as expected. safe_add(9223372036854775807, 1) would overflow the maximum 64-bit integer value, so it returns null instead of raising an error.
Output:
| RESULT1 | RESULT2 |
|---|---|
| 300 | null |
Example 2: Safe addition of field values
Goal: Safely add two numeric fields that might produce overflow.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter safe_sum = safe_add(event_id, numeric_value) | fields event_id, numeric_value, safe_sum | limit 3
Explanation: This query safely adds event_id and numeric_value for each record. If any combination would cause an overflow, the result is null rather than an error.
Output:
| EVENT_ID | NUMERIC_VALUE | SAFE_SUM |
|---|---|---|
| 101 | 5.0 | 106.0 |
| 102 | 200.0 | 302.0 |
| 103 | 50.0 | 153.0 |
Example 3: Use safe_add with coalesce for fallback
Goal: Perform safe addition and provide a fallback value when the result is null due to overflow.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter safe_result = safe_add(event_id, numeric_value) | alter final_result = coalesce(safe_result, 0) | fields event_id, numeric_value, safe_result, final_result | limit 3
Explanation: This query uses safe_add() to add two fields, then applies coalesce() to replace any null results (from overflow or null inputs) with 0 as a fallback value.
Output:
| EVENT_ID | NUMERIC_VALUE | SAFE_RESULT | FINAL_RESULT |
|---|---|---|---|
| 101 | 5.0 | 106.0 | 106.0 |
| 102 | 200.0 | 302.0 | 302.0 |
| 103 | 50.0 | 153.0 | 153.0 |
Related articles
- Stages:
alter,fields,limit - Functions:
add(),safe_subtract(),safe_multiply(),coalesce() - Datasets:
xdr_data
safe_divide
Use the safe_divide() function to perform division of two numeric values with error protection. Unlike the standard divide() function, safe_divide() returns null instead of raising an error when dividing by zero.
Syntax
safe_divide(<dividend>, <divisor>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
dividend |
integer, float | Yes | The number to be divided (numerator). |
divisor |
integer, float | Yes | The number to divide by (denominator). |
Returns
Type: float
Description: The safe_divide() function returns the result of dividing the dividend by the divisor. If the divisor is zero, the function returns null instead of raising an error. If either input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Division by Zero Protection: The primary advantage of
safe_divide()overdivide()is that it returnsnullinstead of raising an error when the divisor is zero. - Null Handling: If either input expression is
null, the function returnsnull. - Return Type: The result is always a float, even when both inputs are integers.
- Common Use Cases: This function is used when the divisor might be zero, such as calculating ratios, percentages, or averages where the denominator could be zero in some records.
Examples
Example 1: Safe division with zero divisor
Goal: Demonstrate that safe_divide() returns null instead of an error when dividing by zero.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = safe_divide(10, 2), result2 = safe_divide(10, 0), result3 = safe_divide(0, 5) | fields result1, result2, result3
Explanation: safe_divide(10, 2) returns 5.0. safe_divide(10, 0) returns null instead of raising a division-by-zero error. safe_divide(0, 5) returns 0.0.
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 5.0 | null | 0.0 |
Example 2: Calculate safe ratios from field values
Goal: Calculate a ratio between two fields where the denominator might be zero.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter ratio = safe_divide(numeric_value, duration_seconds) | fields event_id, numeric_value, duration_seconds, ratio | limit 3
Explanation: This query safely divides numeric_value by duration_seconds. If duration_seconds is zero for any record, the result is null rather than an error, preventing query failure.
Output:
| EVENT_ID | NUMERIC_VALUE | DURATION_SECONDS | RATIO |
|---|---|---|---|
| 101 | 100.0 | 1.5 | 66.66667 |
| 102 | 50.0 | 0.0 | null |
| 103 | 200.0 | 10.2 | 19.60784 |
Example 3: Use safe_divide with coalesce for fallback
Goal: Calculate a safe ratio and provide a default value when division by zero occurs.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter safe_ratio = safe_divide(numeric_value, duration_seconds) | alter final_ratio = coalesce(safe_ratio, 0) | fields event_id, numeric_value, duration_seconds, safe_ratio, final_ratio | limit 3
Explanation: This query uses safe_divide() to calculate a ratio, then applies coalesce() to replace any null results (from division by zero or null inputs) with 0 as a fallback value.
Output:
| EVENT_ID | NUMERIC_VALUE | DURATION_SECONDS | SAFE_RATIO | FINAL_RATIO |
|---|---|---|---|---|
| 101 | 100.0 | 1.5 | 66.66667 | 66.66667 |
| 102 | 50.0 | 0.0 | null | 0 |
| 103 | 200.0 | 10.2 | 19.60784 | 19.60784 |
Related articles
- Stages:
alter,fields,limit - Functions:
divide(),safe_multiply(),safe_add(),coalesce() - Datasets:
xdr_data
safe_multiply
Use the safe_multiply() function to perform multiplication of two numeric values with overflow protection. Unlike the standard multiply() function, safe_multiply() returns null instead of raising an error when the result overflows.
Syntax
safe_multiply(<number1>, <number2>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number1 |
integer, float | Yes | The first numeric value to multiply. |
number2 |
integer, float | Yes | The second numeric value to multiply. |
Returns
Type: integer or float (matches input types)
Description: The safe_multiply() function returns the product of the two input values. If the result would overflow the numeric type, the function returns null instead of raising an error. If either input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Overflow Protection: The primary advantage of
safe_multiply()overmultiply()is that it returnsnullinstead of raising an error when the result exceeds the maximum or minimum value of the numeric type. - Null Handling: If either input expression is
null, the function returnsnull. - Type Preservation: When both inputs are integers, the result is an integer. When either input is a float, the result is a float.
- Common Use Cases: This function is used when working with potentially large numbers where overflow is a concern, such as multiplying large counters, calculating areas with large dimensions, or computing compound values.
Examples
Example 1: Safe multiplication of literal values
Goal: Perform safe multiplication on numeric literals, including cases that might overflow.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = safe_multiply(100, 200) | alter result2 = safe_multiply(9223372036854775807, 2) | fields result1, result2
Explanation: safe_multiply(100, 200) returns 20000 as expected. safe_multiply(9223372036854775807, 2) would overflow the maximum 64-bit integer value, so it returns null instead of raising an error.
Output:
| RESULT1 | RESULT2 |
|---|---|
| 20000 | null |
Example 2: Safe multiplication of field values
Goal: Safely multiply two numeric fields that might produce overflow.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter safe_product = safe_multiply(event_id, numeric_value) | fields event_id, numeric_value, safe_product | limit 3
Explanation: This query safely multiplies event_id and numeric_value for each record. If any combination would cause an overflow, the result is null rather than an error.
Output:
| EVENT_ID | NUMERIC_VALUE | SAFE_PRODUCT |
|---|---|---|
| 101 | 5.0 | 505.0 |
| 102 | 200.0 | 20400.0 |
| 103 | 50.0 | 5150.0 |
Example 3: Use safe_multiply with coalesce for fallback
Goal: Perform safe multiplication and provide a fallback value when the result is null due to overflow.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter safe_result = safe_multiply(event_id, numeric_value) | alter final_result = coalesce(safe_result, -1) | fields event_id, numeric_value, safe_result, final_result | limit 3
Explanation: This query uses safe_multiply() to multiply two fields, then applies coalesce() to replace any null results (from overflow or null inputs) with -1 as a sentinel value.
Output:
| EVENT_ID | NUMERIC_VALUE | SAFE_RESULT | FINAL_RESULT |
|---|---|---|---|
| 101 | 5.0 | 505.0 | 505.0 |
| 102 | 200.0 | 20400.0 | 20400.0 |
| 103 | 50.0 | 5150.0 | 5150.0 |
Related articles
- Stages:
alter,fields,limit - Functions:
multiply(),safe_add(),safe_divide(),coalesce() - Datasets:
xdr_data
safe_negate
Use the safe_negate() function to negate a numeric value with overflow protection. Unlike standard negation, safe_negate() returns null instead of raising an error when the result overflows.
Syntax
safe_negate(<number>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The numeric value to negate. |
Returns
Type: integer or float (matches input type)
Description: The safe_negate() function returns the negated value of the input (i.e., -number). If the result would overflow the numeric type, the function returns null instead of raising an error. If the input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Overflow Protection: The primary advantage of
safe_negate()is that it returnsnullinstead of raising an error when negating the minimum integer value (for example, negating-9223372036854775808would overflow since the maximum positive 64-bit integer is9223372036854775807). - Null Handling: If the input expression is
null, the function returnsnull. - Double Negation:
safe_negate(safe_negate(x))returnsxfor all non-overflow cases. - Common Use Cases: This function is used when working with values that might be at the boundary of the integer range, such as system-generated counters or imported data with extreme values.
Examples
Example 1: Negate literal values safely
Goal: Negate specific numeric literals, including edge cases.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = safe_negate(42), result2 = safe_negate(-100), result3 = safe_negate(0) | fields result1, result2, result3
Explanation: safe_negate(42) returns -42, safe_negate(-100) returns 100, and safe_negate(0) returns 0. These are straightforward negations with no overflow risk.
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| -42 | 100 | 0 |
Example 2: Safely negate field values
Goal: Negate values stored in a dataset field with overflow protection.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter negated_value = safe_negate(numeric_value) | fields event_id, numeric_value, negated_value | limit 3
Explanation: This query negates each value in the numeric_value field. If any value is at the minimum integer boundary, the result is null rather than an error.
Output:
| EVENT_ID | NUMERIC_VALUE | NEGATED_VALUE |
|---|---|---|
| 101 | 5.0 | -5.0 |
| 102 | -200.0 | 200.0 |
| 103 | 50.0 | -50.0 |
Example 3: Use safe_negate to compute absolute difference
Goal: Calculate the absolute difference between two fields using safe negation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter diff = subtract(numeric_value, duration_seconds) | alter abs_diff = if(diff < 0, safe_negate(diff), diff) | fields event_id, numeric_value, duration_seconds, diff, abs_diff | limit 3
Explanation: This query calculates the difference between two fields, then uses safe_negate() to compute the absolute value when the difference is negative. This approach safely handles potential overflow at integer boundaries.
Output:
| EVENT_ID | NUMERIC_VALUE | DURATION_SECONDS | DIFF | ABS_DIFF |
|---|---|---|---|---|
| 101 | 5.0 | 1.5 | 3.5 | 3.5 |
| 102 | 0.8 | 200.0 | -199.2 | 199.2 |
| 103 | 50.0 | 10.2 | 39.8 | 39.8 |
Related articles
- Stages:
alter,fields,limit - Functions:
safe_subtract(),safe_add(),subtract(),if() - Datasets:
xdr_data
safe_subtract
Use the safe_subtract() function to perform subtraction of two numeric values with overflow protection. Unlike the standard subtract() function, safe_subtract() returns null instead of raising an error when the result overflows.
Syntax
safe_subtract(<number1>, <number2>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number1 |
integer, float | Yes | The number to subtract from (minuend). |
number2 |
integer, float | Yes | The number to subtract (subtrahend). |
Returns
Type: integer or float (matches input types)
Description: The safe_subtract() function returns the difference of the two input values (number1 - number2). If the result would overflow the numeric type, the function returns null instead of raising an error. If either input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Overflow Protection: The primary advantage of
safe_subtract()oversubtract()is that it returnsnullinstead of raising an error when the result exceeds the maximum or minimum value of the numeric type. - Null Handling: If either input expression is
null, the function returnsnull. - Type Preservation: When both inputs are integers, the result is an integer. When either input is a float, the result is a float.
- Common Use Cases: This function is used when working with potentially large numbers where overflow is a concern, such as calculating differences between large counters, timestamps represented as integers, or accumulated metrics.
Examples
Example 1: Safe subtraction of literal values
Goal: Perform safe subtraction on numeric literals, including cases that might overflow.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = safe_subtract(200, 100) | alter result2 = safe_subtract(-9223372036854775808, 1) | fields result1, result2
Explanation: safe_subtract(200, 100) returns 100 as expected. safe_subtract(-9223372036854775808, 1) would underflow the minimum 64-bit integer value, so it returns null instead of raising an error.
Output:
| RESULT1 | RESULT2 |
|---|---|
| 100 | null |
Example 2: Safe subtraction of field values
Goal: Safely subtract two numeric fields that might produce overflow.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter safe_diff = safe_subtract(event_id, numeric_value) | fields event_id, numeric_value, safe_diff | limit 3
Explanation: This query safely subtracts numeric_value from event_id for each record. If any combination would cause an overflow, the result is null rather than an error.
Output:
| EVENT_ID | NUMERIC_VALUE | SAFE_DIFF |
|---|---|---|
| 101 | 5.0 | 96.0 |
| 102 | 200.0 | -98.0 |
| 103 | 50.0 | 53.0 |
Example 3: Use safe_subtract with coalesce for fallback
Goal: Perform safe subtraction and provide a fallback value when the result is null due to overflow.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter safe_result = safe_subtract(event_id, numeric_value) | alter final_result = coalesce(safe_result, 0) | fields event_id, numeric_value, safe_result, final_result | limit 3
Explanation: This query uses safe_subtract() to subtract two fields, then applies coalesce() to replace any null results (from overflow or null inputs) with 0 as a fallback value.
Output:
| EVENT_ID | NUMERIC_VALUE | SAFE_RESULT | FINAL_RESULT |
|---|---|---|---|
| 101 | 5.0 | 96.0 | 96.0 |
| 102 | 200.0 | -98.0 | -98.0 |
| 103 | 50.0 | 53.0 | 53.0 |
Related articles
- Stages:
alter,fields,limit - Functions:
subtract(),safe_add(),safe_negate(),coalesce() - Datasets:
xdr_data
sec
Use the sec() function to calculate the secant of a numeric value specified in radians. The secant is the reciprocal of the cosine function.
Syntax
sec(<numeric_expression>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
numeric_expression |
integer, float | Yes | The angle in radians for which to calculate the secant. The value must not be an odd multiple of p/2. |
Returns
Type: float
Description: The sec() function returns the secant of the input angle, which is equivalent to 1 / cos(x). If the input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The
sec()function accepts any real number except values wherecos(x) = 0(i.e., odd multiples of p/2), where the secant is undefined. - Undefined Values: At odd multiples of p/2 (for example, p/2, 3p/2), the function returns
infinity,NaN, ornullsince the secant is undefined at these points. - Null Handling: If the input expression is
null, the function returnsnull. - Relationship:
sec(x) = 1 / cos(x). - Result Range: The result is always = -1 or = 1 (never between -1 and 1).
- Common Use Cases: This function is typically used within the
alterstage for trigonometric calculations, optics computations, and engineering analysis.
Examples
Example 1: Calculate secant of literal values
Goal: Calculate the secant for specific radian values to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = sec(0), result2 = sec(pi()), result3 = sec(1) | fields result1, result2, result3
Explanation: sec(0) returns 1.0 (since cos(0) = 1), sec(p) returns -1.0 (since cos(p) = -1), and sec(1) returns approximately 1.8508.
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 1.0 | -1.0 | 1.85082 |
Example 2: Calculate secant from a field value
Goal: Calculate the secant of values stored in a dataset field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter sec_val = sec(numeric_value) | fields event_id, numeric_value, sec_val | limit 3
Explanation: This query computes the secant for each value in the numeric_value field and stores the result in sec_val.
Output:
| EVENT_ID | NUMERIC_VALUE | SEC_VAL |
|---|---|---|
| 101 | 0.0 | 1.0 |
| 102 | 1.0 | 1.85082 |
| 103 | 3.14159 | -1.0 |
Example 3: Verify secant as reciprocal of cosine
Goal: Demonstrate that sec(x) equals 1 / cos(x) by computing both and comparing.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter sec_val = sec(numeric_value) | alter reciprocal_cos = divide(1, cos(numeric_value)) | fields event_id, numeric_value, sec_val, reciprocal_cos | limit 3
Explanation: This query computes both sec(numeric_value) and 1 / cos(numeric_value) to verify they produce the same result, confirming the mathematical identity sec(x) = 1 / cos(x).
Output:
| EVENT_ID | NUMERIC_VALUE | SEC_VAL | RECIPROCAL_COS |
|---|---|---|---|
| 101 | 0.0 | 1.0 | 1.0 |
| 102 | 1.0 | 1.85082 | 1.85082 |
| 103 | 3.14159 | -1.0 | -1.0 |
Related articles
sha1
Use the sha1() function to compute the SHA-1 (Secure Hash Algorithm 1) hash of an input string.
Syntax
sha1 ("<input_string>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
input_string |
string | Yes | The string to be hashed. |
Returns
The sha1() function returns the SHA-1 hash value as a string.
Usage notes
- The function strictly requires a single string input.
- SHA-1 is a one-way cryptographic hash function, meaning it is computationally infeasible to reverse the hashing process to obtain the original string from its hash.
- To hash values from non-string fields (such as integers or booleans), you must first convert them to a string using the
to_string()function.
Examples
Example 1: Hashing a basic literal string
Goal: Compute the SHA-1 hash of a simple literal string value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_literal = sha1("Hello XQL!") | fields event_id, hashed_literal | limit 3
Explanation: This query adds a new field, hashed_literal, containing the SHA-1 hash of the string "Hello XQL!" for each record.
Output:
| EVENT_ID | HASHED_LITERAL |
|---|---|
| 101 | 6938947f6424594a11b6ff4f04c6439162e84d41 |
| 102 | 6938947f6424594a11b6ff4f04c6439162e84d41 |
| 103 | 6938947f6424594a11b6ff4f04c6439162e84d41 |
Example 2: Hashing an existing string field
Goal: Compute the SHA-1 hash for values within an existing string field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_description = sha1(event_description) | fields event_id, event_description, hashed_description | limit 3
Explanation: The query creates the hashed_description field by applying the sha1() function to the event_description field for each record.
Output:
| EVENT_ID | EVENT_DESCRIPTION | HASHED_DESCRIPTION |
|---|---|---|
| 101 | User login successful | e7751c911ee0541703e8787729227f2f |
| 102 | File access attempt | be2254e015ee6b158055c56c2e28a506 |
| 103 | Network connection established | 24b74f0c43666f272a85e13b06385a86 |
Example 3: Hashing a string derived from a non-string field
Goal: Convert a numeric field to a string and then compute its SHA-1 hash.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_string = to_string(event_id) | alter hashed_id = sha1(event_id_string) | fields event_id, event_id_string, hashed_id | limit 3
Explanation: The event_id is first converted to a string using to_string(), and then sha1() hashes this string representation to create hashed_id.
Output:
| EVENT_ID | EVENT_ID_STRING | HASHED_ID |
|---|---|---|
| 101 | 101 | b00b7407519106093416e91122a6136e090f75f7 |
| 102 | 102 | 041c2c366ff4281f69201103f1673891404c0df2 |
| 103 | 103 | 1488c525f77876a3e5c709e3a35a7707e77a1024 |
Example 4: Hashing an empty string
Goal: Demonstrate the result of hashing an empty string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_empty_string = sha1("") | fields event_id, hashed_empty_string | limit 3
Explanation: Hashing an empty string consistently results in the well-known SHA-1 hash for an empty string.
Output:
| EVENT_ID | HASHED_EMPTY_STRING |
|---|---|
| 101 | da39a3ee5e6b4b0d3255bfef95601890afd80709 |
| 102 | da39a3ee5e6b4b0d3255bfef95601890afd80709 |
| 103 | da39a3ee5e6b4b0d3255bfef95601890afd80709 |
Example 5: Handling NULL input
Goal: Observe the behavior when the input to the function is NULL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_null_field = sha1(dst_domain) | fields event_id, dst_domain, hashed_null_field | li
Explanation: When the input to sha1() is NULL (as seen in event 105), the function consistently returns NULL for the output field.
Output:
| EVENT_ID | DST_DOMAIN | HASHED_NULL_FIELD |
|---|---|---|
| 101 | ec2.amazonaws.com | 7f2f11181827457c134012019c4d93e5 |
| 102 | sts.amazonaws.com | fdf15a896d92008779b1248039601d0f |
| 103 | www.google.com | 121f66cb71158f964092b3a1a36173a7 |
| 104 | dropbox.com | 84b7a137e0c4573130d740a6b47c0b6b |
| 105 | NULL | NULL |
Related articles
sha256
Use the sha256() function to compute the SHA-256 (Secure Hash Algorithm 256) hash of an input string, producing a unique 64-character hexadecimal fingerprint.
Syntax
sha256 ("<input_string>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
input_string |
string | Yes | The string value to be hashed. |
Returns
The sha256() function returns the SHA-256 hash value as a string.
Usage notes
- The function creates a unique, fixed-length digital fingerprint of the input, commonly employed for data integrity verification or for one-way transformation of sensitive data.
- SHA-256 is a one-way cryptographic hash function, meaning it is computationally infeasible to reverse the hashing process to obtain the original string from its hash.
- The function strictly requires a single string input.
Examples
Example 1: Hashing a basic literal string
Goal: Compute the SHA-256 hash of a simple literal string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_literal = sha256("Hello XQL!") | fields event_id, hashed_literal | limit 3
Explanation: This query adds a new field, hashed_literal, containing the SHA-256 hash of the string "Hello XQL!" for each record.
Output:
| EVENT_ID | HASHED_LITERAL |
|---|---|
| 101 | 7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069 |
| 102 | 7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069 |
| 103 | 7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069 |
Example 2: Hashing an existing string field
Goal: Hash the values from an existing string field in the dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_description = sha256(event_description) | fields event_id, event_description, hashed_description | limit 3
Explanation: The query creates hashed_description by applying the sha256() function to the event_description field for each record.
Output:
| EVENT_ID | EVENT_DESCRIPTION | HASHED_DESCRIPTION |
|---|---|---|
| 101 | User login successful | f7d9e4a3b0c3e7f2d1a9b8c7e6d5c4b3a2f1e0d9c8b7a6f5e4d3c2b1a0f9e8d7 |
| 102 | File access attempt | be2254e015ee6b158055c56c2e28a506a77d3b5b112d7c04192b45129c7b960d |
| 103 | Network connection established | 24b74f0c43666f272a85e13b06385a8677c7c3c5b9e0f3c5d6e2e5c8a3d1b7f2 |
Example 3: Hashing a string derived from a non-string field
Goal: Convert a numeric field to a string and then hash it.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_string = to_string(event_id) | alter hashed_id = sha256(event_id_string) | fields event_id, event_id_string, hashed_id | limit 3
Explanation: The event_id is first converted to a string using to_string(), and then sha256() hashes this string representation.
Output:
| EVENT_ID | EVENT_ID_STRING | HASHED_ID |
|---|---|---|
| 101 | 101 | d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35 |
| 102 | 102 | f86dd052d9482d8c9735d55b5d1222416b0451a541315b8813a484196ddc8160 |
| 103 | 103 | 9e0416a9a0899f2c3d1c9f4d7629b3c4f9a0d2f0c7e5b6a7d8f9e0c1b2a3d4e5 |
Example 4: Hashing an empty string
Goal: Demonstrate the result of hashing an empty string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_empty_string = sha256("") | fields event_id, hashed_empty_string | limit 3
Explanation: Hashing an empty string consistently results in the well-known SHA-256 hash for an empty string.
Output:
| EVENT_ID | HASHED_EMPTY_STRING |
|---|---|
| 101 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 |
| 102 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 |
| 103 | e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 |
Example 5: Handling NULL input
Goal: Demonstrate behavior when the input to the hash function is NULL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_null_field = sha256(dst_domain) | fields event_id, dst_domain, hashed_null_field | limit 5
Explanation: When the input to sha256() is NULL (as seen in event 105), the function consistently returns NULL for the output field.
Output:
| EVENT_ID | DST_DOMAIN | HASHED_NULL_FIELD |
|---|---|---|
| 101 | ec2.amazonaws.com | 7f2f11181827457c134012019c4d93e5482329239d57a4141d63e9f425c2763b |
| 102 | sts.amazonaws.com | fdf15a896d92008779b1248039601d0f5e3e2b2a1a0c9b8d7e6f5d4c3b2a1a0d |
| 103 | www.google.com | 121f66cb71158f964092b3a1a36173a728b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3 |
| 104 | dropbox.com | 84b7a137e0c4573130d740a6b47c0b6b23a9b8c7e6d5c4b3a2f1e0d9c8b7a6f5 |
| 105 | NULL | NULL |
Related articles
sha512
Use the sha512() function to compute the SHA-512 (Secure Hash Algorithm 512) hash of an input string.
Syntax
sha512 ("<input_string>")
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
<input_string> |
string | Yes | The string value to be hashed. |
Returns
The sha512() function returns the SHA-512 hash value as a string.
Usage notes
- The function strictly requires a single string input.
- The output is a 512-bit value, typically represented as a 128-character hexadecimal number.
- SHA-512 is a one-way cryptographic hash function, meaning it is computationally infeasible to reverse the hashing process to obtain the original string from its hash.
- If the input string is NULL, the function returns NULL.
Examples
Example 1: Hashing a basic literal string
Goal: Compute the SHA-512 hash of a simple literal string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_literal = sha512("Hello XQL Functions!") | fields event_id, hashed_literal | limit 3
Explanation: This query adds a new field, hashed_literal, containing the SHA-512 hash of "Hello XQL Functions!" for each record.
Output:
| EVENT_ID | HASHED_LITERAL |
|---|---|
| 101 | cb8e63a35f7c320d778a3c861e967a5b3a4a7c8e6f5d4c3b2a1a0b9c8d7e6f5d4c3b2a1a0b9c8d7e6f5d4c3b2a1a0b9c8d7e6f5d4c3b2a1a0b9c8d7e6f5d4c3b |
| 102 | cb8e63a35f7c320d778a3c861e967a5b3a4a7c8e6f5d4c3b2a1a0b9c8d7e6f5d4c3b2a1a0b9c8d7e6f5d4c3b2a1a0b9c8d7e6f5d4c3b2a1a0b9c8d7e6f5d4c3b |
| 103 | cb8e63a35f7c320d778a3c861e967a5b3a4a7c8e6f5d4c3b2a1a0b9c8d7e6f5d4c3b2a1a0b9c8d7e6f5d4c3b2a1a0b9c8d7e6f5d4c3b2a1a0b9c8d7e6f5d4c3b |
Example 2: Hashing an existing string field
Goal: Hash the values of an existing string field in the dataset.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_description = sha512(event_description) | fields event_id, event_description, hashed_description | limit 3
Explanation: The query creates hashed_description by applying the sha512() function to the event_description field for each record.
Output:
| EVENT_ID | EVENT_DESCRIPTION | HASHED_DESCRIPTION |
|---|---|---|
| 101 | User login successful | e1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4 |
| 102 | File access attempt | f1e2d3c4b5a6f7e8d9c0b1a2f3e4d5c6b7a8f9e0d1c2b3a4f5e6d7c8b9a0f1e2d3c4b5a6f7e8d9c0b1a2f3e4d5c6b7a8f9e0d1c2b3a4f5e6d7c8b9a0f1e2 |
| 103 | Network connection established | a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4 |
Example 3: Hashing a string derived from a non-string field
Goal: Convert a numeric field to a string and then hash it.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_string = to_string(event_id) | alter hashed_id = sha512(event_id_string) | fields event_id, event_id_string, hashed_id | limit 3
Explanation: The event_id is first converted to a string using to_string(), and then sha512() hashes this string representation.
Output:
| EVENT_ID | EVENT_ID_STRING | HASHED_ID |
|---|---|---|
| 101 | 101 | 22340356a64b5687790b0e51d45371b2d424075191a385f269a84d4128f6412f11181827457c134012019c4d93e5482329239d57a4141d63e9f425c2763b |
| 102 | 102 | 00d4187c29377a06a096c1410f994784407850a116b0b001a4e107f7b3a4a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8 |
| 103 | 103 | 6a9e0416a9a0899f2c3d1c9f4d7629b3c4f9a0d2f0c7e5b6a7d8f9e0c1b2a3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4 |
Example 4: Hashing an empty string
Goal: Demonstrate the result of hashing an empty string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_empty_string = sha512("") | fields event_id, hashed_empty_string | limit 3
Explanation: Hashing an empty string consistently results in the well-known SHA-512 hash for an empty string.
Output:
| EVENT_ID | HASHED_EMPTY_STRING |
|---|---|
| 101 | cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e |
| 102 | cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e |
| 103 | cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e |
Example 5: Handling NULL input
Goal: Demonstrate the behavior when the input string is NULL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter hashed_null_field = sha512(dst_domain) | fields event_id, dst_domain, hashed_null_field | limit 5
Explanation: When the input to sha512() is NULL (as seen in event 105), the function consistently returns NULL for the output field.
Output:
| EVENT_ID | DST_DOMAIN | HASHED_NULL_FIELD |
|---|---|---|
| 101 | ec2.amazonaws.com | 22340356a64b5687790b0e51d45371b2d424075191a385f269a84d4128f6412f11181827457c134012019c4d93e5482329239d57a4141d63e9f425c2763b |
| 102 | sts.amazonaws.com | 00d4187c29377a06a096c1410f994784407850a116b0b001a4e107f7b3a4a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8 |
| 103 | www.google.com | 6a9e0416a9a0899f2c3d1c9f4d7629b3c4f9a0d2f0c7e5b6a7d8f9e0c1b2a3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d4 |
| 104 | dropbox.com | f1e2d3c4b5a6f7e8d9c0b1a2f3e4d5c6b7a8f9e0d1c2b3a4f5e6d7c8b9a0f1e2d3c4b5a6f7e8d9c0b1a2f3e4d5c6b7a8f9e0d1c2b3a4f5e6d7c8b9a0f1e2 |
| 105 | NULL | NULL |
Related articles
sign
Use the sign() function to determine the sign of a numeric value. The function returns -1, 0, or 1 depending on whether the input is negative, zero, or positive.
Syntax
sign(<number>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The numeric value whose sign is to be determined. |
Returns
Type: integer
Description: The sign() function returns -1 if the input is negative, 0 if the input is zero, and 1 if the input is positive. If the input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The
sign()function accepts any real number. - Null Handling: If the input expression is
null, the function returnsnull. - Return Values: The function always returns one of three values:
-1,0, or1. - NaN Handling: If the input is
NaN, the behavior depends on the implementation and may returnnullorNaN. - Common Use Cases: This function is typically used within the
alterstage for direction detection, trend analysis, conditional logic based on value polarity, and data classification.
Examples
Example 1: Determine sign of literal values
Goal: Determine the sign of specific numeric literals.
XQL code:
dataset = xdr_data | limit 1 | alter sign_pos = sign(42), sign_neg = sign(-17), sign_zero = sign(0) | fields sign_pos, sign_neg, sign_zero
Explanation: sign(42) returns 1 (positive), sign(-17) returns -1 (negative), and sign(0) returns 0 (zero).
Output:
| SIGN_POS | SIGN_NEG | SIGN_ZERO |
|---|---|---|
| 1 | -1 | 0 |
Example 2: Classify field values by sign
Goal: Classify values in a dataset field as positive, negative, or zero.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter value_sign = sign(numeric_value) | alter classification = if(value_sign = 1, "positive", value_sign = -1, "negative", "zero") | fields event_id, numeric_value, value_sign, classification | limit 4
Explanation: This query determines the sign of each numeric_value and maps it to a human-readable classification label using if().
Output:
| EVENT_ID | NUMERIC_VALUE | VALUE_SIGN | CLASSIFICATION |
|---|---|---|---|
| 101 | 5.0 | 1 | positive |
| 102 | -200.0 | -1 | negative |
| 103 | 0.0 | 0 | zero |
| 104 | 50.0 | 1 | positive |
Example 3: Use sign for directional comparison
Goal: Determine the direction of change between two fields.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter change = subtract(numeric_value, duration_seconds) | alter direction = sign(change) | alter trend = if(direction = 1, "increasing", direction = -1, "decreasing", "unchanged") | fields event_id, numeric_value, duration_seconds, change, trend | limit 3
Explanation: This query calculates the difference between numeric_value and duration_seconds, then uses sign() to determine the direction of the change. The result is mapped to a trend label.
Output:
| EVENT_ID | NUMERIC_VALUE | DURATION_SECONDS | CHANGE | TREND |
|---|---|---|---|---|
| 101 | 5.0 | 1.5 | 3.5 | increasing |
| 102 | 0.8 | 200.0 | -199.2 | decreasing |
| 103 | 10.2 | 10.2 | 0.0 | unchanged |
Related articles
- Stages:
alter,fields,limit - Functions:
if(),subtract(),safe_negate() - Datasets:
xdr_data
sin
Use the sin() function to calculate the sine of a numeric value specified in radians.
Syntax
sin(<numeric_expression>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
numeric_expression |
integer, float | Yes | The angle in radians for which to calculate the sine. Any real number is valid. |
Returns
Type: float
Description: The sin() function returns the sine of the input angle. The resulting value is within the range [-1, 1].
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The
sin()function accepts any real number as input. The input is interpreted as an angle in radians. - Null Handling: If the input expression is
null, the function returnsnull. - Degrees to Radians: If your input is in degrees, convert it to radians first by multiplying by
PI() / 180. - Periodicity: The sine function is periodic with period 2π, meaning
sin(x) = sin(x + 2π). - Key Values:
sin(0)returns0.0,sin(π/2)returns1.0,sin(π)returns0.0,sin(3π/2)returns-1.0. - Symmetry: The function is odd, meaning
sin(-x) = -sin(x). - Common Use Cases: This function is typically used within the
alterstage for trigonometric calculations, signal processing, coordinate transformations, and wave analysis.
Examples
Example 1: Calculate sine of literal values
Goal: Calculate the sine for specific radian values to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = sin(0), result2 = sin(divide(pi(), 2)), result3 = sin(pi()) | fields result1, result2, result3
Explanation: sin(0) returns 0.0, sin(π/2) returns 1.0, and sin(π) returns approximately 0.0 (a very small number close to zero due to floating-point precision).
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 0.0 | 1.0 | 0.0 |
Example 2: Calculate sine from a field value
Goal: Calculate the sine of values stored in a dataset field, treating them as angles in radians.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter sin_val = sin(numeric_value) | fields event_id, numeric_value, sin_val | limit 3
Explanation: This query computes the sine for each value in the numeric_value field and stores the result in sin_val. Since sin() accepts any real number, no filtering is needed.
Output:
| EVENT_ID | NUMERIC_VALUE | SIN_VAL |
|---|---|---|
| 101 | 0.0 | 0.0 |
| 102 | 1.5708 | 1.0 |
| 103 | 3.14159 | 0.0 |
Example 3: Use sine in a coordinate transformation
Goal: Use the sine function to compute the y-component of a polar-to-Cartesian coordinate transformation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter y_component = multiply(numeric_value, sin(duration_seconds)) | fields event_id, numeric_value, duration_seconds, y_component | limit 3
Explanation: This query computes the y-component of a polar coordinate transformation using the formula y = r * sin(θ), where numeric_value is the radius and duration_seconds is the angle in radians.
Output:
| EVENT_ID | NUMERIC_VALUE | DURATION_SECONDS | Y_COMPONENT |
|---|---|---|---|
| 101 | 5.0 | 0.0 | 0.0 |
| 102 | 3.0 | 1.5708 | 3.0 |
| 103 | 7.0 | 3.14159 | 0.0 |
Related articles
split
Use the split() function to divide a string into an array of substrings based on a specified delimiter.
Syntax
split (<value> [, <string_delimiter>])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
value |
string | Yes | The string field or literal value to split. |
string_delimiter |
string | No | The string literal used as the delimiter. If omitted or set to an empty string (""), a space (' ') is used by default. |
Returns
The split() function returns an array of strings containing the substrings generated by splitting the input value.
Usage notes
- The function operates exclusively on string inputs.
- The delimiter itself is not included in the resulting array elements.
- If the delimiter appears consecutively, or at the beginning or end of the string, it can result in empty strings as elements in the output array.
- If the input
valueis NULL, the function returns an empty array[].
Examples
Example 1: Basic split with a specific delimiter
Goal: Split an IP address string by the dot (.) character to separate its octets.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102, 105) | alter ip_octets = split(ipv4_address, ".") | fields event_id, ipv4_address, ip_octets | limit 3
Explanation: The function divides the ipv4_address string into an array of individual numeric octets using the specified . delimiter.
Output:
| EVENT_ID | IPV4_ADDRESS | IP_OCTETS |
|---|---|---|
| 101 | 192.168.1.10 | ["192", "168", "1", "10"] |
| 102 | 10.0.0.5 | ["10", "0", "0", "5"] |
| 105 | 192.168.10.20 | ["192", "168", "10", "20"] |
Example 2: Split without a specified delimiter
Goal: Split a log message into individual words using the default delimiter (space).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102) | alter log_words = split(raw_log_data) | fields event_id, raw_log_data, log_words | limit 2
Explanation: By omitting the optional delimiter argument, the function automatically uses a space to break the raw_log_data string into an array of words.
Output:
| EVENT_ID | RAW_LOG_DATA | LOG_WORDS |
|---|---|---|
| 101 | User Alice logged in from 192.168.1.10 | ["User", "Alice", "logged", "in", "from", "192.168.1.10"] |
| 102 | Process cmd.exe attempted to access /etc/passwd | ["Process", "cmd.exe", "attempted", "to", "access", "/etc/passwd"] |
Example 3: Split with an empty string as delimiter
Goal: Explicitly use an empty string as the delimiter, which defaults to splitting by space.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter log_parts = split(raw_log_data, "") | fields event_id, raw_log_data, log_parts | limit 1
Explanation: Providing an empty string "" for the delimiter results in the same behavior as omitting the delimiter; the string is split by spaces.
Output:
| EVENT_ID | RAW_LOG_DATA | LOG_PARTS |
|---|---|---|
| 101 | User Alice logged in from 192.168.1.10 | ["User", "Alice", "logged", "in", "from", "192.168.1.10"] |
Example 4: Split on a delimiter not present in the string
Goal: Attempt to split a string using a delimiter that does not exist within that string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | alter no_split_example = split(event_description, "|") | fields event_id, event_description, no_split_example | limit 1
Explanation: The function returns an array containing the original string as its single element because the pipe (|) character is not present in the event_description.
Output:
| EVENT_ID | EVENT_DESCRIPTION | NO_SPLIT_EXAMPLE |
|---|---|---|
| 101 | User login successful | ["User login successful"] |
Example 5: Split on a field containing NULL values
Goal: Handle input fields that contain NULL values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 105 | alter split_null_domain = split(dst_domain, ".") | fields event_id, dst_domain, split_null_domain | limit 1
Explanation: When the input string field (for example, dst_domain for event ID 105) is NULL, the function returns an empty array.
Output:
| EVENT_ID | DST_DOMAIN | SPLIT_NULL_DOMAIN |
|---|---|---|
| 105 | NULL | [] |
Example 6: Combining split with arrayindex
Goal: Split a string and immediately extract a specific element from the resulting array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102) | alter ip_parts_array = split(ipv4_address, ".") | alter first_octet_string = arrayindex(ip_parts_array, 0) | fields event_id, ipv4_address, ip_parts_array, first_octet_string | limit 2
Explanation: The query first uses split() to tokenize the ipv4_address. Subsequently, arrayindex(..., 0) extracts the first element (the first octet) as a string.
Output:
| EVENT_ID | IPV4_ADDRESS | IP_PARTS_ARRAY | FIRST_OCTET_STRING |
|---|---|---|---|
| 101 | 192.168.1.10 | ["192", "168", "1", "10"] | 192 |
| 102 | 10.0.0.5 | ["10", "0", "0", "5"] | 10 |
Related articles
- Stages:
alter,filter - Functions:
arrayindex,to_string,arraystring - Datasets:
xdr_data
sqrt
Use the sqrt() function to calculate the square root of a numeric value.
Syntax
sqrt(<number>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The numeric value for which to calculate the square root. The value must be greater than or equal to 0. |
Returns
Type: float
Description: The sqrt() function returns the non-negative square root of the input value. If the input is null or negative, the function returns null or NaN.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The input
numbermust be greater than or equal to 0. The square root of a negative number is not a real number. - Negative Input: If the input is negative, the function returns
NaNornull. - Null Handling: If the input expression is
null, the function returnsnull. - Identity Values:
sqrt(0)returns0.0,sqrt(1)returns1.0. - Perfect Squares: For perfect squares (for example, 4, 9, 16, 25), the result is an exact integer value represented as a float.
- Relationship to power():
sqrt(x)is equivalent topower(x, 0.5). - Common Use Cases: This function is typically used within the
alterstage for distance calculations, standard deviation computations, normalization, and geometric formulas.
Examples
Example 1: Calculate square root of literal values
Goal: Calculate the square root for specific numeric literals to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = sqrt(4), result2 = sqrt(9), result3 = sqrt(2) | fields result1, result2, result3
Explanation: sqrt(4) returns 2.0, sqrt(9) returns 3.0, and sqrt(2) returns approximately 1.41421.
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 2.0 | 3.0 | 1.41421 |
Example 2: Calculate square root from a field value
Goal: Calculate the square root of values stored in a dataset field, filtering out negative values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter numeric_value >= 0 | alter sqrt_result = sqrt(numeric_value) | fields event_id, numeric_value, sqrt_result | limit 3
Explanation: This query first filters the dataset to ensure numeric_value contains only non-negative values, then computes the square root for each value using sqrt() in the alter stage.
Output:
| EVENT_ID | NUMERIC_VALUE | SQRT_RESULT |
|---|---|---|
| 101 | 4.0 | 2.0 |
| 102 | 100.0 | 10.0 |
| 103 | 25.0 | 5.0 |
Example 3: Calculate Euclidean distance using sqrt
Goal: Manually calculate the Euclidean distance between two 2D points using sqrt() and arithmetic functions.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter dx = subtract(numeric_value, 10) | alter dy = subtract(duration_seconds, 5) | alter distance = sqrt(add(multiply(dx, dx), multiply(dy, dy))) | fields event_id, numeric_value, duration_seconds, distance | limit 3
Explanation: This query calculates the Euclidean distance from each point (numeric_value, duration_seconds) to the reference point (10, 5) using the formula sqrt((x2-x1)� + (y2-y1)�).
Output:
| EVENT_ID | NUMERIC_VALUE | DURATION_SECONDS | DISTANCE |
|---|---|---|---|
| 101 | 4.0 | 1.5 | 7.28011 |
| 102 | 13.0 | 5.0 | 3.0 |
| 103 | 10.0 | 10.2 | 5.2 |
Related articles
- Stages:
alter,filter,fields,limit - Functions:
power(),cbrt(),euclidean_distance(),multiply() - Datasets:
xdr_data
stddev_population (comp)
Use the stddev_population() function to compute the population standard deviation of a specified numeric field across all rows in each group within the comp stage. Population standard deviation measures the spread of values when the data represents the entire population. This is equivalent to STDDEV_POP in SQL.
Syntax
| comp stddev_population(<field>) [by <group_field1>, <group_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric | Yes | The numeric field from which to compute the population standard deviation. |
group_field |
any | No | One or more fields to group the results by. If omitted, all rows are treated as a single group. |
alias |
string | No | An alias for the output field. If not specified, the output field name defaults to stddev_population_<field>. |
Returns
Type: numeric (float)
Description: The stddev_population() function returns the population standard deviation of the specified field within each group. Returns NULL if all values in the group are NULL. Returns 0 if there is only one non-NULL value.
Usage notes
- Population vs. sample: Use
stddev_population()when the data represents the entire population. Usestddev_sample()when the data is a sample from a larger population. - Formula: Population standard deviation is calculated as the square root of the population variance:
sqrt(sum((x - mean)^2) / N), where N is the number of non-NULL values. - Null handling: NULL values are ignored in the computation.
- Single value: If there is only one non-NULL value, the population standard deviation is 0.
- Data types: Only works with numeric fields.
Examples
Example 1: Standard deviation of response times per host
Goal: Compute the population standard deviation of response times for each host.
XQL code:
dataset = xdr_data | comp stddev_population(action_total_time) by agent_hostname as stddev_response
Explanation: The stddev_population() function computes the population standard deviation of action_total_time for each unique agent_hostname, measuring how spread out the response times are.
Output:
| AGENT_HOSTNAME | STDDEV_RESPONSE |
|---|---|
| workstation-1 | 12.45 |
| workstation-2 | 8.32 |
Example 2: Overall standard deviation of bytes transferred
Goal: Compute the population standard deviation of bytes transferred across all events.
XQL code:
dataset = xdr_data | comp stddev_population(action_network_bytes_received) as bytes_stddev
Explanation: Without a by clause, the stddev_population() function computes the population standard deviation across all rows.
Output:
| BYTES_STDDEV |
|---|
| 2456.78 |
Example 3: Compare standard deviation with mean
Goal: Compute both the mean and standard deviation to understand data distribution per host.
XQL code:
dataset = xdr_data | comp stddev_population(action_total_time) as stddev_time, avg(action_total_time) as avg_time by agent_hostname
Explanation: This query combines stddev_population() with avg() to provide both the average and the spread of response times per host, enabling coefficient of variation analysis.
Output:
| AGENT_HOSTNAME | STDDEV_TIME | AVG_TIME |
|---|---|---|
| workstation-1 | 12.45 | 45.30 |
| workstation-2 | 8.32 | 32.10 |
Related articles
- Stages:
comp,fields,limit - Functions:
stddev_sample(),stddev_population (windowcomp),avg(),var() - Datasets:
xdr_data
stddev_population (windowcomp)
Use the stddev_population() function within the windowcomp stage to compute the population standard deviation of a specified numeric field over a window of rows. Unlike the comp stage version, the windowcomp version preserves all original rows and adds the computed standard deviation as a new field. This is equivalent to STDDEV_POP() OVER(...) in SQL.
Syntax
| windowcomp stddev_population(<field>) [by <partition_field1>, <partition_field2>, ...] [sort [asc|desc] <sort_field1>, ...] [between <lower> [and <upper>] [frame_type=rows|range]] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric | Yes | The numeric field from which to compute the population standard deviation. |
partition_field |
any | No | One or more fields to partition the data by (equivalent to SQL PARTITION BY). |
sort_field |
any | No | One or more fields to define the order within each partition (equivalent to SQL ORDER BY). Defaults to ascending. |
lower |
integer or null |
No | Lower bound of the window frame. 0 = current row, negative = rows before, null = unbounded. |
upper |
integer or null |
No | Upper bound of the window frame. 0 = current row, positive = rows after, null = unbounded. |
frame_type |
rows or range |
No | Type of window frame. rows (default) uses physical row offsets; range uses value-based offsets on the sort field. |
alias |
string | No | An alias for the output field. |
Returns
Type: numeric (float)
Description: The stddev_population() function returns the population standard deviation within the defined window for each row. All original rows are preserved.
Usage notes
- Row preservation: Unlike
comp stddev_population(), thewindowcompversion does not reduce the number of rows. - Default frame: If no window frame is specified, the default frame is from the start of the partition to the current row (
between null and 0). - Null handling: NULL values are ignored in the computation.
- Running standard deviation: Can be combined with
sortto compute a running population standard deviation. - Population vs. sample: Use
stddev_population()for the entire population; usestddev_sample()for a sample.
Examples
Example 1: Population standard deviation per host (all rows preserved)
Goal: Compute the population standard deviation of response times for each host while preserving all rows.
XQL code:
dataset = xdr_data | windowcomp stddev_population(action_total_time) by agent_hostname as stddev_per_host
Explanation: The stddev_population() function computes the population standard deviation of action_total_time within each agent_hostname partition. All original rows are preserved.
Output:
| _TIME | AGENT_HOSTNAME | ACTION_TOTAL_TIME | STDDEV_PER_HOST |
|---|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | 50 | 16.33 |
| 2024-01-15 09:00:00 | workstation-1 | 30 | 16.33 |
| 2024-01-15 10:00:00 | workstation-1 | 70 | 16.33 |
| 2024-01-15 08:30:00 | workstation-2 | 40 | 5.00 |
| 2024-01-15 09:30:00 | workstation-2 | 50 | 5.00 |
Example 2: Running standard deviation over time
Goal: Compute a running population standard deviation of bytes received, ordered by time.
XQL code:
dataset = xdr_data | windowcomp stddev_population(action_network_bytes_received) sort asc _time as running_stddev
Explanation: By sorting on _time, the function computes a running population standard deviation from the start of the dataset up to the current row.
Output:
| _TIME | ACTION_NETWORK_BYTES_RECEIVED | RUNNING_STDDEV |
|---|---|---|
| 2024-01-15 08:00:00 | 500 | 0.00 |
| 2024-01-15 09:00:00 | 250 | 125.00 |
| 2024-01-15 10:00:00 | 400 | 102.14 |
| 2024-01-15 11:00:00 | 100 | 147.90 |
Example 3: Standard deviation within a sliding window
Goal: Compute the population standard deviation within a sliding window of 5 rows.
XQL code:
dataset = xdr_data | windowcomp stddev_population(action_total_time) sort asc _time between -2 and 2 as sliding_stddev
Explanation: The between -2 and 2 clause defines a sliding window of up to 5 rows centered on the current row. The function computes the population standard deviation within that window.
Output:
| _TIME | ACTION_TOTAL_TIME | SLIDING_STDDEV |
|---|---|---|
| 2024-01-15 08:00:00 | 50 | 12.47 |
| 2024-01-15 09:00:00 | 30 | 14.79 |
| 2024-01-15 10:00:00 | 70 | 16.33 |
| 2024-01-15 11:00:00 | 40 | 14.14 |
Related articles
- Stages:
windowcomp,comp,sort - Functions:
stddev_population (comp),stddev_sample(),avg() - Datasets:
xdr_data
stddev_sample (comp)
Use the stddev_sample() function to compute the sample standard deviation of a specified numeric field across all rows in each group within the comp stage. Sample standard deviation uses Bessel's correction (dividing by N-1 instead of N) and is appropriate when the data represents a sample from a larger population. This is equivalent to STDDEV_SAMP in SQL.
Syntax
| comp stddev_sample(<field>) [by <group_field1>, <group_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric | Yes | The numeric field from which to compute the sample standard deviation. |
group_field |
any | No | One or more fields to group the results by. If omitted, all rows are treated as a single group. |
alias |
string | No | An alias for the output field. If not specified, the output field name defaults to stddev_sample_<field>. |
Returns
Type: numeric (float)
Description: The stddev_sample() function returns the sample standard deviation of the specified field within each group. Returns NULL if there are fewer than two non-NULL values in the group.
Usage notes
- Sample vs. population: Use
stddev_sample()when the data is a sample from a larger population. Usestddev_population()when the data represents the entire population. - Formula: Sample standard deviation is calculated as:
sqrt(sum((x - mean)^2) / (N - 1)), where N is the number of non-NULL values (Bessel's correction). - Minimum values: Requires at least two non-NULL values to produce a result. Returns NULL for groups with fewer than two values.
- Null handling: NULL values are ignored in the computation.
- Data types: Only works with numeric fields.
Examples
Example 1: Sample standard deviation of response times per host
Goal: Compute the sample standard deviation of response times for each host.
XQL code:
dataset = xdr_data | comp stddev_sample(action_total_time) by agent_hostname as sample_stddev
Explanation: The stddev_sample() function computes the sample standard deviation of action_total_time for each unique agent_hostname, using Bessel's correction for unbiased estimation.
Output:
| AGENT_HOSTNAME | SAMPLE_STDDEV |
|---|---|
| workstation-1 | 14.42 |
| workstation-2 | 9.62 |
Example 2: Overall sample standard deviation
Goal: Compute the sample standard deviation of bytes transferred across all events.
XQL code:
dataset = xdr_data | comp stddev_sample(action_network_bytes_received) as bytes_sample_stddev
Explanation: Without a by clause, the stddev_sample() function computes the sample standard deviation across all rows.
Output:
| BYTES_SAMPLE_STDDEV |
|---|
| 2678.91 |
Example 3: Compare population and sample standard deviations
Goal: Compare population and sample standard deviations to understand the effect of Bessel's correction.
XQL code:
dataset = xdr_data | comp stddev_sample(action_total_time) as sample_std, stddev_population(action_total_time) as pop_std, count(action_total_time) as n by agent_hostname
Explanation: This query computes both stddev_sample() and stddev_population() alongside the count, showing how the sample standard deviation is slightly larger due to Bessel's correction (dividing by N-1 instead of N).
Output:
| AGENT_HOSTNAME | SAMPLE_STD | POP_STD | N |
|---|---|---|---|
| workstation-1 | 14.42 | 12.45 | 5 |
| workstation-2 | 9.62 | 8.32 | 4 |
Related articles
- Stages:
comp,fields,limit - Functions:
stddev_population(),stddev_sample (windowcomp),avg(),var() - Datasets:
xdr_data
stddev_sample (windowcomp)
Use the stddev_sample() function within the windowcomp stage to compute the sample standard deviation of a specified numeric field over a window of rows. Unlike the comp stage version, the windowcomp version preserves all original rows and adds the computed sample standard deviation as a new field. This is equivalent to STDDEV_SAMP() OVER(...) in SQL.
Syntax
| windowcomp stddev_sample(<field>) [by <partition_field1>, <partition_field2>, ...] [sort [asc|desc] <sort_field1>, ...] [between <lower> [and <upper>] [frame_type=rows|range]] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric | Yes | The numeric field from which to compute the sample standard deviation. |
partition_field |
any | No | One or more fields to partition the data by (equivalent to SQL PARTITION BY). |
sort_field |
any | No | One or more fields to define the order within each partition (equivalent to SQL ORDER BY). Defaults to ascending. |
lower |
integer or null |
No | Lower bound of the window frame. 0 = current row, negative = rows before, null = unbounded. |
upper |
integer or null |
No | Upper bound of the window frame. 0 = current row, positive = rows after, null = unbounded. |
frame_type |
rows or range |
No | Type of window frame. rows (default) uses physical row offsets; range uses value-based offsets on the sort field. |
alias |
string | No | An alias for the output field. |
Returns
Type: numeric (float)
Description: The stddev_sample() function returns the sample standard deviation (using Bessel's correction, N-1) within the defined window for each row. All original rows are preserved. Returns NULL when the window contains fewer than two non-NULL values.
Usage notes
- Row preservation: Unlike
comp stddev_sample(), thewindowcompversion does not reduce the number of rows. - Bessel's correction: Uses N-1 in the denominator for unbiased estimation from a sample.
- Default frame: If no window frame is specified, the default frame is from the start of the partition to the current row (
between null and 0). - Null handling: NULL values are ignored in the computation.
- Minimum values: Requires at least two non-NULL values in the window to produce a result.
- Running standard deviation: Can be combined with
sortto compute a running sample standard deviation.
Examples
Example 1: Sample standard deviation per host (all rows preserved)
Goal: Compute the sample standard deviation of response times for each host while preserving all rows.
XQL code:
dataset = xdr_data | windowcomp stddev_sample(action_total_time) by agent_hostname as sample_stddev_per_host
Explanation: The stddev_sample() function computes the sample standard deviation of action_total_time within each agent_hostname partition using Bessel's correction. All original rows are preserved.
Output:
| _TIME | AGENT_HOSTNAME | ACTION_TOTAL_TIME | SAMPLE_STDDEV_PER_HOST |
|---|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | 50 | 20.00 |
| 2024-01-15 09:00:00 | workstation-1 | 30 | 20.00 |
| 2024-01-15 10:00:00 | workstation-1 | 70 | 20.00 |
| 2024-01-15 08:30:00 | workstation-2 | 40 | 7.07 |
| 2024-01-15 09:30:00 | workstation-2 | 50 | 7.07 |
Example 2: Running sample standard deviation over time
Goal: Compute a running sample standard deviation of bytes received, ordered by time.
XQL code:
dataset = xdr_data | windowcomp stddev_sample(action_network_bytes_received) sort asc _time as running_sample_stddev
Explanation: By sorting on _time, the function computes a running sample standard deviation from the start of the dataset up to the current row. The first row returns NULL because at least two values are needed.
Output:
| _TIME | ACTION_NETWORK_BYTES_RECEIVED | RUNNING_SAMPLE_STDDEV |
|---|---|---|
| 2024-01-15 08:00:00 | 500 | null |
| 2024-01-15 09:00:00 | 250 | 176.78 |
| 2024-01-15 10:00:00 | 400 | 125.83 |
| 2024-01-15 11:00:00 | 100 | 170.78 |
Example 3: Sample standard deviation within a sliding window
Goal: Compute the sample standard deviation within a sliding window of 3 rows.
XQL code:
dataset = xdr_data | windowcomp stddev_sample(action_total_time) sort asc _time between -1 and 1 as sliding_sample_stddev
Explanation: The between -1 and 1 clause defines a sliding window of up to 3 rows centered on the current row. The function computes the sample standard deviation within that window using Bessel's correction.
Output:
| _TIME | ACTION_TOTAL_TIME | SLIDING_SAMPLE_STDDEV |
|---|---|---|
| 2024-01-15 08:00:00 | 50 | 14.14 |
| 2024-01-15 09:00:00 | 30 | 20.00 |
| 2024-01-15 10:00:00 | 70 | 20.82 |
| 2024-01-15 11:00:00 | 40 | 21.21 |
Related articles
- Stages:
windowcomp,comp,sort - Functions:
stddev_sample (comp),stddev_population(),avg() - Datasets:
xdr_data
string_count
Use the string_count() function to count the number of times a specified substring (pattern) appears within a given string.
Syntax
string_count (<string>, <pattern>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The input string field or literal value in which you want to search. |
pattern |
string | Yes | The substring literal that you want to count. |
Returns
The string_count() function returns an integer representing the number of occurrences found.
Usage notes
- By default, XQL queries operate with case-sensitivity unless
config case_sensitive = falseis explicitly set. This also applies tostring_count(). - If the input
stringvalue isNULL, thestring_count()function will returnNULL. - If the
patterndoes not appear in thestring, the function returns0.
Examples
Example 1: Counting occurrences of a specific character in a string field
Goal: Count the occurrences of the character 'o' in the event_description field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102, 103) // Focus on relevant records from sample_xql_raw | alter count_of_o = string_count(event_description, "o") // Counts occurrences of 'o' | fields event_id, event_description, count_of_o
Explanation: The query counts how many times the character 'o' appears in the event_description for each specified event.
Output:
| EVENT_ID | EVENT_DESCRIPTION | COUNT_OF_O |
|---|---|---|
| 101 | "User login successful" | 1 |
| 102 | "File access attempt" | 0 |
| 103 | "Network connection established" | 3 |
Example 2: Counting occurrences of a substring (word) in a string field
Goal: Count the occurrences of the word "access" in the raw_log_data field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102) // Focus on relevant records | alter count_of_access = string_count(raw_log_data, "access") // Counts occurrences of 'access' | fields event_id, raw_log_data, count_of_access
Explanation: The string_count() function correctly identifies and counts the single occurrence of "access" in event ID 102's raw_log_data.
Output:
| EVENT_ID | RAW_LOG_DATA | COUNT_OF_ACCESS |
|---|---|---|
| 101 | "User Alice logged in from 192.168.1.10" | 0 |
| 102 | "Process cmd.exe attempted to access /etc/passwd" | 1 |
Example 3: Counting delimiters in an IP address string
Goal: Count the number of dot (.) delimiters within ipv4_address strings.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102) // Focus on relevant records | alter count_of_dots = string_count(ipv4_address, ".") // Counts occurrences of '.' | fields event_id, ipv4_address, count_of_dots
Explanation: The query accurately counts the three dot separators in each IPv4 address string.
Output:
| EVENT_ID | IPV4_ADDRESS | COUNT_OF_DOTS |
|---|---|---|
| 101 | "192.168.1.10" | 3 |
| 102 | "10.0.0.5" | 3 |
Example 4: Case-insensitive counting (default behavior)
Goal: Demonstrate string_count()'s default case-sensitive behavior by searching for "user" (lowercase) in a field containing "User" (uppercase).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 // Focus on a single record | alter count_user_lowercase_search = string_count(raw_log_data, "user") // Searches for 'user' | fields event_id, raw_log_data, count_user_lowercase_search
Explanation: The pattern "user" (lowercase) does not successfully match "User" in the raw_log_data due to the case-sensitive behavior of XQL.
Output:
| EVENT_ID | RAW_LOG_DATA | COUNT_USER_LOWERCASE_SEARCH |
|---|---|---|
| 101 | "User Alice logged in from 192.168.1.10" | 0 |
Example 5: Case-sensitive counting (with config case_sensitive = false)
Goal: Explicitly set case sensitivity to false to show how it affects string_count() results when searching for "user" vs. "User".
XQL code:
config case_sensitive = false // Explicitly enable case in-sensitivity | dataset = sample_xql_raw | filter event_id = 101 // Focus on a single record | alter count_User_uppercase_search = string_count(raw_log_data, "User") // Searches for 'User' | alter count_user_lowercase_search = string_count(raw_log_data, "user") // Searches for 'user' | fields event_id, raw_log_data, count_User_uppercase_search, count_user_lowercase_search
Explanation: When config case_sensitive is false, string_count() does not distinguish between "User" and "user", returning 1 for both cases.
Output:
| EVENT_ID | RAW_LOG_DATA | COUNT_USER_UPPERCASE_SEARCH | COUNT_USER_LOWERCASE_SEARCH |
|---|---|---|---|
| 101 | "User Alice logged in from 192.168.1.10" | 1 | 1 |
Example 6: Counting a pattern not present in the string
Goal: Demonstrate the result when the specified pattern does not exist in the input string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 // Focus on a single record | alter count_of_nonexistent_pattern = string_count(event_description, "nonexistent_word") // Searches for a non-existent word | fields event_id, event_description, count_of_nonexistent_pattern
Explanation: As expected, string_count() returns 0 when the nonexistent_word pattern is not found in the event_description.
Output:
| EVENT_ID | EVENT_DESCRIPTION | COUNT_OF_NONEXISTENT_PATTERN |
|---|---|---|
| 101 | "User login successful" | 0 |
Example 7: Handling NULL input string
Goal: Show how string_count() behaves when the input string field contains a NULL value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter count_in_null_domain = string_count(dst_domain, ".") // Attempts to count in a NULL domain | fields event_id, dst_domain, count_in_null_domain | filter event_id = 105 // Focus on record with NULL dst_domain
Explanation: Consistent with XQL function behavior, if the input string (dst_domain for event ID 105) is NULL, the string_count() function returns NULL.
Output:
| EVENT_ID | DST_DOMAIN | COUNT_IN_NULL_DOMAIN |
|---|---|---|
| 105 | NULL | NULL |
Related articles
subtract
Use the subtract() function to calculate the difference between two numbers by subtracting the second argument from the first.
Syntax
subtract (<value_1>, <value_2>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
value_1 |
integer, float, string | Yes | The first value (the minuend). |
value_2 |
integer, float, string | Yes | The second value (the subtrahend) to subtract from the first. |
Returns
The subtract() function returns the numerical difference between the two input numbers.
Usage notes
- The function accepts numeric literals, floating-point numbers, and integers.
- The function supports integers or numbers provided as a string type (for example, extracted from a data field).
Examples
Example 1: Subtracting an integer literal from an integer field
Goal: Subtract a specific integer literal from an existing integer field to create a new field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter reduced_event_id = subtract(event_id, 5) | fields event_id, reduced_event_id | limit 3
Explanation: This query calculates reduced_event_id by subtracting 5 from each event_id. For event_id 101, the result is 96.
Output:
| EVENT_ID | REDUCED_EVENT_ID |
|---|---|
| 101 | 96 |
| 102 | 97 |
| 103 | 98 |
Example 2: Subtracting a floating-point literal from a floating-point field
Goal: Subtract a floating-point literal from an existing floating-point field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter adjusted_duration = subtract(duration_seconds, 0.75) | fields event_id, duration_seconds, adjusted_duration | limit 3
Explanation: Here, duration_seconds (which contains decimal values like 1.5 and 0.8) is decreased by 0.75, producing new floating-point values in adjusted_duration.
Output:
| EVENT_ID | DURATION_SECONDS | ADJUSTED_DURATION |
|---|---|---|
| 101 | 1.5 | 0.75 |
| 102 | 0.8 | 0.05 |
| 103 | 10.2 | 9.45 |
Example 3: Subtracting one field from another field
Goal: Calculate the difference between values in two different fields.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter difference_in_ids = subtract(event_id, arrayindex(numeric_codes, 0)) | fields event_id, numeric_codes, difference_in_ids | limit 3
Explanation: For event_id 101, event_id is 101 and the first element of numeric_codes (index 0) is 13, resulting in 101 - 13 = 88. For event_id 102, event_id is 102 and the first numeric_code is -21, so 102 - (-21) = 123.
Output:
| EVENT_ID | NUMERIC_CODES | DIFFERENCE_IN_IDS |
|---|---|---|
| 101 | [13, -47, 29,...] | 88 |
| 102 | [-21, 56, 13,...] | 123 |
| 103 | [90, -33, 7,...] | 13 |
Example 4: Handling negative numbers (subtracting a negative literal)
Goal: Demonstrate the behavior when subtracting a negative number.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter negative_subtraction = subtract(duration_seconds, -2.0) | fields event_id, duration_seconds, negative_subtraction | limit 3
Explanation: For event_id 101, duration_seconds is 1.5. Subtracting -2.0 (which is equivalent to adding 2.0) results in 3.5. This aligns with the understanding that the subtract() function supports operations with negative numbers.
Output:
| EVENT_ID | DURATION_SECONDS | NEGATIVE_SUBTRACTION |
|---|---|---|
| 101 | 1.5 | 3.5 |
| 102 | 0.8 | 2.8 |
| 103 | 10.2 | 12.2 |
Example 5: Subtracting a numeric value extracted from JSON data
Goal: Extract a number from a JSON field and perform a subtraction operation on it.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter simple_json_data != null | alter json_code_number = to_number(simple_json_data -> "code") | alter reduced_json_value = subtract(json_code_number, 50) | fields event_id, simple_json_data, json_code_number, reduced_json_value | limit 3
Explanation: This query extracts the code value (for example, "200") from the simple_json_data field as a string, converts it to a number using to_number(), and then subtracts 50 from it. Note that only event_id 101 has a "code" field in simple_json_data in the sample_xql_raw dataset.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | JSON_CODE_NUMBER | REDUCED_JSON_VALUE |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | 200 | 150 |
Related articles
- Stages:
alter - Functions:
arrayindex,to_number
sum (comp)
Use the sum() function to compute the sum of all values of a specified numeric field across all rows in each group within the comp stage. This is equivalent to the SQL SUM aggregate function.
Syntax
| comp sum(<field>) [by <group_field1>, <group_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric | Yes | The numeric field whose values will be summed. |
group_field |
any | No | One or more fields to group the results by. If omitted, all rows are treated as a single group. |
alias |
string | No | An alias for the output field. If not specified, the output field name defaults to sum_<field>. |
Returns
Type: numeric
Description: The sum() function returns the total sum of all non-NULL values of the specified field within each group. Returns NULL if all values in the group are NULL. Returns 0 if the group is empty.
Usage notes
- Data types: The
sumfunction only works with numeric fields. - Null handling: NULL values are ignored in the computation.
- No grouping: When used without a
byclause, the function returns the sum across all rows. - Multiple aggregations: Can be combined with other aggregation functions in the same
compstage. - Overflow: For very large datasets with large values, be aware of potential numeric overflow.
Examples
Example 1: Total bytes sent per host
Goal: Compute the total bytes sent for each host.
XQL code:
dataset = xdr_data | comp sum(bytes_sent) by agent_hostname as total_bytes_sent
Explanation: The sum() function adds up all bytes_sent values for each unique agent_hostname, returning the total bytes sent per host.
Output:
| AGENT_HOSTNAME | TOTAL_BYTES_SENT |
|---|---|
| workstation-1 | 1048576 |
| workstation-2 | 524288 |
Example 2: Total events across all data
Goal: Compute the total sum of alert severities across all events.
XQL code:
dataset = xdr_data | comp sum(alert_severity) as total_severity
Explanation: Without a by clause, the sum() function computes the total of all alert_severity values across the entire dataset.
Output:
| TOTAL_SEVERITY |
|---|
| 342 |
Example 3: Sum with multiple aggregations
Goal: Compute total bytes sent and received along with event count per host.
XQL code:
dataset = xdr_data | comp sum(bytes_sent) as total_sent, sum(action_network_bytes_received) as total_received, count(*) as event_count by agent_hostname
Explanation: This query combines multiple sum() calls with count() in a single comp stage to provide a comprehensive traffic summary per host.
Output:
| AGENT_HOSTNAME | TOTAL_SENT | TOTAL_RECEIVED | EVENT_COUNT |
|---|---|---|---|
| workstation-1 | 1048576 | 2097152 | 150 |
| workstation-2 | 524288 | 1048576 | 85 |
Related articles
sum (windowcomp)
Use the sum() function within the windowcomp stage to compute the sum of a specified numeric field over a window of rows. Unlike the comp stage version, the windowcomp version preserves all original rows and adds the computed sum as a new field. This is equivalent to SUM() OVER(...) in SQL.
Syntax
| windowcomp sum(<field>) [by <partition_field1>, <partition_field2>, ...] [sort [asc|desc] <sort_field1>, ...] [between <lower> [and <upper>] [frame_type=rows|range]] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric | Yes | The numeric field whose values will be summed over the window. |
partition_field |
any | No | One or more fields to partition the data by (equivalent to SQL PARTITION BY). |
sort_field |
any | No | One or more fields to define the order within each partition (equivalent to SQL ORDER BY). Defaults to ascending. |
lower |
integer or null |
No | Lower bound of the window frame. 0 = current row, negative = rows before, null = unbounded. |
upper |
integer or null |
No | Upper bound of the window frame. 0 = current row, positive = rows after, null = unbounded. |
frame_type |
rows or range |
No | Type of window frame. rows (default) uses physical row offsets; range uses value-based offsets on the sort field. |
alias |
string | No | An alias for the output field. |
Returns
Type: numeric
Description: The sum() function returns the sum of all non-NULL values within the defined window for each row. All original rows are preserved.
Usage notes
- Row preservation: Unlike
comp sum(), thewindowcomp sum()does not reduce the number of rows. Each row retains its original data and gets an additional field with the window sum. - Running total: When combined with
sort, the default frame (between null and 0) produces a cumulative running total. - No partitioning: If no
byclause is specified, the window spans the entire result set. - Default frame: If no window frame is specified, the default frame is from the start of the partition to the current row (
between null and 0). - Null handling: NULL values are ignored in the computation.
Examples
Example 1: Cumulative bytes sent over time
Goal: Compute a running total of bytes sent, ordered by time.
XQL code:
dataset = xdr_data | windowcomp sum(bytes_sent) sort asc _time as cumulative_bytes
Explanation: By sorting on _time in ascending order, the sum() function computes a cumulative running total of bytes_sent from the start of the dataset up to the current row.
Output:
| _TIME | BYTES_SENT | CUMULATIVE_BYTES |
|---|---|---|
| 2024-01-15 08:00:00 | 100 | 100 |
| 2024-01-15 09:00:00 | 250 | 350 |
| 2024-01-15 10:00:00 | 150 | 500 |
| 2024-01-15 11:00:00 | 300 | 800 |
Example 2: Total bytes per host (all rows preserved)
Goal: Compute the total bytes sent per host while preserving all original rows.
XQL code:
dataset = xdr_data | windowcomp sum(bytes_sent) by agent_hostname as total_bytes_per_host
Explanation: The sum() function computes the total bytes_sent within each agent_hostname partition. All original rows are preserved, and each row receives the partition's total.
Output:
| _TIME | AGENT_HOSTNAME | BYTES_SENT | TOTAL_BYTES_PER_HOST |
|---|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | 100 | 500 |
| 2024-01-15 09:00:00 | workstation-1 | 250 | 500 |
| 2024-01-15 10:00:00 | workstation-1 | 150 | 500 |
| 2024-01-15 08:30:00 | workstation-2 | 300 | 700 |
| 2024-01-15 09:30:00 | workstation-2 | 400 | 700 |
Example 3: Moving sum within a sliding window
Goal: Compute the sum of bytes sent within a sliding window of 3 rows.
XQL code:
dataset = xdr_data | windowcomp sum(bytes_sent) sort asc _time between -1 and 1 as moving_sum
Explanation: The between -1 and 1 clause defines a sliding window of 3 rows centered on the current row. The sum() function returns the total bytes_sent within that window for each row.
Output:
| _TIME | BYTES_SENT | MOVING_SUM |
|---|---|---|
| 2024-01-15 08:00:00 | 100 | 350 |
| 2024-01-15 09:00:00 | 250 | 500 |
| 2024-01-15 10:00:00 | 150 | 700 |
| 2024-01-15 11:00:00 | 300 | 450 |
Related articles
- Stages:
windowcomp,comp,sort - Functions:
sum (comp),count(),avg() - Datasets:
xdr_data
tan
Use the tan() function to calculate the tangent of a numeric value specified in radians.
Syntax
tan(<numeric_expression>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
numeric_expression |
integer, float | Yes | The angle in radians for which to calculate the tangent. Any real number is valid, though the tangent is undefined at odd multiples of p/2. |
Returns
Type: float
Description: The tan() function returns the tangent of the input angle. The result can be any real number. If the input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Valid Input Range: The
tan()function accepts any real number as input. The input is interpreted as an angle in radians. - Undefined Values: At odd multiples of p/2 (for example, p/2, 3p/2), the tangent is mathematically undefined and the function may return a very large number,
infinity, orNaN. - Null Handling: If the input expression is
null, the function returnsnull. - Degrees to Radians: If your input is in degrees, convert it to radians first by multiplying by
PI() / 180. - Periodicity: The tangent function is periodic with period p, meaning
tan(x) = tan(x + p). - Key Values:
tan(0)returns0.0,tan(p/4)returns1.0,tan(p)returns0.0. - Symmetry: The function is odd, meaning
tan(-x) = -tan(x). - Common Use Cases: This function is typically used within the
alterstage for trigonometric calculations, slope computations, angle analysis, and engineering formulas.
Examples
Example 1: Calculate tangent of literal values
Goal: Calculate the tangent for specific radian values to verify known mathematical results.
XQL code:
dataset = xdr_data | limit 1 | alter result1 = tan(0), result2 = tan(divide(pi(), 4)), result3 = tan(pi()) | fields result1, result2, result3
Explanation: tan(0) returns 0.0, tan(p/4) returns 1.0 (since sine and cosine are equal at p/4), and tan(p) returns approximately 0.0.
Output:
| RESULT1 | RESULT2 | RESULT3 |
|---|---|---|
| 0.0 | 1.0 | 0.0 |
Example 2: Calculate tangent from a field value
Goal: Calculate the tangent of values stored in a dataset field, treating them as angles in radians.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter tan_val = tan(numeric_value) | fields event_id, numeric_value, tan_val | limit 3
Explanation: This query computes the tangent for each value in the numeric_value field and stores the result in tan_val. Since tan() accepts any real number, no filtering is needed.
Output:
| EVENT_ID | NUMERIC_VALUE | TAN_VAL |
|---|---|---|
| 101 | 0.0 | 0.0 |
| 102 | 0.7854 | 1.0 |
| 103 | 1.0 | 1.55741 |
Example 3: Calculate slope angle from rise and run
Goal: Use the tangent function to verify a slope calculation by computing tan(atan(rise/run)).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter duration_seconds > 0 | alter slope = divide(numeric_value, duration_seconds) | alter angle = atan(slope) | alter tan_angle = tan(angle) | fields event_id, numeric_value, duration_seconds, slope, tan_angle | limit 3
Explanation: This query calculates the slope as numeric_value / duration_seconds, then computes the angle using atan(), and finally verifies by computing tan() of that angle. The tan_angle should match the original slope, confirming the identity tan(atan(x)) = x.
Output:
| EVENT_ID | NUMERIC_VALUE | DURATION_SECONDS | SLOPE | TAN_ANGLE |
|---|---|---|---|---|
| 101 | 3.0 | 4.0 | 0.75 | 0.75 |
| 102 | 5.0 | 1.0 | 5.0 | 5.0 |
| 103 | 10.0 | 10.0 | 1.0 | 1.0 |
Related articles
time_frame_end
Use the time_frame_end() function to return the timestamp object that represents the end of the time frame configured for the overall XQL query.
Syntax
time_frame_end()
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| None | N/A | No | This function does not require any input parameters. The function inherits the time frame from the config timeframe stage. |
Returns
The time_frame_end() function returns a TIMESTAMP object representing the end of the query's time range.
Usage notes
- The function returns the timestamp object in the format
MMM dd YYYY HH:mm:ss(for example,Jun 8th 2022 15:20:06). - The value returned directly corresponds to the end of the time range set by the
config timeframestage of the query. - You can configure the time frame using the
config timeframestage, where the range can be relative or exact. - If the
config timeframeis set to a relative time (for example,last 24Horbetween "-1h" and "now"),time_frame_end()returns thecurrent_time()at the moment the query is executed. - This function is useful when the query uses a custom time frame whose end time is in the past.
Examples
Example 1: With a relative timeframe (last N units)
Goal: Capture the end time of the query when using a relative timeframe (for example, last 2 hours).
XQL code:
config timeframe = 2h // Sets the query timeframe to the last 2 hours from execution | dataset = sample_xql_raw | alter query_end_time = time_frame_end() // Captures the end of the query timeframe | fields event_id, query_end_time | limit 3
Explanation: The config timeframe = 2h specifies that the query should run for the last two hours from the moment it is executed, and because this is a relative timeframe, time_frame_end() returns the current_time at the moment of query execution.
Output:
| EVENT_ID | QUERY_END_TIME |
|---|---|
| 101 | Oct 26th 2023 12:00:00 |
| 102 | Oct 26th 2023 12:00:00 |
| 103 | Oct 26th 2023 12:00:00 |
Example 2: With a relative timeframe (between relative start and "now")
Goal: Capture the end time of the query when using a relative timeframe ending in "now".
XQL code:
config timeframe between "-1h" and "now" // Sets the timeframe from 1 hour ago until now | dataset = sample_xql_raw | alter query_end_time = time_frame_end() // Captures the end of the query timeframe | fields event_id, query_end_time | limit 3
Explanation: Similar to Example 1, the use of "now" in the config timeframe means that time_frame_end() returns the current_time at the point of query execution. The resulting query_end_time reflects this execution time.
Output:
| EVENT_ID | QUERY_END_TIME |
|---|---|
| 101 | Oct 26th 2023 12:00:00 |
| 102 | Oct 26th 2023 12:00:00 |
| 103 | Oct 26th 2023 12:00:00 |
Example 3: With an exact timeframe
Goal: Capture the end time of the query when using a precise, static start and end time.
XQL code:
config timeframe between "2023-10-26 09:00:00 UTC" and "2023-10-26 11:00:00 UTC" // Defines an exact timeframe | dataset = sample_xql_raw | alter query_end_time = time_frame_end() // Captures the end of the query's timeframe | fields event_id, query_end_time | limit 3
Explanation: When an exact timeframe is configured, time_frame_end() directly returns the explicitly defined end timestamp from the config timeframe. In this case, it returns the timestamp for 11:00:00 UTC on October 26th, 2023.
Output:
| EVENT_ID | QUERY_END_TIME |
|---|---|
| 101 | Oct 26th 2023 11:00:00 |
| 102 | Oct 26th 2023 11:00:00 |
| 103 | Oct 26th 2023 11:00:00 |
Related articles
- Stages:
alter,config,fields - Functions:
current_time,timestamp_diff - Datasets:
xdr_data
timestamp_diff
Use the timestamp_diff() function to calculate the numerical difference between two timestamps in a specified unit.
Syntax
timestamp_diff (<timestamp1>, <timestamp2>, <part>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
timestamp1 |
timestamp | Yes | The first timestamp object in the comparison. |
timestamp2 |
timestamp | Yes | The second timestamp object, which is subtracted from the first. |
part |
string | Yes | The unit in which the difference is expressed. Supported values are DAY, HOUR, MINUTE, SECOND, MILLISECOND, and MICROSECOND. |
Returns
The timestamp_diff() function returns a numerical value (integer or float) representing the difference between the two timestamps in the specified unit.
Usage notes
- The function calculates the difference by subtracting
timestamp2fromtimestamp1. - If
timestamp1is chronologically greater (later) thantimestamp2, the function returns a positive value. - If
timestamp1is chronologically less (earlier) thantimestamp2, the function returns a negative value. - If the calculated difference in the specified unit results in a fractional value between 0 and 1 (exclusive of 1, inclusive of 0), the function returns 0.
- Supported values for the
partparameter include:DAY,HOUR,MINUTE,SECOND,MILLISECOND, andMICROSECOND.
Examples
Example 1: Difference in seconds between current_time() and_time
Goal: Calculate the difference in seconds between the current query execution time and the event's timestamp.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter current_ts = current_time() | alter event_ts = _time | alter diff_in_seconds = timestamp_diff(current_ts, event_ts, "SECOND") | fields event_id, event_ts, current_ts, diff_in_seconds | limit 3
Explanation: The query computes the number of full seconds that have passed between the event's _time and the current_time() of the query execution.
Output:
| EVENT_ID | EVENT_TS | CURRENT_TS | DIFF_IN_SECONDS |
|---|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | Oct 26th 2023 12:00:00 | 7200 |
| 102 | Oct 26th 2023 10:05:30 | Oct 26th 2023 12:00:00 | 6870 |
| 103 | Oct 26th 2023 10:15:15 | Oct 26th 2023 12:00:00 | 6285 |
Example 2: Difference in minutes between _time and a static timestamp
Goal: Calculate the difference in minutes between the event timestamp and a specific static timestamp, demonstrating truncation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_ts = _time | alter static_past_ts = parse_timestamp("%Y-%m-%d %H:%M:%S", "2023-10-26 10:05:00") | alter diff_in_minutes = timestamp_diff(event_ts, static_past_ts, "MINUTE") | fields event_id, event_ts, static_past_ts, diff_in_minutes | limit 3
Explanation: The query calculates the difference in minutes. Note that partial minutes (values between 0 and 1) are truncated to 0.
Output:
| EVENT_ID | EVENT_TS | STATIC_PAST_TS | DIFF_IN_MINUTES |
|---|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | Oct 26th 2023 10:05:00 | -5 |
| 102 | Oct 26th 2023 10:05:30 | Oct 26th 2023 10:05:00 | 0 |
| 103 | Oct 26th 2023 10:15:15 | Oct 26th 2023 10:05:00 | 10 |
Example 3: Difference in hours, yielding a negative result
Goal: Calculate the difference in hours where the first timestamp is earlier than the second, resulting in a negative value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_ts = _time | alter static_future_ts = parse_timestamp("%Y-%m-%d %H:%M:%S", "2023-10-27 10:00:00") | alter diff_in_hours = timestamp_diff(event_ts, static_future_ts, "HOUR") | fields event_id, event_ts, static_future_ts, diff_in_hours | limit 3
Explanation: The query demonstrates that when timestamp1 is earlier than timestamp2, the result is negative. Calculations are truncated to full hours.
Output:
| EVENT_ID | EVENT_TS | STATIC_FUTURE_TS | DIFF_IN_HOURS |
|---|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | Oct 27th 2023 10:00:00 | -24 |
| 102 | Oct 26th 2023 10:05:30 | Oct 27th 2023 10:00:00 | -23 |
| 103 | Oct 26th 2023 10:15:15 | Oct 27th 2023 10:00:00 | -23 |
Example 4: Using timestamp_diff() in a filter stage
Goal: Filter events based on a calculated time difference relative to the current time.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter current_ts = current_time() | filter timestamp_diff(current_ts, _time, "HOUR") > 1 | fields event_id, _time | limit 3
Explanation: This query filters for events that occurred more than 1 hour prior to the current execution time.
Output:
| EVENT_ID | _TIME |
|---|---|
| 101 | Oct 26th 2023 10:00:00 |
| 102 | Oct 26th 2023 10:05:30 |
| 103 | Oct 26th 2023 10:15:15 |
Example 5: Difference in milliseconds between _time and a closely past static timestamp
Goal: Calculate a fine-grained difference in milliseconds between two close timestamps.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_ts = _time | alter static_slightly_past_ts = parse_timestamp("%F %R:%E3S", "2023-10-26 10:00:00.000") | alter diff_in_milliseconds = timestamp_diff(event_ts, static_slightly_past_ts, "MILLISECOND") | fields event_id, event_ts, static_slightly_past_ts, diff_in_milliseconds | limit 3
Explanation: The query calculates the exact difference in milliseconds, useful for precise time measurements.
Output:
| EVENT_ID | EVENT_TS | STATIC_SLIGHTLY_PAST_TS | DIFF_IN_MILLISECONDS |
|---|---|---|---|
| 101 | Oct 26th 2023 10:00:00 | Oct 26th 2023 10:00:00 | 0 |
| 102 | Oct 26th 2023 10:05:30 | Oct 26th 2023 10:00:00 | 330000 |
| 103 | Oct 26th 2023 10:15:15 | Oct 26th 2023 10:00:00 | 915000 |
Related articles
- Stages:
alter,filter - Functions:
current_time,parse_timestamp - Datasets:
xdr_data
timestamp_seconds
Use the timestamp_seconds() function to convert an integer value representing Unix epoch time in seconds into a timestamp.
Syntax
timestamp_seconds (<integer>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
integer |
integer | Yes | The numerical value representing epoch time in seconds. This can be a literal integer or a field containing an integer. |
Returns
The timestamp_seconds() function returns a timestamp compatible value, typically formatted as MMM dd YYYY HH:mm:ss.
Usage notes
- The function expects a single integer input, which is implicitly interpreted as the number of seconds that have passed since the Unix epoch (January 1, 1970, 00:00:00 UTC).
- Endpoint Detection and Response (EDR) columns often store epoch values in milliseconds. Ensure your input is in seconds; otherwise, consider using
to_timestamp()with the appropriate unit specification. - If the input integer field or literal is
NULL, the function returnsNULL. - If the integer input value is not a sensible epoch time (for example, an extremely large or small non-epoch value), the function may return
NULLor an unexpected timestamp.
Examples
Example 1: Converting a literal epoch second integer
Goal: Convert a static integer literal (representing a known epoch second value) into a human-readable timestamp.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter known_epoch_seconds = 1698304800 | alter converted_timestamp = timestamp_seconds(known_epoch_seconds) | fields event_id, known_epoch_seconds, converted_timestamp | limit 3
Explanation: The query takes the known_epoch_seconds integer (which is 1698304800, representing 2023-10-26 10:00:00 UTC) and converts it to its corresponding timestamp value.
Output:
| EVENT_ID | KNOWN_EPOCH_SECONDS | CONVERTED_TIMESTAMP |
|---|---|---|
| 101 | 1698304800 | Oct 26th 2023 10:00:00 |
| 102 | 1698304800 | Oct 26th 2023 10:00:00 |
| 103 | 1698304800 | Oct 26th 2023 10:00:00 |
Example 2: Converting an integer field to a timestamp
Goal: Apply the function to an existing integer field to interpret it as an epoch timestamp.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_as_timestamp = timestamp_seconds(to_integer(event_id)) | fields event_id, event_id_as_timestamp | limit 3
Explanation: The integer value of event_id is interpreted as the number of seconds past the Unix epoch. For example, 101 becomes 101 seconds past epoch.
Output:
| EVENT_ID | EVENT_ID_AS_TIMESTAMP |
|---|---|
| 101 | Jan 1st 1970 00:01:41 |
| 102 | Jan 1st 1970 00:01:42 |
| 103 | Jan 1st 1970 00:01:43 |
Example 3: Converting a derived integer from a JSON field to a timestamp
Goal: Extract a numerical value from a JSON field, convert it to an integer, and then convert that integer to a timestamp.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter status_code_string = simple_json_data -> code | alter status_code_int = to_integer(status_code_string) | alter status_code_timestamp = timestamp_seconds(status_code_int) | fields event_id, simple_json_data, status_code_string, status_code_int, status_code_timestamp | limit 3
Explanation: For event 101, the code value 200 is extracted, converted to an integer, and interpreted as 200 seconds from epoch. For events where the field is missing, the result is NULL.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | STATUS_CODE_STRING | STATUS_CODE_INT | STATUS_CODE_TIMESTAMP |
|---|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | "200" | 200 | Jan 1st 1970 00:03:20 |
| 102 | {"status": "fail", "error": "access_denied"} | NULL | NULL | NULL |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL | NULL | NULL |
Example 4: Handling NULL input
Goal: Demonstrate the behavior when the function is provided with a NULL input.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter null_input_value = NULL | alter converted_null_timestamp = timestamp_seconds(null_input_value) | fields event_id, null_input_value, converted_null_timestamp | limit 3
Explanation: The function returns NULL because the input is explicitly NULL.
Output:
| EVENT_ID | NULL_INPUT_VALUE | CONVERTED_NULL_TIMESTAMP |
|---|---|---|
| 101 | NULL | NULL |
| 102 | NULL | NULL |
| 103 | NULL | NULL |
Related articles
to_boolean
Use the to_boolean() function to explicitly transform string representations of boolean values into their native boolean data type.
Syntax
to_boolean (<string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The string field or literal value that you want to convert. |
Returns
The to_boolean() function returns a boolean value (true or false).
Usage notes
- The input string must be either "TRUE" or "FALSE".
- The conversion is case-insensitive, meaning "true", "TRUE", "True", "false", "FALSE", "False", etc., are all valid inputs for conversion.
- If the input string is not "TRUE" or "FALSE" (case-insensitive), or if the input is
NULL, the function will returnNULL.
Examples
Example 1: Converting a literal string "TRUE"
Goal: Convert the literal string "TRUE" to a boolean true value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter is_active_flag = to_boolean("TRUE") | fields event_id, is_active_flag | limit 3
Explanation: This query creates a new field, is_active_flag, which holds the boolean true value for every record, derived from the literal string "TRUE".
Output:
| EVENT_ID | IS_ACTIVE_FLAG |
|---|---|
| 101 | true |
| 102 | true |
| 103 | true |
Example 2: Converting a literal string "FALSE"
Goal: Convert the literal string "FALSE" to a boolean false value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter is_blocked_flag = to_boolean("FALSE") | fields event_id, is_blocked_flag | limit 3
Explanation: This query creates a new field, is_blocked_flag, which holds the boolean false value for every record, derived from the literal string "FALSE".
Output:
| EVENT_ID | IS_BLOCKED_FLAG |
|---|---|
| 101 | false |
| 102 | false |
| 103 | false |
Example 3: Converting a case-insensitive literal string
Goal: Convert mixed-case literal strings (for example, "true", "FaLsE") to their boolean equivalents.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter status_boolean_lower = to_boolean("true") | alter status_boolean_mixed = to_boolean("FaLsE") | fields event_id, status_boolean_lower, status_boolean_mixed | limit 3
Explanation: The query demonstrates that to_boolean() successfully interprets both "true" and "FaLsE" (case-insensitively) into their respective boolean true and false values.
Output:
| EVENT_ID | STATUS_BOOLEAN_LOWER | STATUS_BOOLEAN_MIXED |
|---|---|---|
| 101 | true | false |
| 102 | true | false |
| 103 | true | false |
Example 4: Converting a derived string field
Goal: Convert a string field ("TRUE"/"FALSE") derived from existing data into a boolean type.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter success_string = if(is_successful = true, "TRUE", "FALSE") | alter converted_success = to_boolean(success_string) | fields event_id, is_successful, success_string, converted_success | limit 3
Explanation: The if() function first creates success_string as either "TRUE" or "FALSE" based on is_successful. Then, to_boolean() correctly converts this string representation into a native boolean value in converted_success.
Output:
| EVENT_ID | IS_SUCCESSFUL | SUCCESS_STRING | CONVERTED_SUCCESS |
|---|---|---|---|
| 101 | true | "TRUE" | true |
| 102 | false | "FALSE" | false |
| 103 | true | "TRUE" | true |
Example 5: Handling invalid string input
Goal: Demonstrate the behavior when attempting to convert an invalid string or a NULL value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter invalid_conversion = to_boolean("not_a_boolean_string") | alter null_input_conversion = to_boolean(NULL) | fields event_id, invalid_conversion, null_input_conversion | limit 3
Explanation: As expected for invalid conversions in XQL, both attempts result in NULL values for the new fields, demonstrating to_boolean()'s strict input requirements.
Output:
| EVENT_ID | INVALID_CONVERSION | NULL_INPUT_CONVERSION |
|---|---|---|
| 101 | NULL | NULL |
| 102 | NULL | NULL |
| 103 | NULL | NULL |
Example 6: Using supported operators for deriving a boolean string
Goal: Use to_boolean() within a filter stage to evaluate a derived string field as a boolean condition (for example, checking if an event ID is odd).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter division_result = divide(event_id, 2) | alter is_event_active_string = if(division_result != floor(division_result), "TRUE", "FALSE") | filter to_boolean(is_event_active_string) = true | fields event_id, is_event_active_string | limit 3
Explanation: This query calculates the remainder of dividing event_id by 2. If the result is not a whole number (meaning the ID is odd), it assigns "TRUE" to the string field. to_boolean() converts this string to a boolean for the filter, returning only records with odd event IDs.
Output:
| EVENT_ID | IS_EVENT_ACTIVE_STRING |
|---|---|
| 101 | "TRUE" |
| 103 | "TRUE" |
| 105 | "TRUE" |
Related articles
to_epoch
Use the to_epoch() function to convert a timestamp value into the Unix epoch timestamp format.
Syntax
to_epoch (<timestamp>, <time unit>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
timestamp |
timestamp | Yes | The timestamp value to convert. This must be a TIMESTAMP object, not a string. |
time unit |
string | Yes | The granularity of the returned integer value. Supported values are SECONDS, MILLIS, or MICROS. |
Returns
The to_epoch() function returns an integer representing the Unix epoch timestamp.
Usage notes
- The first parameter must be a
TIMESTAMPobject. If you have a string representation of a timestamp, you must first convert it to aTIMESTAMPobject using functions likeparse_epoch()orto_timestamp(). - The
<time unit>parameter specifies the granularity of the returned integer value (seconds, milliseconds, or microseconds). - If no
<time unit>is configured,SECONDSis used as the default.
Examples
Example 1: Converting _time (timestamp field) to epoch in seconds
Goal: Convert the _time field, which is already a TIMESTAMP object, to its Unix epoch representation in seconds.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter epoch_seconds = to_epoch(_time, "SECONDS") | fields event_id, _time, epoch_seconds | limit 3
Explanation: The _time field is converted to an epoch integer in seconds using the "SECONDS" unit.
Output:
| EVENT_ID | _TIME | EPOCH_SECONDS |
|---|---|---|
| 101 | 2023-10-26 10:00:00 UTC | 1698304800 |
| 102 | 2023-10-26 10:05:30 UTC | 1698305130 |
| 103 | 2023-10-26 10:15:15 UTC | 1698305715 |
Example 2: Converting _time (timestamp field) to epoch in milliseconds
Goal: Convert the _time field to its Unix epoch representation in milliseconds.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter epoch_millis = to_epoch(_time, "MILLIS") | fields event_id, _time, epoch_millis | limit 3
Explanation: The _time field is converted to an epoch integer in milliseconds using the "MILLIS" unit.
Output:
| EVENT_ID | _TIME | EPOCH_MILLIS |
|---|---|---|
| 101 | 2023-10-26 10:00:00 UTC | 1698304800000 |
| 102 | 2023-10-26 10:05:30 UTC | 1698305130000 |
| 103 | 2023-10-26 10:15:15 UTC | 1698305715000 |
Example 3: Converting _time (timestamp field) to epoch in microseconds
Goal: Convert the _time field to its Unix epoch representation in microseconds.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter epoch_micros = to_epoch(_time, "MICROS") | fields event_id, _time, epoch_micros | limit 3
Explanation: The _time field is converted to an epoch integer in microseconds using the "MICROS" unit.
Output:
| EVENT_ID | _TIME | EPOCH_MICROS |
|---|---|---|
| 101 | 2023-10-26 10:00:00 UTC | 1698304800000000 |
| 102 | 2023-10-26 10:05:30 UTC | 1698305130000000 |
| 103 | 2023-10-26 10:15:15 UTC | 1698305715000000 |
Example 4: Converting a string timestamp to epoch
Goal: Convert a string that represents a timestamp into epoch time by first creating a TIMESTAMP object.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter literal_timestamp_string = "2023-10-26 10:00:00 UTC" | alter parsed_timestamp_obj = parse_timestamp("%Y-%m-%d %H:%M:%S UTC", literal_timestamp_string) | alter epoch_from_string = to_epoch(parsed_timestamp_obj, "SECONDS") | fields event_id, literal_timestamp_string, parsed_timestamp_obj, epoch_from_string | limit 3
Explanation: The query first uses parse_timestamp() to create a TIMESTAMP object from a string literal. Then, to_epoch() converts that object into epoch seconds.
Output:
| EVENT_ID | LITERAL_TIMESTAMP_STRING | PARSED_TIMESTAMP_OBJ | EPOCH_FROM_STRING |
|---|---|---|---|
| 101 | "2023-10-26 10:00:00 UTC" | 2023-10-26 10:00:00 UTC | 1698304800 |
| 102 | "2023-10-26 10:00:00 UTC" | 2023-10-26 10:00:00 UTC | 1698304800 |
| 103 | "2023-10-26 10:00:00 UTC" | 2023-10-26 10:00:00 UTC | 1698304800 |
Related articles
- Stages:
alter - Functions:
parse_epoch,to_timestamp
to_float
Use the to_float() function to convert a string value that represents a number or a numeric data type into a floating-point number.
Syntax
to_float (<string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The string field or literal value that you wish to convert to a number. |
Returns
The to_float() function returns a floating-point number.
Usage notes
- The function is functionally identical to the
to_number()function. - The function consistently returns a floating-point number. Even if the input string represents a whole integer (for example, "200"), the output will be a floating-point number (for example, 200.0).
- If the input string does not represent a valid number (for example, contains letters or unparseable characters), or if the input itself is
NULL, the function will returnNULL.
Examples
Example 1: Converting a literal string (decimal representation) to float
Goal: Convert a string literal that represents a decimal number directly into a floating-point number.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter float_from_decimal_string = to_float("1.5") | fields event_id, float_from_decimal_string | limit 3
Explanation: The literal string "1.5" is converted to a float.
Output:
| EVENT_ID | FLOAT_FROM_DECIMAL_STRING |
|---|---|
| 101 | 1.5 |
| 102 | 1.5 |
| 103 | 1.5 |
Example 2: Converting a literal string (integer representation) to float
Goal: Convert a string literal that represents a whole number into its floating-point equivalent.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter float_from_integer_string = to_float("100") | fields event_id, float_from_integer_string | limit 3
Explanation: The literal string "100" is converted to the floating-point number 100.0.
Output:
| EVENT_ID | FLOAT_FROM_INTEGER_STRING |
|---|---|
| 101 | 100.0 |
| 102 | 100.0 |
| 103 | 100.0 |
Example 3: Converting a string extracted from JSON to float
Goal: Extract a numeric value (code) from a JSON string field (simple_json_data) and convert that extracted string to a float.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter json_code_string = simple_json_data -> code | alter converted_json_code = to_float(json_code_string) | fields event_id, simple_json_data, json_code_string, converted_json_code | limit 3
Explanation: For event_id 101, the "code" value "200" is extracted as a string and converted to the number 200.0. For events where the field is missing, it returns NULL.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | JSON_CODE_STRING | CONVERTED_JSON_CODE |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | "200" | 200.0 |
| 102 | {"status": "fail", "error": "access_denied"} | NULL | NULL |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL | NULL |
Example 4: Converting an integer field (via to_string()) to float
Goal: Convert an existing integer field (event_id) to a string first using to_string(), and then convert that string representation into a float.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_as_string = to_string(event_id) | alter float_event_id = to_float(event_id_as_string) | fields event_id, event_id_as_string, float_event_id | limit 3
Explanation: The numeric event_id (for example, 101) is converted to a string "101", and then back to a float 101.0.
Output:
| EVENT_ID | EVENT_ID_AS_STRING | FLOAT_EVENT_ID |
|---|---|---|
| 101 | "101" | 101.0 |
| 102 | "102" | 102.0 |
| 103 | "103" | 103.0 |
Example 5: Handling non-numeric string input (returns NULL)
Goal: Demonstrate the function's behavior when provided with a string that cannot be interpreted as a number (for example, a purely textual field like event_description).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter non_numeric_string = event_description | alter float_conversion_result = to_float(non_numeric_string) | fields event_id, non_numeric_string, float_conversion_result | limit 3
Explanation: Since event_description contains text (for example, "User login successful"), to_float() returns NULL.
Output:
| EVENT_ID | NON_NUMERIC_STRING | FLOAT_CONVERSION_RESULT |
|---|---|---|
| 101 | "User login successful" | NULL |
| 102 | "File access attempt" | NULL |
| 103 | "Network connection established" | NULL |
Related articles
to_integer
Use the to_integer() function to convert a string representation of a number into an integer value.
Syntax
to_integer(<string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The string field or literal value that you wish to convert to a number. |
Returns
The to_integer() function returns an integer.
Usage notes
- When a string representation of a floating-point number (for example, "1.5") is provided as input, the function returns
NULL. This differentiates its behavior from functions likefloor()orround(). - If passed a numeric data type (like a float), the result will be rounded up or down to the nearest integer.
- If the input string does not represent a valid number, or if the input itself is
NULL, the function returnsNULL.
Examples
Example 1: Converting a literal integer string to integer
Goal: Convert a string literal that represents a whole number directly into an integer.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter literal_integer_val = to_integer("42") | fields event_id, literal_integer_val | limit 3
Explanation: The literal string "42" is successfully converted by to_integer() into the integer value 42.
Output:
| EVENT_ID | LITERAL_INTEGER_VAL |
|---|---|
| 101 | 42 |
| 102 | 42 |
| 103 | 42 |
Example 2: Converting a literal floating-point string to integer
Goal: Demonstrate behavior when provided with a string that represents a floating-point number.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter float_string_to_int = to_integer("123.789") | fields event_id, float_string_to_int | limit 3
Explanation: When a string containing a decimal (floating-point representation) is passed to to_integer(), it results in a NULL output.
Output:
| EVENT_ID | FLOAT_STRING_TO_INT |
|---|---|
| 101 | NULL |
| 102 | NULL |
| 103 | NULL |
Example 3: Converting a numeric string from an existing field to integer
Goal: Convert an existing floating-point field to an integer, demonstrating automatic rounding.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter integer_duration = to_integer(duration_seconds) | fields event_id, duration_seconds, integer_duration | limit 3
Explanation: The duration_seconds field is a floating-point number. When to_integer() is applied to a numeric type, it automatically rounds the number to the nearest integer (for example, 1.5 becomes 2, 0.8 becomes 1).
Output:
| EVENT_ID | DURATION_SECONDS | INTEGER_DURATION |
|---|---|---|
| 101 | 1.5 | 2 |
| 102 | 0.8 | 1 |
| 103 | 10.2 | 10 |
Example 4: Converting a string extracted from JSON to integer
Goal: Extract a numeric value from a JSON string field and convert it to an integer.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter json_code_string = simple_json_data -> code | alter parsed_json_code = to_integer(json_code_string) | fields event_id, simple_json_data, json_code_string, parsed_json_code | limit 3
Explanation: For event 101, the "code" value "200" is extracted as a string and converted to the integer 200. For events where the field is missing, the result is NULL.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | JSON_CODE_STRING | PARSED_JSON_CODE |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | "200" | 200 |
| 102 | {"status": "fail", "error": "access_denied"} | NULL | NULL |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL | NULL |
Example 5: Handling non-numeric string input
Goal: Demonstrate behavior when providing a string that cannot be interpreted as a number.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter non_numeric_string = event_description | alter int_conversion_result = to_integer(non_numeric_string) | fields event_id, non_numeric_string, int_conversion_result | limit 3
Explanation: The conversion returns NULL because event_description contains text (for example, "User login successful") and not a valid number.
Output:
| EVENT_ID | NON_NUMERIC_STRING | INT_CONVERSION_RESULT |
|---|---|---|
| 101 | "User login successful" | NULL |
| 102 | "File access attempt" | NULL |
| 103 | "Network connection established" | NULL |
Example 6: Using to_integer() in a filter stage
Goal: Extract a numeric value from a string field, convert it to an integer, and use it for numerical comparison in a filter.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_octet_string = arrayindex(split(ipv4_address, "."), 0) | alter first_octet_int = to_integer(first_octet_string) | filter first_octet_int > 192 | fields event_id, ipv4_address, first_octet_string, first_octet_int | limit 3
Explanation: The query splits the IP address to isolate the first octet as a string. to_integer() converts this string to an integer, allowing the filter stage to numerically compare if the octet is greater than 192.
Output:
| EVENT_ID | IPV4_ADDRESS | FIRST_OCTET_STRING | FIRST_OCTET_INT |
|---|---|---|---|
| 106 | "203.0.113.15" | "203" | 203 |
Related articles
to_json_string
Use the to_json_string() function to convert values of any data type into a JSON formatted string.
Syntax
to_json_string(<data type>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
data type |
integer, boolean, string, object, array | Yes | The field or literal value to convert. |
Returns
The to_json_string() function returns a string.
Usage notes
- The function is versatile and accepts all data types, including integers, booleans, strings, objects, and arrays.
- When the input is an object or an array, the function returns a JSON formatted string representation of that input, preserving its structure.
- When the input is a simple string, it returns the string as its JSON literal representation (in other words, enclosed in quotes, with any internal special characters properly escaped if necessary).
- For numeric or boolean inputs, it converts them into their JSON string literal representations (for example, a number
101becomes the string"101", a booleantruebecomes the string"true"). - This function is particularly useful for standardizing data types for consistent processing or preparing complex data types for functions that require JSON string inputs, such as
json_extract().
Examples
Example 1: Converting a string field
Goal: Convert the event_description string field into its JSON string representation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter description_as_json = to_json_string(event_description) | fields event_id, event_description, description_as_json | limit 3
Explanation: The to_json_string() function takes the event_description string and returns it formatted as a JSON string literal.
Output:
| EVENT_ID | EVENT_DESCRIPTION | DESCRIPTION_AS_JSON |
|---|---|---|
| 101 | "User login successful" | "User login successful" |
| 102 | "File access attempt" | "File access attempt" |
| 103 | "Network connection established" | "Network connection established" |
Example 2: Converting a numeric field (integer)
Goal: Convert the event_id integer field into its JSON string representation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_id_as_json = to_json_string(event_id) | fields event_id, event_id_as_json | limit 3
Explanation: The integer event_id is converted into a string format suitable for JSON.
Output:
| EVENT_ID | EVENT_ID_AS_JSON |
|---|---|
| 101 | "101" |
| 102 | "102" |
| 103 | "103" |
Example 3: Converting a numeric field (float)
Goal: Convert the duration_seconds floating-point number field into its JSON string representation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter duration_as_json = to_json_string(duration_seconds) | fields event_id, duration_seconds, duration_as_json | limit 3
Explanation: The floating-point duration_seconds field is converted into a string format.
Output:
| EVENT_ID | DURATION_SECONDS | DURATION_AS_JSON |
|---|---|---|
| 101 | 1.5 | "1.5" |
| 102 | 0.8 | "0.8" |
| 103 | 10.2 | "10.2" |
Example 4: Converting a boolean field
Goal: Convert the is_successful boolean field into its JSON string representation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter successful_as_json = to_json_string(is_successful) | fields event_id, is_successful, successful_as_json | limit 3
Explanation: The boolean is_successful values (true or false) are converted into their corresponding string representations.
Output:
| EVENT_ID | IS_SUCCESSFUL | SUCCESSFUL_AS_JSON |
|---|---|---|
| 101 | true | "true" |
| 102 | false | "false" |
| 103 | true | "true" |
Example 5: Converting a JSON object field to a JSON string
Goal: Convert the simple_json_data field, which holds a JSON object, into a single JSON string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter simple_data_as_json = to_json_string(simple_json_data) | fields event_id, simple_json_data, simple_data_as_json | limit 3
Explanation: The entire JSON object in simple_json_data is converted into a string. Note that the entire structure is enclosed in outer double quotes, and original double quotes within the JSON are escaped with a backslash (\") to ensure it is a valid JSON string literal.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | SIMPLE_DATA_AS_JSON |
|---|---|---|
| 101 | {"status": "ok", "code": 200} | "{"status": "ok", "code": 200}" |
| 102 | {"status": "fail", "error": "access_denied"} | "{"status": "fail", "error": "access_denied"}" |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | "{"connection_id": "CONN-001", "protocol": "TCP"}" |
Example 6: Converting an array of JSON objects field to a JSON string
Goal: Convert the array_of_json_objects field, which contains an array, into a JSON string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter array_data_as_json = to_json_string(array_of_json_objects) | fields event_id, array_of_json_objects, array_data_as_json | limit 3
Explanation: The array structure, including its nested JSON objects, is converted into a single, correctly quoted and escaped string.
Output:
| EVENT_ID | ARRAY_OF_JSON_OBJECTS | ARRAY_DATA_AS_JSON |
|---|---|---|
| 101 | [{"action": "read", "file": "doc1.txt"}, {"action": "write", "file": "report.log"}] | "[{"action": "read", "file": "doc1.txt"}, {"action": "write", "file": "report.log"}]" |
| 102 | [{"event": "file_open", "path": "/etc/passwd"}] | "[{"event": "file_open", "path": "/etc/passwd"}]" |
| 103 | [{"conn_type": "outbound", "bytes": 1024}, {"conn_type": "inbound", "bytes": 512}] | "[{"conn_type": "outbound", "bytes": 1024}, {"conn_type": "inbound", "bytes": 512}]" |
Related articles
- Stages:
alter - Functions:
json_extract,json_extract_array,json_extract_scalar - Datasets:
xdr_data
to_number
Use the to_number() function to convert a string value that represents a number or a numeric data type into a floating-point number.
Syntax
to_number (<string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The string field or literal value that you wish to convert to a number. |
Returns
The to_number() function returns a floating-point number.
Usage notes
- The function requires a string value that represents a number or a numeric data type.
- The function is functionally identical to the
to_float()function. - The function consistently returns a floating-point number. Even if the input string represents a whole integer (for example, "200"), the output will be a floating-point number (for example, 200.0).
- If the input string cannot be successfully converted to a numeric value (for example, it contains letters or unparseable characters), the function will return
NULL. - If the input string itself is
NULL, the function will returnNULL.
Examples
Example 1: Converting a literal integer string
Goal: Convert a string literal representing an integer into a numerical (float) value.
XQL code:
config timeframe = 1d // Sets the query time context | dataset = sample_xql_raw // Specifies the dataset to use | alter converted_integer_string = to_number("42") // Converts a literal string "42" to a number | fields event_id, converted_integer_string // Selects relevant fields for display | limit 3 // Limits the output for brevity
Explanation: The literal string "42" is successfully converted by to_number() into a floating-point number 42.0.
Output:
| EVENT_ID | CONVERTED_INTEGER_STRING |
|---|---|
| 101 | 42.0 |
| 102 | 42.0 |
| 103 | 42.0 |
Example 2: Converting a literal floating-point string
Goal: Convert a string literal representing a decimal number into a floating-point value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter converted_float_string = to_number("123.45") // Converts a literal string "123.45" to a number | fields event_id, converted_float_string | limit 3
Explanation: The literal string "123.45" is correctly converted into the floating-point number 123.45.
Output:
| EVENT_ID | CONVERTED_FLOAT_STRING |
|---|---|
| 101 | 123.45 |
| 102 | 123.45 |
| 103 | 123.45 |
Example 3: Converting a numeric string extracted from a JSON field
Goal: Extract a numerical value from a JSON string field and convert it from its string representation to a number.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter extracted_code_as_string = simple_json_data -> code // Extracts 'code' as a string | alter converted_json_code = to_number(extracted_code_as_string) // Converts the extracted string to a number | fields event_id, simple_json_data, converted_json_code | limit 3
Explanation: For event_id 101, the "code" value "200" is extracted as a string and then successfully converted to the number 200.0. For event_id 102 and 103, where simple_json_data does not contain a "code" field, extracted_code_as_string becomes NULL, and subsequently, converted_json_code also becomes NULL.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | CONVERTED_JSON_CODE |
|---|---|---|
| 101 | {"status": "ok", "code": 200} | 200.0 |
| 102 | {"status": "fail", "error": "access_denied"} | NULL |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL |
Example 4: Attempting to convert a string with non-numeric characters
Goal: Demonstrate the behavior when attempting to convert a string that contains non-numerical characters.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter mem_free_string = nested_json_data -> system.mem_free // Extracts "80%" as a string | alter converted_mem_free = to_number(mem_free_string) // Attempts to convert "80%" to a number | fields event_id, nested_json_data, converted_mem_free | filter event_id = 104 // Focus on the relevant record for this example | limit 1
Explanation: to_number() cannot perform the conversion and returns NULL for invalid inputs because "80%" is not a pure numeric string.
Output:
| EVENT_ID | NESTED_JSON_DATA | CONVERTED_MEM_FREE |
|---|---|---|
| 104 | {"system": {"cpu_util": 0.15, "mem_free": "80%"}, "status": "active"} | NULL |
Example 5: Converting a NULL input field
Goal: Demonstrate the behavior when the input field is explicitly NULL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 105 // Focus on the relevant record for this example | alter null_input_field = dst_domain // This field is NULL for some records (for example, event_id 105) | alter converted_null = to_number(null_input_field) // Attempts to convert a NULL field to a number | fields event_id, dst_domain, converted_null | limit 1
Explanation: When the input to to_number() is NULL, the function consistently returns NULL.
Output:
| EVENT_ID | DST_DOMAIN | CONVERTED_NULL |
|---|---|---|
| 105 | NULL | NULL |
Related articles
- Stages:
alter,filter - Functions:
to_float,to_integer,json_extract_scalar - Datasets:
xdr_data
to_string
Use the to_string() function to convert a non-string value (such as a number, float, or boolean) into its string representation.
Syntax
to_string (<field>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
integer, float, boolean | Yes | The field or literal value that you wish to convert to a string. |
Returns
The to_string() function returns a string data type.
Usage notes
- The function supports converting numerical types (integers and floats) and boolean values into strings.
- If the input field or literal is
NULL, the function returnsNULL. - This function is essential when a string input is required for other XQL functions (like
concat(),format_string(), orsplit()) or for performing string-based comparisons infilterstages.
Examples
Example 1: Converting a numeric (integer) field
Goal: Convert an integer field (event_id) to its string representation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter converted_event_id = to_string(event_id) | fields event_id, converted_event_id | limit 3
Explanation: The numeric event_id (for example, 101) is successfully converted by to_string() into the string "101".
Output:
| EVENT_ID | CONVERTED_EVENT_ID |
|---|---|
| 101 | "101" |
| 102 | "102" |
| 103 | "103" |
Example 2: Converting a numeric (float) field
Goal: Convert a floating-point field (duration_seconds) to its string representation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter converted_duration = to_string(duration_seconds) | fields event_id, duration_seconds, converted_duration | limit 3
Explanation: The floating-point duration_seconds (for example, 1.5) is converted by to_string() into the string "1.5".
Output:
| EVENT_ID | DURATION_SECONDS | CONVERTED_DURATION |
|---|---|---|
| 101 | 1.5 | "1.5" |
| 102 | 0.8 | "0.8" |
| 103 | 10.2 | "10.2" |
Example 3: Converting a boolean field
Goal: Convert a boolean field (is_successful) to its string representation.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter converted_status = to_string(is_successful) | fields event_id, is_successful, converted_status | limit 3
Explanation: The boolean is_successful value (for example, true) is converted by to_string() into the string "true".
Output:
| EVENT_ID | IS_SUCCESSFUL | CONVERTED_STATUS |
|---|---|---|
| 101 | true | "true" |
| 102 | false | "false" |
| 103 | true | "true" |
Example 4: Converting a literal numeric value
Goal: Convert a literal integer and a literal float to their string representations.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter literal_int_to_string = to_string(99) | alter literal_float_to_string = to_string(3.14) | fields event_id, literal_int_to_string, literal_float_to_string | limit 3
Explanation: Both the integer 99 and the float 3.14 are directly converted into their respective string representations.
Output:
| EVENT_ID | LITERAL_INT_TO_STRING | LITERAL_FLOAT_TO_STRING |
|---|---|---|
| 101 | "99" | "3.14" |
| 102 | "99" | "3.14" |
| 103 | "99" | "3.14" |
Example 5: Using to_string() in a filter condition
Goal: Convert a field to a string to enable string-based comparison in a filter stage.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter to_string(event_id) = "101" | fields event_id, event_description, is_successful | limit 3
Explanation: The event_id field is converted to a string before being compared to the string literal "101", successfully filtering for the event with ID 101.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL |
|---|---|---|
| 101 | "User login successful" | true |
Example 6: Handling NULL input field
Goal: Demonstrate the behavior when the input field is explicitly NULL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 105 | alter null_input_field = dst_domain | alter converted_null = to_string(null_input_field) | fields event_id, dst_domain, converted_null | limit 1
Explanation: When the input to to_string() is NULL (for example, dst_domain for event ID 105), the function consistently returns NULL.
Output:
| EVENT_ID | DST_DOMAIN | CONVERTED_NULL |
|---|---|---|
| 105 | NULL | NULL |
Related articles
to_timestamp
Use the to_timestamp() function to convert an integer value representing Unix epoch time into a human-readable TIMESTAMP data type.
Syntax
to_timestamp (<integer>, <units>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
integer |
integer | Yes | The numerical value representing epoch time. This can be a literal integer or a field containing an integer. |
units |
string | No | A string literal that specifies the unit of the epoch integer. Supported values are "SECONDS", "MILLIS" (milliseconds), or "MICROS" (microseconds). The default value is "SECONDS" if the parameter is omitted. |
Returns
The to_timestamp() function returns a TIMESTAMP compatible value.
Usage notes
- The function is essential when you need to display or use epoch-based numerical time representations as standard timestamps for analysis, filtering, or display.
- If the
<units>parameter is not supplied, it defaults to "SECONDS". to_timestamp()is often used after a function likeparse_epoch()(which converts a string representation of a timestamp into an epoch integer) orto_epoch()(which converts a timestamp into an epoch integer).- If the input integer field or literal is NULL, the function will return NULL.
- If the integer input value does not match the units parameter (for example, a non-sensical value for the given unit), this function will return NULL.
Examples
Example 1: Converting a numeric field to a timestamp (default seconds unit)
Goal: Convert an integer field to a timestamp, relying on the default behavior to treat the value as epoch seconds.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter epoch_timestamp_default_seconds = to_timestamp(to_integer(event_id)) | fields event_id, epoch_timestamp_default_seconds | limit 3
Explanation: The event_id is passed through to_integer() to guarantee data type compliance, and then converted by to_timestamp() into a TIMESTAMP value corresponding to the seconds after the Unix epoch because no unit was specified, defaulting to SECONDS.
Output:
| EVENT_ID | EPOCH_TIMESTAMP_DEFAULT_SECONDS |
|---|---|
| 101 | 1970-01-01 00:01:41 UTC |
| 102 | 1970-01-01 00:01:42 UTC |
| 103 | 1970-01-01 00:01:43 UTC |
Example 2: Converting a numeric field to a timestamp (explicit seconds unit)
Goal: Explicitly convert an integer field to a timestamp, treating its value as epoch seconds.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter epoch_timestamp_explicit_seconds = to_timestamp(to_integer(event_id), "SECONDS") | fields event_id, epoch_timestamp_explicit_seconds | limit 3
Explanation: The event_id is passed through to_integer() to guarantee data type compliance, and is then explicitly converted using the "SECONDS" unit, yielding the same result as the default behavior.
Output:
| EVENT_ID | EPOCH_TIMESTAMP_EXPLICIT_SECONDS |
|---|---|
| 101 | 1970-01-01 00:01:41 UTC |
| 102 | 1970-01-01 00:01:42 UTC |
| 103 | 1970-01-01 00:01:43 UTC |
Example 3: Converting a literal integer to a timestamp (milliseconds unit)
Goal: Convert a static integer literal, representing a specific point in time in milliseconds, to a timestamp.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter literal_timestamp_millis = to_timestamp(1672531200000, "MILLIS") | fields event_id, literal_timestamp_millis | limit 3
Explanation: The literal integer 1672531200000 is explicitly converted as milliseconds, resulting in the constant timestamp for January 1, 2023, 00:00:00 UTC across all records.
Output:
| EVENT_ID | LITERAL_TIMESTAMP_MILLIS |
|---|---|
| 101 | 2023-01-01 00:00:00 UTC |
| 102 | 2023-01-01 00:00:00 UTC |
| 103 | 2023-01-01 00:00:00 UTC |
Example 4: Converting a literal integer to a timestamp (microseconds unit)
Goal: Convert a static integer literal, representing a specific point in time in microseconds, to a timestamp.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter literal_timestamp_micros = to_timestamp(1672531200000000, "MICROS") | fields event_id, literal_timestamp_micros | limit 3
Explanation: The literal integer 1672531200000000 is explicitly converted as microseconds, resulting in the constant timestamp for January 1, 2023, 00:00:00 UTC across all records.
Output:
| EVENT_ID | LITERAL_TIMESTAMP_MICROS |
|---|---|
| 101 | 2023-01-01 00:00:00 UTC |
| 102 | 2023-01-01 00:00:00 UTC |
| 103 | 2023-01-01 00:00:00 UTC |
Example 5: Converting a derived integer from an array field to a timestamp (milliseconds unit)
Goal: Extract an integer from an array, treat it as epoch milliseconds, and convert it to a timestamp.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_numeric_code = to_integer(arrayindex(numeric_codes, 0)) | alter derived_timestamp_micros = to_timestamp(first_numeric_code, "MILLIS") | fields event_id, numeric_codes, derived_timestamp_micros | limit 3
Explanation: For each event, the first value from its numeric_codes array is extracted and explicitly converted to an integer. This integer value is then interpreted as milliseconds from the Unix epoch and converted into a timestamp. Note that negative epoch values represent times before 1970-01-01 00:00:00 UTC.
Output:
| EVENT_ID | NUMERIC_CODES | DERIVED_TIMESTAMP_MICROS |
|---|---|---|
| 101 | [13, -47, 29, 82, -15] | 1970-01-01 00:00:00.013 UTC |
| 102 | [-21, 56, 13, -88, 42] | 1969-12-31 23:59:59.979 UTC |
| 103 | [90, -33, 7, 51, -62, 18] | 1970-01-01 00:00:00.090 UTC |
Example 6: Handling NULL input
Goal: Demonstrate behavior when the input integer is NULL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter null_integer_field = NULL | alter converted_null_timestamp = to_timestamp(null_integer_field, "SECONDS") | fields event_id, converted_null_timestamp | limit 3
Explanation: When the input to to_timestamp() is NULL, the function consistently returns NULL.
Output:
| EVENT_ID | CONVERTED_NULL_TIMESTAMP |
|---|---|
| 101 | NULL |
| 102 | NULL |
| 103 | NULL |
Related articles
- Stages:
alter - Functions:
to_epoch,parse_epoch - Datasets:
xdr_data
trim
Use the trim() function to remove specified characters or whitespace from the beginning and end of a given string.
Syntax
trim (<string>, [trim_characters])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string |
string | Yes | The input string field or literal value to be trimmed. |
trim_characters |
string | No | A string containing the characters you want to remove. If this parameter is omitted, the function will remove whitespace characters (spaces and tabs). |
Returns
The trim() function returns a string with the specified characters or whitespace removed from both the start and end.
Usage notes
- The function removes characters from both the beginning (left) and end (right) of the string.
- If
trim_charactersis not provided, the function defaults to removing leading and trailing spaces and tabs. - The function is versatile for cleaning and standardizing string data within queries.
Examples
Example 1: Removing leading and trailing whitespace (default behavior)
Goal: Remove spaces from both ends of a literal string where no specific characters are defined.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter original_string = " User login successful " | alter trimmed_string = trim(original_string) | fields event_id, original_string, trimmed_string | limit 1
Explanation: The query detects and removes the leading and trailing spaces from the original_string, resulting in a clean string "User login successful".
Output:
| EVENT_ID | ORIGINAL_STRING | TRIMMED_STRING |
|---|---|---|
| 101 | " User login successful " | "User login successful" |
Example 2: Removing specific characters from both ends
Goal: Remove explicit characters ("w") from both ends of the dst_domain string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 103 | alter domain_without_w = trim(dst_domain, "w") | fields event_id, dst_domain, domain_without_w
Explanation: The function removes all leading and trailing 'w' characters from the dst_domain string (for example, "www.google.com" becomes ".google.com").
Output:
| EVENT_ID | DST_DOMAIN | DOMAIN_WITHOUT_W |
|---|---|---|
| 103 | "www.google.com" | ".google.com" |
Example 3: Removing multiple specific characters
Goal: Remove a set of explicit characters ("w", "m", and ".") from both ends of the dst_domain string.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 110 | alter domain_without_w_m_period = trim(dst_domain, "wm.") | fields event_id, dst_domain, domain_without_w_m_period
Explanation: The function removes all occurrences of 'w', 'm', and '.' characters found at the start or end of the string. For "www.mongodb.com", the leading "www." and the trailing "m" are removed, leaving "ongodb.co".
Output:
| EVENT_ID | DST_DOMAIN | DOMAIN_WITHOUT_W_M_PERIOD |
|---|---|---|
| 110 | "www.mongodb.com" | "ongodb.co" |
Related articles
trunc
Use the trunc() function to truncate a numeric value to a specified number of decimal places by removing (not rounding) the extra digits.
Syntax
trunc(<number> [, <decimal_places>])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
number |
integer, float | Yes | The numeric value to truncate. |
decimal_places |
integer | No | The number of decimal places to keep. Defaults to 0 (truncate to integer). Negative values truncate digits to the left of the decimal point. |
Returns
Type: float or integer
Description: The trunc() function returns the input value truncated to the specified number of decimal places. Unlike round(), which rounds to the nearest value, trunc() simply removes digits beyond the specified precision. If the input is null, the function returns null.
Usage notes
- Input type: XQL doesn't support NaN or infinite values as input and these value types also can not be returned.
- Truncation vs. Rounding:
trunc()removes digits without rounding. For example,trunc(2.789, 1)returns2.7, not2.8. - Default Behavior: When
decimal_placesis omitted, the function truncates to 0 decimal places (i.e., returns the integer part). - Negative Decimal Places: A negative
decimal_placesvalue truncates digits to the left of the decimal point. For example,trunc(1234, -2)returns1200. - Null Handling: If the input expression is
null, the function returnsnull. - Direction: Truncation is always toward zero. For positive numbers, this is equivalent to
floor(). For negative numbers, this is equivalent toceil()(rounding toward zero, not toward negative infinity). - Common Use Cases: This function is typically used within the
alterstage for precision control, data formatting, bucketing values, and removing unwanted decimal places.
Examples
Example 1: Truncate literal values to different precisions
Goal: Truncate a numeric literal to various decimal places to demonstrate the behavior.
XQL code:
dataset = xdr_data | limit 1 | alter trunc0 = trunc(3.14159), trunc2 = trunc(3.14159, 2), trunc4 = trunc(3.14159, 4) | fields trunc0, trunc2, trunc4
Explanation: trunc(3.14159) returns 3 (no decimal places), trunc(3.14159, 2) returns 3.14 (two decimal places), and trunc(3.14159, 4) returns 3.1415 (four decimal places). Note that the digits are removed, not rounded.
Output:
| TRUNC0 | TRUNC2 | TRUNC4 |
|---|---|---|
| 3 | 3.14 | 3.1415 |
Example 2: Truncate field values to integer
Goal: Truncate floating-point field values to their integer part.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter truncated_duration = trunc(duration_seconds) | fields event_id, duration_seconds, truncated_duration | limit 3
Explanation: This query truncates each duration_seconds value to its integer part by removing the decimal portion. For example, 1.5 becomes 1 and 10.2 becomes 10. Unlike floor(), trunc() rounds toward zero, so -2.7 would become -2 (not -3).
Output:
| EVENT_ID | DURATION_SECONDS | TRUNCATED_DURATION |
|---|---|---|
| 101 | 1.5 | 1 |
| 102 | 0.8 | 0 |
| 103 | 10.2 | 10 |
Example 3: Truncate with negative decimal places
Goal: Truncate values to the nearest hundred using negative decimal places.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter truncated_id = trunc(event_id, -2) | fields event_id, truncated_id | limit 3
Explanation: Using trunc() with -2 decimal places truncates the last two digits of the integer, effectively rounding down to the nearest hundred. For example, 101 becomes 100 and 215 becomes 200.
Output:
| EVENT_ID | TRUNCATED_ID |
|---|---|
| 101 | 100 |
| 102 | 100 |
| 103 | 100 |
Example 4: Compare trunc with round and floor for negative numbers
Goal: Demonstrate the difference between trunc(), round(), and floor() for negative numbers.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter neg_val = multiply(duration_seconds, -1) | alter trunc_val = trunc(neg_val) | alter round_val = round(neg_val) | alter floor_val = floor(neg_val) | fields event_id, neg_val, trunc_val, round_val, floor_val | limit 3
Explanation: For negative numbers, trunc() rounds toward zero (for example, -1.5 becomes -1), round() rounds to the nearest integer (for example, -1.5 becomes -2), and floor() rounds toward negative infinity (for example, -1.5 becomes -2). This demonstrates the key behavioral difference between these functions.
Output:
| EVENT_ID | NEG_VAL | TRUNC_VAL | ROUND_VAL | FLOOR_VAL |
|---|---|---|---|---|
| 101 | -1.5 | -1 | -2 | -2 |
| 102 | -0.8 | 0 | -1 | -1 |
| 103 | -10.2 | -10 | -10 | -11 |
Related articles
uppercase
Use the uppercase() function to convert all characters in a given string field value or literal to their uppercase equivalents.
Syntax
uppercase (<string>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
<string> |
string | Yes | The input string field or literal value to be converted to uppercase. |
Returns
The uppercase() function returns a string with all characters converted to uppercase.
Usage notes
- The
uppercase()function is typically used within thealterstage to create new fields or modify existing ones. - The function can also be used in
filterstages, particularly in scenarios where case-insensitive comparisons are needed or to align withconfig case_sensitive = falsebehavior.
Examples
Example 1: uppercase() on a direct string field
Goal: Convert the event_description field to all uppercase letters.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter upper_description = uppercase(event_description) | fields event_id, event_description, upper_description | limit 3
Explanation: The uppercase() function converts the text in the event_description field to its all-uppercase equivalent, creating a new field upper_description.
Output:
| event_id | event_description | upper_description |
|---|---|---|
| 101 | "User login successful" | "USER LOGIN SUCCESSFUL" |
| 102 | "File access attempt" | "FILE ACCESS ATTEMPT" |
| 103 | "Network connection established" | "NETWORK CONNECTION ESTABLISHED" |
Example 2: uppercase() on a string field (for example, Domain Name)
Goal: Standardize domain names in the dst_domain field to uppercase.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter upper_domain = uppercase(dst_domain) | fields event_id, dst_domain, upper_domain | limit 3
Explanation: The uppercase() function transforms the dst_domain strings, including any surrounding quotes, into their uppercase format in the upper_domain field.
Output:
| event_id | dst_domain | upper_domain |
|---|---|---|
| 101 | "ec2.amazonaws.com" | "EC2.AMAZONAWS.COM" |
| 102 | "sts.amazonaws.com" | "STS.AMAZONAWS.COM" |
| 103 | "www.google.com" | "WWW.GOOGLE.COM" |
Example 3: uppercase() used in conjunction with filter
Goal: Convert raw_log_data to uppercase and then use the result in a filter stage to find specific patterns regardless of original case.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter upper_log_data = uppercase(raw_log_data) | filter upper_log_data contains "PROCESS" | fields event_id, raw_log_data, upper_log_data | limit 2
Explanation: The raw_log_data is converted to upper_log_data, which is then used in a contains filter. This effectively performs a case-insensitive search for "process" by first normalizing the case.
Output:
| event_id | raw_log_data | upper_log_data |
|---|---|---|
| 102 | "Process cmd.exe attempted to access /etc/passwd" | "PROCESS CMD.EXE ATTEMPTED TO ACCESS /ETC/PASSWD" |
| 105 | "Transformed data from source X, processed 1000 records." | "TRANSFORMED DATA FROM SOURCE X, PROCESSED 1000 RECORDS." |
Example 4: uppercase() on an extracted JSON string field
Goal: Extract a string value from a JSON field (simple_json_data) and apply uppercase() to it.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter json_status_string = simple_json_data -> status | alter uppercase_json_status = uppercase(json_status_string) | fields event_id, simple_json_data, json_status_string, uppercase_json_status | limit 3
Explanation: The status field is extracted from simple_json_data as a string (json_status_string), and then uppercase() converts this extracted value to uppercase for the uppercase_json_status field. Events where the status field does not exist will result in NULL.
Output:
| event_id | simple_json_data | json_status_string | uppercase_json_status |
|---|---|---|---|
| 101 | {"status": "ok", "code": 200} | "ok" | "OK" |
| 102 | {"status": "fail", "error": "access_denied"} | "fail" | "FAIL" |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | NULL | NULL |
Example 5: uppercase() within arraymap() for an array of Strings
Goal: Convert every element within the string_tags array to uppercase using arraymap().
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter uppercase_tags = arraymap(string_tags, uppercase("@element")) | fields event_id, string_tags, uppercase_tags | limit 3
Explanation: The arraymap() function iterates through each element (@element) of the string_tags array, applying the uppercase() function to each one. The result is a new array, uppercase_tags, where all original elements are now in uppercase.
Output:
| event_id | string_tags | uppercase_tags |
|---|---|---|
| 101 | ["security", "login"] | ["SECURITY", "LOGIN"] |
| 102 | ["filesystem", "critical"] | ["FILESYSTEM", "CRITICAL"] |
| 103 | ["network", "cloud"] | ["NETWORK", "CLOUD"] |
Related articles
values
Use the values() function to collect all distinct (unique) values of a specified field across grouped rows within the comp stage and return them as an array. This is similar to ARRAY_AGG(DISTINCT ...) in SQL.
Syntax
| comp values(<field>) [by <group_field1>, <group_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
any | Yes | The field whose distinct values will be collected into an array. |
group_field |
any | No | One or more fields to group the results by. If omitted, all rows are treated as a single group. |
alias |
string | No | An alias for the output field. If not specified, the output field name defaults to values_<field>. |
Returns
Type: array
Description: The values() function returns an array containing all distinct (unique) values of the specified field within each group. NULL values may be excluded. The order of elements in the array is not guaranteed.
Usage notes
- Distinct values: Unlike the
list()function which collects all values including duplicates,values()returns only unique values. - Data types: Works with any data type (string, numeric, datetime, etc.).
- Null handling: NULL values are typically excluded from the result array.
- No ordering: The order of elements in the resulting array is not guaranteed.
- No grouping: When used without a
byclause, all rows are aggregated into a single group. - Use case: Useful for finding all unique values of a field within groups, such as all unique users who accessed a resource.
Examples
Example 1: Distinct source IPs per destination
Goal: Find all unique source IP addresses that connected to each destination IP.
XQL code:
dataset = xdr_data | comp values(action_local_ip) by action_remote_ip as unique_source_ips
Explanation: The values() function collects all distinct action_local_ip values for each unique action_remote_ip, eliminating duplicate IPs.
Output:
| ACTION_REMOTE_IP | UNIQUE_SOURCE_IPS |
|---|---|
| 10.0.0.1 | [192.168.1.10, 192.168.1.20] |
| 10.0.0.2 | [192.168.1.30] |
Example 2: All unique usernames across events
Goal: Find all distinct usernames across all events.
XQL code:
dataset = xdr_data | comp values(actor_effective_username) as unique_users
Explanation: Without a by clause, the values() function collects all distinct actor_effective_username values across the entire dataset.
Output:
| UNIQUE_USERS |
|---|
| [admin, user1, user2, svc_account] |
Example 3: Distinct event types per host
Goal: Find all unique event types observed on each host.
XQL code:
dataset = xdr_data | comp values(event_type) by agent_hostname as event_types, count(*) as total_events
Explanation: This query combines values() with count() to show both the distinct event types and the total event count per host.
Output:
| AGENT_HOSTNAME | EVENT_TYPES | TOTAL_EVENTS |
|---|---|---|
| workstation-1 | [NETWORK, PROCESS, FILE] | 150 |
| workstation-2 | [NETWORK, REGISTRY] | 85 |
Related articles
var
Use the var() function to compute the variance of a specified numeric field across all rows in each group within the comp stage. Variance measures how far values are spread out from the mean. By default, var() computes the population variance. This is equivalent to VAR_POP in SQL.
Syntax
| comp var(<field>) [by <group_field1>, <group_field2>, ...] [as <alias>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
numeric | Yes | The numeric field from which to compute the variance. |
group_field |
any | No | One or more fields to group the results by. If omitted, all rows are treated as a single group. |
alias |
string | No | An alias for the output field. If not specified, the output field name defaults to var_<field>. |
Returns
Type: numeric (float)
Description: The var() function returns the population variance of the specified field within each group. Returns NULL if all values in the group are NULL. Returns 0 if there is only one non-NULL value.
Usage notes
- Variance definition: Variance is the average of the squared differences from the mean:
sum((x - mean)^2) / N. - Relationship to standard deviation: Variance is the square of the standard deviation.
var(x) = stddev_population(x)^2. - Null handling: NULL values are ignored in the computation.
- Data types: Only works with numeric fields.
- Single value: If there is only one non-NULL value, the variance is 0.
- Use case: Variance is useful for statistical analysis, anomaly detection, and understanding data distribution.
Examples
Example 1: Variance of response times per host
Goal: Compute the variance of response times for each host.
XQL code:
dataset = xdr_data | comp var(action_total_time) by agent_hostname as response_variance
Explanation: The var() function computes the population variance of action_total_time for each unique agent_hostname, measuring how spread out the response times are from the mean.
Output:
| AGENT_HOSTNAME | RESPONSE_VARIANCE |
|---|---|
| workstation-1 | 155.00 |
| workstation-2 | 69.22 |
Example 2: Overall variance of bytes transferred
Goal: Compute the variance of bytes transferred across all events.
XQL code:
dataset = xdr_data | comp var(action_network_bytes_received) as bytes_variance
Explanation: Without a by clause, the var() function computes the population variance across all rows.
Output:
| BYTES_VARIANCE |
|---|
| 6035782.45 |
Example 3: Variance with mean and standard deviation
Goal: Compute variance alongside mean and standard deviation for comprehensive statistical analysis.
XQL code:
dataset = xdr_data | comp var(action_total_time) as variance, avg(action_total_time) as mean, stddev_population(action_total_time) as stddev by agent_hostname
Explanation: This query combines var(), avg(), and stddev_population() to provide a complete statistical summary per host. Note that the variance equals the square of the standard deviation.
Output:
| AGENT_HOSTNAME | VARIANCE | MEAN | STDDEV |
|---|---|---|---|
| workstation-1 | 155.00 | 45.30 | 12.45 |
| workstation-2 | 69.22 | 32.10 | 8.32 |
Related articles
- Stages:
comp,fields,limit - Functions:
stddev_population(),stddev_sample(),avg() - Datasets:
xdr_data
wildcard_match
Use the wildcard_match function to determine if a given string matches a specified wildcard pattern. The function is primarily used for flexible pattern matching beyond literal equality, often for filtering or categorizing data.
Syntax
wildcard_match(<string_value>, <wildcard_pattern>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
string_value |
string | Yes | The input string field or literal value to be evaluated against the pattern. |
wildcard_pattern |
string | Yes | The pattern string, which can include wildcard characters * and ?. |
Returns
The function returns a boolean value: true if the string matches the pattern, and false otherwise.
Usage notes
- Availability: This function is only available with Cortex XSIAM licenses that include Cortex Cloud.
- Wildcard characters:
*(Asterisk): Matches a sequence of zero or more (possibly different) characters.?(Question Mark): Matches exactly one character.- Case sensitivity: By default, the function is case-sensitive. To perform a case-insensitive match, you must add the
(?i)syntax once at the beginning of the regular expression within the pattern string. - Stage usage: This function is typically used within the
alterstage to create new boolean fields or directly withinfilterstages to narrow down results.
Examples
Example 1: Basic wildcard matching with *
Goal: Check if the event_description starts with "User" and ends with "successful".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter matches_user_login = wildcard_match(event_description, "User*successful") | fields event_id, event_description, matches_user_login | limit 2
Explanation: The function returns true for event 101 because "User login successful" matches the pattern "User*successful". The query returns false for event 102 because "File access attempt" does not match.
Output:
| event_id | event_description | matches_user_login |
|---|---|---|
| 101 | "User login successful" | true |
| 102 | "File access attempt" | false |
Example 2: Wildcard matching with ?
Goal: Use the ? wildcard to match exactly one character within the raw_log_data field, targeting a specific process name pattern like "c?d.exe".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter matches_cmd_pattern = wildcard_match(raw_log_data, "Process c?d.exe*") | fields event_id, raw_log_data, matches_cmd_pattern | limit 2
Explanation: For event 102, the string "Process cmd.exe..." matches the pattern because the 'm' in "cmd" is a single character matched by ?. Event 101 does not match the pattern.
Output:
| event_id | raw_log_data | matches_cmd_pattern |
|---|---|---|
| 101 | "User Alice logged in from 192.168.1.10" | false |
| 102 | "Process cmd.exe attempted to access /etc/passwd" | true |
Example 3: Complex pattern with * and ?
Goal: Combine both wildcards to match a complex file path pattern in raw_log_data.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter matches_complex_pattern = wildcard_match(raw_log_data, "*cmd.ex? attempted to access /*/passw?d") | fields event_id, raw_log_data, matches_complex_pattern | limit 2
Explanation: The pattern uses * to match variable segments ("Process " and "tc/") and ? to match specific single characters ('e' in exe and 'd' in passwd). This correctly identifies event 102 as a match.
Output:
| event_id | raw_log_data | matches_complex_pattern |
|---|---|---|
| 101 | "User Alice logged in from 192.168.1.10" | false |
| 102 | "Process cmd.exe attempted to access /etc/passwd" | true |
Example 4: Case-insensitive matching
Goal: Perform a case-insensitive check on event_description using the (?i) flag.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter matches_case_insensitive = wildcard_match(event_description, "(?i)user*login*successful") | fields event_id, event_description, matches_case_insensitive | limit 2
Explanation: Even though event_description starts with an uppercase "User" and the pattern specifies "user", the (?i) flag enables case-insensitive matching, resulting in true for event 101.
Output:
| event_id | event_description | matches_case_insensitive |
|---|---|---|
| 101 | "User login successful" | true |
| 102 | "File access attempt" | false |
Related articles
Stages
XQL stages define how data flows through a query pipeline.
Use this section to:
Stages overview
XQL pipeline stages define query structure and control query flow.
Each stage performs one operation. Stages connect with the pipe (|) operator.
Stages list
The following table lists all available XQL pipeline stages:
| Stage | Description |
|---|---|
alter |
Manipulate data by changing existing field values or creating new fields |
arrayexpand |
Expand an array field into multiple rows |
bin |
Group numeric values into bins |
call |
Call a saved XQL query |
comp |
Aggregate data using grouping and aggregate functions |
config |
Configure query settings |
dataset |
Specify the dataset to query |
dedup |
Remove duplicate rows |
fields |
Select or exclude specific fields |
filter |
Filter rows based on a condition |
iploc |
Enrich IP addresses with geolocation data |
join |
Join two datasets |
limit |
Limit the number of rows returned |
pivot |
Rotate row-level data into columns using aggregate functions |
preset |
Apply preset configurations |
replacenull |
Replace null values with a specified value |
search |
Search for records matching a text query |
sort |
Sort rows by one or more fields |
tag |
Add tags to query results |
target |
Specify the target output for query results |
top |
Return the top N rows by a specified field |
transaction |
Group events into transactions |
transpose |
Transpose rows into columns |
union |
Combine the results of two or more queries |
view |
Query a saved view |
windowcomp |
Perform analytic (window) functions over a defined window of rows without collapsing the dataset |
| Stage | Description |
|---|---|
alter |
Manipulate data by changing existing field values or creating new fields |
arrayexpand |
Expand an array field into multiple rows |
bin |
Group numeric values into bins |
call |
Call a saved XQL query |
comp |
Aggregate data using grouping and aggregate functions |
config |
Configure query settings |
dataset |
Specify the dataset to query |
dedup |
Remove duplicate rows |
fields |
Select or exclude specific fields |
filter |
Filter rows based on a condition |
iploc |
Enrich IP addresses with geolocation data |
join |
Join two datasets |
limit |
Limit the number of rows returned |
pivot |
Rotate row-level data into columns using aggregate functions |
preset |
Apply preset configurations |
replacenull |
Replace null values with a specified value |
search |
Perform free-text searches across ingested data |
sort |
Sort rows by one or more fields |
tag |
Add tags to query results |
target |
Specify the target output for query results |
top |
Return the top N rows by a specified field |
transaction |
Group events into transactions |
transpose |
Transpose rows into columns |
union |
Combine the results of two or more queries |
view |
Query a saved view |
windowcomp |
Perform analytic (window) functions over a defined window of rows without collapsing the dataset |
alter
Use the alter stage to manipulate data by changing existing field values or creating new fields based on constants, other fields, or the results of various XQL functions.
Syntax
alter <field1> = <function value1> [, <field2> = <function_value2>, ...]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
<field> |
string | Yes | The name of the field to create or modify. |
<function_value> |
various | Yes | The constant, field reference, or function result to assign to the field. |
Returns
The alter stage returns the dataset with the specified fields modified or added. New columns created by the alter stage are added as the last columns in the result set.
Usage notes
- New fields and field values can only be created in the
alterstage. No other stage allows for the creation of new fields and/or values. - After defining or modifying a field with
alter, you can apply other stages, such asfilter, to this new or modified field. - New columns created by the
alterstage are added as the last columns in the result set. If a specific column order is desired, it can be adjusted using thefieldsstage later in the query. - XQL supports single (
"<text>") and triple ("""<text>""") double quotes for defining string fields. - Single quotes treat values literally, while triple quotes process escape sequences (like
\tfor tab) and escaped backslashes. Choose the appropriate quoting based on your desired interpretation of special characters.
Examples
Example 1: Creating a new field with a constant value
Goal: Add a new column with a fixed value for all records.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter analysis_tag = "initial_review" | fields event_id, analysis_tag
Explanation: A new field analysis_tag is created, and the value "initial_review" is assigned to every record.
Output:
| EVENT_ID | ANALYSIS_TAG |
|---|---|
| 101 | initial_review |
| 102 | initial_review |
| 103 | initial_review |
Example 2: Creating a new field based on an existing field
Goal: Duplicate a field or create a new field that directly references an existing one.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter replicated_description = event_description | fields event_id, replicated_description
Explanation: The replicated_description field is created, mirroring the event_description field.
Output:
| EVENT_ID | REPLICATED_DESCRIPTION |
|---|---|
| 101 | User login successful |
| 102 | File access attempt |
| 103 | Network connection established |
Example 3: Modifying an existing field
Goal: Overwrite the current value of a known field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_description = concat("Processed: ", event_description) | fields event_id, event_description
Explanation: The original event_description is updated by prepending "Processed: " to its value.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | Processed: User login successful |
| 102 | Processed: File access attempt |
| 103 | Processed: Network connection established |
Example 4: Using string manipulation functions (concat)
Goal: Join multiple strings together to reformat text data.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter event_summary = concat(event_description, " - Success: ", to_string(is_successful)) | fields event_id, event_summary
Explanation*: event_summary is created by concatenating the event description, a static string, and the boolean is_successful converted to a string.
Output:
| EVENT_ID | EVENT_SUMMARY |
|---|---|
| 101 | User login successful - Success: true |
| 102 | File access attempt - Success: false |
| 103 | Network connection established - Success: true |
Example 5: Using string manipulation functions (lowercase)
Goal: Convert a string to all lowercase letters.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter lower_case_log = lowercase(raw_log_data) | fields event_id, lower_case_log
Explanation: The raw_log_data field's content is converted to lowercase and stored in lower_case_log.
Output:
| EVENT_ID | LOWER_CASE_LOG |
|---|---|
| 101 | user alice logged in from 192.168.1.10 |
| 102 | process cmd.exe attempted to access /etc/passwd |
Example 6: Using string manipulation functions (split)
Goal: Divide a string into an array of substrings based on a delimiter.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter log_words = split(raw_log_data, " ") | fields event_id, log_words
Explanation: The raw_log_data string is split into an array of words based on spaces, creating the log_words field.
Output:
| EVENT_ID | LOG_WORDS |
|---|---|
| 101 | ["User", "Alice", "logged", "in", "from", "192.168.1.10"] |
| 102 | ["Process", "cmd.exe", "attempted", "to", "access", "/etc/passwd"] |
Example 7: Using JSON functions (json_extract_scalar)
Goal: Extract a single scalar value (for example, string, number, boolean) from a JSON object.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter json_status = json_extract_scalar(simple_json_data, "$.status") | fields event_id, json_status
Explanation: Extracts the value of the "status" key from the simple_json_data JSON object into json_status.
Output:
| EVENT_ID | JSON_STATUS |
|---|---|
| 101 | ok |
| 102 | fail |
Example 8: Using JSON functions (json_extract_array)
Goal: Convert a JSON array string to an XQL-native array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter parsed_actions = json_extract_array(array_of_json_objects, "$") | fields event_id, parsed_actions
Explanation: Converts the array_of_json_objects string (which contains a JSON array) into a native XQL array stored in parsed_actions.
Output:
| EVENT_ID | PARSED_ACTIONS |
|---|---|
| 101 | [{"action": "read", "file": "doc1.txt"}, {"action": "write", "file": "report.log"}] |
| 102 | [{"event": "file_open", "path": "/etc/passwd"}] |
Example 9: Using conditional and null handling functions (if)
Goal: Apply logic to assign values based on conditions.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter outcome_category = if(is_successful, "Operational", "Alertable") | fields event_id, outcome_category
Explanation: If is_successful is true, creates outcome_category as "Operational". If is_successful is false, creates outcome_category as "Alertable".
Output:
| EVENT_ID | OUTCOME_CATEGORY |
|---|---|
| 101 | Operational |
| 102 | Alertable |
| 103 | Operational |
Example 10: Using conditional and null handling functions (coalesce)
Goal: Return the first non-NULL expression among its arguments.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter resolved_ip = coalesce(ipv4_address, ipv6_address) | fields event_id, resolved_ip
Explanation: Assigns the value of ipv4_address to resolved_ip. If ipv4_address is NULL, the field is assigned ipv6_address instead.
Output:
| EVENT_ID | RESOLVED_IP |
|---|---|
| 101 | 192.168.1.10 |
| 103 | 2001:0db8::1 |
Example 11: Using time functions (format_timestamp)
Goal: Format a timestamp into a specified string format.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter formatted_timestamp = format_timestamp("%Y-%m-%d %H:%M:%S", _time) | fields event_id, formatted_timestamp
Explanation: Converts the _time field into a readable string format YYYY-MM-DD HH:MM:SS.
Output:
| EVENT_ID | FORMATTED_TIMESTAMP |
|---|---|
| 101 | 2023-10-26 10:00:00 |
| 102 | 2023-10-26 10:05:30 |
Example 12: Using mathematical functions (add)
Goal: Add two numerical values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter adjusted_duration = add(duration_seconds, 5.0) | fields event_id, adjusted_duration
Explanation: Adds 5.0 to duration_seconds for each record, storing the result in adjusted_duration.
Output:
| EVENT_ID | ADJUSTED_DURATION |
|---|---|
| 101 | 6.5 |
| 102 | 5.8 |
Example 13: Using mathematical functions (multiply)
Goal: Multiply two numerical values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter doubled_duration = multiply(duration_seconds, 2) | fields event_id, doubled_duration
Explanation: Multiplies duration_seconds by 2, storing the result in doubled_duration.
Output:
| EVENT_ID | DOUBLED_DURATION |
|---|---|
| 101 | 3.0 |
| 102 | 1.6 |
Example 14: Using mathematical functions (divide)
Goal: Perform division on numerical values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter duration_in_minutes = divide(duration_seconds, 60) | fields event_id, duration_in_minutes
Explanation: Converts duration_seconds to minutes by dividing by 60, storing the result in duration_in_minutes.
Output:
| EVENT_ID | DURATION_IN_MINUTES |
|---|---|
| 101 | 0.025 |
| 102 | 0.0133 |
Example 15: Using array functions (arraycreate)
Goal: Form a new array from specified values.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter default_tags = arraycreate("default_tag", "processed") | fields event_id, default_tags
Explanation: Creates a new array default_tags containing the specified string values for each record.
Output:
| EVENT_ID | DEFAULT_TAGS |
|---|---|
| 101 | ["default_tag", "processed"] |
| 102 | ["default_tag", "processed"] |
Example 16: Using array functions (arraymap)
Goal: Apply a function to each element of an array.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter positive_codes = arraymap(numeric_codes, if("@element" < 0, 0, "@element")) | fields event_id, positive_codes
Explanation: Creates positive_codes by going through the array numeric_codes and replacing any negative values with 0.
Output:
| EVENT_ID | POSITIVE_CODES |
|---|---|
| 101 | [13, 0, 29, 82, 0] |
| 102 | [0, 56, 13, 0, 42] |
Example 17: Using array functions (arrayrange)
Goal: Generate a portion of an array based on specified indices.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter first_two_tags = arrayrange(string_tags, 0, 2) | fields event_id, first_two_tags
Explanation: Extracts the first two elements (indices 0 and 1) from the string_tags array into first_two_tags.
Output:
| EVENT_ID | FIRST_TWO_TAGS |
|---|---|
| 101 | ["security", "login"] |
| 102 | ["filesystem", "critical"] |
Related articles
- Stages:
filter,fields - Functions:
concat,lowercase,split,json_extract_scalar,json_extract_array,if,coalesce,format_timestamp,add,multiply,divide,arraycreate,arraymap,arrayrange
arrayexpand
Use the arrayexpand stage to expand the values of a multi-value array field into separate events, creating a new record in the result set for each item present in the array.This is particularly useful when you need to analyze or filter individual elements within an array as if they were separate rows of data.
Syntax
arrayexpand <array_field> [limit <limit_number>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
array_field |
string | Yes | The name of the array field you wish to expand. |
limit_number |
integer | No | Specifies the maximum number of records to create from the array expansion. If an array has more elements than this limit, only up to the specified number of records will be generated from its expansion. |
Returns
The arrayexpand stage returns a dataset where, for each element in the specified array field, a new row is generated in the result set, duplicating all other fields from the original row.
Usage notes
- The records created by
arrayexpandare returned in no particular order. - If a specific order is required, you must apply a
sortstage afterarrayexpand. - The expansion duplicates all other fields from the original row for every new record created.
Examples
Example 1: Basic arrayexpand on a simple array
Goal: Expand the string_tags array into separate records. XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, string_tags | arrayexpand string_tags | limit 5
Explanation: For each original row in sample_xql_raw that has values in string_tags (for example, event ID 101 has ["security", "login"]), arrayexpand creates a separate row for each tag. Event ID 101 results in two rows: one for "security" and one for "login", each retaining the original event_id.
Output:
| event_id | string_tags |
|---|---|
| 101 | security |
| 101 | login |
| 102 | filesystem |
| 102 | critical |
| 103 | network |
Example 2: arrayexpand with limit
Goal: Expand the numeric_codes array but restrict the number of expanded records for each original row to a specified limit.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, numeric_codes | arrayexpand numeric_codes limit 2 | limit 5
Explanation: For original rows like event ID 101, which has numeric_codes containing 5 elements, this query creates new records for only the first two elements. If the array has fewer than two elements, the query creates records for all existing elements.
Output:
| event_id | numeric_codes |
|---|---|
| 101 | 13 |
| 101 | -47 |
| 102 | -21 |
| 102 | 56 |
| 103 | 90 |
Example 3: arrayexpand followed by sort
Goal: Expand string_tags and then sort the resulting records by the expanded tag value.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, string_tags | arrayexpand string_tags | sort asc string_tags | limit 5
Explanation: This query first expands the string_tags array for each event. Then, it sorts all the generated records based on the string_tags field (which now holds individual tag values), ensuring the final output is ordered alphabetically by tag.
Output:
| event_id | string_tags |
|---|---|
| 103 | cloud |
| 102 | critical |
| 105 | data_ops |
| 102 | filesystem |
| 101 | login |
Example 4: arrayexpand on an array of JSON objects
Goal: Expand an array where each element is a JSON object, then extract a specific scalar value from those expanded objects.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter array_length(array_of_json_objects) > 0 | fields event_id, array_of_json_objects | arrayexpand array_of_json_objects | alter action_type = json_extract_scalar(array_of_json_objects, "$.action") | fields event_id, action_type | limit 5
Explanation: For an event like ID 101, which has an array of JSON objects, this query first expands the array into separate records. Then, for each of these new records, it extracts the value associated with the "action" key using json_extract_scalar(), creating a new action_type field.
Output:
| event_id | action_type |
|---|---|
| 101 | read |
| 101 | write |
| 106 | NULL |
| 106 | NULL |
| 105 | NULL |
Related articles
- Stages:
sort,fields,limit,alter - Functions:
json_extract_scalar,array_length - Datasets:
xdr_data
bin
Use the bin stage to discretize a continuous numerical field or timestamp into separate buckets, or "bins." This is commonly used to group data into ranges, like age groups or time intervals, for aggregation and analysis.
Syntax
You can add the bin stage to your queries using two different formats, depending on whether you are grouping events by quantity or by time span.
Quantity:
bin <field_name> bins=<number>
Time span:
bin <field_name> span=<number><timescale> [timeshift=<epoch time> [timezone="<time zone>"]]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field_name |
string | Yes | The name of the numeric or timestamp field to be binned. When grouping by quantity, the field must be a number. When grouping by time, the field must be a date type. Otherwise, the query fails. |
bins |
number | No | The maximum number of bins to divide the data into. Instead of specifying a fixed bin size with span, use bins to let the stage automatically calculate an appropriate bin size so that the values are distributed across (at most) the specified number of bins. Provide either span or bins, but not both. |
span |
string | No | The size of each bin. For timestamps, this is a number followed by a timescale suffix (for example, 1h, 15m, 1d). See Time suffixes for the list of supported suffixes. For numeric fields, this is an integer representing the interval size. Provide either span or bins, but not both. |
timeshift |
number | No | A start time for grouping the events, expressed as a Unix epoch time. Use with span when binning by time. If not set, the query runs according to the last time set in the log. |
timezone |
string | No | The time zone applied when grouping events by time. Configure it using an hours offset, such as "+08:00", or using a time zone name from the List of Supported Time Zones, such as "America/Chicago". Optionally used together with timeshift. |
Time suffixes
When binning by time span, <span> is a combination of a number and one of the following time suffixes. The time suffix is not case sensitive.
| Time suffix | Description |
|---|---|
MS |
milliseconds |
S |
seconds |
M |
minutes |
H |
hours |
D |
days |
W |
weeks |
MO |
months |
Y |
years |
Returns
The bin stage modifies the specified field in the dataset, replacing the original continuous values with the starting value of the bin interval they fall into. The resulting field retains its original name.
Usage notes
- The
binstage is often used immediately before an aggregation stage likecompto group records by time or numeric ranges. The most common use case is for timecharts. - Binning simplifies complex continuous data by separating it into manageable categories.
- When binning timestamps, the returned value is the start time of the interval. For example, with
span=1h, a timestamp of10:45becomes10:00. - The
spanparameter determines the granularity of the groups. - You must specify either
spanorbins, but not both. Usespanwhen you know the exact bin size you want, and usebinswhen you want a specific number of buckets and want the stage to determine the bin size automatically. - When you use
bins, the stage calculates a bin size that distributes the values across at most the specified number of bins, so the actual number of populated bins can be fewer. - When you group events by quantity, the binned field must be a number. When you group events by time, the binned field must be a date type. Otherwise, the query fails.
- The
binstage is only supported using the equal sign (=) operator, without any boolean operators (and,or). - Use the optional
timeshiftparameter to define a start time for grouping the events according to the Unix epoch time, and use the optionaltimezoneparameter to apply a specific time zone. If neither is set, the query runs according to the last time set in the log.
Examples
Example 1: Binning by time
Goal: Group events into 1-hour intervals to prepare for counting events per hour.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | bin _time span = 1h | comp count(event_id) as events_per_hour by _time | fields _time, events_per_hour
Explanation: The _time field is binned into 1-hour buckets. The comp stage then counts the number of events that fall into each hour, creating a timeline of activity.
Output:
| _time | events_per_hour |
|---|---|
| 2023-10-26 10:00:00 | 45 |
| 2023-10-26 11:00:00 | 32 |
| 2023-10-26 12:00:00 | 50 |
Example 2: Binning numeric values
Goal: Group file sizes into buckets of 100MB to analyze the distribution of file sizes.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter file_size_mb = divide(file_size, 1024 * 1024) | bin file_size_mb span = 100 | comp count(event_id) as file_count by file_size_mb | fields file_size_mb, file_count
Explanation: First, file size is converted to megabytes. Then, bin groups these sizes into 100MB intervals (0-100, 100-200, etc.). The comp stage counts how many files fall into each size range.
Output:
| file_size_mb | file_count |
|---|---|
| 0 | 150 |
| 100 | 40 |
| 200 | 12 |
Example 3: Binning into a fixed number of buckets
Goal: Group file sizes into at most 5 buckets without specifying an exact bin size, letting the stage calculate the interval automatically.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | alter file_size_mb = divide(file_size, 1024 * 1024) | bin file_size_mb bins = 5 | comp count(event_id) as file_count by file_size_mb | fields file_size_mb, file_count
Explanation: Instead of defining a fixed interval with span, the bins = 5 parameter instructs the stage to divide the range of file_size_mb values into at most 5 buckets, automatically calculating an appropriate bin size. The comp stage then counts how many files fall into each bucket.
Output:
| file_size_mb | file_count |
|---|---|
| 0 | 120 |
| 50 | 60 |
| 100 | 15 |
| 150 | 5 |
| 200 | 2 |
Example 4: Binning by time with a time zone offset
Goal: Group events into 1-hour intervals starting from a specific epoch time, using a time zone configured with an hours offset.
XQL code:
dataset = xdr_data | bin _time span = 1h timeshift = 1615353499 timezone = "+08:00" | limit 1000
Explanation: The _time field is grouped into 1-hour increments starting from the Unix epoch time 1615353499, applying a time zone offset of +08:00. The limit stage returns a maximum of 1,000 records.
Example 5: Binning by time with a time zone name
Goal: Group events into 1-hour intervals starting from a specific epoch time, using a named time zone.
XQL code:
dataset = xdr_data | bin _time span = 1h timeshift = 1615353499 timezone = "America/Los_Angeles" | limit 1000
Explanation: The _time field is grouped into 1-hour increments starting from the Unix epoch time 1615353499, applying the America/Los_Angeles time zone. The limit stage returns a maximum of 1,000 records.
Related articles
- Stages: comp, alter
- Functions: count, divide
call
Use the call stage to reference and execute a saved query from the Query Library as a sub-query within your current XQL query. This allows you to modularize complex logic, reuse common query patterns, and maintain cleaner query structures.
Syntax
call <saved_query_name>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
saved_query_name |
string | Yes | The exact name of the saved query in the Query Library that you want to execute. If the name contains spaces, it must be enclosed in double quotes (for example, "My Saved Query"). |
Returns
The call stage returns the dataset produced by the execution of the referenced saved query. The subsequent stages in your main query will process this returned dataset.
Usage notes
- The
callstage effectively replaces itself with the full XQL string of the saved query at execution time. - It is best practice to use
callat the beginning of your query pipeline to fetch a prepared dataset, though it can be used wherever a dataset transformation is valid, provided the saved query's output is compatible with the preceding stages. - Recursive calls (a query calling itself) are not supported.
- Ensure the saved query you are calling exists in the Query Library and that you have permission to view it.
- If the saved query name changes, you must update the
callstatement in your queries to reflect the new name.
Examples
Example 1: Calling a saved query
Goal: Use a pre-defined saved query named "Failed Logins Last 24h" to start an investigation.
XQL code:
call "Failed Logins Last 24h" | filter user_name != "admin" | fields _time, user_name, src_ip
Explanation: The query first executes the saved query "Failed Logins Last 24h". The results of that query are then passed to the filter stage, which removes records where the user is "admin", and finally selects specific fields for display.
Output: The output depends entirely on the data returned by the saved query and the subsequent filter.
Example 2: Reusing data preparation logic
Goal: Reuse a standardized data cleaning query named clean_xdr_data before performing a specific aggregation.
XQL code:
call clean_xdr_data | comp count(event_id) by agent_os_type
Explanation: The clean_xdr_data saved query is executed first (likely filtering out noise and normalizing fields). The resulting "clean" dataset is then aggregated to count events by OS type.
Output:
| agent_os_type | count |
|---|---|
| Windows | 1500 |
| Linux | 450 |
| macOS | 200 |
Related articles
comp
Use the comp stage (short for computation) to perform aggregation functions on your dataset. This stage groups records based on specified fields and calculates summary statistics�such as counts, averages, or sums�for each group. The stage is essential for transforming raw event data into meaningful metrics and trends.
Syntax
comp <function1>(<field1>) [as <alias1>], [<function2>(<field2>) [as <alias2>], ...] by <group_field1> [, <group_field2>, ...]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
function |
function | Yes | The aggregation function to apply (for example, count, sum, avg, max, min, values). |
field |
string | Yes | The name of the field to be aggregated. |
alias |
string | No | An optional name for the resulting aggregated field. If omitted, a default name is generated (usually function_field). |
group_field |
string | Yes | The field(s) used to group the results. All records with the same value in the group_field are calculated together. |
Returns
The comp stage returns a summary dataset where each row represents a unique combination of the by (grouping) fields. The columns include the grouping fields and the results of the aggregation functions. All other original fields are discarded.
Usage notes
- The
compstage is a "blocking" operation; it must process all input records before producing any output. - Common aggregation functions include
count,sum,avg,min,max,count_distinct, andvalues. - You can group by multiple fields (for example,
by user, host), which creates a separate row for every unique pair of user and host. - It is highly recommended to provide an alias (using
as) for aggregated columns to make the output readable and easier to reference in later stages. - If you need to group by time, consider using the
binstage on a timestamp field before thecompstage.
Examples
Example 1: Basic Counting
Goal: Count the number of events associated with each user. XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp count(event_id) as total_events by user_name | fields user_name, total_events
Explanation: This query groups all records by user_name and counts the number of event_ids for each user, storing the result in total_events. Output:
| user_name | total_events |
|---|---|
| alice | 150 |
| bob | 42 |
| charlie | 5 |
Example 2: Multiple Aggregations
Goal: Find the first and last occurrence of an event for each IP address. XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp min(_time) as first_seen, max(_time) as last_seen by src_ip | fields src_ip, first_seen, last_seen
Explanation: Grouping by src_ip, the query calculates the minimum (earliest) timestamp and maximum (latest) timestamp for each IP address. Output:
| src_ip | first_seen | last_seen |
|---|---|---|
| 192.168.1.5 | 2023-10-26 08:00:00 | 2023-10-26 17:30:00 |
| 10.0.0.42 | 2023-10-26 09:15:00 | 2023-10-26 09:20:00 |
Example 3: Grouping by Time (after Binning)
Goal: Count the number of failed logins per hour. XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_type = "login_failed" | bin _time span = 1h | comp count(event_id) as failure_count by _time | fields _time, failure_count
Explanation: The bin stage buckets the timestamps into 1-hour intervals. The comp stage then groups by these 1-hour buckets to count the failed login events. Output:
| _time | failure_count |
|---|---|
| 2023-10-26 10:00:00 | 12 |
| 2023-10-26 11:00:00 | 8 |
| 2023-10-26 12:00:00 | 25 |
Example 4: Collecting Unique Values
Goal: List all unique applications used by each host. XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp values(app_name) as distinct_apps by host_name | fields host_name, distinct_apps
Explanation: The values function collects a list of all unique app_name entries for each host_name. Output:
| host_name | distinct_apps |
|---|---|
| server-01 | ["nginx", "ssh", "python"] |
| laptop-99 | ["chrome", "slack"] |
Related articles
config
Use the config stage to configure the behavior of your query, specifically controlling case sensitivity and the execution time frame. This stage is crucial for query optimization and must always be the very first stage in your XQL query.
Syntax
config case_sensitive = true | false config timeframe = <number><time unit> config timeframe between <start> and <end>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
case_sensitive |
boolean | No | Controls whether field values are evaluated in a case-sensitive manner. Default is false. |
timeframe |
string | No | Defines the specific time range for the query's execution. |
number |
integer | Yes (if timeframe used) | The duration value for the timeframe. |
time_unit |
string | Yes (if timeframe used) | The unit of time (S, M, H, D, W, MO, Y). Not case-sensitive. |
start |
string | Yes (if between used) | The start of the time range. Can be a relative offset (for example, "-1h"), "begin", or an exact timestamp. |
end |
string | Yes (if between used) | The end of the time range. Can be a relative offset, "now", or an exact timestamp. |
Returns
The config stage does not return a value itself but sets the execution context (rules and scope) for the subsequent query stages.
Usage notes
- The
configstage must always be the first stage in your XQL query. - For
case_sensitive, if not explicitly set, XQL queries operate with case-insensitivity (false) by default. - For
timeframe, available time units are: S (seconds), M (minutes), H (hours), D (days), W (weeks), MO (months), Y (years). These are not case-sensitive. - While the Query Builder's time picker automatically sets the timeframe, it will only appear in your query text if you manually type the
config timeframecommand.
Examples
Example 1: Case-sensitive search
Goal: Configure the query to strictly match the case of string values during filtering.
XQL code:
config case_sensitive = true | dataset = sample_xql_raw | filter event_description = "user login successful" | fields event_id, event_description | limit 5
Explanation: The query attempts to find records where event_description is exactly "user login successful" (lowercase). Given the dataset contains "User login successful" (uppercase 'U'), this query yields no results because case_sensitive is set to true.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| (No results) |
Example 2: Case-insensitive search
Goal: Configure the query to ignore case differences when matching string values.
XQL code:
config case_sensitive = false | dataset = sample_xql_raw | filter event_description = "user login successful" | fields event_id, event_description | limit 5
Explanation: With case_sensitive set to false, the query successfully matches the lowercase string "user login successful" to the dataset's "User login successful", retrieving the record.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | User login successful |
Example 3: Relative time (simple duration)
Goal: Retrieve records from the specified duration counting back from the current query execution time.
XQL code:
config timeframe = 1h | dataset = sample_xql_raw | fields _time, event_id, event_description | limit 10
Explanation: If executed at 2023-10-26 10:30:00 UTC, this query retrieves events from the last hour (09:30:00 to 10:30:00 UTC), essentially capturing events 101 through 105 from the sample data.
Output:
| _TIME | EVENT_ID | EVENT_DESCRIPTION |
|---|---|---|
| 2023-10-26 10:00:00 UTC | 101 | User login successful |
| 2023-10-26 10:05:30 UTC | 102 | File access attempt |
| 2023-10-26 10:15:15 UTC | 103 | Network connection established |
| 2023-10-26 10:20:00 UTC | 104 | System heartbeat |
| 2023-10-26 10:30:45 UTC | 105 | Data transformation |
Example 4: Relative time (range ending now)
Goal: Retrieve records within a range starting from a relative point in the past and ending at the current time.
XQL code:
config timeframe between "-30m" and "now" | dataset = sample_xql_raw | fields _time, event_id, event_description | limit 10
Explanation: If executed at 2023-10-26 10:45:00 UTC, this returns events from 10:15:00 UTC to 10:45:00 UTC. This window captures events 103 through 107 (conceptual match based on sample data timing).
Output:
| _TIME | EVENT_ID | EVENT_DESCRIPTION |
|---|---|---|
| 2023-10-26 10:15:15 UTC | 103 | Network connection established |
| 2023-10-26 10:20:00 UTC | 104 | System heartbeat |
| 2023-10-26 10:30:45 UTC | 105 | Data transformation |
| 2023-10-26 10:40:10 UTC | 106 | Unauthorized access detected |
| 2023-10-26 10:45:00 UTC | 107 | Cloud resource modification |
Example 5: Relative time (from beginning to past offset)
Goal: Retrieve records from the Unix epoch up to a specific relative point in the past.
XQL code:
config timeframe between "begin" and "-1y" | dataset = sample_xql_raw | fields _time, event_id, event_description | limit 10
Explanation: This queries data from 1970-01-01 up to one year ago from the current execution time. If "now" is significantly in the future relative to the sample data (for example, late 2024), this would successfully retrieve the 2023 records.
Output:
| _TIME | EVENT_ID | EVENT_DESCRIPTION |
|---|---|---|
| 2023-10-26 10:00:00 UTC | 101 | User login successful |
| 2023-10-26 10:05:30 UTC | 102 | File access attempt |
| ... | ... | ... |
Example 6: Relative time (between two offsets)
Goal: Define a relative window spanning between two points in the past relative to the current execution time.
XQL code:
config timeframe between "-2h" and "-1h" | dataset = sample_xql_raw | fields _time, event_id, event_description | limit 10
Explanation: If executed at 2023-10-26 11:00:00 UTC, the window is 09:00:00 to 10:00:00. Only event 101 (at exactly 10:00:00) fits this window.
Output:
| _TIME | EVENT_ID | EVENT_DESCRIPTION |
|---|---|---|
| 2023-10-26 10:00:00 UTC | 101 | User login successful |
Example 7: Exact timeframe
Goal: Define a precise, static start and end timestamp for the query.
XQL code:
config timeframe between "2023-10-26 10:00:00 UTC" and "2023-10-26 10:30:00 UTC" | dataset = sample_xql_raw | fields _time, event_id, event_description | limit 100
Explanation: This query explicitly selects records between 10:00:00 and 10:30:00 UTC on the specified date.
Output:
| _TIME | EVENT_ID | EVENT_DESCRIPTION |
|---|---|---|
| 2023-10-26 10:00:00 UTC | 101 | User login successful |
| 2023-10-26 10:05:30 UTC | 102 | File access attempt |
| 2023-10-26 10:15:15 UTC | 103 | Network connection established |
| 2023-10-26 10:20:00 UTC | 104 | System heartbeat |
| 2023-10-26 10:30:45 UTC | 105 | Data transformation |
Related articles
dataset
Use the dataset stage to explicitly define the data table your XQL query will retrieve records from. This is a fundamental component used to specify the data source and is crucial for query optimization.
Syntax
dataset [=] <dataset_name> dataset in (<dataset_name1>, <dataset_name2>, ...) cold_dataset = <dataset_name>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
dataset_name |
string | Yes | The name of the dataset to query. If omitted, the query defaults to xdr_data. |
in |
operator | No | An operator used to specify a list of multiple datasets to query simultaneously. |
Returns
The dataset stage returns raw records and all available fields from the specified data source(s).
Usage notes
- The
datasetstage must always be the very first stage in your XQL query, unless it is preceded by aconfigstage. - If you do not explicitly define a dataset, Cortex XDR/XSIAM will default to querying the
xdr_datadataset. - Dataset names in queries are always treated as if they are lowercase, even if you type them with uppercase characters (Case Insensitivity).
- Specifying the dataset early is a best practice for streamlining queries, as it helps reduce the amount of data processed.
- The
cold_datasetsyntax is used specifically for querying data stored in cold storage.
Examples
Example 1: Basic Dataset Specification
Goal: Explicitly specify a single data source for the query.
XQL code:
config timeframe = 1d // Set a practical timeframe for the query | dataset = sample_xql_raw // Specifies the data source for the query | limit 5 // Limits the number of returned records to improve performance
Explanation: This query retrieves all available fields from the sample_xql_raw dataset within the specified timeframe.
Output:
| event_id | _time | event_description |
|---|---|---|
| 101 | 2023-10-26 10:00:00 UTC | "User login successful" |
| 102 | 2023-10-26 10:05:30 UTC | "File access attempt" |
| 103 | 2023-10-26 10:15:15 UTC | "Network connection established" |
| 104 | 2023-10-26 10:20:00 UTC | "System heartbeat" |
| 105 | 2023-10-26 10:30:45 UTC | "Data transformation" |
Example 2: Specifying Multiple Datasets
Goal: Query across several different datasets using the in operator.
XQL code:
config timeframe = 1d // Ensures the query operates within a defined time window | dataset in ("sample_xql_raw") // Specifies one or more datasets to query from | filter is_successful = true // Filters for successful events | fields event_id, event_description, is_successful // Selects only the necessary fields for output | limit 5 // Prevents excessive results and improves query performance
Explanation: This query demonstrates the dataset in syntax. While sample_xql_raw is a single dataset, this syntax allows listing multiple datasets (for example, dataset in ("dataset1", "dataset2")) to aggregate results from multiple sources.
Output:
| event_id | event_description | is_successful |
|---|---|---|
| 101 | "User login successful" | true |
| 103 | "Network connection established" | true |
| 104 | "System heartbeat" | true |
| 105 | "Data transformation" | true |
| 107 | "Cloud resource modification" | true |
Example 3: cold_dataset Note (conceptual example)
Goal: Query data that is stored in cold storage.
XQL code:
config timeframe = 7d | cold_dataset = sample_xql_raw_cold // Placeholder for a conceptual cold dataset | limit 10
Explanation: The cold_dataset = <dataset name> syntax is used specifically for querying data stored in cold storage. This example conceptually queries a cold dataset named sample_xql_raw_cold.
Output:
| event_id | _time | event_description |
|---|---|---|
| 101 | 2023-10-26 10:00:00 UTC | "User login successful" |
| 102 | 2023-10-26 10:05:30 UTC | "File access attempt" |
| 103 | 2023-10-26 10:15:15 UTC | "Network connection established" |
Example 4: Default dataset (xdr_data)
Goal: Implicitly query the default dataset (xdr_data) by omitting the dataset stage.
XQL code:
// This query implicitly uses the 'xdr_data' dataset filter event_id = 101 | fields event_id, event_description
Explanation: If no dataset stage is explicitly defined, XQL queries automatically run against the xdr_data dataset. This example directly filters and selects fields, implicitly targeting the default dataset (represented here by sample_xql_raw data for context).
Output:
| event_id | event_description |
|---|---|
| 101 | "User login successful" |
Related articles
dedup
Use the dedup stage to eliminate redundant records from your query's result set, ensuring that each returned record or combination of field values is unique.
Syntax
dedup <field1>[,<field2>, ...] by asc | desc <field>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field1, field2... |
string, integer, float | Yes | One or more fields used to identify duplicate records. If multiple fields are specified, the combination of values must be unique. |
by |
clause | No | Determines which of the duplicate records is kept based on the value of a specified field. You must specify asc (ascending) or desc (descending). |
Returns
The dedup stage returns a result set where the specified field (or combination of fields) contains only unique values.
Usage notes
- When records contain duplicate values (or duplicate sets of values) for the specified fields,
dedupensures only one such record is retained. - The
byclause is optional but crucial: it determines which of the duplicate records is kept. If nobyclause is provided, the record returned is arbitrary among the duplicates. - The
dedupstage can only be used with fields that contain numbers or strings. - Note that the
dedupstage does not preserve the sort order established by preceding stages. If a specific order is required for the final output after deduplication, asortstage should be placed afterdedup. - While highly useful, the
dedupstage can be resource-intensive, especially when applied to very large datasets likexdr_data. This is becausededupoperations often involve a self-join, which can significantly impact query performance and cost. - Best practice: Avoid using
dedupunless it is explicitly necessary for your analytical objective. When you do use it, ensure that any precedingfilterorfieldsstages have already minimized the data being processed to optimize performance.
Examples
Example 1: Basic dedup on a single field
Goal: Remove duplicate records based on the specified single field (is_successful), retaining an arbitrary record from the duplicates.
XQL code:
dataset = sample_xql_raw | fields event_id, is_successful | dedup is_successful
Explanation: This query removes duplicate records based on the is_successful field. Since no by clause is provided, the specific event_id associated with each true or false result is arbitrary.
Output:
| EVENT_ID | IS_SUCCESSFUL |
|---|---|
| 101 | true |
| 102 | false |
Example 2: Dedup by earliest time
Goal: Return unique records based on a field, explicitly keeping the record with the earliest timestamp.
XQL code:
dataset = sample_xql_raw | fields event_id, _time, is_successful | dedup is_successful by asc _time
Explanation: This query deduplicates based on is_successful. By using by asc _time, it ensures that for any set of duplicate records (for example, all successful events), the record with the earliest _time value is kept.
Output:
| EVENT_ID | _TIME | IS_SUCCESSFUL |
|---|---|---|
| 101 | 2023-10-26 10:00:00 UTC | true |
| 102 | 2023-10-26 10:05:30 UTC | false |
Example 3: Dedup by latest time
Goal: Return unique records based on a field, explicitly keeping the record with the latest timestamp.
XQL code:
dataset = sample_xql_raw | fields event_id, _time, is_successful | dedup is_successful by desc _time
Explanation: This query deduplicates based on is_successful. By using by desc _time, it ensures that for any set of duplicate records, the record with the latest _time value is kept.
Output:
| EVENT_ID | _TIME | IS_SUCCESSFUL |
|---|---|---|
| 110 | 2023-10-26 11:00:10 UTC | true |
| 109 | 2023-10-26 10:55:55 UTC | false |
Example 4: Dedup on multiple fields
Goal: Remove records where the combination of values across multiple specified fields is identical.
XQL code:
dataset = sample_xql_raw | fields event_id, event_description, is_successful | dedup event_description, is_successful
Explanation: This query removes records where the combination of event_description and is_successful is duplicated. In the sample data, since each event_description is unique, the combinations are unique, and all records are returned. If duplicates existed, only one per combination would be kept.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL |
|---|---|---|
| 101 | "User login successful" | true |
| 102 | "File access attempt" | false |
| 103 | "Network connection established" | true |
| 104 | "System heartbeat" | true |
| 105 | "Data transformation" | true |
| 106 | "Unauthorized access detected" | false |
| 107 | "Cloud resource modification" | true |
| 108 | "Software update initiated" | true |
| 109 | "API request throttled" | false |
| 110 | "Database backup completed" | true |
Example 5: Dedup on multiple fields with a by clause
Goal: Deduplicate based on multiple fields and use a specific ordering criterion to determine which record to keep.
XQL code:
dataset = sample_xql_raw | fields event_id, event_description, is_successful, duration_seconds | dedup event_description, is_successful by asc duration_seconds
Explanation: This query deduplicates based on the unique combination of event_description and is_successful. The by asc duration_seconds clause specifies that if duplicate combinations were found, the record with the smallest duration_seconds would be retained.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL | DURATION_SECONDS |
|---|---|---|---|
| 101 | "User login successful" | true | 1.5 |
| 102 | "File access attempt" | false | 0.8 |
| 103 | "Network connection established" | true | 10.2 |
| 104 | "System heartbeat" | true | 0.1 |
| 105 | "Data transformation" | true | 5.0 |
| 106 | "Unauthorized access detected" | false | 2.1 |
| 107 | "Cloud resource modification" | true | 7.8 |
| 108 | "Software update initiated" | true | 15.3 |
| 109 | "API request throttled" | false | 0.05 |
| 110 | "Database backup completed" | true | 60.0 |
Related articles
fields
Use the fields stage to precisely define the columns that are returned in your XQL query result set. Use this stage, to ensure that all subsequent query stages operate exclusively on the columns you have explicitly declared.
Syntax
fields [-] <field_1> [as <alias_1>], <field_2> [as <alias_2>], ...
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field_n |
string | Yes | The name of the field to include in the results. |
alias_n |
string | No | The alias name to assign to the field using the as clause. |
- |
operator | No | The minus character used to exclude a specific field from the result set. |
as |
clause | No | The clause used to assign an alias to an existing field. |
Returns
The fields stage returns specific columns, which are then utilized as fields in all subsequent stages of the query.
Usage notes
- In Cortex Data Model (XDM) queries, the syntax is as follows:
fields [-] fieldset.xdm_<fieldset name1>, fieldset.xdm_<fieldset name2>, ..., where the field names are replaced by dataset_name.field_name. For example,fields amazon_eks_raw.logStream. - In dataset queries, the following system fields cannot be excluded and are always displayed if they exist in the results:
_time,_insert_time,_raw_log,_product,_vendor,_tag,_snapshot_id,_snapshot_log_count,_snapshot_collection_ts, and_id. - In XDM queries, the
_timefield cannot be excluded and is always displayed if it exists in the results. - The
fieldsstage does not allow the use of any functions. - New fields and field values cannot be created within the
fieldsstage; they must be created within thealterstage. - If you use the
asclause, all subsequent stages in the query must refer to the field by its new alias. - To perform exclusion from a wider set of selected fields, you must use multiple
fieldsstages: one for initial inclusion, followed by one or more for exclusion. - Employing the
fieldsstage early in your query, immediately after any primary filtering, significantly reduces the amount of data processed. - Avoid using
fields(or omitting thefieldsstage when running dataset queries) with large datasets likexdr_data, as this can vastly impact performance.
Examples
Example 1: Basic field selection
Goal: Explicitly list the field names you wish to include in your results.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, event_description | limit 2
Explanation: The query selects only the event_id and event_description columns from the dataset.
Output:
| event_id | event_description |
|---|---|
| 101 | "User login successful" |
| 102 | "File access attempt" |
Example 2: Aliasing fields
Goal: Rename fields for clarity or brevity in your result set using the as clause.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id as EventIdentifier, is_successful as Status | limit 2
Explanation: The query renames event_id to EventIdentifier and is_successful to Status in the output.
Output:
| EventIdentifier | Status |
|---|---|
| 101 | true |
| 102 | false |
Example 3: Including fields with wildcards
Goal: Include all fields that match a specified pattern using a wildcard (*).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_* | limit 2
Explanation: The query selects all fields starting with the string "event_", such as event_id and event_description.
Output:
| event_id | event_description |
|---|---|
| 101 | "User login successful" |
| 102 | "File access attempt" |
Example 4: Excluding fields
Goal: Exclude a specific field from the result set using the minus character (-).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_*, _time, is_successful | fields - event_id | limit 2
Explanation: The query first selects a broad set of fields including event_*, _time, and is_successful. A second fields stage then explicitly excludes event_id from that selection.
Output:
| _time | event_description | is_successful |
|---|---|---|
| 2023-10-26 10:00:00 UTC | "User login successful" | true |
| 2023-10-26 10:05:30 UTC | "File access attempt" | false |
Related articles
filter
Use the filter stage to precisely narrow down the data records returned by your query. The stage identifies which records should be included in the result set by evaluating boolean expressions. If a record satisfies the filter condition (i.e., the expression returns true), it is returned; otherwise, it is excluded.
Syntax
filter <boolean_expression>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
boolean_expression |
boolean | Yes | A logical expression that evaluates to true or false. Only records where this expression evaluates to true are passed to the next stage. |
Returns
The filter stage returns a subset of the original dataset containing only the records for which the boolean expression evaluates to true.
Usage notes
- Applying the
filterstage as early as possible in your query is a best practice. This significantly reduces the dataset size for subsequent stages, improving performance and reducing processing cost, especially with large datasets. - The
filterstage supports various operators to express diverse filtering conditions, including comparison operators (=,!=,<,<=,>,>=), boolean operators (and,or,not), and string/range operators (in,not in,contains,~=,!~=,incidr,incidr6). - Parentheses
()can be used to explicitly define the order of evaluation for logical conditions. - Filters can check for the presence or absence of values using
nullor empty string"". - XQL treats string values differently based on whether single (
") or triple (""") double quotes are used. Single double quotes treat the string literally (where*matches any sequence), while triple double quotes enable regex-style pattern matching and escape sequence interpretation. - You can employ subqueries within the
filterstage, particularly with theinornot inoperators, to define a list of values for comparison derived from another dataset or subset. - Functions can be used within filters (for example,
to_number(),json_extract_scalar()) for complex data transformations and evaluations during the filtering process.
Examples
Example 1: Comparison operator - equals (=)
Goal: Filter for records where the event_id is exactly 101.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id = 101 | fields event_id, event_description
Explanation: Returns true if the field value is exactly equal to the specified value.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | "User login successful" |
Example 2: Comparison operator - not equal to (!=)
Goal: Filter for records where the is_successful field is not true.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter is_successful != true | fields event_id, is_successful
Explanation: Returns true if the field value is not equal to the specified value.
Output:
| EVENT_ID | IS_SUCCESSFUL |
|---|---|
| 102 | false |
| 106 | false |
| 109 | false |
Example 3: Comparison operator -less than (<)
Goal: Filter for records where duration_seconds is strictly less than 1.0.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter duration_seconds < 1.0 | fields event_id, duration_seconds
Explanation: Returns true if the numeric field value is strictly less than the specified value.
Output:
| EVENT_ID | DURATION_SECONDS |
|---|---|
| 104 | 0.1 |
| 109 | 0.05 |
Example 4: Comparison operator - less than or equal to (<=)
Goal: Filter for records where the extracted JSON status code is less than or equal to 200.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter to_number(json_extract_scalar(simple_json_data, "$.code")) <= 200 | fields event_id, simple_json_data
Explanation: Returns true if the numeric field value is less than or equal to the specified value.
Output:
| EVENT_ID | SIMPLE_JSON_DATA |
|---|---|
| 101 | {"status": "ok", "code": 200} |
| 102 | {"status": "fail", "error": "access_denied"} |
Example 5: Comparison operator - greater than (>)
Goal: Filter for records where duration_seconds is strictly greater than 5.0.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter duration_seconds > 5.0 | fields event_id, duration_seconds
Explanation: Returns true if the numeric field value is strictly greater than the specified value.
Output:
| EVENT_ID | DURATION_SECONDS |
|---|---|
| 103 | 10.2 |
| 107 | 7.8 |
| 108 | 15.3 |
| 110 | 60.0 |
Example 6: Comparison operator - greater than or equal to (>=)
Goal: Filter for records where the extracted JSON status code is greater than or equal to 200.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter to_number(json_extract_scalar(simple_json_data, "$.code")) >= 200 | fields event_id, simple_json_data
Explanation: Returns true if the numeric field value is greater than or equal to the specified value.
Output:
| EVENT_ID | SIMPLE_JSON_DATA |
|---|---|
| 101 | {"status": "ok", "code": 200} |
Example 7: Boolean operator - AND (and)
Goal: Filter for records where is_successful is true AND duration_seconds is greater than 5.0.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter is_successful = true and duration_seconds > 5.0 | fields event_id, is_successful, duration_seconds
Explanation: Returns true only if all conditions separated by and are met.
Output:
| EVENT_ID | IS_SUCCESSFUL | DURATION_SECONDS |
|---|---|---|
| 103 | true | 10.2 |
| 107 | true | 7.8 |
| 108 | true | 15.3 |
| 110 | true | 60.0 |
Example 8: Boolean operator - OR (or)
Goal: Filter for records where event_description is "User login successful" OR is_successful is false.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_description = "User login successful" or is_successful = false | fields event_id, event_description, is_successful
Explanation: Returns true if any of the conditions separated by or are met.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL |
|---|---|---|
| 101 | "User login successful" | true |
| 102 | "File access attempt" | false |
| 106 | "Unauthorized access detected" | false |
| 109 | "API request throttled" | false |
Example 9: Boolean operator - NOT (not)
Goal: Filter for records where is_successful is NOT true.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter not is_successful = true | fields event_id, is_successful
Explanation: Returns true if the condition immediately following not is not met.
Output:
| EVENT_ID | IS_SUCCESSFUL |
|---|---|
| 102 | false |
| 106 | false |
| 109 | false |
Example 10: Boolean operator - parentheses grouping
Goal: Filter for records where the description is either "User login successful" or "System heartbeat", AND is_successful is true.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter (event_description = "User login successful" or event_description = "System heartbeat") and is_successful = true | fields event_id, event_description, is_successful
Explanation: Parentheses explicitly define the order of evaluation for logical conditions.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL |
|---|---|---|
| 101 | "User login successful" | true |
| 104 | "System heartbeat" | true |
Example 11: String operator - IN (in)
Goal: Filter for records where event_description matches any value in the provided list.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_description in ("User login successful", "Network connection established") | fields event_id, event_description
Explanation: Checks if a field's value is present within a provided list.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | "User login successful" |
| 103 | "Network connection established" |
Example 12: String operator - NOT IN (not in)
Goal: Filter for records where event_description does NOT match any pattern in the provided list.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_description not in ("*heartbeat*", "*transformation*") | fields event_id, event_description
Explanation: Checks if a field's value is not present within a provided list. Supports wildcards (*) for string values.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | "User login successful" |
| 102 | "File access attempt" |
| 103 | "Network connection established" |
| 106 | "Unauthorized access detected" |
| 107 | "Cloud resource modification" |
| 108 | "Software update initiated" |
| 109 | "API request throttled" |
| 110 | "Database backup completed" |
Example 13: String operator - contains
Goal: Filter for records where raw_log_data contains the substring "Process".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter raw_log_data contains "Process" | fields event_id, raw_log_data
Explanation: Returns true if the string field value contains the specified substring.
Output:
| EVENT_ID | RAW_LOG_DATA |
|---|---|
| 102 | "Process cmd.exe attempted to access /etc/passwd" |
Example 14: Regular expression match (~=)
Goal: Filter for records where event_description matches a regex pattern for login success or failure.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_description ~= ".*login (?:successful|failed).*" | fields event_id, event_description
Explanation: Returns true if the regular expression matches.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | "User login successful" |
| 106 | "Unauthorized access detected" |
Example 15: Regular expression does not match (!~=)
Goal: Filter for records where event_description does NOT match a case-insensitive regex pattern for system heartbeat or update.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter not event_description ~= "(?i).*system (?:heartbeat|update).*" | fields event_id, event_description
Explanation: Returns true if the regular expression does not match.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | "User login successful" |
| 102 | "File access attempt" |
| 103 | "Network connection established" |
| 105 | "Data transformation" |
| 106 | "Unauthorized access detected" |
| 109 | "API request throttled" |
| 110 | "Database backup completed" |
Example 16: Range operator - incidr (IPv4)
Goal: Filter for records where ipv4_address falls within the 192.168.1.0/24 CIDR range.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv4_address incidr "192.168.1.0/24" | fields event_id, ipv4_address
Explanation: Returns true if an IPv4 address falls within specified CIDR ranges.
Output:
| EVENT_ID | IPV4_ADDRESS |
|---|---|
| 101 | "192.168.1.10" |
Example 17: Range operator - not incidr (IPv4)
Goal: Filter for records where ipv4_address does NOT fall within typical private IP ranges.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv4_address not incidr "10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16" | fields event_id, ipv4_address
Explanation: Returns true if an IPv4 address does not fall within the specified CIDR ranges.
Output:
| EVENT_ID | IPV4_ADDRESS |
|---|---|
| 106 | "203.0.113.15" |
Example 18: Range operator - incidr6 (IPv6)
Goal: Filter for records where ipv6_address falls within the 2001:0db8::/32 CIDR range.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv6_address incidr6 "2001:0db8::/32" | fields event_id, ipv6_address
Explanation: Returns true if an IPv6 address falls within specified CIDR6 ranges.
Output:
| EVENT_ID | IPV6_ADDRESS |
|---|---|
| 103 | "2001:0db8::1" |
| 107 | "2001:0db8:cafe::1" |
| 109 | "2001:0db8:1234::abcd" |
Example 19: Range operator - not incidr6 (IPv6)
Goal: Filter for records where ipv6_address does NOT fall within the fe80::/10 CIDR range.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv6_address not incidr6 "fe80::/10" | fields event_id, ipv6_address
Explanation: Returns true if an IPv6 address does not fall within the specified CIDR6 range.
Output:
| EVENT_ID | IPV6_ADDRESS |
|---|---|
| 103 | "2001:0db8::1" |
| 107 | "2001:0db8:cafe::1" |
| 109 | "2001:0db8:1234::abcd" |
Example 20: Null value filtering (AND)
Goal: Filter for records where ipv6_address is neither null nor empty.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv6_address != null and ipv6_address != "" | fields event_id, ipv6_address
Explanation: Filters out records where a field is null or an empty string "".
Output:
| EVENT_ID | IPV6_ADDRESS |
|---|---|
| 103 | "2001:0db8::1" |
| 107 | "2001:0db8:cafe::1" |
| 109 | "2001:0db8:1234::abcd" |
Example 21: Null value filtering (NOT IN)
Goal: Filter for records where ipv6_address is not in the set of null or empty strings.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter ipv6_address not in("", null) | fields event_id, ipv6_address
Explanation: An alternative way to filter out nulls or empty strings using the not in operator.
Output:
| EVENT_ID | IPV6_ADDRESS |
|---|---|
| 103 | "2001:0db8::1" |
| 107 | "2001:0db8:cafe::1" |
| 109 | "2001:0db8:1234::abcd" |
Example 22: String manipulation - single quotes
Goal: Filter using single double quotes ("text") where wildcards behave normally.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_description = "User login*" | fields event_id, event_description
Explanation: Treats the string value literally. Wildcards (*) match any sequence of characters. Escape sequences are treated as plain characters.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | "User login successful" |
Example 23: String manipulation - triple quotes
Goal: Filter using triple double quotes ("""text""") to enable regex-style pattern matching.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter raw_log_data = """Process cmd.exe*passwd""" | fields event_id, raw_log_data
Explanation: Enables regex-style pattern matching and escape sequence interpretation. Wildcards (*) still act as XQL wildcards.
Output:
| EVENT_ID | RAW_LOG_DATA |
|---|---|
| 102 | "Process cmd.exe attempted to access /etc/passwd" |
Example 24: Subquery filtering - IN
Goal: Filter for events in the main dataset whose IDs are found in a specific subset of successful events (using a subquery).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in ( dataset = sample_xql_raw | filter is_successful = true and duration_seconds > 5.0 | fields event_id ) | fields event_id, event_description, is_successful, duration_seconds
Explanation: The inner query identifies event_ids where is_successful is true AND duration_seconds > 5.0. The outer filter then includes only records from the main dataset that have these event_ids.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL | DURATION_SECONDS |
|---|---|---|---|
| 103 | "Network connection established" | true | 10.2 |
| 107 | "Cloud resource modification" | true | 7.8 |
| 108 | "Software update initiated" | true | 15.3 |
| 110 | "Database backup completed" | true | 60.0 |
Example 25: Subquery filtering - NOT IN
Goal: Exclude events whose IDs are found in a specific subset of unsuccessful events (using a subquery).
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id not in ( dataset = sample_xql_raw | filter is_successful = false and duration_seconds < 1.0 | fields event_id ) | fields event_id, event_description, is_successful, duration_seconds
Explanation: The inner query identifies event_ids where is_successful is false AND duration_seconds < 1.0. The outer filter includes all records except those with these specific event_ids (102 and 109).
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL | DURATION_SECONDS |
|---|---|---|---|
| 101 | "User login successful" | true | 1.5 |
| 103 | "Network connection established" | true | 10.2 |
| 104 | "System heartbeat" | true | 0.1 |
| 105 | "Data transformation" | true | 5.0 |
| 106 | "Unauthorized access detected" | false | 2.1 |
| 107 | "Cloud resource modification" | true | 7.8 |
| 108 | "Software update initiated" | true | 15.3 |
| 110 | "Database backup completed" | true | 60.0 |
Related articles
iploc
Use the iploc stage to enrich event data by associating IPv4 addresses with predefined geolocation attributes. This capability is fundamental for security analysts to understand the geographic origin or destination of network activity within their environment.
Syntax
iploc <field> [loc_field1 [as <alias1>], loc_field2 [as <alias2>], ...]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
string, integer | Yes | The input field containing the IPv4 address to be geolocated. |
loc_field |
string | No | Specific geolocation attributes to return (for example, loc_country, loc_city). If omitted, a default set is added. |
alias |
string | No | The alias name for the geolocation field, using the as clause. |
Returns
The iploc stage returns the original event records enriched with additional columns containing geolocation information (such as loc_country, loc_city, loc_latlon, etc.) corresponding to the provided IPv4 address.
Usage notes
- The
iplocstage can only be used with fields that contain numbers or strings. - Geolocation data generated by this stage can be visualized on a graph of
type = map, where the x-axis is set toloc_countryorloc_latlon, and the y-axis is a number field. - Optimization: It is crucial to optimize queries for performance and cost. Apply
filterstages beforeiplocto reduce the dataset size, ensuringiploconly processes relevant records. - Optimization: Use the
fieldsstage early in your query to select only the necessary columns, minimizing the data processed by subsequent stages includingiploc.
Examples
Example 1: Basic iploc (default geolocation fields)
Goal: Enrich the ipv4_address field with the default set of geolocation attributes.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 5 | iploc ipv4_address
Explanation: The query applies the iploc stage to the ipv4_address field. Since no specific output fields are defined, it returns the default geolocation columns. Note that for private IPs (RFC1918), the country is often identified as "Private" with NULL values for granular details.
Output:
| EVENT_ID | IPV4_ADDRESS | LOC_COUNTRY | LOC_CITY | LOC_LATLON |
|---|---|---|---|---|
| 101 | 192.168.1.10 | Private | NULL | NULL |
| 102 | 10.0.0.5 | Private | NULL | NULL |
| 103 | NULL | NULL | NULL | NULL |
| 104 | 172.31.255.255 | Private | NULL | NULL |
| 105 | 192.168.10.20 | Private | NULL | NULL |
Example 2: Specifying selected geolocation fields
Goal: Enrich the ipv4_address field but return only the Country and City attributes.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 5 | iploc ipv4_address loc_country, loc_city
Explanation: The query uses iploc on ipv4_address but explicitly requests only the loc_country and loc_city columns to be added to the result set.
Output:
| EVENT_ID | IPV4_ADDRESS | LOC_COUNTRY | LOC_CITY |
|---|---|---|---|
| 101 | 192.168.1.10 | Private | NULL |
| 102 | 10.0.0.5 | Private | NULL |
| 103 | NULL | NULL | NULL |
| 104 | 172.31.255.255 | Private | NULL |
| 105 | 192.168.10.20 | Private | NULL |
Example 3: Aliasing geolocation fields
Goal: Enrich the ipv4_address field with specific attributes and rename the output columns for clarity.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | limit 5 | iploc ipv4_address loc_country as IP_Country, loc_latlon as IP_LatLon
Explanation: The query extracts loc_country and loc_latlon for the ipv4_address, renaming them to IP_Country and IP_LatLon respectively using the as clause.
Output:
| EVENT_ID | IPV4_ADDRESS | IP_COUNTRY | IP_LATLON |
|---|---|---|---|
| 101 | 192.168.1.10 | Private | NULL |
| 102 | 10.0.0.5 | Private | NULL |
| 103 | NULL | NULL | NULL |
| 104 | 172.31.255.255 | Private | NULL |
| 105 | 192.168.10.20 | Private | NULL |
Example 4: Viewing iploc results as a map graph
Goal: Combine iploc with aggregation to count IP addresses by country and visualize the data.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | iploc ipv4_address loc_country as country | filter country != null and ipv4_address != null | comp count() as ip_count by country | view graph type = map xaxis = country yaxis = ip_count | limit 10
Explanation: The query enriches the data with loc_country (aliased as country), filters out nulls, and aggregates the count of IPs per country. The view stage then configures the output to be displayed as a map graph. The table output below represents the underlying data for the visualization.
Output:
| COUNTRY | IP_COUNT |
|---|---|
| Private | 8 |
| NULL | 2 |
Related articles
join
Use the join stage to combine the results of two queries into a single result set based on a specified condition.
Syntax
join conflict_strategy = both|left|right type = inner|left|right ((<xql query>) as <execution_name> <boolean_expr>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
conflict_strategy |
string | No | Identifies how column name conflicts are resolved if a field name exists in both the parent (left) query's result set and the joined (right) query's result set. Valid values are both, left, or right. The default is right. |
type |
string | No | Defines the type of join, dictating which records are included in the final result set based on the join condition. Valid values are inner, left, or right. The default is inner. |
xql query |
query block | Yes | The XQL query whose results you want to combine with the parent query. This sub-query must be enclosed in parentheses. |
execution_name |
string | Yes | Provides an alias for the joined query's result set using the as clause. This alias is used to refer to fields from the joined query (for example, alias.field_name). |
boolean_expr |
expression | Yes | Identifies the conditions (join keys) that must be met to place a record in the join result set. |
Returns
The join stage returns a unified result set containing rows from the parent query combined with rows from the sub-query, based on the specified join type and condition.
Usage notes
- The
joinstage can combine results, but it does not preserve sort order. If sorting is needed, specify thesortstage after thejoinstage. joinoperations, especially on large datasets likexdr_data, can be resource-intensive. It is a Best practice to pare down datasets before joining them.- Always use the
fieldsstage early in your queries, including within the sub-queries of ajoin, to select only necessary columns. This minimizes the data processed and improves performance. - The
config case_sensitivestage can be used at the beginning of the query or when adding ajoinstage to control case sensitivity for field value evaluation. - By default, forensic datasets are not included in XQL query results unless explicitly defined. Queries for forensic data require specific enabling steps.
Examples
Example 1: Inner join
Goal: Perform an inner join to return only the records where there is a match in event_id from both the left and right datasets.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102, 103, 104) // Simulates left side | fields event_id, event_description | join type = inner ( dataset = sample_xql_raw | filter event_id in (103, 104, 105, 106) // Simulates right side | fields event_id as joined_event_id, is_successful as success_status ) as right_data right_data.joined_event_id = event_id // Join condition
Explanation: This query joins records from sample_xql_raw where event_id is 101, 102, 103, or 104, with records where event_id is 103, 104, 105, or 106. Only event_ids present in both sets will be returned. The joined_event_id from right_data is matched with event_id from the main query.
Output:
| event_id | event_description | joined_event_id | success_status |
|---|---|---|---|
| 103 | Network connection established | 103 | true |
| 104 | System heartbeat | 104 | true |
Example 2: Left join
Goal: Perform a left join to return all records from the left dataset, and the matching records from the right.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102, 103, 104) // Simulates left side | fields event_id, event_description | join type = left ( dataset = sample_xql_raw | filter event_id in (103, 104, 105, 106) // Simulates right side | fields event_id as joined_event_id, is_successful as success_status ) as right_data right_data.joined_event_id = event_id // Join condition
Explanation: This query returns all event_ids 101, 102, 103, 104 from the left side. For event_ids 101 and 102, since there are no matching records on the right side, NULL is populated for joined_event_id and success_status.
Output:
| event_id | event_description | joined_event_id | success_status |
|---|---|---|---|
| 101 | User login successful | NULL | NULL |
| 102 | File access attempt | NULL | NULL |
| 103 | Network connection established | 103 | true |
| 104 | System heartbeat | 104 | true |
Example 3: Right join
Goal: Perform a right join to return all records from the right dataset, and the matching records from the left.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102, 103, 104) // Simulates left side | fields event_id, event_description | join type = right ( dataset = sample_xql_raw | filter event_id in (103, 104, 105, 106) // Simulates right side | fields event_id as joined_event_id, is_successful as success_status ) as right_data right_data.joined_event_id = event_id // Join condition
Explanation: This query returns all event_ids 103, 104, 105, 106 from the right side. For event_ids 105 and 106, since there are no matching records on the left side, NULL is populated for event_description.
Output:
| event_id | event_description | joined_event_id | success_status |
|---|---|---|---|
| 103 | Network connection established | 103 | true |
| 104 | System heartbeat | 104 | true |
| NULL | NULL | 105 | true |
| NULL | NULL | 106 | false |
Example 4: Conflict strategy left
Goal: Perform an inner join while prioritizing the column from the original (parent) query's result set when a conflict exists.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102, 103, 104) // Simulates left side with original event_description | fields event_id, event_description | join conflict_strategy = left // Prioritize left side event_description type = inner ( dataset = sample_xql_raw | filter event_id in (103, 104, 105, 106) // Simulates right side data for join | fields event_id as joined_event_id, is_successful as event_description // This event_description will be discarded due to conflict_strategy = left ) as right_data right_data.joined_event_id = event_id // Join condition | fields event_id, event_description, joined_event_id // Select fields to show output
Explanation: The sub-query renames is_successful to event_description to create a conflict. Since conflict_strategy = left is specified, the event_description from the primary (left) query, which contains string values (for example, "Network connection established"), is preserved.
Output:
| event_id | event_description | joined_event_id |
|---|---|---|
| 103 | Network connection established | 103 |
| 104 | System heartbeat | 104 |
Example 5: Conflict strategy right
Goal: Perform an inner join while prioritizing the column from the inner (joined) query's result set when a conflict exists.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter event_id in (101, 102, 103, 104) // Simulates left side with original event_description | fields event_id, event_description | join conflict_strategy = right // Prioritize right side event_description type = inner ( dataset = sample_xql_raw | filter event_id in (103, 104, 105, 106) // Simulates right side data for join | fields event_id as joined_event_id, is_successful as event_description // This event_description will be kept ) as right_data right_data.joined_event_id = event_id // Join condition | fields event_id, event_description, joined_event_id // Select fields to show output
Explanation: With conflict_strategy = right, the event_description column from the inner (right) query is kept. This results in the event_description column containing the boolean values from is_successful (for example, true), while the original string event_description from the left query is discarded for the joined records.
Output:
| event_id | event_description | joined_event_id |
|---|---|---|
| 103 | true | 103 |
| 104 | true | 104 |
Related articles
limit
Use the limit stage to explicitly set the upper bound for the number of records returned by an XQL query. This is crucial for optimizing query performance, reducing data processing volume, and minimizing memory usage for operations like sorting.
Syntax
limit <number>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
<number> |
integer | Yes | The maximum number of records to return in the result set. |
Returns
The limit stage returns a subset of the input records, restricted to the maximum count specified by the <number> parameter.
Usage notes
- Unless a
limitstage is explicitly stated, standard XQL queries have a default maximum limit of 1,000,000 results. - Basic XQL queries (and XDM queries in Cortex XSIAM) that contain no stages beyond a
fieldsstage have a default limit of 1,000 results. - The 1,000-result default limit for basic queries does not apply to widgets, Correlation Rules, public APIs, saved queries, or scheduled queries, which maintain the 1,000,000-result limit if unspecified.
- We recommend placing the
limitstage after sorting (sort) to ensure you are retrieving the top or bottom records based on your criteria, rather than an arbitrary subset. - Applying
limitafter filtering (filter) ensures that the limit applies only to the relevant records, optimizing data processing.
Examples
Example 1: Basic limit to restrict total records
Goal: Retrieve a specified number of records from the dataset without specific ordering or filtering.
XQL code:
dataset = sample_xql_raw | limit 5
Explanation: This query returns the first 5 records found in the sample_xql_raw dataset. Since no sort order is defined, the records are returned in the order they appear in the source.
Output:
| event_id | _time | event_description | is_successful | duration_seconds | simple_json_data | nested_json_data | array_of_json_objects | string_tags | numeric_codes | raw_log_data | ipv4_address | ipv6_address |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 101 | 2023-10-26 10:00:00 UTC | "User login successful" | true | 1.5 | {"status": "ok", "code": 200} | {"user": {"id": "U1", "name": "Alice"}, "session": {"start": "10:00", "type": "web"}} | [{"action": "read", "file": "doc1.txt"}, {"action": "write", "file": "report.log"}] | ["security", "login"] | [13, -47, 29, 82, -15] | "User Alice logged in from 192.168.1.10" | "192.168.1.10" | NULL |
| 102 | 2023-10-26 10:05:30 UTC | "File access attempt" | false | 0.8 | {"status": "fail", "error": "access_denied"} | {"process": {"name": "cmd.exe", "pid": 1234}, "target": {"path": "/var/log", "permission": "rwx"}} | [{"event": "file_open", "path": "/etc/passwd"}] | ["filesystem", "critical"] | [-21, 56, 13, -88, 42] | "Process cmd.exe attempted to access /etc/passwd" | "10.0.0.5" | NULL |
| 103 | 2023-10-26 10:15:15 UTC | "Network connection established" | true | 10.2 | {"connection_id": "CONN-001", "protocol": "TCP"} | {"source": {"ip": "172.16.0.1", "port": 5000}, "destination": {"ip": "1.1.1.1", "port": 443}} | [{"conn_type": "outbound", "bytes": 1024}, {"conn_type": "inbound", "bytes": 512}] | ["network", "cloud"] | [90, -33, 7, 51, -62, 18] | "Outbound connection to 1.1.1.1:443 initiated by AppX" | NULL | "2001:0db8::1" |
| 104 | 2023-10-26 10:20:00 UTC | "System heartbeat" | true | 0.1 | {"health": "good"} | {"system": {"cpu_util": 0.15, "mem_free": "80%"}, "status": "active"} | [] | ["monitoring"] | [] | "System health check passed" | "172.31.255.255" | NULL |
| 105 | 2023-10-26 10:30:45 UTC | "Data transformation" | true | 5.0 | {"transform_stage": 1} | {"pipeline": {"id": "P5", "status": "running"}, "data": {"records_in": 1000, "records_out": 950}} | [{"step": "parse", "time_ms": 100}, {"step": "filter", "time_ms": 200}, {"step": "enrich", "time_ms": 300}] | ["data_ops"] | [77, -9, 35, -47, 61] | "Transformed data from source X, processed 1000 records." | "192.168.10.20" | NULL |
Example 2: Limit after a filter stage
Goal: Restrict the number of results returned after applying specific criteria to the dataset.
XQL code:
dataset = sample_xql_raw | filter is_successful = false | limit 2
Explanation: The query first filters for events where is_successful is false. The limit stage then restricts the output to the first 2 of these filtered records.
Output:
| event_id | _time | event_description | is_successful | duration_seconds | simple_json_data | nested_json_data | array_of_json_objects | string_tags | numeric_codes | raw_log_data | ipv4_address | ipv6_address |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 102 | 2023-10-26 10:05:30 UTC | "File access attempt" | false | 0.8 | {"status": "fail", "error": "access_denied"} | {"process": {"name": "cmd.exe", "pid": 1234}, "target": {"path": "/var/log", "permission": "rwx"}} | [{"event": "file_open", "path": "/etc/passwd"}] | ["filesystem", "critical"] | [-21, 56, 13, -88, 42] | "Process cmd.exe attempted to access /etc/passwd" | "10.0.0.5" | NULL |
| 106 | 2023-10-26 10:40:10 UTC | "Unauthorized access detected" | false | 2.1 | {"alert_id": "SEC-001", "severity": "high"} | {"actor": {"type": "user", "name": "unknown"}, "target": {"resource": "db_server", "action": "read"}} | [{"alert_type": "login_fail", "count": 5}, {"alert_source": "IDS"}] | ["security", "attack"] | [-12, 24, 68, -59, 37, 80] | "Multiple failed login attempts to db_server from external source." | "203.0.113.15" | NULL |
Example 3: Limit after a sort stage
Goal: Retrieve a specific number of top or bottom records based on a field's value.
XQL code:
dataset = sample_xql_raw | sort desc duration_seconds | limit 3
Explanation: The query sorts all records by duration_seconds in descending order. The limit stage then returns the top 3 records, effectively showing the three events with the longest duration.
Output:
| event_id | _time | event_description | is_successful | duration_seconds | simple_json_data | nested_json_data | array_of_json_objects | string_tags | numeric_codes | raw_log_data | ipv4_address | ipv6_address |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 110 | 2023-10-26 11:00:10 UTC | "Database backup completed" | true | 60.0 | {"backup_id": "DB-005", "size_gb": 500} | {"db": {"name": "prod_db", "type": "SQL"}, "storage": {"location": "S3", "cost_usd": 15}} | [{"stage": "compress", "time_s": 120}, {"stage": "upload", "time_s": 480}] | ["database", "backup", "successful"] | [27, -70, 92, 11, -36, 64] | "Full backup of prod_db to S3 completed." | "192.168.50.5" | NULL |
| 108 | 2023-10-26 10:50:20 UTC | "Software update initiated" | true | 15.3 | {"update_id": "SW-789", "status": "pending"} | {"system": {"hostname": "webserver01", "os": "Linux"}, "patch": {"version": "1.2.3"}} | [] | ["maintenance", "system"] | [38, -25, 73, 19, -81] | "Patch deployment started on webserver01. Expected downtime: 15 min." | "172.20.1.100" | NULL |
| 103 | 2023-10-26 10:15:15 UTC | "Network connection established" | true | 10.2 | {"connection_id": "CONN-001", "protocol": "TCP"} | {"source": {"ip": "172.16.0.1", "port": 5000}, "destination": {"ip": "1.1.1.1", "port": 443}} | [{"conn_type": "outbound", "bytes": 1024}, {"conn_type": "inbound", "bytes": 512}] | ["network", "cloud"] | [90, -33, 7, 51, -62, 18] | "Outbound connection to 1.1.1.1:443 initiated by AppX" | NULL | "2001:0db8::1" |
Example 4: Limit after comp (aggregation)
Goal: Restrict the number of aggregated groups returned in the result set.
XQL code:
dataset = sample_xql_raw | filter is_successful = true | comp count(event_id) as successful_events by string_tags | limit 2
Explanation: The query filters for successful events and then counts them, grouping by their string_tags. The limit stage restricts the output to just 2 of these aggregated groups.
Output:
| string_tags | successful_events |
|---|---|
| ["security", "login"] | 1 |
| ["network", "cloud"] | 1 |
Related articles
pivot
Use the pivot stage to rotate row-level data into columns, aligning with BigQuery's native PIVOT operator. The Pivot stage applies one or more aggregation functions to a specified field and transposes the distinct values of a pivot column (specified in the FOR / IN clause) into new output columns. This is useful for transforming long-format data into a wide-format summary, making it easier to compare values side by side.
The pivot stage transforms row-oriented data into a columnar summary by:
- Selecting a column whose distinct values become new column headers (the pivot key, specified in the
INclause). - Applying one or more aggregate functions to compute the values that populate those new columns.
- Optionally grouping the remaining rows by a by clause to produce one output column per group.
Syntax
pivot <aggregation_function>(<field>)[, <aggregation_function2>(<field2>), ...] for <pivot_column> IN ("<value1>", "<value2>", ...) [by <group_field1>[, <group_field2>, ...]]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
aggregation_function |
function | Yes | The aggregation function to apply to the target field. Allowed functions: count, sum, avg, min, max, count_distinct, approx_count, var, stddev_sample, stddev_population, approx_quantiles, list. A maximum of 3 aggregation functions can be used within a single pivot stage. The allowed aggregation functions are subject to tenant configuration. |
field |
string | Yes | The name of the field whose values are aggregated. |
pivot_column |
string | Yes | The field (specified after for) whose distinct values become the new column names in the output. Must resolve to a primitive data type — JSON fields and Records cannot be used as the pivot key (see Limitations). |
value1, value2, ... |
string | Yes | A comma-separated list of quoted values from the pivot_column that define which new columns to create. Each value becomes a separate column in the result. A maximum of 10 values can be specified in the IN clause. |
group_field |
string | No | One or more fields specified after by that group the output rows. When the by clause is used, the total resulting group columns are capped to 5 values. If omitted, the output consists only of the aggregated data across the IN values. |
Returns
The pivot stage returns a transformed dataset where:
- The
pivot_columnis removed from the output schema. - A new column is created for each value specified in the
IN (...)clause, named after that value. - Each new column contains the result of the aggregation function applied to the
fieldfor the correspondingpivot_columnvalue. - When a single aggregation function is used, the new columns are named directly after the
INvalues (for example,NETWORK,FILE,PROCESS). - When multiple aggregation functions are used, the new columns follow the naming pattern
<function>_<index>_<value>(for example,sum_1_NETWORK,max_2_FILE). - If the
byclause is specified, the group fields are preserved in the output. If omitted, only the aggregated pivot columns are returned. - All other fields from the input dataset that are not part of the aggregation or pivot key are discarded.
Usage notes
- The
pivotstage is a "blocking" operation; it must process all input records before producing any output. - The values listed in the
IN (...)clause must be quoted strings. - Only one
INcondition with a single set of values is supported perpivotstage. - The
pivotstage is not supported in Materialized Views. - The
pivotstage is typically used after a data source stage (such asdataset) and can be combined with other stages likefilter,alter,sort,comp, orfieldsfor further processing. - After a
pivot, the newly created columns (from theINclause values) become regular columns in the dataset. They can be referenced in any subsequent stage —filter,alter,sort,fields, etc. — just like any other column.
Limitations
The following constraints apply to the pivot stage.
| Feature | Constraint / Behavior |
|---|---|
| Max Aggregations | 3 functions per pivot stage. When multiple aggregations are used, column names are auto-generated (for example, sum_1_NETWORK). |
| Max Pivot Values | 10 values in the IN clause. This threshold prevents "wide table" performance degradation and avoids exceeding BigQuery column limits. |
| Optional BY | If the by clause is omitted, the output returns aggregate data only. When used, the by clause is limited to 5 group values to ensure query stability. |
| Data Types | Primitive types only for the pivot key. The FOR expression must resolve to a primitive data type. JSON fields and Records cannot be used as the pivot key — they must be cast to STRING in a previous stage as a workaround. |
Note: Not all XQL aggregation functions are supported in
pivot. Functions such asfirst,last,least, andmedianare not supported. See the Parameters section for the full list of allowed aggregation functions.
Supported contexts
| Context | Supported |
|---|---|
| Correlation | No |
| Parsing Rule | No |
| Dataset RBAC | No |
| Scheduled Queries | Yes |
| Widgets/Reports | Yes |
Examples
Example 1: Basic Pivot — Single aggregation using the BY clause
Goal: Sum bytes transferred per host, pivoted across event types.
XQL code:
dataset = xdr_data | pivot sum(bytes_transferred) for event_type IN ("NETWORK", "FILE", "PROCESS") by host | limit 100
Explanation: This query takes the bytes_transferred field, applies a sum aggregation, and pivots the results so that each distinct event_type value (NETWORK, FILE, PROCESS) becomes its own column. The by host clause groups the output by host.
Starting dataset (xdr_data):
| _id | host | event_type | bytes_transferred |
|---|---|---|---|
1 |
STORY |
NETWORK |
1024 |
2 |
STORY |
NETWORK |
2048 |
3 |
STORY |
FILE |
512 |
4 |
STORY |
PROCESS |
256 |
5 |
EVENT_LOG |
NETWORK |
4096 |
6 |
EVENT_LOG |
FILE |
768 |
7 |
EVENT_LOG |
PROCESS |
128 |
8 |
INJECTION |
NETWORK |
2048 |
9 |
INJECTION |
PROCESS |
64 |
Output:
| host | NETWORK | FILE | PROCESS |
|---|---|---|---|
STORY |
3072 | 512 | 256 |
EVENT_LOG |
4096 | 768 | 128 |
INJECTION |
2048 | null |
64 |
Example 2: Pivot without a BY clause
Goal: Count events by type without grouping by any other field.
XQL code:
dataset = xdr_data | pivot count(event_type) for event_type IN ("NETWORK", "FILE", "PROCESS", "REGISTRY") | limit 100
Explanation: When the by clause is omitted, the output contains only the aggregated data across the IN values — a single row with one column per pivot value.
Before pivot:
| event_type | count(event_type) |
|---|---|
NETWORK |
5420 |
FILE |
1893 |
PROCESS |
3102 |
REGISTRY |
764 |
Output:
| NETWORK | FILE | PROCESS | REGISTRY |
|---|---|---|---|
| 5420 | 1893 | 3102 | 764 |
Example 3: Using pivoted columns in subsequent stages
Goal: Pivot event counts by host, then filter and sort the results.
XQL code:
dataset = xdr_data | pivot count(event_type) for event_type IN ("NETWORK", "FILE", "PROCESS") by agent_hostname | filter NETWORK > 100 | sort desc NETWORK | fields agent_hostname, NETWORK, FILE, PROCESS | limit 50
Explanation: After the pivot stage, the newly created columns (NETWORK, FILE, PROCESS) become regular fields in the dataset. They can be referenced in any subsequent stage — filter, sort, fields, etc. — just like any other column. Here, the query filters for hosts with more than 100 network events and sorts by the NETWORK column in descending order.
After pivot:
| agent_hostname | NETWORK | FILE | PROCESS |
|---|---|---|---|
host-alpha |
250 | 80 | 410 |
host-beta |
150 | 42 | 310 |
host-gamma |
88 | 17 | 205 |
host-delta |
12 | 5 | 55 |
After filter (final output):
| agent_hostname | NETWORK | FILE | PROCESS |
|---|---|---|---|
host-alpha |
250 | 80 | 410 |
host-beta |
150 | 42 | 310 |
Example 4: Multiple aggregations in a single pivot
Goal: Use two aggregate functions — sum and max — in one pivot statement.
XQL code:
dataset = xdr_data | pivot sum(bytes_transferred), max(bytes_transferred) for event_type IN ("NETWORK", "FILE") by host | limit 100
Explanation: This query applies both sum and max aggregations to bytes_transferred, pivoted by event_type. When multiple aggregation functions are used, the output column names follow the pattern <function>_<index>_<value> (for example, sum_1_NETWORK, max_2_FILE).
Starting dataset (xdr_data):
| _id | host | event_type | bytes_transferred |
|---|---|---|---|
1 |
host-alpha |
NETWORK |
1024 |
2 |
host-alpha |
NETWORK |
3072 |
3 |
host-alpha |
FILE |
512 |
4 |
host-alpha |
FILE |
768 |
5 |
host-beta |
NETWORK |
2048 |
6 |
host-beta |
FILE |
256 |
Output:
| host | sum_1_NETWORK | sum_2_FILE | max_1_NETWORK | max_2_FILE |
|---|---|---|---|---|
host-alpha |
4096 | 1280 | 3072 | 768 |
host-beta |
2048 | 256 | 2048 | 256 |
Example 5: Pivot with two BY fields
Goal: Group the pivoted output by two fields to produce a more granular breakdown.
XQL code:
dataset = xdr_data | pivot sum(bytes_transferred) for event_type IN ("NETWORK", "FILE") by host, source_zone | limit 100
Explanation: This query pivots bytes_transferred by event_type and groups the results by both host and source_zone, producing a more detailed breakdown.
Starting dataset (xdr_data):
| _id | host | source_zone | event_type | bytes_transferred |
|---|---|---|---|---|
1 |
host-alpha |
DMZ |
NETWORK |
1024 |
2 |
host-alpha |
DMZ |
NETWORK |
512 |
3 |
host-alpha |
Internal |
NETWORK |
2048 |
4 |
host-alpha |
Internal |
FILE |
768 |
5 |
host-beta |
DMZ |
NETWORK |
4096 |
6 |
host-beta |
DMZ |
FILE |
256 |
7 |
host-beta |
Internal |
NETWORK |
1536 |
Output:
| host | source_zone | NETWORK | FILE |
|---|---|---|---|
host-alpha |
DMZ |
1536 | null |
host-alpha |
Internal |
2048 | 768 |
host-beta |
DMZ |
4096 | 256 |
host-beta |
Internal |
1536 | null |
Related articles
- Stages:
comp,fields,filter,transpose - Functions:
count,sum,min,max
preset
Use the preset stage to specify a predefined collection of fields from the xdr_data dataset as your data source, optimized for analyzing specific types of network or endpoint activity.
Syntax
preset = <preset_name>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
preset_name |
string | Yes | The specific name of the preset to query (for example, authentication_story, network_story). |
Returns
The preset stage returns a result set containing events and fields specific to the defined preset schema. These presets are often subsets of the xdr_data dataset, pre-filtered and organized for specific use cases like authentication, network traffic, or file operations.
Usage notes
- Presets act as predefined views or "stories" (for example,
authentication_story,network_story) that combine events and logs into a common schema. - While presets offer convenience by pre-grouping fields,
XQL Query Optimization Principlesadvise that for specific use cases, directly queryingdataset=xdr_datawith explicit filters (for example,filter event_type = ...) can often lead to better performance. - General presets are designed for "well decorated, de-duplicated" results and may not prioritize performance impact; overly broad queries using presets can exceed optimization limits.
- To optimize performance when using presets (or their raw dataset alternatives), always apply
filterstages as early as possible and use thefieldsstage to select only the necessary columns.
Examples
Example 1: Authentication story preset
Goal: Analyze authentication events using the authentication_story preset.
XQL code:
config timeframe = 7d | preset = authentication_story | fields agent_hostname, os_actor_effective_username, action_local_ip | limit 10
Explanation: This query uses the authentication_story preset to focus on authentication logs, stitching together relevant information into a common schema. An optimized alternative would be querying dataset = xdr_data and filtering by dfe_labels = "authentication".
Output:
| AGENT_HOSTNAME | OS_ACTOR_EFFECTIVE_USERNAME | ACTION_LOCAL_IP |
|---|---|---|
| WORKSTATION-01 | jdoe | 192.168.1.15 |
| SERVER-DB-02 | admin | 10.0.0.50 |
| WORKSTATION-03 | asmith | 192.168.1.20 |
Example 2: Network story preset
Goal: Aggregate network activity information using the network_story preset.
XQL code:
config timeframe = 7d | preset = network_story | filter action_remote_port = 443 | fields agent_hostname, action_local_ip, action_remote_ip, action_remote_port | limit 10
Explanation: This query utilizes the network_story preset to provide a common schema for network events and filters specifically for HTTPS traffic (port 443). An optimized alternative involves querying dataset = xdr_data with filter event_type = NETWORK.
Output:
| AGENT_HOSTNAME | ACTION_LOCAL_IP | ACTION_REMOTE_IP | ACTION_REMOTE_PORT |
|---|---|---|---|
| HOST-A | 10.10.10.5 | 172.217.16.14 | 443 |
| HOST-B | 10.10.10.8 | 142.250.185.78 | 443 |
| HOST-C | 10.10.10.12 | 204.79.197.200 | 443 |
Example 3: XDR event log preset
Goal: Analyze forensic event log data using the xdr_event_log preset.
XQL code:
config timeframe = 30d | preset = xdr_event_log | filter EVTX_Event_ID = 104 | fields host_name, Timestamp, message, EVTX_Event_ID | limit 10
Explanation: This query uses the xdr_event_log preset to normalize and view event logs, specifically filtering for Windows System Event ID 104 (Log cleared). An optimized alternative would query dataset = xdr_data filtering for event_type = ENUM.EVENT_LOG.
Output:
| HOST_NAME | TIMESTAMP | MESSAGE | EVTX_EVENT_ID |
|---|---|---|---|
| DC-01 | 1698304800000 | The System log file was cleared. | 104 |
| DC-02 | 1698305130000 | The System log file was cleared. | 104 |
Example 4: XDR file preset
Goal: Investigate file-related events such as writes or accesses using the xdr_file preset.
XQL code:
config timeframe = 7d | preset = xdr_file | filter action_file_extension = "exe" | fields event_id, action_file_name, action_file_path | limit 10
Explanation: This query uses the xdr_file preset to focus on file activities, filtering specifically for executable files. An optimized alternative involves querying dataset = xdr_data with filter event_type = ENUM.FILE.
Output:
| EVENT_ID | ACTION_FILE_NAME | ACTION_FILE_PATH |
|---|---|---|
| ev_101 | update.exe | C:\Temp\update.exe |
| ev_102 | malware.exe | C:\Users\Public\malware.exe |
Example 5: Host inventory users preset
Goal: Retrieve information about users discovered on endpoints using the host_inventory_users preset.
XQL code:
config timeframe = 30d | preset = host_inventory_users | filter disabled = true | fields endpoint_name, name, full_name, disabled | limit 10
Explanation: This query leverages the host_inventory_users preset (requiring Host Insights) to identify disabled user accounts on endpoints.
Output:
| ENDPOINT_NAME | NAME | FULL_NAME | DISABLED |
|---|---|---|---|
| LAPTOP-55 | Guest | Guest User | true |
| SERVER-01 | old_admin | Old Administrator | true |
Example 6: Host inventory shares preset
Goal: View details about shared resources on hosts using the host_inventory_shares preset.
XQL code:
config case_sensitive = false timeframe = 30d | preset = host_inventory_shares | filter description not contains "print" | fields endpoint_name, description, share_type | limit 5
Explanation: This query uses the host_inventory_shares preset to list shared resources, filtering out print shares to focus on other types of shares.
Output:
| ENDPOINT_NAME | DESCRIPTION | SHARE_TYPE |
|---|---|---|
| FILE-SERVER | Finance Docs | Disk |
| BACKUP-SRV | Daily Backups | Disk |
Example 7: Host users to groups preset
Goal: Analyze user-to-group mappings using the host_users_to_groups preset.
XQL code:
config case_sensitive = false timeframe = 30d | preset = host_users_to_groups | fields endpoint_name, user_name, group_name | limit 5
Explanation: This query uses the host_users_to_groups preset (derived from Host Insights) to view the relationships between users and groups on endpoints.
Output:
| ENDPOINT_NAME | USER_NAME | GROUP_NAME |
|---|---|---|
| WORKSTATION-A | alice | Administrators |
| WORKSTATION-A | alice | Remote Desktop Users |
Example 8: Device control preset
Goal: Monitor USB device connections using the device_control preset.
XQL code:
config timeframe = 7d | preset = device_control | filter action_device_type = "USB" | fields agent_hostname, action_device_id, action_device_info | limit 10
Explanation: This query utilizes the device_control preset to view events related to USB device connections and disconnections.
Output:
| AGENT_HOSTNAME | ACTION_DEVICE_ID | ACTION_DEVICE_INFO |
|---|---|---|
| USER-PC-01 | USB\VID_0781&PID_5581 | SanDisk Ultra |
| LAB-PC-04 | USB\VID_0951&PID_1666 | Kingston DataTraveler |
Related articles
replacenull
Use the replacenull stage to ensure data completeness by replacing null (or null-equivalent) values within a specified field with a default value. The stage is schema-aware: it uses the field's metadata type to determine which replacement value is valid, and supports both primitive types (String, Number, Boolean, Enum) and complex types (Array, JSON, Datetime).
Syntax
replacenull <field> = <replacement_value>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field |
string | Yes | The name of the field whose null (or null-equivalent) values you want to replace. |
replacement_value |
string, number, boolean, array, JSON, or datetime | Yes | The value that replaces any NULL (or null-equivalent) occurrences in the specified field. The value must match the data type of the field. Literal strings must be enclosed in double quotes, and complex types must be constructed with the appropriate function (see Usage notes). |
Returns
The replacenull stage returns the dataset with the specified field modified, where all NULL (and null-equivalent) values have been substituted with the provided replacement value. All other records and fields are returned unchanged.
Usage notes
- The
replacenullstage is schema-aware. It reads the field's metadata type before applying the replacement logic, so thereplacement_valueyou provide must be compatible with the field's data type. -
The stage supports the following field types, each with its own replacement rules:
Field type Null-equivalent condition How to specify the replacement value String NULLA quoted string literal, for example "invalid host".Number NULLA numeric literal, for example 0.Boolean NULLtrueorfalse.Enum NULLA valid enum value. Array NULLor empty array[]An array constructed with arraycreate(), for examplearraycreate("no-record").JSON NULLA JSON object, typically an empty object {}or one constructed withobject_create().Datetime NULLA quoted datetime string in a supported format (see below). - Empty array detection: For Array fields, both
NULLvalues and empty arrays ([]) are treated as null-equivalent and are replaced. - Datetime formats: For Datetime fields, the replacement value must be provided as a quoted string in one of the following supported formats:
- ISO 8601 with
Z:%Y-%m-%dT%H:%M:%SZ(for example,"1970-01-01T00:00:00Z") - ISO 8601 without
Z:%Y-%m-%dT%H:%M:%S(for example,"1970-01-01T00:00:00") - Standard format:
%Y-%m-%d %H:%M:%S(for example,"1970-01-01 00:00:00")
- ISO 8601 with
- If you employ the
replacenullstage, any subsequent stages that refer to the modified field's value must use the newly defined replacement value instead of checking forNULL. - Apply
filterstages as early as possible in your query. This reduces the total dataset size beforereplacenullprocesses the records, minimizing the amount of data it needs to operate on. - Use the
fieldsstage immediately after initial filtering to select only the necessary columns. This reduces the data footprint passed toreplacenulland subsequent stages, improving overall query performance.
Examples
Example 1: Basic replacenull on a String field
Goal: Replace NULL values in a primitive String field with a default label.
XQL code:
dataset = xdr_data | comp count() as count by agent_hostname | replacenull agent_hostname = "invalid host" | limit 100
Explanation: The replacenull agent_hostname = "invalid host" stage replaces any NULL values in the agent_hostname field with the string "invalid host".
Output:
| COUNT | AGENT_HOSTNAME |
|---|---|
| 42 | server-01 |
| 15 | invalid host |
| 7 | server-03 |
Example 2: replacenull on an Array field (empty arrays and nulls)
Goal: Replace both NULL values and empty arrays ([]) in an Array field with a default array.
XQL code:
dataset = xdr_data | fields host, dns_records | replacenull dns_records = arraycreate("no-record") | limit 100
Explanation: Because dns_records is an Array field, both NULL values and empty arrays are treated as null-equivalent. The replacenull dns_records = arraycreate("no-record") stage replaces those values with the array ["no-record"].
Before replacenull:
| HOST | DNS_RECORDS |
|---|---|
| server-01 | ["a.example.com", "b.example.com"] |
| server-02 | null |
| server-03 | [] |
After replacenull:
| HOST | DNS_RECORDS |
|---|---|
| server-01 | ["a.example.com", "b.example.com"] |
| server-02 | ["no-record"] |
| server-03 | ["no-record"] |
Example 3: Type-specific replacements across multiple field types
Goal: Apply replacenull to several fields of different types — String, Number, Datetime, and JSON — in a single query, using a replacement value appropriate to each type.
XQL code:
dataset = xdr_data | replacenull host = "N/A" | replacenull severity = 0 | replacenull event_time = "1970-01-01T00:00:00Z" | replacenull metadata = object_create("env", "dev") | limit 100
Explanation: Each replacenull stage targets a field of a specific type:
host(String) —NULLvalues are replaced with"N/A".severity(Number) —NULLvalues are replaced with0.event_time(Datetime) —NULLvalues are replaced with the ISO 8601 datetime"1970-01-01T00:00:00Z".metadata(JSON) —NULLvalues are replaced with the object{"env": "dev"}constructed byobject_create().
Before replacenull:
| HOST | SEVERITY | EVENT_TIME | METADATA |
|---|---|---|---|
| server-01 | null |
2026-03-24T10:30:00Z |
null |
null |
5 | null |
{"env": "prod"} |
null |
null |
null |
{} |
After replacenull:
| HOST | SEVERITY | EVENT_TIME | METADATA |
|---|---|---|---|
| server-01 | 0 | 2026-03-24T10:30:00Z |
{"env": "dev"} |
| N/A | 5 | 1970-01-01T00:00:00Z |
{"env": "prod"} |
| N/A | 0 | 1970-01-01T00:00:00Z |
{} |
Example 4: replacenull on a field derived from a JSON function
Goal: Replace NULL values in a field created by an alter stage using a JSON function, where the extracted value can be NULL if the key does not exist.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, simple_json_data // Select relevant fields, including the JSON source | alter json_code = json_extract_scalar(simple_json_data, "$.code") // Extract 'code'; can be NULL | replacenull json_code = "Code Not Found" // Replace NULLs in the new 'json_code' field | limit 5
Explanation: The query extracts the value of the "code" key using json_extract_scalar(simple_json_data, "$.code"). For records where this key does not exist (102, 103, 104, 105), the result is NULL. The replacenull json_code = "Code Not Found" stage then replaces these NULL values.
Output:
| EVENT_ID | SIMPLE_JSON_DATA | JSON_CODE |
|---|---|---|
| 101 | {"status": "ok", "code": 200} | 200 |
| 102 | {"status": "fail", "error": "access_denied"} | Code Not Found |
| 103 | {"connection_id": "CONN-001", "protocol": "TCP"} | Code Not Found |
| 104 | {"health": "good"} | Code Not Found |
| 105 | {"transform_stage": 1} | Code Not Found |
Example 5: Filtering based on the replaced value
Goal: Demonstrate how subsequent filter stages must use the replacement value when querying for values that were originally NULL.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, ipv4_address // Select necessary fields | replacenull ipv4_address = "UNKNOWN_IP" // Replace NULLs in ipv4_address | filter ipv4_address = "UNKNOWN_IP" // Filter using the replacement value | limit 5
Explanation: The replacenull ipv4_address = "UNKNOWN_IP" stage replaces NULL entries in ipv4_address. Since ipv4_address is NULL for event_id 103, 107, and 109, the subsequent filter filter ipv4_address = "UNKNOWN_IP" successfully identifies and returns only those records.
Output:
| EVENT_ID | IPV4_ADDRESS |
|---|---|
| 103 | UNKNOWN_IP |
| 107 | UNKNOWN_IP |
| 109 | UNKNOWN_IP |
Related articles
- Stages:
alter,filter,fields,comp - Functions:
arraycreate,object_create,json_extract_scalar,coalesce
search
Use the search stage to perform free-text string searching across your ingested data, allowing you to find specified text strings within fields of single or multiple datasets.
Syntax
search "<free_text1>"[,"<free_text2>", ...] [mode="<search_mode>"] [dataset = <dataset name>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
<free_text> |
string | Yes | The text string to search for. Multiple strings imply an OR condition. |
mode |
string | No | Scopes the investigation to route execution. Scoping the query accelerates response times for complex queries and provides granular control over the query. Accepted values are raw, normalize, and all. Syntax: mode="search_mode". See Search modes. |
dataset |
dataset | No | Refines the search by explicitly specifying a dataset. |
Search modes
The mode parameter accepts the following values:
| Mode | Description |
|---|---|
raw |
Searches across all columns in raw datasets. This is the default mode for general and wildcard searches. |
normalize |
Restricts the search to normalized datasets (such as xdr_data). For maximum performance, this mode searches string columns only and explicitly bypasses enum fields. |
all |
Searches across all datasets in the tenant. This is the legacy behavior. |
Returns
The search stage returns records containing the specified text string(s). When searching a single dataset, all field columns of that dataset are included. When searching multiple datasets, the results include key columns such as _time, _vendor, _product, _dataset, and raw_data.
Usage notes
- The
searchstage must be the first stage in your XQL query, though it can be preceded by aconfigstage. - Queries containing the
searchstage do not support aggregation stages such asbin,comp,top, ordedup. - Queries using the
searchstage are limited to the last 90 days of data. - By default, forensic datasets are not included in
searchstage queries unless specifically enabled. - If searching multiple datasets, the
raw_datafield column contains the JSON with the relevant raw information, allowing for drill-down. - Syntax limitation: The
modeparameter cannot be combined with a specific, non-wildcard dataset. For example,search "login failure" mode=normalize dataset = xdr_datareturns an error. If you know the exact dataset, query it directly without themodeparameter. - Optimized search volume: The
rawandnormalizemodes are optimal for 1 to 10 distinct terms, such as specific IPs or hostnames. For heavy workflows that span large tenants across all datasets, use theallmode.
Syntax examples
The following tables summarize valid and invalid combinations of the search stage syntax.
Use cases
| Use case | Example | Result |
|---|---|---|
| Basic default search | search "login failure" |
Automatically defaults to the raw mode and searches across wildcard tables |
| Explicit mode definition | search "login failure" mode=all |
Forces the search across both raw and normalized datasets |
| Explicit mode with wildcard-only dataset | search "login failure" mode=raw dataset = * |
Explicitly assigns the mode while searching all wildcard tables |
| Using modes with wildcard datasets | search "login failure" mode=normalize dataset = xdr_* |
Explicitly scopes the normalized mode to datasets matching the wildcard |
| Searching multiple wildcard datasets | search "login failure" mode=normalize dataset in (xdr_*, panw_*) |
Applies the performance mode across multiple wildcard dataset patterns |
| Implicit mode assignment (wildcard) | search "login failure" dataset = xdr_* |
Because a wildcard is used without an explicit mode, this automatically defaults to the raw mode |
| Specific dataset query (no mode needed) | search "login failure" dataset = xdr_data |
Directly queries a specific dataset. The mode parameter is intentionally left blank |
| Piping to additional filters | search "login failure" mode=raw \| filter agent_os = WINDOWS |
Quickly searches raw datasets and filters the subsequent results |
Invalid use cases
| Use case | Example | Result |
|---|---|---|
| Mode combined with a specific dataset (invalid) | search "login failure" mode=normalize dataset = xdr_data |
Returns an error: the mode parameter is not allowed when querying a specific, non-wildcard dataset |
| Multiple modes provided (invalid) | search "login failure" mode=raw mode=all |
Returns an error for a duplicate argument |
| Mode combined with a list of specific datasets (invalid) | search "login failure" mode=raw dataset in (xdr_data, panw_data) |
Returns an error: wildcards must be present in the dataset list when using a mode |
Examples
Example 1: Basic free-text search across all datasets
Goal: Searches for the phrase "login successful" across all available datasets in the tenant (implicitly).
XQL code:
search "login successful" mode=all
Explanation: This query searches for the string "login successful" across all datasets. In the context of the sample data, it finds the relevant login event.
Output:
| _time | _dataset | event_description | raw_log_data |
|---|---|---|---|
| 2023-10-26 10:00:00 UTC | sample_xql_raw | "User login successful" | "User Alice logged in from 192.168.1.10" |
Example 2: Free-text search within a specific dataset
Goal: Explicitly searches for the string "cmd.exe" only within the sample_xql_raw dataset.
XQL code:
search "cmd.exe" dataset = sample_xql_raw
Explanation: This query restricts the free-text search for "cmd.exe" to the specified sample_xql_raw dataset.
Output:
| _time | _dataset | event_description | raw_log_data |
|---|---|---|---|
| 2023-10-26 10:05:30 UTC | sample_xql_raw | "File access attempt" | "Process cmd.exe attempted to access /etc/passwd" |
Example 3: Searching for multiple free-text strings
Goal: Searches for events containing either "connection" or "backup" within the sample_xql_raw dataset.
XQL code:
search "connection", "backup" dataset = sample_xql_raw
Explanation: This query searches for records containing either "connection" OR "backup" within the specified dataset.
Output:
| _time | _dataset | event_description | raw_log_data |
|---|---|---|---|
| 2023-10-26 10:15:15 UTC | sample_xql_raw | "Network connection established" | "Outbound connection to 1.1.1.1:443 initiated by AppX" |
| 2023-10-26 11:00:10 UTC | sample_xql_raw | "Database backup completed" | "Full backup of prod_db to S3 completed." |
Example 4: Using config timeframe with search
Goal: Searches for "successful" events within the last 24 hours.
XQL code:
config timeframe = 24h search "successful" dataset = sample_xql_raw
Explanation: The config timeframe stage is used before the search stage to limit the query execution window to the last 24 hours.
Output:
| _time | _dataset | event_description | is_successful |
|---|---|---|---|
| 2023-10-26 10:00:00 UTC | sample_xql_raw | "User login successful" | true |
Example 5: Searching raw datasets
Goal: Searches for the phrase "login failure" across all columns in raw datasets.
XQL code:
search "login failure"
Explanation: The default mode for the search stage is raw. The default mode scopes the search to all columns in raw datasets.
Output:
| _time | _dataset | event_description | raw_log_data |
|---|---|---|---|
| 2023-10-26 10:20:00 UTC | sample_xql_raw | "User login failure" | "User Bob failed to log in from 10.0.0.5" |
Example 6: Restricting the search to normalized datasets using the Normalize mode
Goal: Searches for the phrase "login failure" within normalized datasets only.
XQL code:
search "login failure" mode="normalize"
Explanation: The mode="normalize" parameter restricts the search to normalized datasets (such as xdr_data). For maximum performance, this mode searches string columns only and explicitly bypasses enum fields.
Output:
| _time | _dataset | event_description | raw_log_data |
|---|---|---|---|
| 2023-10-26 10:20:00 UTC | xdr_data | "User login failure" | "User Bob failed to log in from 10.0.0.5" |
Related articles
- Stages:
config
sort
Use the sort stage to identify the sort order for records returned in the result set.
Syntax
sort asc|desc <field1>[, asc|desc <field2>...]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
asc |
keyword | No | Sorts records in ascending order (lowest to highest). |
desc |
keyword | No | Sorts records in descending order (highest to lowest). |
field |
string | Yes | Specifies one or more fields to sort by. If multiple fields are provided, records are sorted in the order the fields are specified. |
Returns
The sort stage returns the query result set organized according to the specified order.
Usage notes
- Be aware that the
unionandjoinstages do not preserve sort order. If you require a specific sort order after combining datasets, always place thesortstage after yourunionorjoinstage. - For correct sorting results when a query includes strings representing numbers, it is recommended to convert all string fields to integers or numbers (for example, using
to_integer()orto_number()functions) before applying thesortstage. - When sorting by multiple columns, while the sort operation is saved correctly, the user interface will only display the results according to the first sorted column.
- Sort operations can concentrate data on a single worker, which for large datasets might exceed its capacity. Including a
limitstage after asortstage can help reduce the maximum memory a worker needs to devote to the sort task, thereby improving performance.
Examples
Example 1: Single field sort (ascending)
Goal: Sorts records by event_id in ascending order.
XQL code:
dataset = sample_xql_raw | sort asc event_id | fields event_id, event_description
Explanation: This query sorts the events by their unique event_id in ascending order (lowest to highest).
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | User login successful |
| 102 | File access attempt |
| 103 | Network connection established |
| 104 | System heartbeat |
| 105 | Data transformation |
| 106 | Unauthorized access detected |
| 107 | Cloud resource modification |
| 108 | Software update initiated |
| 109 | API request throttled |
| 110 | Database backup completed |
Example 2: Single field sort (descending)
Goal: Sorts records by duration_seconds in descending order.
XQL code:
dataset = sample_xql_raw | sort desc duration_seconds | fields event_id, event_description, duration_seconds
Explanation: This example sorts events by duration_seconds in descending order, showing the longest duration events first.
Output:
| EVENT_ID | EVENT_DESCRIPTION | DURATION_SECONDS |
|---|---|---|
| 110 | Database backup completed | 60.0 |
| 108 | Software update initiated | 15.3 |
| 103 | Network connection established | 10.2 |
| 107 | Cloud resource modification | 7.8 |
| 105 | Data transformation | 5.0 |
| 106 | Unauthorized access detected | 2.1 |
| 101 | User login successful | 1.5 |
| 102 | File access attempt | 0.8 |
| 104 | System heartbeat | 0.1 |
| 109 | API request throttled | 0.05 |
Example 3: Multiple field sort
Goal: Sorts records by is_successful (desc) then duration_seconds (asc).
XQL code:
dataset = sample_xql_raw | sort desc is_successful, asc duration_seconds | fields event_id, event_description, is_successful, duration_seconds
Explanation: This example first sorts by is_successful (placing true results first due to descending sort order on boolean), and then by duration_seconds in ascending order for events with the same is_successful status.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL | DURATION_SECONDS |
|---|---|---|---|
| 104 | System heartbeat | true | 0.1 |
| 101 | User login successful | true | 1.5 |
| 105 | Data transformation | true | 5.0 |
| 107 | Cloud resource modification | true | 7.8 |
| 103 | Network connection established | true | 10.2 |
| 108 | Software update initiated | true | 15.3 |
| 110 | Database backup completed | true | 60.0 |
| 109 | API request throttled | false | 0.05 |
| 102 | File access attempt | false | 0.8 |
| 106 | Unauthorized access detected | false | 2.1 |
Example 4: Numeric conversion sort
Goal: Extracts a numeric code from JSON and sorts by it in ascending order.
XQL code:
dataset = sample_xql_raw | alter status_code = to_number(coalesce(json_extract_scalar(simple_json_data, "$.code"), json_extract_scalar(simple_json_data, "$.error_code"))) | filter status_code != null // Ensure we only sort non-null numeric codes | sort asc status_code | fields event_id, event_description, simple_json_data, status_code
Explanation: This example demonstrates how to extract a numeric value (either code or error_code) from the simple_json_data JSON field, convert it to a number using to_number(), and then sort by it. This ensures numeric sorting rather than string sorting (for example, ensuring 200 comes before 429).
Output:
| EVENT_ID | EVENT_DESCRIPTION | SIMPLE_JSON_DATA | STATUS_CODE |
|---|---|---|---|
| 101 | User login successful | {"status": "ok", "code": 200} | 200 |
| 109 | API request throttled | {"error_code": 429, "message": "Rate limit exceeded"} | 429 |
Related articles
tag
Use the tag stage to augment your data by adding custom labels to records. These labels are appended to the _tag system field, making it easier to categorize and search for specific events later.
Syntax
tag add <tag name> tag add "<tag name1>", "<tag name2>", ...
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
add |
keyword | Yes | The command operation to append a tag. |
<tag name> |
string | Yes | The string value to be added as a tag. Must be enclosed in quotes if it contains spaces or special characters. |
Returns
The tag stage returns the original records, enriched with the specified string values appended to the _tag system field.
Usage notes
- The
tagstage specifically modifies the_tagsystem field. Tags can only be applied to this field. - While the
tagstage itself is a straightforward operation, general XQL optimization principles should be applied to the query as a whole. - Apply
filterstages as early as possible in your query to reduce the dataset size before thetagstage processes the records. - Utilize the
fieldsstage immediately after initial filtering to select only the necessary columns. This minimizes the data footprint passed totagand subsequent stages. - Always use the smallest practical
timeframeto limit data scanning.
Examples
Example 1: Adding a single tag to records
Goal: Adds "audit_processed" to the _tag field for all records.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, event_description | tag add "audit_processed" | limit 3
Explanation: The tag add "audit_processed" stage appends the string "audit_processed" to the _tag system field for all records that pass through this stage.
Output:
| EVENT_ID | EVENT_DESCRIPTION |
|---|---|
| 101 | "User login successful" |
| 102 | "File access attempt" |
| 103 | "Network connection established" |
Example 2: Adding a list of tags to records
Goal: Adds "security_incident" and "review_needed" to _tag for unsuccessful events.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter is_successful = false | fields event_id, event_description, is_successful | tag add "security_incident", "review_needed" | limit 3
Explanation: The filter is_successful = false stage first narrows down the dataset to only unsuccessful events. The tag add "security_incident", "review_needed" stage then applies both specified tags to the _tag system field of these filtered records.
Output:
| EVENT_ID | EVENT_DESCRIPTION | IS_SUCCESSFUL |
|---|---|---|
| 102 | "File access attempt" | false |
| 106 | "Unauthorized access detected" | false |
| 109 | "API request throttled" | false |
Related articles
target
Use the target stage to persist the results of your query to a new or existing dataset or lookup table. This allows the results to be used in subsequent queries, facilitating complex data pipelines and long-term storage.
Syntax
target type=dataset|lookup [append=true|false] <dataset name>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
type |
string | Yes | Defines the kind of storage for your query results. Supported values are dataset (persistent storage) or lookup (small reference tables). |
append |
boolean | No | Controls how results are added to an existing dataset or lookup table. true appends results; false (default) overwrites existing data. |
dataset name |
string | Yes | A unique name for your new or existing dataset or lookup table. |
Returns
The target stage persists the query results to the specified storage destination (dataset or lookup table) and allows them to be referenced in future queries.
Usage notes
- The
targetstage must be the final stage in your XQL query. You cannot place any other stages after it. - Datasets created via the
targetstage are persistent and can be queried later using the standarddataset = <dataset name>syntax. - For very long time windows or complex operations, running multiple smaller queries and appending their results to a working dataset using
target type=dataset append=truecan significantly outperform a single, long-running query. - Be mindful of the size limit for
lookuptables, which is 50 MB (or 30 MB if uploaded via the Dataset Management page).
Examples
Example 1: Create new dataset (implicit append)
Goal: Save all successful login events to a new dataset called my_successful_logins.
XQL code:
dataset = sample_xql_raw | filter event_description = "User login successful" and is_successful = true | fields event_id, event_description, _time | target type=dataset my_successful_logins
Explanation: The query filters the sample_xql_raw dataset for successful user logins and saves the selected fields to a new persistent dataset named my_successful_logins. Since append is not specified, it defaults to false (overwrite) behavior when creating new, but functionally acts as a creation step.
Output:
| event_id | event_description | _time |
|---|---|---|
| 101 | "User login successful" | 2023-10-26 10:00:00 UTC |
Example 2: Explicitly creating a new dataset (append=false)
Goal: Save network connection durations to a dataset named event_durations_summary, explicitly overwriting any existing data.
XQL code:
dataset = sample_xql_raw | filter event_description = "Network connection established" | fields event_id, duration_seconds, _time | target type=dataset append=false event_durations_summary
Explanation: This query filters for network connection events and saves them to event_durations_summary. The append=false parameter ensures that if this dataset already exists, its previous content is completely overwritten with these new results.
Output:
| event_id | duration_seconds | _time |
|---|---|---|
| 103 | 10.2 | 2023-10-26 10:15:15 UTC |
Example 3: Appending to an existing dataset (append=true)
Goal: Append "Database backup completed" events to the previously created my_successful_logins dataset.
XQL code:
dataset = sample_xql_raw | filter event_description = "Database backup completed" and is_successful = true | fields event_id, event_description, _time | target type=dataset append=true my_successful_logins
Explanation: This query filters for successful database backup events. The append=true parameter appends these new records to the existing my_successful_logins dataset (created in Example 1) instead of overwriting it.
Output:
| event_id | event_description | _time |
|---|---|---|
| 101 | "User login successful" | 2023-10-26 10:00:00 UTC |
| 110 | "Database backup completed" | 2023-10-26 11:00:10 UTC |
Example 4: Creating a lookup table (type=lookup)
Goal: Create a small lookup table named event_codes_lookup containing event_id and extracted status codes.
XQL code:
dataset = sample_xql_raw | alter status_code = to_number(json_extract_scalar(simple_json_data, "$.code")) | filter status_code != null | fields event_id, status_code | target type=lookup event_codes_lookup
Explanation: The query extracts status codes from the JSON data, filters out nulls, and saves the event_id and status_code mapping to a lookup table named event_codes_lookup. Lookup tables are optimized for small, static reference data.
Output:
| event_id | status_code |
|---|---|
| 101 | 200 |
| 109 | 429 |
Related articles
top
Use the top stage to identify and return the most frequently occurring (or highest-sum) elements for a given field. The stage provides approximate counts and percentages, making it scalable for large datasets.
Syntax
top <integer> <field> [by <field1> ,<field2>...] [top_count as <column name>, top_percent as <column name>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
integer |
integer | No | Represents the number of top elements to return. If omitted, it defaults to up to 10 elements. |
field |
string | Yes | The field for which to find the top elements. |
by field1, ... |
string | No | An optional clause to group rows based on specified fields before identifying top elements within each group. |
top_count as ... |
string | No | Optional alias to rename the default TOP_COUNT result column. |
top_percent as ... |
string | No | Optional alias to rename the default TOP_PERCENT result column. |
Returns
The top stage returns a result set containing the specified fields, along with TOP_COUNT (the approximate count of the value) and TOP_PERCENT (the percentage of the value relative to the total).
Usage notes
- The
topstage produces approximate results, which are optimized for memory usage and time, particularly beneficial when dealing with vast amounts of data. - Early Filtering: Apply
filterstages as early as possible in your query to reduce the dataset size before thetopstage processes the records. - Precise Field Selection: Utilize the
fieldsstage immediately after initial filtering to select only the necessary columns. This minimizes the data footprint passed totopand subsequent stages, improving overall query performance. - Timeframe Management: Always use the smallest practical
timeframeto limit data scanning.
Examples
Example 1: Basic top stage example
Goal: Identifies the top 3 most frequent event descriptions by count.
XQL code:
config timeframe = 1d // Use a practical timeframe | dataset = sample_xql_raw // Specify the dataset | fields event_id, event_description // Select relevant fields | top 3 event_description // Find the top 3 event descriptions by frequency | limit 5 // Limit results for brevity
Explanation: The query calculates the approximate frequency of each unique event_description and returns the top 3 based on that frequency. The query also provides the percentage of each in the total.
Output:
| event_description | TOP_COUNT | TOP_PERCENT |
|---|---|---|
| "User login successful" | 1 | ~10.0% |
| "File access attempt" | 1 | ~10.0% |
| "Network connection established" | 1 | ~10.0% |
Example 2: Top stage with by clause
Goal: Finds the top 1 event description for each 'is_successful' status.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields is_successful, event_description // Select relevant fields | top 1 event_description by is_successful // Find the top 1 event description within each 'is_successful' group | limit 5
Explanation: The by is_successful clause groups the records first by their is_successful status, and then top 1 event_description is applied independently to each of these groups.
Output:
| is_successful | event_description | TOP_COUNT | TOP_PERCENT |
|---|---|---|---|
| true | "User login successful" | 1 | ~16.7% |
| false | "File access attempt" | 1 | ~33.3% |
Example 3: Top stage with custom column names
Goal: Shows the top successful/unsuccessful statuses with custom count/percentage names.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields is_successful // Focus on the boolean field for clear counting | top is_successful top_count as StatusCount, top_percent as StatusPercentage // Use custom column names | limit 5
Explanation: The query identifies the frequencies of true and false in the is_successful field. The top_count as StatusCount and top_percent as StatusPercentage clauses rename the output columns as specified, enhancing readability.
Output:
| is_successful | StatusCount | StatusPercentage |
|---|---|---|
| true | 7 | 70.0% |
| false | 3 | 30.0% |
Related articles
- Stages:
filter,fields,limit - Functions:
approx_top - Datasets:
xdr_data
transaction
Use the transaction stage to group related events into logical sequences or "transactions" based on specified fields. This stage aggregates all fields from the individual events into JSON string arrays and calculates summary statistics for each sequence, such as duration and event count.
Syntax
transaction <field_1>, <field_2>, ... [span = <time> [timeshift = <epoch time> [timezone = "<time zone>"]] | startswith = <condition> endswith = <condition> [allowunclosed = true|false]] [maxevents = <number>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
field_n |
string | Yes | One or more fields used to define the groups for the transaction. |
span |
string | No | Sets a maximum time frame for each transaction (for example, 30m, 1h). |
timeshift |
integer | No | Defines a specific start time (epoch) for grouping events when using span. |
timezone |
string | No | Defines the time zone for the timeshift parameter (for example, "+00:00"). |
startswith |
boolean expression | No | A condition defining the event that starts a transaction. |
endswith |
boolean expression | No | A condition defining the event that ends a transaction. |
allowunclosed |
boolean | No | If true (default), includes transactions that do not have a matching ending event. |
maxevents |
integer | No | Defines the maximum number of events to include per transaction. The default is 100. |
Returns
The transaction stage returns aggregated records representing the grouped sequences. All original fields from the grouped events are aggregated into JSON string arrays.
Additionally, the stage appends the following system fields to each transaction record:
_start_time: The timestamp of the first event in the transaction._end_time: The timestamp of the last event in the transaction._duration: The difference in seconds between the start and end timestamps._num_of_rows: The count of events included in the transaction._transaction_id: A unique identifier for the transaction.
Usage notes
- The
transactionstage aggregates all fields in a JSON string array based on the transaction fields. - A maximum of 50 fields can be aggregated in a single
transactionstage. - Transaction operations can be resource-intensive, especially on large datasets. To optimize performance, apply
filterstages as early as possible to reduce the dataset size before thetransactionstage processes records. - Use the
fieldsstage immediately after initial filtering to select only the necessary columns, minimizing the data footprint passed to the transaction stage. - When using
allowunclosed = true(the default), a transaction that does not find a matching ending event will define its last event as 12 hours after the starting event.
Examples
Example 1: Basic transaction grouping
Goal: Group events into transactions based on identical values in the event_id and event_description fields.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | transaction event_id, event_description | limit 5
Explanation: This query groups rows that share identical values for both event_id and event_description into a single transaction. Since these fields are unique in the sample data, each row forms its own transaction.
Output:
| EVENT_ID | EVENT_DESCRIPTION | _START_TIME | _END_TIME | _DURATION | _NUM_OF_ROWS | _TRANSACTION_ID |
|---|---|---|---|---|---|---|
| 101 | "User login successful" | 2023-10-26 10:00:00 UTC | 2023-10-26 10:00:00 UTC | 0 | 1 | ... |
| 102 | "File access attempt" | 2023-10-26 10:05:30 UTC | 2023-10-26 10:05:30 UTC | 0 | 1 | ... |
Example 2: Transaction with time span
Goal: Group successful events into transactions that occur within a 1-hour time window.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | filter is_successful = true | transaction is_successful span=1h | limit 5
Explanation: The query filters for successful events and then groups them into a single transaction if they occur within the specified 1-hour span. In the sample data, multiple successful events fall within this window.
Output:
| IS_SUCCESSFUL | _START_TIME | _END_TIME | _DURATION | _NUM_OF_ROWS | _TRANSACTION_ID |
|---|---|---|---|---|---|
| true | 2023-10-26 10:00:00 UTC | 2023-10-26 11:00:10 UTC | ~3610 | 7 | ... |
Example 3: Transaction with timeshift and timezone
Goal: Group successful events within 30-minute windows, aligned to a specific start time and timezone.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | transaction is_successful span=30m timeshift=1698304800 timezone="+00:00" | limit 5
Explanation: This query groups events by is_successful into 30-minute windows. The windows are calculated relative to the timeshift epoch (corresponding to 2023-10-26 10:00:00 UTC).
Output:
| IS_SUCCESSFUL | _START_TIME | _END_TIME | _DURATION | _NUM_OF_ROWS | _TRANSACTION_ID |
|---|---|---|---|---|---|
| true | 2023-10-26 10:00:00 UTC | 2023-10-26 10:30:45 UTC | ~1845 | 4 | ... |
| true | 2023-10-26 10:45:00 UTC | 2023-10-26 11:00:10 UTC | ~910 | 3 | ... |
| false | 2023-10-26 10:05:30 UTC | 2023-10-26 10:05:30 UTC | 0 | 1 | ... |
| false | 2023-10-26 10:40:10 UTC | 2023-10-26 10:55:55 UTC | ~945 | 2 | ... |
Example 4: Transaction with start and end conditions
Goal: Identify transactions that begin with a log entry containing "User" and end with one containing "S3".
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | transaction raw_log_data startswith="User" endswith="S3" | limit 5
Explanation: The query groups events based on the raw_log_data field. A transaction starts when a value contains "User" and ends when a value contains "S3".
Output:
| RAW_LOG_DATA | _START_TIME | _END_TIME | _DURATION | _NUM_OF_ROWS | _TRANSACTION_ID |
|---|---|---|---|---|---|
| "User Alice logged in..." | 2023-10-26 10:00:00 UTC | 2023-10-26 10:00:00 UTC | 0 | 1 | ... |
| "Full backup of prod_db to S3..." | 2023-10-26 11:00:10 UTC | 2023-10-26 11:00:10 UTC | 0 | 1 | ... |
Example 5: Transaction with max events limit
Goal: Group events by success status but strictly limit each transaction to a single event.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | transaction is_successful maxevents=1 | limit 5
Explanation: By setting maxevents=1, the query forces every event into its own distinct transaction, regardless of whether they share the same is_successful status or fall within a time span.
Output:
| IS_SUCCESSFUL | _START_TIME | _END_TIME | _DURATION | _NUM_OF_ROWS | _TRANSACTION_ID |
|---|---|---|---|---|---|
| true | 2023-10-26 10:00:00 UTC | 2023-10-26 10:00:00 UTC | 0 | 1 | ... |
| false | 2023-10-26 10:05:30 UTC | 2023-10-26 10:05:30 UTC | 0 | 1 | ... |
| true | 2023-10-26 10:15:15 UTC | 2023-10-26 10:15:15 UTC | 0 | 1 | ... |
Related articles
transpose
Use the transpose stage to turn rows into columns. Each input row becomes a separate output column, effectively rotating the dataset from a columnar (wide) orientation to a row-based (tall) orientation, converting column headers into data values. This is useful for transforming vertically oriented data into a horizontal layout, making it easier to compare field values across rows side by side.
To maintain system reliability and avoid unpredictable SQL state mutations, the transpose stage enforces several constraints, most notably that it must be the terminal stage of the pipeline (see Usage notes and Limitations).
Syntax
transpose [<max_rows>] [column_name=<string>] [header_field=<field>] [include_empty=<bool>]
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
max_rows |
integer | Yes | The maximum number of input rows to transpose into columns. The maximum allowed value is 50. If the user provides a value larger than 50, the number of rows is capped at 50. |
column_name |
string | No | The name of the output field that contains the original input field names. Default is "column". In the output, this field appears as field_name. |
header_field |
string | No | The name of an input field whose values are used as the output column names. If not provided, output columns are named "value_1", "value_2", and so on. |
include_empty |
boolean | No | If set to false, excludes any input field (column) that had no values across all transposed rows. Default is true. |
Returns
The transpose stage returns a transformed dataset where:
- Each input row becomes a separate output column.
- A new field (named by
column_name, default"field_name") is added, containing the original input field names. - Output column names are derived from the
header_fieldvalues if specified, or default to"value_1","value_2", etc. - The number of transposed rows is limited by the
max_rowsparameter (default5, maximum50). - If
include_emptyisfalse, fields that had no values across all transposed rows are excluded from the output. - All transposed values are cast to
STRINGas the universal data type, regardless of their original type. This ensures the transpose operation succeeds across diverse datasets with mixed column types. - Null padding: If the source data contains fewer rows than the specified
max_rowslimit (for example,transpose 50called on a 30-row result set), the remaining value columns are automatically filled withNULLvalues to maintain a consistent output structure.
Usage notes
- Terminal stage enforcement: The
transposestage must be the last stage in the XQL pipeline. No subsequent stages (such asfilter,comp,join, orunion) are allowed aftertranspose. This is because transposing data fundamentally alters the schema — column headers become data and vice versa — making it impractical to apply further transformations on the dynamically generated schema. - The
transposestage is a "blocking" operation; it must process all input records before producing any output. - You must limit the number of rows to transpose using the
max_rowsparameter, up to a maximum of 50 rows. - In Cortex XSOAR, you must use a limit keyword. For example:
xdr-xql-generic-query query="dataset = management_auditing | pivot count(management_auditing_result) for management_auditing_type in (\"USER\", \"AUTH\") by management_auditing_severity" max_fields="20" query_name="TestPivotQuery" parse_result_file_to_context="false"
or
xdr-xql-generic-query query="dataset =management_auditing | limit 10 | transpose 2" query_name="TestAniQuery"
- The
column_nameparameter controls the label of the field that holds the original field names in the transposed output. - When
header_fieldis specified, the values of that field in each input row are used as the names of the corresponding output columns, making the output more descriptive. - The
transposestage is typically used after aggregation stages (such ascomp) or data source stages (such asdataset) to reshape summary data for display or comparison. - No ordering guarantee: The order of the output data is based on the previous stage output. If a specific order is needed, use a
sortstage beforetranspose. - Graphs are not supported for transposed output.
Limitations
| Feature | Constraint / Behavior |
|---|---|
| Terminal Stage | Must be the last stage in the XQL pipeline. No subsequent filter, comp, join, or union stages are allowed. |
| Max Rows | 50 rows maximum. The user can provide their own smaller row count limit via the max_rows argument. |
| Null Padding | If source data has fewer rows than the specified limit, remaining value columns are filled with NULL. |
| Data Typing | All transposed values are cast to STRING as the universal data type. |
| Ordering | No ordering guarantee. Data order is based on previous stage output. |
| Graphs | Graphs are not supported for transposed output. |
Supported contexts
| Context | Supported |
|---|---|
| Correlation | No |
| Parsing Rule | No |
| Dataset RBAC | No |
| Scheduled Queries | Yes |
| Widgets/Reports | Yes |
Examples
Example 1: Basic transpose
Goal: Transpose a small result set of selected fields.
XQL code:
dataset = xdr_data | fields id, severity, custom_fields | transpose 5
Explanation: This query selects three fields and transposes up to 5 rows. Each original field name appears in the field_name column, and each row's values become separate output columns (value_1 through value_5). Since there are only 3 source rows but the limit is 5, the remaining columns (value_4, value_5) are filled with NULL.
Before transpose (3 rows × 3 columns):
| id | severity | custom_fields |
|---|---|---|
evt-001 |
5 |
{"priority": "high"} |
evt-002 |
3 |
{"priority": "low"} |
evt-003 |
8 |
null |
After transpose (3 rows × 6 columns):
| field_name | value_1 | value_2 | value_3 | value_4 | value_5 |
|---|---|---|---|---|---|
id |
"evt-001" |
"evt-002" |
"evt-003" |
null |
null |
severity |
"5" |
"3" |
"8" |
null |
null |
custom_fields |
"{"priority": "high"}" |
"{"priority": "low"}" |
null |
null |
null |
Note: All values are cast to
STRINGin the transposed output, regardless of their original data type.
Example 2: Transpose with custom row limit
Goal: Transpose the first 20 rows into columns.
XQL code:
dataset = xdr_data | fields src_ip, event_type | transpose 20
Explanation: This query transposes up to 20 input rows into columns. Each transposed row becomes a column named "value_1" through "value_20", and the original field names appear in the field_name column. If fewer than 20 rows exist in the input, the remaining columns are padded with NULL.
Example 3: Transpose with custom column name and header field
Goal: Transpose rows using a custom label for the field name column and use the sourcetype field values as output column names.
XQL code:
dataset = xdr_data | fields sourcetype, event_count, severity | transpose column_name="Test Name" header_field=sourcetype include_empty=false
Explanation: This query transposes the input rows, placing the original field names into a column called "Test Name" instead of the default "field_name". The values of the sourcetype field in each input row are used as the names of the output columns. Any fields that have no values across all transposed rows are excluded because include_empty is set to false.
Output:
| Test Name | syslog | firewall | endpoint |
|---|---|---|---|
| event_count | 150 | 42 | 5 |
| severity | low | high | medium |
Example 4: Transpose after aggregation
Goal: Aggregate event counts by type, then transpose the summary for a horizontal comparison.
XQL code:
dataset = xdr_data | comp count(event_id) as event_count by event_type | transpose 10
Explanation: This query first aggregates the data to count events by type, then transposes the result so each event type's row becomes a column. This is useful for creating a horizontal summary view of aggregated data. Since transpose must be the terminal stage, no further processing is applied after it.
Related articles
- Stages: pivot, comp, fields, sort
union
Use the union stage to combine the result sets of two queries into a single, unified result set. The stage is invaluable for consolidating data from different sources or different filtered views of the same data.
Syntax
union <datasetname> union (<inner xql query>)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
datasetname |
string | Yes (Alternative 1) | The name of the existing dataset to combine with the current query's result set. |
inner xql query |
query block | Yes (Alternative 2) | An inner XQL subquery defined inline, whose results will be combined with the current query's result set. |
Returns
The union stage returns a single combined result set containing rows from both the parent query and the joined source (dataset or subquery). All fields from both sources become available to subsequent stages.
Usage notes
- The
unionstage does not preserve sort order. - If a specific order is required for the final output after the union, you must place a
sortstage after theunionstage. - Combining datasets can be resource-intensive, similar to
joinoperations. - Always apply
filterstages as early as possible in your queries to reduce the amount of data being processed before theunionstage. - Utilize the
fieldsstage early to select only necessary columns, minimizing data processing. - For very large datasets or complex operations, consider breaking a single, long-running query into multiple smaller queries and potentially saving intermediate results to a new dataset using the
targetstage.
Examples
Example 1: Union with a named dataset
Goal: Combines events from the sample_xql_raw dataset that match "File access attempt" with a conceptually created successful_logins dataset (containing "User login successful" events).
XQL code:
dataset = sample_xql_raw | filter event_description = "File access attempt" | fields event_id, event_description, is_successful | union successful_logins // Assumes 'successful_logins' dataset exists
Explanation: The query filters the current dataset for file access attempts and then uses union to combine these results with all records from the existing successful_logins dataset.
Output:
| event_id | event_description | is_successful |
|---|---|---|
| 102 | File access attempt | false |
| 101 | User login successful | true |
Example 2: Union with an Inner XQL Query
Goal: Combines records from sample_xql_raw where is_successful is false with records where duration_seconds is greater than 10.0, derived from a separate inner subquery.
XQL code:
dataset = sample_xql_raw | filter is_successful = false | fields event_id, event_description, is_successful, duration_seconds | union ( dataset = sample_xql_raw | filter duration_seconds > 10.0 | fields event_id, event_description, is_successful, duration_seconds )
Explanation: The main query retrieves unsuccessful events. The union stage executes an inner subquery to retrieve events with a duration greater than 10.0 seconds. The results of both queries are combined into a single output.
Output:
| event_id | event_description | is_successful | duration_seconds |
|---|---|---|---|
| 102 | File access attempt | false | 0.8 |
| 106 | Unauthorized access detected | false | 2.1 |
| 109 | API request throttled | false | 0.05 |
| 103 | Network connection established | true | 10.2 |
| 108 | Software update initiated | true | 15.3 |
| 110 | Database backup completed | true | 60.0 |
Related articles
view
Use the view stage to customize how your query results are displayed, enabling highlighting, graphing, and column reordering.
Syntax
view highlight fields = <field1>[,<field2>,...] values = <value1>[,<value2>,...] view graph type = <graph_type> xaxis = <field1> yaxis = <field2> [<optional parameters>] [series = <field3>] view column order = default | populated
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
highlight |
keyword | No | Indicates the view operation is to highlight specific text. |
fields |
string | Yes (for highlight) | A comma-separated list of fields in which to search for the value to highlight. |
values |
string | Yes (for highlight) | A comma-separated list of string values to highlight within the specified fields. |
graph |
keyword | No | Indicates the view operation is to generate a graph. |
type |
string | Yes (for graph) | Specifies the type of graph (for example, pie, column, area, bubble, line, map, scatter). |
xaxis |
string | Yes (for graph) | The field to be used for the X-axis. Must be collatable. |
yaxis |
string | Yes (for graph) | The field to be used for the Y-axis. Must be collatable. |
series |
string | No | Used for certain graph types (area, bubble, column, line, map, scatter) to group chart results based on this field's values. |
column order |
keyword | No | Indicates the view operation is to reorder columns. |
default |
keyword | No | Displays columns in their original order. |
populated |
keyword | No | Displays columns with the most non-null values first. |
Returns
The view stage returns the query results formatted according to the specified visualization or ordering rules.
Usage notes
- For graph types, the fields specified for
xaxisandyaxismust be collatable. - The
seriesparameter is available for specific graph types (area,bubble,column,line,map,scatter) to group chart results based onyaxisvalues. - The
view column orderoption applies only to the Query Builder's display and is disregarded in widgets, Correlation Rules, public APIs, reports, and dashboards.
Examples
Example 1: Highlighting specific values
Goal: Highlight the text "successful" wherever it appears within the event_description field.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | view highlight fields = event_description values = "successful"
Explanation: This query will display the records and visually highlight the text "successful" in the event_description column (for example, in "User login successful").
Output:
| event_id | event_description |
|---|---|
| 101 | "User login successful" |
| 102 | "File access attempt" |
| 103 | "Network connection established" |
Example 2: Visualizing categorical data (Pie chart)
Goal: Create a pie chart showing the count of events grouped by their is_successful status.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp count() by is_successful as event_count | view graph type = pie xaxis = is_successful yaxis = event_count
Explanation: This query counts the total number of events for each is_successful status (true or false). The query then displays these counts as a pie chart, where is_successful defines the slices (xaxis) and event_count defines their size (yaxis).
Output:
| is_successful | event_count |
|---|---|
| true | 7 |
| false | 3 |
Example 3: Trend analysis (column graph)
Goal: Display a column graph showing the count of events per hour.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | bin _time span = 1h | comp count() as hourly_events by _time | view graph type = column xaxis = _time yaxis = hourly_events
Explanation: This query groups events into one-hour bins based on _time, counts the hourly_events for each bin, and presents the data as a column graph showing the hourly distribution.
Output:
| _time | hourly_events |
|---|---|
| 2023-10-26 10:00:00 UTC | 9 |
| 2023-10-26 11:00:00 UTC | 1 |
Example 4: Adding granularity to graphs (series)
Goal: Show the sum of duration_seconds over time, segmented by is_successful status using a series.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | bin _time span = 1h | comp sum(duration_seconds) as total_duration by _time, is_successful | view graph type = column xaxis = _time yaxis = total_duration series = is_successful
Explanation: This query aggregates duration_seconds by hourly _time buckets and is_successful status. The view stage creates a column graph where each hour is represented, segmented by the success status.
Output:
| _time | is_successful | total_duration |
|---|---|---|
| 2023-10-26 10:00:00 UTC | true | 39.9 |
| 2023-10-26 10:00:00 UTC | false | 2.95 |
| 2023-10-26 11:00:00 UTC | true | 60.0 |
Example 5: Prioritizing display (column order)
Goal: Reorder the columns in the results table to display columns with the most non-null values first.
XQL code:
config timeframe = 1d | dataset = sample_xql_raw | comp count() as event_count by is_successful | view column order = populated
Explanation: This query counts events by is_successful and then reorders the resulting columns. Columns that are consistently populated appear earlier in the table view.
Output:
| is_successful | event_count |
|---|---|
| true | 7 |
| false | 3 |
Related articles
windowcomp
Use the windowcomp stage (short for window computation) to perform analytic (window) functions over a defined window of rows without collapsing or reducing the dataset. Unlike the comp stage, which aggregates rows into summary groups, windowcomp preserves all original rows and appends the computed result as a new field. This is equivalent to SQL OVER(...) window functions and is essential for running totals, rolling averages, ranking, and row-level comparisons against group-level statistics.
Syntax
windowcomp <function>(<field>) [by <partition_field1> [, <partition_field2>, ...]] [sort [asc|desc] <sort_field1> [, [asc|desc] <sort_field2>, ...]] [between <lower> [and <upper>] [frame_type=rows|range]] [as <alias>]
Alternative syntax (using over() clause)
Some navigation functions (first_value, last_value, lag) support an alternative SQL-like syntax:
windowcomp <function>(<field>) as <alias> over(partition by <partition_field> order by <sort_field> [asc|desc])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
function |
function | Yes | The window function to apply (for example, avg, count, sum, max, min, median, rank, row_number, first_value, last_value, lag, stddev_population, stddev_sample). |
field |
string | Depends | The field to compute over. Required for most functions; optional for count() (counts all rows when omitted) and not used by rank() or row_number(). |
by |
clause | No | Partition-by clause that divides the input rows into independent partitions over which the window function is evaluated. Accepts one or more partition_field values separated by commas. If the by clause is omitted, all rows in the result set are treated as a single partition. Equivalent to SQL PARTITION BY. |
sort |
clause | No | Sort/order-by clause that defines the ordering of rows within each partition. Accepts one or more sort_field values, each optionally prefixed with asc (ascending, default) or desc (descending). This clause is optional for aggregate functions but required for ranking functions (rank, row_number, dense_rank) and navigation functions (first_value, last_value, lag). When sort is present without a between clause, the default window frame between null and 0 is applied. |
between window frame clause |
clause | No | Defines a sliding or fixed window frame relative to the current row using the syntax between <lower> and <upper> [frame_type=rows\|range]. The lower and upper bounds specify the range of rows included in the computation: negative integers for preceding rows, 0 for the current row, positive integers for following rows, and null for unbounded boundaries. Numbering functions (rank, row_number, dense_rank) and the lag function cannot be used with this clause. If sort is included but between is not, the default frame between null and 0 is used. If neither sort nor between is specified, the entire partition is the window. |
partition_field |
string | No | One or more fields used to partition the data into distinct groups (equivalent to SQL PARTITION BY). The by clause breaks up the input field rows into separate partitions, over which the windowcomp function is independently evaluated. Multiple partition fields are allowed. If omitted, all rows in the input table comprise a single partition. |
sort_field |
string | No | One or more fields that define how rows are ordered within a partition as either ascending (asc) or descending (desc). Defaults to ascending. This clause is optional in most situations, but is required for navigation functions (first_value, last_value, lag) and the rank() function. |
lower |
integer or null |
No | Lower bound of the window frame. 0 = current row, negative integer = rows before the current row, null = unbounded (start of partition). If only a start number is defined (without an end), only a negative number is allowed. If both start and end are defined, the end number must be greater than the start number. Numbering functions and the lag function cannot be used with the window frame clause. If sort is included but the window frame clause is not, the default frame between null and 0 is used. |
upper |
integer or null |
No | Upper bound of the window frame. 0 = current row, positive integer = rows after the current row, null = unbounded (end of partition). The upper boundary must be greater than the lower boundary when both are specified. |
frame_type |
rows or range |
No | Defines the type of window frame. rows (default): Computes the window frame based on physical offsets from the current row (for example, include two rows before and after the current row). To apply the default, nothing needs to be added to the syntax. range: Computes the window frame based on a logical range of rows around the current row, based on the current row's sort key value. The provided range value is added or subtracted to the current row's key value to define a starting or ending range boundary. When using range with start or end numeric nonzero boundaries, exactly one numeric-type sort field is required. When frame_type=range is set, the sort clause must be included; otherwise, only between null and null is supported. |
alias |
string | No | An optional name for the resulting computed field, assigned using the as clause. If omitted, a default name is generated. When the new field name already exists in the schema, the existing field is replaced with the new computed values. |
Returns
The windowcomp stage returns the original dataset with all rows preserved, plus one additional column containing the result of the window function. Each row receives the computed value based on its position within the defined window frame and partition.
Usage notes
- Row preservation: Unlike the
compstage,windowcompdoes not collapse or reduce rows. Every original row is retained, and the computed value is appended as a new field. - One function per stage: Only one function can be defined per field within a single
windowcompstage. To compute multiple window functions, chain multiplewindowcompstages. - Default window frame: If no
betweenclause is specified and asortclause is present, the default frame is from the start of the partition to the current row (between null and 0). If nosortclause is specified, the default window encompasses the entire partition. - Sort requirement: The
sortclause is mandatory for ranking functions (rank,row_number) and is critical when defining a window using thebetweenclause. - Null handling: NULL values are generally ignored in aggregate computations (
avg,sum,countwith a field,min,max, etc.). - Partitioning: If no
byclause is specified, the window spans the entire result set as a single partition. - Between clause: The
betweenclause defines a sliding or fixed window frame relative to the current row. Use negative numbers for preceding rows,0for the current row, positive numbers for following rows, andnullfor unbounded boundaries. - Performance: Window computations can be resource-intensive on large datasets. Consider filtering data before applying
windowcompto improve performance.
Supported functions
The following functions are supported within the windowcomp stage:
Aggregate functions
| Function | Description |
|---|---|
avg(<field>) |
Calculate the average value of a numeric field over the window. |
count([<field>]) |
Count the number of rows (or non-null values of a field) over the window. |
max(<field>) |
Return the maximum value of a field over the window. |
min(<field>) |
Return the minimum value of a field over the window. |
median(<field>) |
Return the median value of a numeric field over the window. |
sum(<field>) |
Compute the sum of a numeric field over the window. |
Statistical functions
| Function | Description |
|---|---|
stddev_population(<field>) |
Compute the population standard deviation of a numeric field over the window. |
stddev_sample(<field>) |
Compute the sample standard deviation of a numeric field over the window (uses Bessel's correction with N-1 denominator). |
Ranking functions
| Function | Description |
|---|---|
rank() |
Assign a rank to each row within a partition. Tied values receive the same rank, and subsequent ranks have gaps. |
row_number() |
Assign a unique sequential integer to each row within a partition, starting at 1. |
dense_rank() |
Assign a rank to each row within a partition. Tied values receive the same rank, and subsequent ranks have no gaps. |
Navigation functions
| Function | Description |
|---|---|
first_value(<field>) |
Return the value of a field from the first row in the window frame. |
last_value(<field>) |
Return the value of a field from the last row in the window frame. |
lag(<field>) |
Return the value of a field from the previous row in the partition (based on sort order). |
latest(<field>) |
Retrieve the single chronologically latest value for a field within the window. |
Examples
Example 1: Rolling average over a partition
Goal: Calculate the average of duration_seconds for all events within each is_successful group, and display this average for every row. XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, duration_seconds | windowcomp avg(duration_seconds) by is_successful as avg_in_partition | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: The by is_successful clause partitions the data into two groups (true and false). The avg() function calculates the average of duration_seconds for each partition. Since no between clause is specified and no sort is used within the windowcomp, the entire partition is the window. The result is a single average value replicated for every row in that partition. Output:
| _time | event_id | is_successful | duration_seconds | avg_in_partition |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | 0.8 | 0.9833 |
| 2023-10-26 10:40:10 UTC | 106 | false | 2.1 | 0.9833 |
| 2023-10-26 10:55:55 UTC | 109 | false | 0.05 | 0.9833 |
| 2023-10-26 10:00:00 UTC | 101 | true | 1.5 | 14.2714 |
| 2023-10-26 10:15:15 UTC | 103 | true | 10.2 | 14.2714 |
| 2023-10-26 10:20:00 UTC | 104 | true | 0.1 | 14.2714 |
| 2023-10-26 10:30:45 UTC | 105 | true | 5.0 | 14.2714 |
| 2023-10-26 10:45:00 UTC | 107 | true | 7.8 | 14.2714 |
| 2023-10-26 10:50:20 UTC | 108 | true | 15.3 | 14.2714 |
| 2023-10-26 11:00:10 UTC | 110 | true | 60.0 | 14.2714 |
Example 2: Rolling window with between clause
Goal: Calculate a rolling average from the duration_seconds of the current row and the two immediately preceding rows within its partition, ordered by _time. XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, duration_seconds | windowcomp avg(duration_seconds) by is_successful sort asc _time between -2 and 0 as rolling_avg | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: The between -2 and 0 clause defines a rolling window including the current row (0) and the two immediately preceding rows (-2, -1) within its partition. For each row, the avg() function calculates the average of duration_seconds strictly within this rolling window. If there are not enough preceding rows, the window starts from the beginning of the partition. Output:
| _time | event_id | is_successful | duration_seconds | rolling_avg |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | 0.8 | 0.8 |
| 2023-10-26 10:40:10 UTC | 106 | false | 2.1 | 1.45 |
| 2023-10-26 10:55:55 UTC | 109 | false | 0.05 | 0.9833 |
| 2023-10-26 10:00:00 UTC | 101 | true | 1.5 | 1.5 |
| 2023-10-26 10:15:15 UTC | 103 | true | 10.2 | 5.85 |
| 2023-10-26 10:20:00 UTC | 104 | true | 0.1 | 3.9333 |
| 2023-10-26 10:30:45 UTC | 105 | true | 5.0 | 5.1 |
| 2023-10-26 10:45:00 UTC | 107 | true | 7.8 | 4.3 |
| 2023-10-26 10:50:20 UTC | 108 | true | 15.3 | 9.3667 |
| 2023-10-26 11:00:10 UTC | 110 | true | 60.0 | 27.7 |
Example 3: Counting rows in a partition
Goal: Count the total number of events (rows) for all events within each is_successful group, replicating this total count for every row. XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, event_description | windowcomp count() by is_successful sort asc _time as count_in_partition | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: The count() function without a field argument counts all rows in each partition. For the false partition (3 rows), the count is 3 for each row. For the true partition (7 rows), the count is 7 for each row. Output:
| _time | event_id | is_successful | event_description | count_in_partition |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | "File access attempt" | 3 |
| 2023-10-26 10:40:10 UTC | 106 | false | "Unauthorized access detected" | 3 |
| 2023-10-26 10:55:55 UTC | 109 | false | "API request throttled" | 3 |
| 2023-10-26 10:00:00 UTC | 101 | true | "User login successful" | 7 |
| 2023-10-26 10:15:15 UTC | 103 | true | "Network connection established" | 7 |
| 2023-10-26 10:20:00 UTC | 104 | true | "System heartbeat" | 7 |
| 2023-10-26 10:30:45 UTC | 105 | true | "Data transformation" | 7 |
| 2023-10-26 10:45:00 UTC | 107 | true | "Cloud resource modification" | 7 |
| 2023-10-26 10:50:20 UTC | 108 | true | "Software update initiated" | 7 |
| 2023-10-26 11:00:10 UTC | 110 | true | "Database backup completed" | 7 |
Example 4: Running maximum over time
Goal: Compute a running maximum of bytes sent, ordered by time. XQL code:
dataset = xdr_data | windowcomp max(bytes_sent) sort asc _time as running_max_bytes
Explanation: By sorting on _time in ascending order, the max() function computes a running maximum of bytes_sent from the start of the dataset up to the current row. Since no by clause is specified, the entire result set is treated as a single partition. Output:
| _TIME | BYTES_SENT | RUNNING_MAX_BYTES |
|---|---|---|
| 2024-01-15 08:00:00 | 100 | 100 |
| 2024-01-15 09:00:00 | 250 | 250 |
| 2024-01-15 10:00:00 | 150 | 250 |
| 2024-01-15 11:00:00 | 300 | 300 |
Example 5: Cumulative sum (running total)
Goal: Compute a cumulative sum of bytes sent over time. XQL code:
dataset = xdr_data | windowcomp sum(bytes_sent) sort asc _time as cumulative_bytes
Explanation: The sum() function with sort asc _time and the default frame (between null and 0) produces a cumulative running total of bytes_sent from the start of the dataset up to the current row. Output:
| _TIME | BYTES_SENT | CUMULATIVE_BYTES |
|---|---|---|
| 2024-01-15 08:00:00 | 100 | 100 |
| 2024-01-15 09:00:00 | 250 | 350 |
| 2024-01-15 10:00:00 | 150 | 500 |
| 2024-01-15 11:00:00 | 300 | 800 |
Example 6: Row numbering within partitions
Goal: Assign a sequential event number to each event per host, ordered by time. XQL code:
dataset = xdr_data | windowcomp row_number() by agent_hostname sort asc _time as event_seq
Explanation: The row_number() function assigns a unique sequential integer starting at 1 for each row within each agent_hostname partition, ordered by _time. This is useful for identifying the nth event per host. Output:
| _TIME | AGENT_HOSTNAME | EVENT_SEQ |
|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | 1 |
| 2024-01-15 09:00:00 | workstation-1 | 2 |
| 2024-01-15 10:00:00 | workstation-1 | 3 |
| 2024-01-15 08:30:00 | workstation-2 | 1 |
| 2024-01-15 09:30:00 | workstation-2 | 2 |
Example 7: Ranking with gaps
Goal: Rank alerts by severity within each host, with gaps for tied values. XQL code:
dataset = xdr_data | windowcomp rank() by agent_hostname sort desc alert_severity as severity_rank
Explanation: The rank() function assigns a rank to each row within each agent_hostname partition based on alert_severity in descending order. Rows with equal severity receive the same rank, and subsequent ranks have gaps (for example, if two rows share rank 1, the next rank is 3). Output:
| _TIME | AGENT_HOSTNAME | ALERT_SEVERITY | SEVERITY_RANK |
|---|---|---|---|
| 2024-01-15 09:00:00 | workstation-1 | 7 | 1 |
| 2024-01-15 10:00:00 | workstation-1 | 5 | 2 |
| 2024-01-15 08:00:00 | workstation-1 | 3 | 3 |
| 2024-01-15 09:30:00 | workstation-2 | 4 | 1 |
| 2024-01-15 08:30:00 | workstation-2 | 2 | 2 |
Example 8: Fixed window (current row to end of partition)
Goal: Calculate the average for each row over a window that starts from the current row and extends to the end of its partition. XQL code:
config timeframe = 1d | dataset = sample_xql_raw | fields event_id, _time, is_successful, duration_seconds | windowcomp avg(duration_seconds) by is_successful sort asc _time between 0 and null as avg_from_current | sort asc is_successful, asc _time, asc event_id | limit 10
Explanation: The between 0 and null clause sets a window starting from the current row (0) through to the very end of the partition (null). For each row, the avg() calculates the average of duration_seconds from the current row's value to the last value in its is_successful partition. Output:
| _time | event_id | is_successful | duration_seconds | avg_from_current |
|---|---|---|---|---|
| 2023-10-26 10:05:30 UTC | 102 | false | 0.8 | 0.9833 |
| 2023-10-26 10:40:10 UTC | 106 | false | 2.1 | 1.075 |
| 2023-10-26 10:55:55 UTC | 109 | false | 0.05 | 0.05 |
| 2023-10-26 10:00:00 UTC | 101 | true | 1.5 | 14.2714 |
| 2023-10-26 10:15:15 UTC | 103 | true | 10.2 | 16.4 |
| 2023-10-26 10:20:00 UTC | 104 | true | 0.1 | 17.64 |
| 2023-10-26 10:30:45 UTC | 105 | true | 5.0 | 22.025 |
| 2023-10-26 10:45:00 UTC | 107 | true | 7.8 | 27.7 |
| 2023-10-26 10:50:20 UTC | 108 | true | 15.3 | 37.65 |
| 2023-10-26 11:00:10 UTC | 110 | true | 60.0 | 60.0 |
Example 9: Sliding window maximum
Goal: Compute the maximum bytes sent within a sliding window of 3 rows (current row plus one row before and one row after). XQL code:
dataset = xdr_data | windowcomp max(bytes_sent) sort asc _time between -1 and 1 as local_max
Explanation: The between -1 and 1 clause defines a sliding window of 3 rows centered on the current row. The max() function returns the maximum bytes_sent value within that window for each row. Output:
| _TIME | BYTES_SENT | LOCAL_MAX |
|---|---|---|
| 2024-01-15 08:00:00 | 100 | 250 |
| 2024-01-15 09:00:00 | 250 | 250 |
| 2024-01-15 10:00:00 | 150 | 300 |
| 2024-01-15 11:00:00 | 300 | 300 |
Example 10: First value with over() syntax
Goal: Identify the first process executed on each host by time. XQL code:
dataset = xdr_data | filter action_process_image_name != null | windowcomp first_value(action_process_image_name) as initial_process over(partition by agent_hostname order by _time asc) | fields _time, agent_hostname, action_process_image_name, initial_process | limit 10
Explanation: The windowcomp stage partitions the events by agent_hostname and orders them chronologically using _time asc. The first_value() function captures the first action_process_image_name encountered in each partition. This value is assigned to the initial_process alias and appended to every row for that host. Output:
| _TIME | AGENT_HOSTNAME | ACTION_PROCESS_IMAGE_NAME | INITIAL_PROCESS |
|---|---|---|---|
| 2024-01-15 08:00:00 | workstation-1 | svchost.exe | svchost.exe |
| 2024-01-15 09:00:00 | workstation-1 | chrome.exe | svchost.exe |
| 2024-01-15 10:00:00 | workstation-1 | powershell.exe | svchost.exe |
| 2024-01-15 08:30:00 | workstation-2 | explorer.exe | explorer.exe |
| 2024-01-15 09:30:00 | workstation-2 | notepad.exe | explorer.exe |
Example 11: Filtering by rank (top-n per group)
Goal: Find the top 3 events by bytes sent within each event type. XQL code:
dataset = xdr_data | windowcomp rank() by event_type sort desc bytes_sent as bytes_rank | filter bytes_rank <= 3 | fields event_type, bytes_sent, bytes_rank
Explanation: The rank() function ranks events within each event_type partition by bytes_sent in descending order. The subsequent filter stage keeps only the top 3 ranked events per group. This pattern is commonly used for top-N analysis. Output:
| EVENT_TYPE | BYTES_SENT | BYTES_RANK |
|---|---|---|
| NETWORK | 5000 | 1 |
| NETWORK | 3200 | 2 |
| NETWORK | 2800 | 3 |
| PROCESS | 1500 | 1 |
| PROCESS | 1200 | 2 |
| PROCESS | 800 | 3 |
Related articles
- Stages:
comp,sort,fields,filter,dedup - Functions:
avg,count,max,median,min,sum,rank,row_number,stddev_population,stddev_sample,first_value,last_value,lag - Datasets:
xdr_data