Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
100 commits
Select commit Hold shift + click to select a range
4b693fb
Adding ES|QL command URI_PART
eyalkoren Dec 26, 2025
3a92c2d
[CI] Auto commit changes from spotless
Dec 26, 2025
5bb2450
Fix yaml test to include new capability
eyalkoren Dec 27, 2025
0ec10eb
Merge remote-tracking branch 'eyalkoren/esql-uri_parts-command' into …
eyalkoren Dec 27, 2025
84172a6
Making UriPartsFunction a singleton
eyalkoren Dec 28, 2025
c39da7c
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Dec 28, 2025
b990cf1
Refix yaml test
eyalkoren Dec 28, 2025
34d8d16
[CI] Auto commit changes from spotless
Dec 28, 2025
6cd0eb3
Ensure consistent creation of UriParts and UriPartsExec
eyalkoren Dec 28, 2025
24c8e28
Merge remote-tracking branch 'eyalkoren/esql-uri_parts-command' into …
eyalkoren Dec 28, 2025
c1cce24
[CI] Auto commit changes from spotless
Dec 28, 2025
fac8358
Extending tests
eyalkoren Dec 28, 2025
318e57a
Workaround generative test failure through dataset changes
eyalkoren Dec 28, 2025
2f14092
Fix also dataset mappings
eyalkoren Dec 28, 2025
1950acc
Optimizing rules
eyalkoren Dec 28, 2025
7397c82
Adding unit tests for planning, analysis and optimizations
eyalkoren Dec 30, 2025
14c922e
Spotless
eyalkoren Dec 30, 2025
8117d21
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Dec 30, 2025
fecdf1c
Handling inconsistency between coordinating and data node
eyalkoren Jan 1, 2026
ceabffb
spotless
eyalkoren Jan 1, 2026
41a94df
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Jan 1, 2026
0c36fe1
Fix tests
eyalkoren Jan 4, 2026
f835ef8
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Jan 4, 2026
67998e9
Add serialization tests
eyalkoren Jan 5, 2026
3b881ff
Update docs/changelog/140004.yaml
eyalkoren Jan 5, 2026
58fd5b2
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Jan 5, 2026
5c24bd0
Update docs/changelog/140004.yaml
eyalkoren Jan 8, 2026
38e0380
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Jan 19, 2026
b33a887
Restoring regenerated ANTLR products
eyalkoren Jan 19, 2026
a3159b8
Restoring AnalyzerTests after merge
eyalkoren Jan 19, 2026
b5460c1
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Jan 19, 2026
ea9ac7f
Making evaluation allocation-free and write directly to blocks
eyalkoren Jan 27, 2026
8f7d68d
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Jan 28, 2026
fd22eed
Complete merge
eyalkoren Jan 28, 2026
2ed210f
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Jan 28, 2026
d5215f2
Some fixes
eyalkoren Jan 28, 2026
c120466
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Jan 28, 2026
8d8ffa2
Applying review comments
eyalkoren Jan 28, 2026
1a94463
Adding infrastructure for multi-value unit tests
eyalkoren Jan 29, 2026
9768d70
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Jan 29, 2026
4e793e3
Adding approximation optimization support and test
eyalkoren Jan 29, 2026
b4c8ba3
Simplify row output evaluation
eyalkoren Jan 29, 2026
9ef68fa
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Jan 29, 2026
e9b9997
Add more csv test cases
eyalkoren Feb 1, 2026
5eb2ab6
Applying OperatorTestCase tests for AbstractCompoundOutputEvaluatorTests
eyalkoren Feb 2, 2026
c67ad86
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 2, 2026
d261373
Complete merge fixes
eyalkoren Feb 2, 2026
2cbfe74
Add docs
eyalkoren Feb 2, 2026
e2bd54c
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 2, 2026
4340112
Complete merge
eyalkoren Feb 2, 2026
7ec42eb
Adding to toc
eyalkoren Feb 3, 2026
3bf8574
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 3, 2026
d346fb4
Minimizing capability name
eyalkoren Feb 3, 2026
11fdd7e
Adding chicken to syntax description in docs
eyalkoren Feb 3, 2026
1dcd144
Making all compound output commands implement Streaming
eyalkoren Feb 3, 2026
d00d217
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 3, 2026
84f6dc5
Fix: creating a collector and RowOutput per evaluator instance
eyalkoren Feb 4, 2026
7d1bfab
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 4, 2026
654b75f
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 4, 2026
05b6e65
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 8, 2026
4ba1271
Applying some review comments
eyalkoren Feb 9, 2026
6880575
Refactor command name - enable on official builds
eyalkoren Feb 9, 2026
597e8b2
Adding requested csv tests
eyalkoren Feb 9, 2026
55d40e4
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 9, 2026
92a4626
Removing unused inport
eyalkoren Feb 9, 2026
3fc1184
Refactor to avoid hard coded warnings mode
eyalkoren Feb 10, 2026
479049f
Spotless
eyalkoren Feb 10, 2026
1360926
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 10, 2026
c15e691
Swtich to use UriParts logic from shared web-utils lib
eyalkoren Feb 10, 2026
dd057b2
Applying code review request
eyalkoren Feb 10, 2026
bb80e54
Applying review comments
eyalkoren Feb 10, 2026
8fc353e
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 10, 2026
0a49935
Switching to use SequenceBytesRefBlockSourceOperator
eyalkoren Feb 10, 2026
675e0f3
Merge branch 'main' into esql-uri_parts-command
eyalkoren Feb 11, 2026
9db6c5d
Merge branch 'main' into esql-uri_parts-command
eyalkoren Feb 11, 2026
5a84db8
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 15, 2026
3e3df4f
Complete merge
eyalkoren Feb 15, 2026
fd75ee9
[CI] Auto commit changes from spotless
Feb 15, 2026
bea8c40
Adding generative tests
eyalkoren Feb 15, 2026
6d4b01e
spotless
eyalkoren Feb 15, 2026
910b96f
Merge remote-tracking branch 'eyalkoren/esql-uri_parts-command' into …
eyalkoren Feb 15, 2026
0d856fa
Aligning generative test validation with other command generators
eyalkoren Feb 15, 2026
a924285
spotless
eyalkoren Feb 15, 2026
d86122c
Changing web-utils dependency to implementation
eyalkoren Feb 15, 2026
caca597
Publishing web-utils lib
eyalkoren Feb 16, 2026
1ec3af4
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 16, 2026
b1c2b45
Remove snapshot build feature flag
eyalkoren Feb 16, 2026
ebeae1a
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 16, 2026
a16bdba
Complete merge
eyalkoren Feb 16, 2026
d4be7b2
Fix 60_usage.yml test
eyalkoren Feb 16, 2026
fb6556f
Adding special sources to csv tests
eyalkoren Feb 17, 2026
ee224a9
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 17, 2026
2f3d4ec
Move mappings to new location
eyalkoren Feb 17, 2026
dc3fae2
Restoring strict generative test validation
eyalkoren Feb 17, 2026
35363ed
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 17, 2026
3e6b438
Fixing generative test framework and restoring even stricter validation
eyalkoren Feb 17, 2026
05b1647
[CI] Auto commit changes from spotless
Feb 17, 2026
332bf3e
Commenting out invalid column validation for LOOKUP_JOIN generative test
eyalkoren Feb 18, 2026
ae46d4f
Merge remote-tracking branch 'upstream/main' into esql-uri_parts-command
eyalkoren Feb 18, 2026
a1eb5b6
Remove dev-command leftover
eyalkoren Feb 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/changelog/140004.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 140004
summary: "Adding ES|QL command URI_PART"
area: ES|QL
type: feature
issues:
- 134885
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
% This is generated by ESQL's AbstractFunctionTestCase. Do not edit it. See ../README.md for how to regenerate it.

