Link Search Menu Expand Document Documentation Menu

multisearch

The multisearch command runs multiple subsearches and merges their results. It allows you to combine data from different queries on the same or different sources. You can optionally apply subsequent processing, such as aggregation or sorting, to the combined results. Each subsearch can have different filtering criteria, data transformations, and field selections.

Multisearch is particularly useful for comparative analysis, union operations, and creating comprehensive datasets from multiple search criteria. The command supports timestamp-based result interleaving when working with time-series data.

Use multisearch for:

  • Comparative analysis: Compare metrics across different segments, regions, or time periods.
  • Success rate monitoring: Calculate success rates by comparing successful to total operations.
  • Multi-source data combination: Merge data from different indexes or apply different filters to the same source.
  • A/B testing analysis: Combine results from different test groups for comparison.
  • Time-series data merging: Interleave events from multiple sources based on timestamps.

Syntax

The multisearch command has the following syntax:

multisearch <subsearch1> <subsearch2> [<subsearch3> ...]

The following are examples of the multisearch command syntax:

| multisearch [search source=table | where condition1] [search source=table | where condition2]
| multisearch [search source=index1 | fields field1, field2] [search source=index2 | fields field1, field2]
| multisearch [search source=table | where status="success"] [search source=table | where status="error"]

Parameters

The multisearch command supports the following parameters.

Parameter Required/Optional Description
<subsearchN> Required At least two subsearches are required. Each subsearch must be enclosed in square brackets and start with the search keyword ([search source=index | <commands>]). All PPL commands are supported within subsearches.
<result-processing> Optional Commands applied to the merged results after the multisearch operation (for example, stats, sort, or head).

Example 1: Comparing errors with debug logs

This example merges error logs with debug logs side by side. This is useful when investigating whether debug-level logs from the same services provide clues about the root cause of errors:

| multisearch [search source=otellogs
| where severityText = 'ERROR'
| eval env = 'errors'
| fields env, `resource.attributes.service.name`, body] [search source=otellogs
| where severityText = 'DEBUG'
| eval env = 'debug'
| fields env, `resource.attributes.service.name`, body]
| sort env, `resource.attributes.service.name`

The query returns the following results:

env resource.attributes.service.name body
debug cart Cache miss for key user:session:U200 in Valkey cluster
debug cart Valkey SETEX user:session:U300 3600 - session refreshed
debug product-catalog gRPC call /ProductCatalogService/GetProduct completed in 12ms
errors checkout NullPointerException in CheckoutService.placeOrder at line 142
errors checkout Kafka producer delivery failed: message too large for topic order-events (max 1048576 bytes)
errors frontend-proxy [2024-02-01T09:20:00.456Z] “POST /api/checkout HTTP/1.1” 503 - 0 30000 checkout-8d4f7b-mk2p9
errors payment Payment failed: connection timeout to payment gateway after 30000ms
errors payment Out of memory: Java heap space - shutting down pod payment-6f8d4b-ht7q3
errors product-catalog Database primary node unreachable: connection refused to db-primary-01:5432
errors recommendation Failed to process recommendation request: invalid product ID from 203.0.113.50

Example 2: Segmenting logs by severity tier

This example separates critical and non-critical logs for comparative analysis:

| multisearch [search source=otellogs
| where severityNumber >= 17
| eval tier = "critical"
| fields severityText, severityNumber, tier] [search source=otellogs
| where severityNumber < 17 AND severityNumber >= 13
| eval tier = "warning"
| fields severityText, severityNumber, tier]
| sort - severityNumber

The query returns the following results:

severityText severityNumber tier
ERROR 17 critical
ERROR 17 critical
ERROR 17 critical
ERROR 17 critical
ERROR 17 critical
ERROR 17 critical
ERROR 17 critical
WARN 13 warning
WARN 13 warning
WARN 13 warning
WARN 13 warning

Example 3: Merging time-series data from multiple sources

This example demonstrates how to combine time-series data from different sources while maintaining chronological order. The results are automatically sorted by timestamp to create a unified timeline:

| multisearch [search source=time_data
| where category IN ("A", "B")] [search source=time_data2
| where category IN ("E", "F")]
| fields @timestamp, category, value, timestamp
| head 5

The query returns the following results:

@timestamp category value timestamp
2025-08-01 04:00:00 E 2001 2025-08-01 04:00:00
2025-08-01 03:47:41 A 8762 2025-08-01 03:47:41
2025-08-01 02:30:00 F 2002 2025-08-01 02:30:00
2025-08-01 01:14:11 B 9015 2025-08-01 01:14:11
2025-08-01 01:00:00 E 2003 2025-08-01 01:00:00

Example 4: Handling missing fields across subsearches

This example demonstrates how multisearch handles schema differences when subsearches return different fields. When one subsearch includes a field that others don’t have, missing values are automatically filled with null values:

| multisearch [search source=otellogs
| where severityText = 'ERROR'
| eval needs_page = "yes"
| fields severityText, `resource.attributes.service.name`, needs_page] [search source=otellogs
| where severityText = 'WARN'
| fields severityText, `resource.attributes.service.name`]
| sort `resource.attributes.service.name`
| head 5

The query returns the following results:

severityText resource.attributes.service.name needs_page
ERROR checkout yes
ERROR checkout yes
ERROR frontend-proxy yes
WARN frontend-proxy null
WARN frontend-proxy null

Limitations

The multisearch command has the following limitations:

  • At least two subsearches must be specified.
  • When fields with the same name exist across subsearches but have incompatible types, the system automatically resolves conflicts by renaming the conflicting fields. The first occurrence retains the original name, while subsequent conflicting fields are renamed using a numeric suffix (for example, age becomes age0, age1, and so on). This ensures that all data is preserved while maintaining schema consistency.