AQL Best Practices
Use the recommendations below to optimize your queries and use less resources for their calculation.
Use superapi Efficiently
The superapi operator makes one API call per input row, when the call includes the input_fields parameter. When queries pipe many rows through endpoints that return large responses, the cumulative response size can exceed the 50 MB limit, causing some rows to be skipped.
When the total exceeds 50 MB, the operator stops making additional API calls. The size check occurs after each response is received.
If a call pushes the cumulative total over the 50 MB limit, that call completes and returns data normally, and only subsequent calls are skipped. Therefore, rows processed before the limit is reached return normally, while rows that would have been processed after the limit is reached receive a warning in their output instead of API results.
To avoid hitting this limit, reduce the scope of your API calls using the following practices:
1. Limit Input Rows
Add | limit N before | superapi to cap the number of rows that trigger API calls.
| Inefficient Query | Recommended Query |
|---|---|
|
|
|
2. Use a Smaller Page Size
Lower the limit= parameter in your endpoint URL to reduce the size of each individual API response.
| Inefficient Query | Recommended Query |
|---|---|
|
|
|
3. Filter Before the API Call
Use | where conditions before | superapi to reduce the number of rows that need API enrichment.
| Inefficient Query | Recommended Query |
|---|---|
|
|
|
Use OCSF Index to Reduce Parsing Overhead
If your data exists in OCSF, the OCSF-normalized index pre-parses and structures all event data at ingestion time. Fields are extracted, typed, and stored as structured columns, so queries run directly against pre-processed data with no runtime parsing overhead. By contrast, the eventlog index parses raw messages at query time, reducing query speeds and making high-volume ingestion more expensive.
To reduce this parsing overhead, Anomali recommends the following practice when using the ocsf Version 1.2 index:
Filter on category_uid or category_name Early
Always narrow the scope by filtering on category_uid or category_name early in your query. This allows the query planner to target only the relevant category tables instead of scanning all of them, significantly reducing the amount of data scanned and improving query speed.
| Inefficient Query | Recommended Query |
|---|---|
|
|
|
|
|
|
See OCSF Schema Overview for more information on OCSF Version 1.2 parsing and naming conventions.
Resolving error: "To optimize your experience and reduce your AVC usage, Anomali recommends reducing the time range to 24h to proceed."
When you issue a search, you might encounter the error mentioned above. To resolve this issue, Anomali recommends the following practices:
1. Specify Sourcetype with Parsed Fields:
Use sourcetype as the primary constraint filter in the search query, while using parsed fields. See the Anomali Security Analytics Data Onboarding Guide for the complete list of supported log sources.
| Inefficient Query | Recommended Query |
|---|---|
|
|
|
2. Avoid Wildcard Matching on Sourcetype
Avoid performing any wildcard matching such as sourcetype contains '%' in the search query.
| Inefficient Query | Recommended Query |
|---|---|
|
|
|
3. Avoid message on large search ranges
Avoid using the message field on large search time ranges. Anomali recommends that you restrict a search query with the message field to only 24 hours.
| Inefficient Query | Recommended Query |
|---|---|
|
|
|
4. Turbosearch on Indexed Fields
Use the turbosearch operator on the following indexed fields:
-
account_id -
dest -
dest_ip -
dvc_name -
file_hash -
file_hash2 -
file_hash3 -
file_name -
host -
http_referrer -
message_id -
query -
src -
src_ip -
url -
user
| Inefficient Query | Recommended Query |
|---|---|
|
|
|
If you require additional fields from the eventlog schema, Anomali recommends that you contact Anomali Support for assistance in enabling those for your needs.
Searching across different time ranges
Anomali lets you issue searches across multiple time ranges. Anomali recommends the following solutions for launching efficient searches across different time ranges:
| I want to search for a time range of | Anomali's Recommendation | Additional Information |
|---|---|---|
| Less than 7 days |
Use a regular search, considering all the AQL Best Practices. For example:
|
See defining your AQL search query for more information on how to create an AQL query expressions and define a search time range. |
| 7 days to 90 days |
Use the turbosearch operator to analyze event data across large time spans, up to 90 days. For example:
|
See turbosearch. |
| Greater than 90 days | Your data is archived beyond 90 days. Refer to the Anomali Search Data Retention Policy to understand the next steps to search this data. | See Anomali Virtual Compute to understand its usage and the different user actions that lead to AVC usage. |
Use rex Operator and json_extract Efficiently
To reduce the number of records the rex operator and json_extract process, Anomali recommends using the rex operator and the calc operator's json_extract function after all conditional clauses used to filter the data.
| Before | After |
|---|---|
|
|
|
Use array_agg Operator Effectively
The array_agg operator enforces a limit of 50 distinct values. If the data being aggregated exceeds this limit, the results are truncated. Anomali recommends the following solutions to effectively use array_agg and avoid hitting resource limits:
-
Use low cardinality fields.
-
Filter or transform the data before applying the
array_aggoperator. -
Use the group by clause for high cardinality fields.
Use the dedup Operator Effectively
-
Use the
dedupoperator over small data sets. Reduce the data set size by limiting time range or filtering out events. -
Do not apply the
dedupoperator to themessagefield. Doing so impacts search performance because each raw event is held in memory for this operation.
Stagger Scheduled Tasks
Stagger any task that you can schedule to avoid overloading the system with too many scheduled jobs. For example, instead of scheduling lots of alerts at 2:00 AM, consider staggering them between 2:00 AM and 3:00 AM.
Note: Even if you schedule a job at, say, 2:00 AM, the system might stagger it to balance workloads.
Anomali recommends you consider staggering the following tasks:
-
Scheduled Alerts
-
Scheduled Reports
Use Definitive Operators
If possible, use definitive operators such as = and != instead of operators such as contains. For more accurate results, check the values in your tables before using them in the query.
| Before | After |
|---|---|
|
|
|
Place Limits Last
Place the limit operator last in the query to avoid getting non-deterministic results. In the Before example, the limit is placed before the second where clause, which means that the where clause will be applied only to 100000 events.
If you place the limit operator last, all matching events are calculated first and then limited.
| Before | After |
|---|---|
|
|
|
Use Smallest Possible Time Range
Limit your query to the shortest time frame necessary. The larger the time range, the more data that needs to be scanned, which increases the query execution time.
Specify Targeted Search Table
Specify a system lookup table, such as iocmatch, or a custom lookup table to reduce the data volume scanned. By default, queries scan the eventlog table, which contains all organizational data.
| Example |
|---|
|
|
Prioritize Predicates
Prioritize predicates (where statements) in terms of order: place them earlier but only if it does not affect the accuracy of the query.
In the Before example, the calc line uses the bytes_in and bytes_out fields, which are unrelated to the where clause, which uses sourcetype. You can place the where clause before, and now calculations will be skipped for fields with the source type other than aws_cloudtrail.
| Before | After |
|---|---|
|
|
|
Use Normalized Fields
When extracting values from JSON, check if the field to extract is a normalized column in the eventlog table schema. If yes, use the normalized column instead.
In the After example, the username field in the JSON string message field has been normalized as user in the table schema.
| Before | After |
|---|---|
|
|
|