```esql
ROW uri = "http://myusername:mypassword@www.example.com:80/foo.gif?key1=val1&key2=val2#fragment"
| URI_PARTS parts = uri
| KEEP parts.*
```

| parts.domain:keyword | parts.fragment:keyword | parts.path:keyword | parts.extension:keyword | parts.port:integer | parts.query:keyword | parts.scheme:keyword | parts.user_info:keyword | parts.username:keyword | parts.password:keyword |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| www.example.com | fragment | /foo.gif | gif | 80 | key1=val1&key2=val2 | http | myusername:mypassword | myusername | mypassword |
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
```yaml {applies_to}
serverless: preview
stack: preview
```

The `URI_PARTS` processing command parses a Uniform Resource Identifier (URI) string and extracts its components into new columns.

::::{note}
This command doesn't support multi-value inputs.
::::


**Syntax**

```esql
URI_PARTS prefix = expression
```

**Parameters**

`prefix`
: The prefix for the output columns. The extracted components are available as `prefix.component`.

`expression`
: The string expression containing the URI to parse.

**Description**

The `URI_PARTS` command parses a URI string and extracts its components into new columns.
The new columns are prefixed with the specified `prefix` followed by a dot (`.`).

This command is the query-time equivalent of the [URI parts ingest processor](/reference/enrich-processor/uri-parts-processor.md).

