Skip to content

Commit 5d3ac8c

Browse files
Convert mvexpand.rst examples to doctest
Signed-off-by: Srikanth Padakanti <srikanth_padakanti@apple.com>
1 parent 6b04a01 commit 5d3ac8c

4 files changed

Lines changed: 97 additions & 164 deletions

File tree

docs/user/ppl/cmd/mvexpand.rst

Lines changed: 65 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
=============
1+
=================================
22
mvexpand
3-
=============
3+
=================================
44

55
.. rubric:: Table of contents
66

@@ -11,191 +11,93 @@ mvexpand
1111

1212
Description
1313
============
14-
| The ``mvexpand`` command expands each value in a multivalue (array) field into a separate row, similar to Splunk's `mvexpand` command.
15-
| For each document, every value in the specified field is returned as a new row. This is especially useful for log analytics and data exploration involving array fields.
16-
17-
| Key features of ``mvexpand``:
18-
- Expands array fields into multiple rows, one per value.
19-
- Supports an optional ``limit`` parameter to restrict the number of expanded values per document.
20-
- Handles empty, null, and non-array fields gracefully.
21-
- Works as a streaming/distributable command for performance and scalability.
14+
| The ``mvexpand`` command expands each value in a multivalue (array) field into a separate row,
15+
| similar to Splunk's ``mvexpand`` command. For each document, every element in the specified
16+
| array field is returned as a new row.
2217
2318
Syntax
2419
======
25-
mvexpand <field> [limit=<int>]
26-
27-
* **field**: The multivalue (array) field to expand. (Required)
28-
* **limit**: Maximum number of values per document to expand. (Optional)
29-
30-
Usage
31-
=====
32-
Basic expansion::
33-
34-
source=logs | mvexpand tags
35-
36-
Expansion with limit::
37-
38-
source=docs | mvexpand ids limit=3
20+
``mvexpand <field> [limit=<int>]``
3921

40-
Limitations
41-
===========
42-
- Only one field can be expanded per mvexpand command.
43-
- For non-array fields, the value is returned as-is.
44-
- For empty or null arrays, no rows are returned.
45-
- Large arrays may be subject to resource/memory limits; exceeding them results in an error or warning.
22+
* ``field``: The multivalue (array) field to expand. (Required)
23+
* ``limit``: Maximum number of values per document to expand. (Optional)
4624

47-
Output ordering and default limit
48-
--------------------------------
49-
If no `limit` is specified, mvexpand expands all elements in the array (there is no implicit per-document cap). Elements are emitted in the same order they appear in the array (array iteration order). If the underlying field does not provide a defined order, the output order is undefined. Use `limit` to bound the number of expanded rows per document and to avoid resource issues on very large arrays.
50-
51-
Examples and Edge Cases
52-
=======================
53-
54-
Example 1: Basic Expansion
25+
Notes about these doctests
5526
--------------------------
56-
Expand all values from an array field.
57-
58-
Input document::
59-
60-
{ "tags": ["error", "warning", "info"] }
61-
62-
PPL query::
27+
- The tests below target a single, deterministic document by using ``where case='<name>'`` so the doctests are stable.
28+
- The test index name used in these examples is ``mvexpand_logs``.
6329

64-
source=logs | mvexpand tags
30+
Example 1: Basic Expansion (single document)
31+
-------------------------------------------
32+
Input document (case "basic") contains three tag values.
6533

66-
Output (example)::
34+
PPL query / expected output::
6735

36+
os> source=mvexpand_logs | where case='basic' | mvexpand tags | fields tags.value
6837
fetched rows / total rows = 3/3
69-
+--------+
70-
| tags |
71-
+--------+
72-
| error |
73-
| warning|
74-
| info |
75-
+--------+
38+
+------------+
39+
| tags.value |
40+
|------------|
41+
| error |
42+
| warning |
43+
| info |
44+
+------------+
7645

7746
Example 2: Expansion with Limit
7847
-------------------------------
79-
Limit the number of expanded values per document.
48+
Input document (case "ids") contains an array of integers; expand and apply limit.
8049

81-
Input document::
82-
83-
{ "ids": [1, 2, 3, 4, 5] }
84-
85-
PPL query::
86-
87-
source=docs | mvexpand ids limit=3
88-
89-
Output (example)::
50+
PPL query / expected output::
9051

52+
os> source=mvexpand_logs | where case='ids' | mvexpand ids limit=3 | fields ids.value
9153
fetched rows / total rows = 3/3
92-
+-----+
93-
| ids |
94-
+-----+
95-
| 1 |
96-
| 2 |
97-
| 3 |
98-
+-----+
99-
100-
Example 3: Empty or Null Arrays
101-
------------------------------
102-
Handles documents with empty or null array fields.
103-
104-
Input document::
105-
106-
{ "tags": [] }
107-
108-
PPL query::
109-
110-
source=logs | mvexpand tags
111-
112-
Output (example)::
54+
+-----------+
55+
| ids.value |
56+
|-----------|
57+
| 1 |
58+
| 2 |
59+
| 3 |
60+
+-----------+
61+
62+
Example 3: Empty and Null Arrays
63+
--------------------------------
64+
Empty array (case "empty")::
11365

