Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions docs/changelog/135901.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 135901
summary: Add support for dot-separated attribute names (e.g. `foo.bar`) and for parameters (e.g. `??my_param`) in FUSE GROUP BY
area: ES|QL
type: bug
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,33 @@ _score:double | new_fork:keyword | _id:keyword
0.01587 | fork1 | 26
;

fuseWithRrfAndDiscriminatorColumnWithDots
required_capability: fork_v9
required_capability: fuse_v6
required_capability: semantic_text_field_caps
required_capability: metadata_score
required_capability: dots_in_fuse

FROM books METADATA _id, _index, _score
| FORK ( WHERE title:"Tolkien" | SORT _score, _id DESC | LIMIT 3)
( WHERE author:"Tolkien" | SORT _score, _id DESC | LIMIT 3)
| EVAL new.fork = _fork
| DROP _fork
| FUSE rrf GROUP BY new.fork
| SORT _score DESC, _id, _index
| EVAL new.fork = mv_sort(new.fork)
| EVAL _score = round(_score, 5)
| KEEP _score, new.fork, _id
;

_score:double | new.fork:keyword | _id:keyword
0.03279 | [fork1, fork2] | 4
0.01613 | fork1 | 56
0.01613 | fork2 | 60
0.01587 | fork2 | 1
0.01587 | fork1 | 26
;

fuseWithRrfAndKeyColumns
required_capability: fork_v9
required_capability: fuse_v6
Expand Down
5 changes: 5 additions & 0 deletions x-pack/plugin/esql/src/main/antlr/lexer/Fuse.g4
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ KEY : 'key';

FUSE_WITH: WITH -> type(WITH), popMode, pushMode(EXPRESSION_MODE);
FUSE_COMMA: COMMA -> type(COMMA);
FUSE_DOT: DOT -> type(DOT);
FUSE_PARAM : PARAM -> type(PARAM);
FUSE_NAMED_OR_POSITIONAL_PARAM : NAMED_OR_POSITIONAL_PARAM -> type(NAMED_OR_POSITIONAL_PARAM);
FUSE_DOUBLE_PARAMS : DOUBLE_PARAMS -> type(DOUBLE_PARAMS);
FUSE_NAMED_OR_POSITIONAL_DOUBLE_PARAMS : NAMED_OR_POSITIONAL_DOUBLE_PARAMS -> type(NAMED_OR_POSITIONAL_DOUBLE_PARAMS);
FUSE_BY: BY -> type(BY);
FUSE_QUOTED_IDENTIFIER: QUOTED_IDENTIFIER -> type(QUOTED_IDENTIFIER);
FUSE_UNQUOTED_IDENTIFIER: UNQUOTED_IDENTIFIER -> type(UNQUOTED_IDENTIFIER);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1593,7 +1593,12 @@ public enum Cap {
* Fix management of plans with no columns
* https://github.com/elastic/elasticsearch/issues/120272
*/
FIX_NO_COLUMNS;
FIX_NO_COLUMNS,

/**
* Support for dots in FUSE attributes
*/
DOTS_IN_FUSE;

private final boolean enabled;

Expand Down

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4307,6 +4307,46 @@ public void testValidFuse() {
assertThat(fuse.fuseType(), equalTo(Fuse.FuseType.RRF));
options = fuse.options();
assertThat(options.get("rank_constant"), equalTo(Literal.integer(null, 15)));

plan = statement("""
FROM foo* METADATA _id, _index, _score
| EVAL a.b = my_group
| FORK ( WHERE a:"baz" )
( WHERE b:"bar" )
| FUSE GROUP BY a.b KEY BY my_key1,my_key2 SCORE BY my_score WITH {"rank_constant": 15 }
""");

fuse = as(plan, Fuse.class);
assertThat(fuse.keys().size(), equalTo(2));
assertThat(fuse.keys().get(0), instanceOf(UnresolvedAttribute.class));
assertThat(fuse.keys().get(0).name(), equalTo("my_key1"));
assertThat(fuse.keys().get(1), instanceOf(UnresolvedAttribute.class));
assertThat(fuse.keys().get(1).name(), equalTo("my_key2"));
assertThat(fuse.discriminator().name(), equalTo("a.b"));
assertThat(fuse.score().name(), equalTo("my_score"));
assertThat(fuse.fuseType(), equalTo(Fuse.FuseType.RRF));
options = fuse.options();
assertThat(options.get("rank_constant"), equalTo(Literal.integer(null, 15)));

plan = statement("""
FROM foo* METADATA _id, _index, _score
| EVAL ??p = my_group
| FORK ( WHERE a:"baz" )
( WHERE b:"bar" )
| FUSE GROUP BY ??p KEY BY my_key1,my_key2 SCORE BY my_score WITH {"rank_constant": 15 }
""", new QueryParams(List.of(paramAsConstant("p", "a.b"))));

fuse = as(plan, Fuse.class);
assertThat(fuse.keys().size(), equalTo(2));
assertThat(fuse.keys().get(0), instanceOf(UnresolvedAttribute.class));
assertThat(fuse.keys().get(0).name(), equalTo("my_key1"));
assertThat(fuse.keys().get(1), instanceOf(UnresolvedAttribute.class));
assertThat(fuse.keys().get(1).name(), equalTo("my_key2"));
assertThat(fuse.discriminator().name(), equalTo("a.b"));
assertThat(fuse.score().name(), equalTo("my_score"));
assertThat(fuse.fuseType(), equalTo(Fuse.FuseType.RRF));
options = fuse.options();
assertThat(options.get("rank_constant"), equalTo(Literal.integer(null, 15)));
}

public void testInvalidFuse() {
Expand Down