Skip to content

Commit

Permalink
Allow match field in enrich fields (#102734) (#103082)
Browse files Browse the repository at this point in the history
It's perfectly fine for the match field of an enrich policy to be
included in the enrich fields. However ESQL enrich consistently fails on
such an enrich policy because it mistakenly excludes the match field
from the enrich mapping during resolution.
  • Loading branch information
dnhatn authored Dec 6, 2023
1 parent bdd2b42 commit 5a0c79a
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 2 deletions.
5 changes: 5 additions & 0 deletions docs/changelog/102734.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 102734
summary: Allow match field in enrich fields
area: ES|QL
type: bug
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,10 @@ public static List<NamedExpression> calculateEnrichFields(
List<NamedExpression> enrichFields,
EnrichPolicy policy
) {
Map<String, Attribute> fieldMap = mapping.stream().collect(Collectors.toMap(NamedExpression::name, Function.identity()));
fieldMap.remove(policy.getMatchField());
Set<String> policyEnrichFieldSet = new HashSet<>(policy.getEnrichFields());
Map<String, Attribute> fieldMap = mapping.stream()
.filter(e -> policyEnrichFieldSet.contains(e.name()))
.collect(Collectors.toMap(NamedExpression::name, Function.identity()));
List<NamedExpression> result = new ArrayList<>();
if (enrichFields == null || enrichFields.isEmpty()) {
// use the policy to infer the enrich fields
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.enrich.EnrichPolicy;
import org.elasticsearch.xpack.esql.enrich.EnrichPolicyResolution;
import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry;
import org.elasticsearch.xpack.esql.expression.function.aggregate.Max;
import org.elasticsearch.xpack.esql.plan.logical.EsqlUnresolvedRelation;
import org.elasticsearch.xpack.esql.plan.logical.Eval;
Expand All @@ -29,16 +32,20 @@
import org.elasticsearch.xpack.ql.plan.logical.EsRelation;
import org.elasticsearch.xpack.ql.plan.logical.Filter;
import org.elasticsearch.xpack.ql.plan.logical.Limit;
import org.elasticsearch.xpack.ql.plan.logical.LogicalPlan;
import org.elasticsearch.xpack.ql.plan.logical.OrderBy;
import org.elasticsearch.xpack.ql.type.DataType;
import org.elasticsearch.xpack.ql.type.DataTypes;
import org.elasticsearch.xpack.ql.type.TypesTests;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.IntStream;

import static org.elasticsearch.xpack.esql.EsqlTestUtils.TEST_VERIFIER;
import static org.elasticsearch.xpack.esql.EsqlTestUtils.as;
import static org.elasticsearch.xpack.esql.EsqlTestUtils.configuration;
import static org.elasticsearch.xpack.esql.EsqlTestUtils.withDefaultLimitWarning;
import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.analyze;
import static org.elasticsearch.xpack.esql.analysis.AnalyzerTestUtils.analyzer;
Expand Down Expand Up @@ -1311,6 +1318,27 @@ public void testEnrichExcludesPolicyKey() {
assertThat(e.getMessage(), containsString("Unknown column [id]"));
}

public void testEnrichFieldsIncludeMatchField() {
String query = """
FROM test
| EVAL x = to_string(languages)
| ENRICH languages ON x
| KEEP language_name, language_code
""";
IndexResolution testIndex = loadMapping("mapping-basic.json", "test");
IndexResolution languageIndex = loadMapping("mapping-languages.json", "languages");
var enrichPolicy = new EnrichPolicy("match", null, List.of("unused"), "language_code", List.of("language_code", "language_name"));
EnrichResolution enrichResolution = new EnrichResolution(
Set.of(new EnrichPolicyResolution("languages", enrichPolicy, languageIndex)),
Set.of("languages")
);
AnalyzerContext context = new AnalyzerContext(configuration(query), new EsqlFunctionRegistry(), testIndex, enrichResolution);
Analyzer analyzer = new Analyzer(context, TEST_VERIFIER);
LogicalPlan plan = analyze(query, analyzer);
var limit = as(plan, Limit.class);
assertThat(Expressions.names(limit.output()), contains("language_name", "language_code"));
}

public void testChainedEvalFieldsUse() {
var query = "from test | eval x0 = pow(salary, 1), x1 = pow(x0, 2), x2 = pow(x1, 3)";
int additionalEvals = randomIntBetween(0, 5);
Expand Down

0 comments on commit 5a0c79a

Please sign in to comment.