Skip to content

Commit 2254dd4

Browse files
astefankanoshiou
andauthored
ESQL: Keep DROP attributes when resolving field names (elastic#127009) (elastic#128147)
(cherry picked from commit 54f2668) Co-authored-by: kanoshiou <[email protected]>
1 parent c2537a5 commit 2254dd4

File tree

7 files changed

+104
-11
lines changed

7 files changed

+104
-11
lines changed

docs/changelog/127009.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 127009
2+
summary: "ESQL: Keep `DROP` attributes when resolving field names"
3+
area: ES|QL
4+
type: bug
5+
issues:
6+
- 126418

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ public abstract class GenerativeRestTest extends ESRestTestCase {
5050
"token recognition error at: '``", // https://github.com/elastic/elasticsearch/issues/125870
5151
// https://github.com/elastic/elasticsearch/issues/127167
5252
"optimized incorrectly due to missing references", // https://github.com/elastic/elasticsearch/issues/116781
53-
"No matches found for pattern", // https://github.com/elastic/elasticsearch/issues/126418
5453
"The incoming YAML document exceeds the limit:" // still to investigate, but it seems to be specific to the test framework
5554
);
5655

x-pack/plugin/esql/qa/testFixtures/src/main/resources/drop.csv-spec

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,19 @@ Milky Way
172172
Milky Way
173173
Milky Way
174174
;
175+
176+
dropAgainWithWildcardAfterEval
177+
required_capability: drop_again_with_wildcard_after_eval
178+
from languages
179+
| eval language_code = 12, x = 13
180+
| drop language_code
181+
| drop language*
182+
| keep x
183+
| limit 3
184+
;
185+
186+
x:integer
187+
13
188+
13
189+
13
190+
;

x-pack/plugin/esql/qa/testFixtures/src/main/resources/lookup-join.csv-spec

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,3 +1544,26 @@ French
15441544
Spanish
15451545
German
15461546
;
1547+
1548+
dropAgainWithWildcardAfterEval2
1549+
required_capability: join_lookup_v12
1550+
required_capability: drop_again_with_wildcard_after_eval
1551+
from addresses,cartesian_multipolygons,hosts
1552+
| rename city.name as message
1553+
| lookup join message_types_lookup on message
1554+
| eval card = -6013949614291505456, hOntTwnVC = null, PQAF = null, DXkxCFXyw = null, number = -7336429038807752405
1555+
| eval dewAwHC = -1186293612, message = null
1556+
| sort number ASC, street ASC, ip0 DESC, name ASC NULLS FIRST, host ASC
1557+
| drop number, host_group, *umber, `city.country.continent.name`, dewAwHC, `zip_code`, `message`, city.country.continent.planet.name, `name`, `ip1`, message, zip_code
1558+
| drop description, *e, id
1559+
| keep `hOntTwnVC`, city.country.continent.planet.galaxy, street
1560+
| limit 5
1561+
;
1562+
1563+
hOntTwnVC:null | city.country.continent.planet.galaxy:keyword | street:keyword
1564+
null | Milky Way | Kearny St
1565+
null | Milky Way | Keizersgracht
1566+
null | Milky Way | Marunouchi
1567+
null | null | null
1568+
null | null | null
1569+
;

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,13 @@ public enum Cap {
848848
/**
849849
* Resolve groupings before resolving references to groupings in the aggregations.
850850
*/
851-
RESOLVE_GROUPINGS_BEFORE_RESOLVING_REFERENCES_TO_GROUPINGS_IN_AGGREGATIONS;
851+
RESOLVE_GROUPINGS_BEFORE_RESOLVING_REFERENCES_TO_GROUPINGS_IN_AGGREGATIONS,
852+
853+
/**
854+
* Support for keeping `DROP` attributes when resolving field names.
855+
* see <a href="https://github.com/elastic/elasticsearch/issues/126418"> ES|QL: no matches for pattern #126418 </a>
856+
*/
857+
DROP_AGAIN_WITH_WILDCARD_AFTER_EVAL;
852858

853859
private final boolean enabled;
854860

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/session/EsqlSession.java

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -554,9 +554,15 @@ static PreAnalysisResult fieldNames(LogicalPlan parsed, Set<String> enrichPolicy
554554
}
555555

556556
var referencesBuilder = AttributeSet.builder();
557-
// "keep" attributes are special whenever a wildcard is used in their name
557+
// "keep" and "drop" attributes are special whenever a wildcard is used in their name, as the wildcard can shadow some
558+
// attributes ("lookup join" generated columns among others) and steps like removal of Aliases should ignore the fields
559+
// to remove if their name matches one of these wildcards.
560+
//
558561
// ie "from test | eval lang = languages + 1 | keep *l" should consider both "languages" and "*l" as valid fields to ask for
559-
var keepCommandRefsBuilder = AttributeSet.builder();
562+
// "from test | eval first_name = 1 | drop first_name | drop *name should also consider "*name" as valid field to ask for
563+
//
564+
// NOTE: the grammar allows wildcards to be used in other commands as well, but these are forbidden in the LogicalPlanBuilder
565+
var shadowingRefsBuilder = AttributeSet.builder();
560566
var keepJoinRefsBuilder = AttributeSet.builder();
561567
Set<String> wildcardJoinIndices = new java.util.HashSet<>();
562568

@@ -581,12 +587,12 @@ static PreAnalysisResult fieldNames(LogicalPlan parsed, Set<String> enrichPolicy
581587
if (join.config().type() instanceof JoinTypes.UsingJoinType usingJoinType) {
582588
keepJoinRefsBuilder.addAll(usingJoinType.columns());
583589
}
584-
if (keepCommandRefsBuilder.isEmpty()) {
590+
if (shadowingRefsBuilder.isEmpty()) {
585591
// No KEEP commands after the JOIN, so we need to mark this index for "*" field resolution
586592
wildcardJoinIndices.add(((UnresolvedRelation) join.right()).indexPattern().indexPattern());
587593
} else {
588594
// Keep commands can reference the join columns with names that shadow aliases, so we block their removal
589-
keepJoinRefsBuilder.addAll(keepCommandRefsBuilder);
595+
keepJoinRefsBuilder.addAll(shadowingRefsBuilder);
590596
}
591597
} else {
592598
referencesBuilder.addAll(p.references());
@@ -598,12 +604,10 @@ static PreAnalysisResult fieldNames(LogicalPlan parsed, Set<String> enrichPolicy
598604
p.forEachExpression(UnresolvedNamePattern.class, up -> {
599605
var ua = new UnresolvedAttribute(up.source(), up.name());
600606
referencesBuilder.add(ua);
601-
if (p instanceof Keep) {
602-
keepCommandRefsBuilder.add(ua);
603-
}
607+
shadowingRefsBuilder.add(ua);
604608
});
605609
if (p instanceof Keep) {
606-
keepCommandRefsBuilder.addAll(p.references());
610+
shadowingRefsBuilder.addAll(p.references());
607611
}
608612
}
609613

@@ -633,7 +637,7 @@ static PreAnalysisResult fieldNames(LogicalPlan parsed, Set<String> enrichPolicy
633637
if (fieldNames.contains(alias.name())) {
634638
return;
635639
}
636-
referencesBuilder.removeIf(attr -> matchByName(attr, alias.name(), keepCommandRefsBuilder.contains(attr)));
640+
referencesBuilder.removeIf(attr -> matchByName(attr, alias.name(), shadowingRefsBuilder.contains(attr)));
637641
});
638642
}
639643
});

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/session/IndexResolverFieldNamesTests.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,45 @@ public void testEnrichAndJoinMaskingEvalWh() {
16321632
| keep emp_no, language_name""", Set.of("emp_no", "language_name", "languages", "language_name.*", "languages.*", "emp_no.*"));
16331633
}
16341634

1635+
public void testDropAgainWithWildcardAfterEval() {
1636+
assertFieldNames("""
1637+
from employees
1638+
| eval full_name = 12
1639+
| drop full_name
1640+
| drop *name
1641+
| keep emp_no
1642+
""", Set.of("emp_no", "emp_no.*", "*name", "*name.*"));
1643+
}
1644+
1645+
public void testDropWildcardedFields_AfterRename() {
1646+
assertFieldNames(
1647+
"""
1648+
from employees
1649+
| rename first_name AS first_names, last_name AS last_names
1650+
| eval first_names = 1
1651+
| drop first_names
1652+
| drop *_names
1653+
| keep gender""",
1654+
Set.of("first_name", "first_name.*", "last_name", "last_name.*", "*_names", "*_names.*", "gender", "gender.*")
1655+
);
1656+
}
1657+
1658+
public void testDropWildcardFields_WithLookupJoin() {
1659+
assumeTrue("LOOKUP JOIN available as snapshot only", EsqlCapabilities.Cap.JOIN_LOOKUP_V12.isEnabled());
1660+
assertFieldNames(
1661+
"""
1662+
FROM sample_data
1663+
| EVAL client_ip = client_ip::keyword
1664+
| LOOKUP JOIN clientips_lookup ON client_ip
1665+
| LOOKUP JOIN message_types_lookup ON message
1666+
| KEEP @timestamp, message, *e*
1667+
| SORT @timestamp
1668+
| DROP *e""",
1669+
Set.of("client_ip", "client_ip.*", "message", "message.*", "@timestamp", "@timestamp.*", "*e*", "*e", "*e.*"),
1670+
Set.of()
1671+
);
1672+
}
1673+
16351674
private Set<String> fieldNames(String query, Set<String> enrichPolicyMatchFields) {
16361675
var preAnalysisResult = new EsqlSession.PreAnalysisResult(null);
16371676
return EsqlSession.fieldNames(parser.createStatement(query), enrichPolicyMatchFields, preAnalysisResult).fieldNames();

0 commit comments

Comments
 (0)