Skip to content

Commit f80b370

Browse files
cimequinoxelasticsearchmachineivancea
authored
ES|QL: support for parameters in LIKE and RLIKE (#138051)
* Parser and ExpressionBuilder changes for like parameters * Documentation examples for like parameters * Unit tests for like parameters * Add EsqlCapabilities LIKE_PARAMETER_SUPPORT * Add yamlRestTest for like with parameters * Tests check for LIKE_PARAMETER_SUPPORT capability * Handle RLIKE param, LIKE param list, RLIKE param list * StatementParserTests for RLIKE, LIKE list, RLIKE list * AnalyzerTests for LIKE, LIKE list, RLIKE, RLIKE list * Add yamlRestTest for LIKE, RLIKE and error case for LIKE list * Add RestEsqlTestCase for LIKE, RLIKE and LIKE list * Fix typo in docs and explain why we use an inline example instead of directive * Update docs/changelog/138051.yaml * Include anonymous and positional parameters in tests * Collect parameter errors instead of immediately throwing them * Use anonymous and positional parameters in RestEsqlTestCase and also use explicit sort * [CI] Auto commit changes from spotless * Update x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/RLike.java ReST ─▶ REST Co-authored-by: Iván Cea Fontenla <[email protected]> * Update x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java ReST ─▶ REST Co-authored-by: Iván Cea Fontenla <[email protected]> * Move stringOrParameter to EsqlBaseParser.g4 * Refactor stringToStringOrParam to reuse visitParam via a private helper class * Move code for ease of review, add comments, improve naming of source arguments --------- Co-authored-by: elasticsearchmachine <[email protected]> Co-authored-by: Iván Cea Fontenla <[email protected]>
1 parent 24531db commit f80b370

File tree

21 files changed

+1941
-1395
lines changed

21 files changed

+1941
-1395
lines changed

docs/changelog/138051.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 138051
2+
summary: Support for parameters in LIKE and RLIKE
3+
area: ES|QL
4+
type: enhancement
5+
issues: []

docs/reference/query-languages/esql/_snippets/operators/detailedDescription/like.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,15 @@ ROW message = "foobar"
3131
```
3232

3333

34+
Patterns may be specified with REST query placeholders as well
35+
36+
```esql
37+
FROM employees
38+
| WHERE first_name LIKE ?pattern
39+
| KEEP first_name, last_name
40+
```
41+
42+
```{applies_to}
43+
stack: ga 9.3
44+
```
45+

docs/reference/query-languages/esql/_snippets/operators/detailedDescription/rlike.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,15 @@ ROW message = "foobar"
3131
```
3232

3333

34+
Patterns may be specified with REST query placeholders as well
35+
36+
```esql
37+
FROM employees
38+
| WHERE first_name RLIKE ?pattern
39+
| KEEP first_name, last_name
40+
```
41+
42+
```{applies_to}
43+
stack: ga 9.3
44+
```
45+

x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/RestEsqlTestCase.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,6 +1858,46 @@ public void testMatchFunctionAcrossMultipleIndicesWithMissingField() throws IOEx
18581858
}
18591859
}
18601860