66+
os> source=mvexpand_logs | where case='empty' | mvexpand tags | fields tags.value
11467
fetched rows / total rows = 0/0
115-
+------+
116-
| tags |
117-
+------+
118-
+------+
68+
+------------+
69+
| tags.value |
70+
|------------|
71+
+------------+
11972

120-
Input document::
121-
122-
{ "tags": null }
123-
124-
PPL query::
125-
126-
source=logs | mvexpand tags
127-
128-
Output (example)::
73+
Null array (case "null")::
12974

75+
os> source=mvexpand_logs | where case='null' | mvexpand tags | fields tags.value
13076
fetched rows / total rows = 0/0
131-
+------+
132-
| tags |
133-
+------+
134-
+------+
135-
136-
Example 4: Non-array Field
137-
--------------------------
138-
If the field is a single value (not an array), mvexpand returns the value as-is.
77+
+------------+
78+
| tags.value |
79+
|------------|
80+
+------------+
13981

140-
Input document::
141-
142-
{ "tags": "error" }
143-
144-
PPL query::
145-
146-
source=logs | mvexpand tags
147-
148-
Output (example)::
82+
Example 4: Single-value array (case "single")
83+
---------------------------------------------
84+
Single-element array should expand to one row.
14985

86+
os> source=mvexpand_logs | where case='single' | mvexpand tags | fields tags.value
15087
fetched rows / total rows = 1/1
151-
+-------+
152-
| tags |
153-
+-------+
154-
| error |
155-
+-------+
156-
157-
Example 5: Large Arrays and Memory / resource limits
158-
----------------------------------------------------
159-
If an array is very large it can trigger engine or cluster resource limits and the query can fail with an error. There is no mvexpand-specific configuration. Instead, limits that can cause a query to be terminated are enforced at the node / engine level and by SQL/PPL query controls.
160-
161-
- OpenSearch node protections (for example, heap / query memory limits such as plugins.query.memory_limit) can terminate queries that exceed configured memory budgets.
162-
- SQL/PPL execution limits (timeouts, request/response size limits, and engine memory budgets) also apply to queries that use mvexpand.
163-
- Note: in the current Calcite-based engine, circuit-breaking protections are applied primarily to the index scan operator; protections for other operators (including some operators used internally to implement mvexpand) are under research. Do not assume operator-level circuit breaking will fully protect mvexpand in all cases.
88+
+------------+
89+
| tags.value |
90+
|------------|
91+
| error |
92+
+------------+
16493

165-
To avoid failures when expanding large arrays:
166-
- Use mvexpand's limit parameter to bound the number of expanded values per document (for example: mvexpand field limit=1000).
167-
- Reduce the input size before expanding (filter with where, project only needed fields).
168-
- Tune cluster and SQL/PPL execution settings (circuit breakers, request/response size, timeouts, memory limits) appropriate for your deployment.
169-
170-
For node and SQL/PPL settings see:
171-
https://docs.opensearch.org/1.0/search-plugins/ppl/settings/
172-
173-
Example 6: Multiple Fields (Limitation)
174-
---------------------------------------
175-
mvexpand only supports expanding one field per command. To expand multiple fields, use multiple mvexpand commands or document the limitation.
176-
177-
PPL query::
178-
179-
source=docs | mvexpand a | mvexpand b
180-
181-
Example 7: Edge Case - Field Missing
182-
------------------------------------
183-
If the field does not exist in a document, no row is produced for that document.
184-
185-
Input document::
186-
187-
{ "other": [1,2] }
188-
189-
PPL query::
190-
191-
source=docs | mvexpand tags
192-
193-
Output (example)::
94+
Example 5: Missing Field
95+
------------------------
96+
If the field is missing in the document (case "missing"), no rows are produced.
19497

98+
os> source=mvexpand_logs | where case='missing' | mvexpand tags | fields tags.value
19599
fetched rows / total rows = 0/0
196-
+------+
197-
| tags |
198-
+------+
199-
+------+
200-
201-
---
100+
+------------+
101+
| tags.value |
102+
|------------|
103+
+------------+
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{"case":"basic","tags":[{"value":"error"},{"value":"warning"},{"value":"info"}]}
2+
{"case":"empty","tags":[]}
3+
{"case":"null","tags":null}
4+
{"case":"single","tags":[{"value":"error"}]}
5+
{"case":"ids","ids":[{"value":1},{"value":2},{"value":3},{"value":4},{"value":5}]}
6+
{"case":"missing","other":[1,2]}

doctest/test_docs.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
'otellogs': 'otellogs.json',
4848
'time_data': 'time_test_data.json',
4949
'time_data2': 'time_test_data2.json',
50-
'time_test': 'time_test.json'
50+
'time_test': 'time_test.json',
51+
'mvexpand_logs': 'mvexpand_logs.json',
5152
}
5253

5354
DEBUG_MODE = os.environ.get('DOCTEST_DEBUG', 'false').lower() == 'true'
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"mappings": {
3+
"properties": {
4+
"case": {
5+
"type": "keyword"
6+
},
7+
"tags": {
8+
"type": "nested",
9+
"properties": {
10+
"value": { "type": "keyword" }
11+
}
12+
},
13+
"ids": {
14+
"type": "nested",
15+
"properties": {
16+
"value": { "type": "integer" }
17+
}
18+
},
19+
"other": {
20+
"type": "keyword"
21+
}
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)