Hello,
I’m trying to extract and merge specific pairs of parent/child spans for OpenTelemetry traces produced by Jaeger.
For the record, here’s what a Jaeger trace document looks like in OpenSearch (I’ve removed some of the items of the tags array for readability):
search source = jaeger-span-2026-10-10
| fields operationName, tags
| head 1
{
"schema": [
{
"name": "operationName",
"type": "string"
},
{
"name": "tags",
"type": "array"
}
],
"datarows": [
[
"GET /my/endpoint",
[
{
"type": "string",
"value": "io.opentelemetry.jetty-12.0",
"key": "otel.scope.name"
},
{
"type": "string",
"value": "2.32.0-alpha",
"key": "otel.scope.version"
},
{
"type": "string",
"value": "GET",
"key": "http.request.method"
},
{
"type": "string",
"value": "format=json",
"key": "url.query"
},
{
"type": "string",
"value": "/my/endpoint",
"key": "url.path"
},
{
"type": "string",
"value": "my.server.com",
"key": "server.address"
},
{
"type": "string",
"value": "193.0.13.50",
"key": "client.address"
},
{
"type": "string",
"value": "Java/25.0.4.1",
"key": "user_agent.original"
},
{
"type": "string",
"value": "https",
"key": "url.scheme"
}
]
]
],
"total": 1,
"size": 1
}
My goal is to find pairs of parent/child spans where the child span refers to a specific operation.
With the following join query, I managed to isolate such pairs:
search source = jaeger-span-2026-10-10
| where match(operationName, 'Child operation')
| inner join left = childSpan right = parentSpan on parentSpan.spanID = childSpan.parentSpanID jaeger-span-2026-10-10
| fields parentSpan.tags, childSpan.tags
| head 1
{
"schema": [
{
"name": "parentSpan.tags",
"type": "array"
},
{
"name": "tags",
"type": "array"
}
],
"datarows": [
[
[
{
"type": "string",
"value": "io.opentelemetry.jetty-12.0",
"key": "otel.scope.name"
},
{
"type": "string",
"value": "2.32.0-alpha",
"key": "otel.scope.version"
},
{
"type": "string",
"value": "GET",
"key": "http.request.method"
},
{
"type": "string",
"value": "format=json",
"key": "url.query"
},
{
"type": "string",
"value": "/my/endpoint",
"key": "url.path"
},
{
"type": "string",
"value": "my.server.com",
"key": "server.address"
},
{
"type": "string",
"value": "193.0.13.50",
"key": "client.address"
},
{
"type": "string",
"value": "Java/25.0.4.1",
"key": "user_agent.original"
},
{
"type": "string",
"value": "https",
"key": "url.scheme"
}
],
[
{
"type": "string",
"value": "my.app",
"key": "otel.scope.name"
},
{
"type": "string",
"value": "XXX-AAA-BBB",
"key": "api_key"
}
]
]
],
"total": 1,
"size": 1
}
By adding the mvappend step to the pipeline, I get a result which is close to what I want:
...
| eval tags = mvappend(parentSpan.tags, childSpan.tags)
| fields tags
| head 1
{
"schema": [
{
"name": "tags",
"type": "array"
}
],
"datarows": [
[
[
{
"type": "string",
"value": "io.opentelemetry.jetty-12.0",
"key": "otel.scope.name"
},
{
"type": "string",
"value": "2.32.0-alpha",
"key": "otel.scope.version"
},
{
"type": "string",
"value": "GET",
"key": "http.request.method"
},
{
"type": "string",
"value": "format=json",
"key": "url.query"
},
{
"type": "string",
"value": "/my/endpoint",
"key": "url.path"
},
{
"type": "string",
"value": "my.server.com",
"key": "server.address"
},
{
"type": "string",
"value": "193.0.13.50",
"key": "client.address"
},
{
"type": "string",
"value": "Java/25.0.4.1",
"key": "user_agent.original"
},
{
"type": "string",
"value": "https",
"key": "url.scheme"
},
{
"type": "string",
"value": "my.app",
"key": "otel.scope.name"
},
{
"type": "string",
"value": "XXX-AAA-BBB",
"key": "api_key"
}
]
]
],
"total": 1,
"size": 1
}
Now my question is: how do I get to transform this array of objects into something like the following?
{
"http.request.method": "GET",
"url.path": "/my/endpoint",
"api_key": "XXX-AAA-BBB"
}
Ideally I’d like to keep values with a specific key only.
I’ve spent hours playing with the functions listed on Collection functions | OpenSearch Documentation but couldn’t get it work.
Thanks!