1861+
public void testParamsWithLike() throws IOException {
1862+
assumeTrue("like parameter support", EsqlCapabilities.Cap.LIKE_PARAMETER_SUPPORT.isEnabled());
1863+
bulkLoadTestData(11);
1864+
var anonymous_query = requestObjectBuilder().query(
1865+
format(null, "from {} | where keyword like ? | keep keyword | sort keyword", testIndexName())
1866+
).params("[\"key*0\"]");
1867+
Map<String, Object> result = runEsql(anonymous_query);
1868+
assertEquals(List.of(List.of("keyword0"), List.of("keyword10")), result.get("values"));
1869+
}
1870+
1871+
public void testParamsWithLikeList() throws IOException {
1872+
assumeTrue("like parameter support", EsqlCapabilities.Cap.LIKE_PARAMETER_SUPPORT.isEnabled());
1873+
bulkLoadTestData(11);
1874+
var positional_query = requestObjectBuilder().query(
1875+
format(null, "from {} | where keyword like (?1, ?2) | keep keyword | sort keyword", testIndexName())
1876+
).params("[\"key*0\", \"key*1\"]");
1877+
Map<String, Object> result = runEsql(positional_query);
1878+
assertEquals(List.of(List.of("keyword0"), List.of("keyword1"), List.of("keyword10")), result.get("values"));
1879+
}
1880+
1881+
public void testParamsWithRLike() throws IOException {
1882+
assumeTrue("like parameter support", EsqlCapabilities.Cap.LIKE_PARAMETER_SUPPORT.isEnabled());
1883+
bulkLoadTestData(11);
1884+
var query = requestObjectBuilder().query(
1885+
format(null, "from {} | where keyword rlike ?pattern | keep keyword | sort keyword", testIndexName())
1886+
).params("[{\"pattern\" : \"key.*0\"}]");
1887+
Map<String, Object> result = runEsql(query);
1888+
assertEquals(List.of(List.of("keyword0"), List.of("keyword10")), result.get("values"));
1889+
}
1890+
1891+
public void testParamsWithRLikeList() throws IOException {
1892+
assumeTrue("like parameter support", EsqlCapabilities.Cap.LIKE_PARAMETER_SUPPORT.isEnabled());
1893+
bulkLoadTestData(11);
1894+
var query = requestObjectBuilder().query(
1895+
format(null, "from {} | where keyword rlike (?p1, ?p2) | keep keyword | sort keyword", testIndexName())
1896+
).params("[{\"p1\" : \"key.*0\"}, {\"p2\" : \"key.*1\"}]");
1897+
Map<String, Object> result = runEsql(query);
1898+
assertEquals(List.of(List.of("keyword0"), List.of("keyword1"), List.of("keyword10")), result.get("values"));
1899+
}
1900+
18611901
@SuppressWarnings("fallthrough")
18621902
public void testRandomTimezoneBuckets() throws IOException {
18631903
assumeTrue("timezone support for date_trunc is required", EsqlCapabilities.Cap.DATE_TRUNC_TIMEZONE_SUPPORT.isEnabled());

x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,11 @@ identifierOrParameter
214214
| doubleParameter
215215
;
216216

217+
stringOrParameter
218+
: string
219+
| parameter
220+
;
221+
217222
limitCommand
218223
: LIMIT constant
219224
;

x-pack/plugin/esql/src/main/antlr/parser/Expression.g4

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ booleanExpression
1818
;
1919

2020
regexBooleanExpression
21-
: valueExpression (NOT)? LIKE string #likeExpression
22-
| valueExpression (NOT)? RLIKE string #rlikeExpression
23-
| valueExpression (NOT)? LIKE LP string (COMMA string )* RP #likeListExpression
24-
| valueExpression (NOT)? RLIKE LP string (COMMA string )* RP #rlikeListExpression
21+
: valueExpression (NOT)? LIKE stringOrParameter #likeExpression
22+
| valueExpression (NOT)? RLIKE stringOrParameter #rlikeExpression
23+
| valueExpression (NOT)? LIKE LP stringOrParameter (COMMA stringOrParameter )* RP #likeListExpression
24+
| valueExpression (NOT)? RLIKE LP stringOrParameter (COMMA stringOrParameter )* RP #rlikeListExpression
2525
;
2626

2727
matchBooleanExpression

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,11 @@ public enum Cap {
16881688
*/
16891689
TIME_SERIES_WINDOW_V1,
16901690

1691+
/**
1692+
* Support like/rlike parameters https://github.com/elastic/elasticsearch/issues/131356
1693+
*/
1694+
LIKE_PARAMETER_SUPPORT,
1695+
16911696
/**
16921697
* PromQL support in ESQL, before it is released into tech preview.
16931698
* When implementing new functionality or breaking changes,

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/RLike.java

Lines changed: 44 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,50 @@ public class RLike extends RegexMatch<RLikePattern> {
3131
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "RLike", RLike::new);
3232
public static final String NAME = "RLIKE";
3333

34-
@FunctionInfo(returnType = "boolean", description = """
35-
Use `RLIKE` to filter data based on string patterns using
36-
<<regexp-syntax,regular expressions>>. `RLIKE` usually acts on a field placed on
37-
the left-hand side of the operator, but it can also act on a constant (literal)
38-
expression. The right-hand side of the operator represents the pattern.""", detailedDescription = """
39-
Matching special characters (eg. `.`, `*`, `(`...) will require escaping.
40-
The escape character is backslash `\\`. Since also backslash is a special character in string literals,
41-
it will require further escaping.
42-
43-
<<load-esql-example, file=string tag=rlikeEscapingSingleQuotes>>
44-
45-
To reduce the overhead of escaping, we suggest using triple quotes strings `\"\"\"`
46-
47-
<<load-esql-example, file=string tag=rlikeEscapingTripleQuotes>>
48-
```{applies_to}
49-
stack: ga 9.2
50-
serverless: ga
51-
```
52-
53-
Both a single pattern or a list of patterns are supported. If a list of patterns is provided,
54-
the expression will return true if any of the patterns match.
55-
56-
<<load-esql-example, file=where-like tag=rlikeListDocExample>>
57-
""", operator = NAME, examples = @Example(file = "docs", tag = "rlike"))
34+
@FunctionInfo(
35+
returnType = "boolean",
36+
description = """
37+
Use `RLIKE` to filter data based on string patterns using
38+
<<regexp-syntax,regular expressions>>. `RLIKE` usually acts on a field placed on
39+
the left-hand side of the operator, but it can also act on a constant (literal)
40+
expression. The right-hand side of the operator represents the pattern.""",
41+
42+
// we use an inline example here because ?pattern not supported in csv-spec test
43+
detailedDescription = """
44+
Matching special characters (eg. `.`, `*`, `(`...) will require escaping.
45+
The escape character is backslash `\\`. Since also backslash is a special character in string literals,
46+
it will require further escaping.
47+
48+
<<load-esql-example, file=string tag=rlikeEscapingSingleQuotes>>
49+
50+
To reduce the overhead of escaping, we suggest using triple quotes strings `\"\"\"`
51+
52+
<<load-esql-example, file=string tag=rlikeEscapingTripleQuotes>>
53+
```{applies_to}
54+
stack: ga 9.2
55+
serverless: ga
56+
```
57+
58+
Both a single pattern or a list of patterns are supported. If a list of patterns is provided,
59+
the expression will return true if any of the patterns match.
60+
61+
<<load-esql-example, file=where-like tag=rlikeListDocExample>>
62+
63+
Patterns may be specified with REST query placeholders as well
64+
65+
```esql
66+
FROM employees
67+
| WHERE first_name RLIKE ?pattern
68+
| KEEP first_name, last_name
69+
```
70+
71+
```{applies_to}
72+
stack: ga 9.3
73+
```
74+
""",
75+
operator = NAME,
76+
examples = @Example(file = "docs", tag = "rlike")
77+
)
5878
public RLike(
5979
Source source,
6080
@Param(name = "str", type = { "keyword", "text" }, description = "A literal value.") Expression value,

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/string/regex/WildcardLike.java

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -36,36 +36,55 @@ public class WildcardLike extends RegexMatch<WildcardPattern> {
3636
);
3737
public static final String NAME = "LIKE";
3838

39-
@FunctionInfo(returnType = "boolean", description = """
40-
Use `LIKE` to filter data based on string patterns using wildcards. `LIKE`
41-
usually acts on a field placed on the left-hand side of the operator, but it can
42-
also act on a constant (literal) expression. The right-hand side of the operator
43-
represents the pattern.
44-
45-
The following wildcard characters are supported:
46-
47-
* `*` matches zero or more characters.
48-
* `?` matches one character.""", detailedDescription = """
49-
Matching the exact characters `*` and `.` will require escaping.
50-
The escape character is backslash `\\`. Since also backslash is a special character in string literals,
51-
it will require further escaping.
52-
53-
<<load-esql-example, file=string tag=likeEscapingSingleQuotes>>
54-
55-
To reduce the overhead of escaping, we suggest using triple quotes strings `\"\"\"`
56-
57-
<<load-esql-example, file=string tag=likeEscapingTripleQuotes>>
58-
59-
```{applies_to}
60-
stack: ga 9.1
61-
serverless: ga
62-
```
63-
Both a single pattern or a list of patterns are supported. If a list of patterns is provided,
64-
the expression will return true if any of the patterns match.
65-
66-
<<load-esql-example, file=where-like tag=likeListDocExample>>
67-
68-
""", operator = NAME, examples = @Example(file = "docs", tag = "like"))
39+
@FunctionInfo(
40+
returnType = "boolean",
41+
description = """
42+
Use `LIKE` to filter data based on string patterns using wildcards. `LIKE`
43+
usually acts on a field placed on the left-hand side of the operator, but it can
44+
also act on a constant (literal) expression. The right-hand side of the operator
45+
represents the pattern.
46+
47+
The following wildcard characters are supported:
48+
49+
* `*` matches zero or more characters.
50+
* `?` matches one character.""",
51+
52+
// we use an inline example here because ?pattern not supported in csv-spec test
53+
detailedDescription = """
54+
Matching the exact characters `*` and `.` will require escaping.
55+
The escape character is backslash `\\`. Since also backslash is a special character in string literals,
56+
it will require further escaping.
57+
58+
<<load-esql-example, file=string tag=likeEscapingSingleQuotes>>
59+
60+
To reduce the overhead of escaping, we suggest using triple quotes strings `\"\"\"`
61+
62+
<<load-esql-example, file=string tag=likeEscapingTripleQuotes>>
63+
64+
```{applies_to}
65+
stack: ga 9.1
66+
serverless: ga
67+
```
68+
Both a single pattern or a list of patterns are supported. If a list of patterns is provided,
69+
the expression will return true if any of the patterns match.
70+
71+
<<load-esql-example, file=where-like tag=likeListDocExample>>
72+
73+
Patterns may be specified with REST query placeholders as well
74+
75+
```esql
76+
FROM employees
77+
| WHERE first_name LIKE ?pattern
78+
| KEEP first_name, last_name
79+
```
80+
81+
```{applies_to}
82+
stack: ga 9.3
83+
```
84+
""",
85+
operator = NAME,
86+
examples = @Example(file = "docs", tag = "like")
87+
)
6988
public WildcardLike(
7089
Source source,
7190
@Param(name = "str", type = { "keyword", "text" }, description = "A literal expression.") Expression left,

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)