The following columns are created:

`prefix.domain`
: The host part of the URI.

`prefix.fragment`
: The fragment part of the URI (the part after `#`).

`prefix.path`
: The path part of the URI.

`prefix.extension`
: The file extension extracted from the path.

`prefix.port`
: The port number as an integer.

`prefix.query`
: The query string part of the URI (the part after `?`).

`prefix.scheme`
: The scheme (protocol) of the URI (e.g., `http`, `https`, `ftp`).

`prefix.user_info`
: The user information part of the URI.

`prefix.username`
: The username extracted from the user information.

`prefix.password`
: The password extracted from the user information.

If a component is missing from the URI, the corresponding column contains `null`.
If the expression evaluates to `null`, all output columns are `null`.
If the expression is not a valid URI, a warning is issued and all output columns are `null`.

**Examples**

The following example parses a URI and extracts its parts:

:::{include} ../examples/uri_parts.csv-spec/basic.md
:::

You can use the extracted parts in subsequent commands, for example to filter by domain:

```esql
FROM web_logs
| URI_PARTS p = uri
| WHERE p.domain == "www.example.com"
| STATS COUNT(*) BY p.path
```
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
* [`SAMPLE`](/reference/query-languages/esql/commands/sample.md) {applies_to}`stack: preview` {applies_to}`serverless: preview`
* [`SORT`](/reference/query-languages/esql/commands/sort.md)
* [`STATS`](/reference/query-languages/esql/commands/stats-by.md)
* [`URI_PARTS`](/reference/query-languages/esql/commands/uri-parts.md) {applies_to}`stack: preview` {applies_to}`serverless: preview`
* [`WHERE`](/reference/query-languages/esql/commands/where.md)
10 changes: 10 additions & 0 deletions docs/reference/query-languages/esql/commands/uri-parts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
navigation_title: "URI_PARTS"
mapped_pages:
- https://www.elastic.co/guide/en/elasticsearch/reference/current/esql-commands.html#esql-uri_parts
---

# {{esql}} `URI_PARTS` command [esql-uri_parts]

:::{include} ../_snippets/commands/layout/uri_parts.md
:::

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/reference/query-languages/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ toc:
- file: esql/commands/sample.md
- file: esql/commands/sort.md
- file: esql/commands/stats-by.md
- file: esql/commands/uri-parts.md
- file: esql/commands/where.md
- file: esql/esql-functions-operators.md
children:
Expand Down
2 changes: 2 additions & 0 deletions libs/web-utils/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

apply plugin: 'elasticsearch.publish'

dependencies {
api project(':libs:core')
implementation "org.apache.httpcomponents:httpclient:${versions.httpclient}"
Expand Down
22 changes: 11 additions & 11 deletions libs/web-utils/src/main/java/org/elasticsearch/web/UriParts.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@

public class UriParts {

private static final String DOMAIN = "domain";
private static final String FRAGMENT = "fragment";
private static final String PATH = "path";
private static final String PORT = "port";
private static final String QUERY = "query";
private static final String SCHEME = "scheme";
private static final String USER_INFO = "user_info";
private static final String EXTENSION = "extension";
private static final String USERNAME = "username";
private static final String PASSWORD = "password";
public static final String DOMAIN = "domain";
public static final String FRAGMENT = "fragment";
public static final String PATH = "path";
public static final String EXTENSION = "extension";
public static final String PORT = "port";
public static final String QUERY = "query";
public static final String SCHEME = "scheme";
public static final String USER_INFO = "user_info";
public static final String USERNAME = "username";
public static final String PASSWORD = "password";

private static final LinkedHashMap<String, Class<?>> URI_PARTS_TYPES;

Expand All @@ -39,10 +39,10 @@ public class UriParts {
URI_PARTS_TYPES.putLast(DOMAIN, String.class);
URI_PARTS_TYPES.putLast(FRAGMENT, String.class);
URI_PARTS_TYPES.putLast(PATH, String.class);
URI_PARTS_TYPES.putLast(EXTENSION, String.class);
URI_PARTS_TYPES.putLast(PORT, Integer.class);
URI_PARTS_TYPES.putLast(QUERY, String.class);
URI_PARTS_TYPES.putLast(SCHEME, String.class);
URI_PARTS_TYPES.putLast(EXTENSION, String.class);
URI_PARTS_TYPES.putLast(USER_INFO, String.class);
URI_PARTS_TYPES.putLast(USERNAME, String.class);
URI_PARTS_TYPES.putLast(PASSWORD, String.class);
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugin/esql/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ dependencies {
implementation project('compute:ann')
implementation project(':libs:dissect')
implementation project(':libs:grok')
implementation project(':libs:web-utils')
implementation project(':libs:exponential-histogram')
api "org.apache.lucene:lucene-spatial3d:${versions.lucene}"
api "org.antlr:antlr4-runtime:${versions.antlr4}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,25 @@
import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator;
import org.elasticsearch.core.Releasables;

import java.util.function.Supplier;

public class ColumnExtractOperator extends AbstractPageMappingOperator {

public record Factory(
ElementType[] types,
ExpressionEvaluator.Factory inputEvalSupplier,
Supplier<ColumnExtractOperator.Evaluator> evaluatorSupplier
) implements OperatorFactory {
public record Factory(ElementType[] types, ExpressionEvaluator.Factory inputEvalSupplier, Evaluator.Factory evaluatorProvider)
implements
OperatorFactory {

@Override
public Operator get(DriverContext driverContext) {
return new ColumnExtractOperator(types, inputEvalSupplier.get(driverContext), evaluatorSupplier.get(), driverContext);
return new ColumnExtractOperator(
types,
inputEvalSupplier.get(driverContext),
evaluatorProvider.create(driverContext),
driverContext
);
}

@Override
public String describe() {
return "ColumnExtractOperator[evaluator=" + evaluatorSupplier.get() + "]";
return "ColumnExtractOperator[evaluator=" + evaluatorProvider.describe() + "]";
}
}

Expand Down Expand Up @@ -60,6 +61,7 @@ protected Page process(Page page) {
Block.Builder[] blockBuilders = new Block.Builder[types.length];
try {
for (int i = 0; i < types.length; i++) {
// noinspection resource we release in the finally section
blockBuilders[i] = types[i].newBlockBuilder(rowsCount, driverContext.blockFactory());
}

Expand All @@ -76,11 +78,17 @@ protected Page process(Page page) {
}

Block[] blocks = new Block[blockBuilders.length];
for (int i = 0; i < blockBuilders.length; i++) {
blocks[i] = blockBuilders[i].build();
}
try {
for (int i = 0; i < blockBuilders.length; i++) {
blocks[i] = blockBuilders[i].build();
}

return page.appendBlocks(blocks);
return page.appendBlocks(blocks);
} catch (Exception e) {
// If we built blocks but failed to append them, we need to release them
Releasables.closeExpectNoException(blocks);
throw e;
}
}
} finally {
Releasables.closeExpectNoException(blockBuilders);
Expand All @@ -98,6 +106,12 @@ public String toString() {
}

public interface Evaluator {
interface Factory {
Evaluator create(DriverContext driverContext);

String describe();
}

void computeRow(BytesRefBlock input, int row, Block.Builder[] target, BytesRef spare);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.hamcrest.Matcher;

import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.LongStream;

Expand Down Expand Up @@ -51,7 +50,17 @@ public String toString() {

@Override
protected Operator.OperatorFactory simple(SimpleOptions options) {
Supplier<ColumnExtractOperator.Evaluator> expEval = () -> new FirstWord(0);
ColumnExtractOperator.Evaluator.Factory expEval = new ColumnExtractOperator.Evaluator.Factory() {
@Override
public ColumnExtractOperator.Evaluator create(DriverContext driverContext) {
return new FirstWord(0);
}

@Override
public String describe() {
return "FirstWord";
}
};
return new ColumnExtractOperator.Factory(
new ElementType[] { ElementType.BYTES_REF },
dvrCtx -> new EvalOperator.ExpressionEvaluator() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ public void run(CommandGenerator generator, CommandGenerator.CommandDescription
final QueryExecuted result = previousResult == null
? execute(command, 0)
: execute(previousResult.query() + command, previousResult.depth());
previousResult = result;

final boolean hasException = result.exception() != null;
if (hasException || checkResults(List.of(), generator, current, previousResult, result).success() == false) {
Expand All @@ -193,6 +192,7 @@ public void run(CommandGenerator generator, CommandGenerator.CommandDescription
continueExecuting = true;
currentSchema = result.outputSchema();
}
previousResult = result;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ public class CsvTestsDataLoader {
private static final TestDataset DENSE_VECTOR = new TestDataset("dense_vector");
private static final TestDataset DENSE_VECTOR_BFLOAT16 = new TestDataset("dense_vector_bfloat16");
private static final TestDataset DENSE_VECTOR_ARITHMETIC = new TestDataset("dense_vector_arithmetic");
private static final TestDataset WEB_LOGS = new TestDataset("web_logs");
private static final TestDataset COLORS = new TestDataset("colors");
private static final TestDataset COLORS_CMYK_LOOKUP = new TestDataset("colors_cmyk").withSetting("lookup-settings.json");
private static final TestDataset BASE_CONVERSION = new TestDataset("base_conversion");
Expand Down Expand Up @@ -302,6 +303,7 @@ public class CsvTestsDataLoader {
Map.entry(DENSE_VECTOR.indexName, DENSE_VECTOR),
Map.entry(DENSE_VECTOR_BFLOAT16.indexName, DENSE_VECTOR_BFLOAT16),
Map.entry(DENSE_VECTOR_ARITHMETIC.indexName, DENSE_VECTOR_ARITHMETIC),
Map.entry(WEB_LOGS.indexName, WEB_LOGS),
Map.entry(COLORS.indexName, COLORS),
Map.entry(COLORS_CMYK_LOOKUP.indexName, COLORS_CMYK_LOOKUP),
Map.entry(BASE_CONVERSION.indexName, BASE_CONVERSION),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.elasticsearch.xpack.esql.generator.command.pipe.SortGenerator;
import org.elasticsearch.xpack.esql.generator.command.pipe.StatsGenerator;
import org.elasticsearch.xpack.esql.generator.command.pipe.TimeSeriesStatsGenerator;
import org.elasticsearch.xpack.esql.generator.command.pipe.UriPartsGenerator;
import org.elasticsearch.xpack.esql.generator.command.pipe.WhereGenerator;
import org.elasticsearch.xpack.esql.generator.command.source.FromGenerator;
import org.elasticsearch.xpack.esql.generator.command.source.PromQLGenerator;
Expand Down Expand Up @@ -111,6 +112,7 @@ public class EsqlQueryGenerator {
SampleGenerator.INSTANCE,
SortGenerator.INSTANCE,
StatsGenerator.INSTANCE,
UriPartsGenerator.INSTANCE,
WhereGenerator.INSTANCE
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,11 @@ public ValidationResult validateOutput(
prevCols--;
}

if (prevCols > columns.size()) {
return new ValidationResult(false, "Expecting at least [" + prevCols + "] columns, got [" + columns.size() + "]");
}
// todo: awaits fix https://github.com/elastic/elasticsearch/issues/142636
// if (prevCols > columns.size()) {
// return new ValidationResult(false, "Expecting at least [" + prevCols + "] columns, got [" + columns.size() + "]");
// }

return VALIDATION_OK;
}
}
Loading
Loading