Skip to content

Commit 32aaacb

Browse files
LOOKUP JOIN using field-caps for field mapping (#117246)
* LOOKUP JOIN using field-caps for field mapping Removes the hard-coded hack for languages_lookup, and instead does a field-caps check for the real join index. * Update docs/changelog/117246.yaml * Some code review comments
1 parent 9729659 commit 32aaacb

File tree

6 files changed

+135
-79
lines changed

6 files changed

+135
-79
lines changed

docs/changelog/117246.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 117246
2+
summary: LOOKUP JOIN using field-caps for field mapping
3+
area: ES|QL
4+
type: enhancement
5+
issues: []

x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ public class CsvTestsDataLoader {
5656
private static final TestsDataset APPS = new TestsDataset("apps");
5757
private static final TestsDataset APPS_SHORT = APPS.withIndex("apps_short").withTypeMapping(Map.of("id", "short"));
5858
private static final TestsDataset LANGUAGES = new TestsDataset("languages");
59+
private static final TestsDataset LANGUAGES_LOOKUP = LANGUAGES.withIndex("languages_lookup")
60+
.withSetting("languages_lookup-settings.json");
5961
private static final TestsDataset ALERTS = new TestsDataset("alerts");
6062
private static final TestsDataset UL_LOGS = new TestsDataset("ul_logs");
6163
private static final TestsDataset SAMPLE_DATA = new TestsDataset("sample_data");
@@ -93,14 +95,13 @@ public class CsvTestsDataLoader {
9395
private static final TestsDataset BOOKS = new TestsDataset("books");
9496
private static final TestsDataset SEMANTIC_TEXT = new TestsDataset("semantic_text").withInferenceEndpoint(true);
9597

96-
private static final String LOOKUP_INDEX_SUFFIX = "_lookup";
97-
9898
public static final Map<String, TestsDataset> CSV_DATASET_MAP = Map.ofEntries(
9999
Map.entry(EMPLOYEES.indexName, EMPLOYEES),
100100
Map.entry(HOSTS.indexName, HOSTS),
101101
Map.entry(APPS.indexName, APPS),
102102
Map.entry(APPS_SHORT.indexName, APPS_SHORT),
103103
Map.entry(LANGUAGES.indexName, LANGUAGES),
104+
Map.entry(LANGUAGES_LOOKUP.indexName, LANGUAGES_LOOKUP),
104105
Map.entry(UL_LOGS.indexName, UL_LOGS),
105106
Map.entry(SAMPLE_DATA.indexName, SAMPLE_DATA),
106107
Map.entry(ALERTS.indexName, ALERTS),
@@ -130,9 +131,7 @@ public class CsvTestsDataLoader {
130131
Map.entry(DISTANCES.indexName, DISTANCES),
131132
Map.entry(ADDRESSES.indexName, ADDRESSES),
132133
Map.entry(BOOKS.indexName, BOOKS),
133-
Map.entry(SEMANTIC_TEXT.indexName, SEMANTIC_TEXT),
134-
// JOIN LOOKUP alias
135-
Map.entry(LANGUAGES.indexName + LOOKUP_INDEX_SUFFIX, LANGUAGES.withIndex(LANGUAGES.indexName + LOOKUP_INDEX_SUFFIX))
134+
Map.entry(SEMANTIC_TEXT.indexName, SEMANTIC_TEXT)
136135
);
137136

138137
private static final EnrichConfig LANGUAGES_ENRICH = new EnrichConfig("languages_policy", "enrich-policy-languages.json");
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"index": {
3+
"mode": "lookup"
4+
}
5+
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Analyzer.java

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import org.elasticsearch.xpack.esql.expression.predicate.operator.arithmetic.EsqlArithmeticOperation;
6363
import org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.In;
6464
import org.elasticsearch.xpack.esql.index.EsIndex;
65+
import org.elasticsearch.xpack.esql.index.IndexResolution;
6566
import org.elasticsearch.xpack.esql.parser.ParsingException;
6667
import org.elasticsearch.xpack.esql.plan.TableIdentifier;
6768
import org.elasticsearch.xpack.esql.plan.logical.Aggregate;
@@ -106,7 +107,6 @@
106107
import java.util.HashSet;
107108
import java.util.LinkedHashMap;
108109
import java.util.List;
109-
import java.util.Locale;
110110
import java.util.Map;
111111
import java.util.Set;
112112
import java.util.function.Function;
@@ -199,57 +199,42 @@ private static class ResolveTable extends ParameterizedAnalyzerRule<UnresolvedRe
199199

200200
@Override
201201
protected LogicalPlan rule(UnresolvedRelation plan, AnalyzerContext context) {
202-
if (plan.indexMode().equals(IndexMode.LOOKUP)) {
203-
return hackLookupMapping(plan);
204-
}
205-
if (context.indexResolution().isValid() == false) {
206-
return plan.unresolvedMessage().equals(context.indexResolution().toString())
202+
return resolveIndex(plan, plan.indexMode().equals(IndexMode.LOOKUP) ? context.lookupResolution() : context.indexResolution());
203+
}
204+
205+
private LogicalPlan resolveIndex(UnresolvedRelation plan, IndexResolution indexResolution) {
206+
if (indexResolution.isValid() == false) {
207+
return plan.unresolvedMessage().equals(indexResolution.toString())
207208
? plan
208209
: new UnresolvedRelation(
209210
plan.source(),
210211
plan.table(),
211212
plan.frozen(),
212213
plan.metadataFields(),
213214
plan.indexMode(),
214-
context.indexResolution().toString(),
215+
indexResolution.toString(),
215216
plan.commandName()
216217
);
217218
}
218219
TableIdentifier table = plan.table();
219-
if (context.indexResolution().matches(table.index()) == false) {
220+
if (indexResolution.matches(table.index()) == false) {
220221
// TODO: fix this (and tests), or drop check (seems SQL-inherited, where's also defective)
221222
new UnresolvedRelation(
222223
plan.source(),
223224
plan.table(),
224225
plan.frozen(),
225226
plan.metadataFields(),
226227
plan.indexMode(),
227-
"invalid [" + table + "] resolution to [" + context.indexResolution() + "]",
228+
"invalid [" + table + "] resolution to [" + indexResolution + "]",
228229
plan.commandName()
229230
);
230231
}
231232

232-
EsIndex esIndex = context.indexResolution().get();
233+
EsIndex esIndex = indexResolution.get();
233234
var attributes = mappingAsAttributes(plan.source(), esIndex.mapping());
234235
attributes.addAll(plan.metadataFields());
235236
return new EsRelation(plan.source(), esIndex, attributes.isEmpty() ? NO_FIELDS : attributes, plan.indexMode());
236237
}
237-
238-
private LogicalPlan hackLookupMapping(UnresolvedRelation plan) {
239-
if (plan.table().index().toLowerCase(Locale.ROOT).equals("languages_lookup")) {
240-
EsIndex esIndex = new EsIndex(
241-
"languages_lookup",
242-
Map.ofEntries(
243-
Map.entry("language_code", new EsField("language_code", DataType.LONG, Map.of(), true)),
244-
Map.entry("language_name", new EsField("language", DataType.KEYWORD, Map.of(), true))
245-
),
246-
Map.of("languages_lookup", IndexMode.LOOKUP)
247-
);
248-
var attributes = mappingAsAttributes(plan.source(), esIndex.mapping());
249-
return new EsRelation(plan.source(), esIndex, attributes.isEmpty() ? NO_FIELDS : attributes, plan.indexMode());
250-
}
251-
return plan;
252-
}
253238
}
254239

255240
/**

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/AnalyzerContext.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,17 @@ public record AnalyzerContext(
1515
Configuration configuration,
1616
EsqlFunctionRegistry functionRegistry,
1717
IndexResolution indexResolution,
18+
IndexResolution lookupResolution,
1819
EnrichResolution enrichResolution
19-
) {}
20+
) {
21+
// Currently for tests only, since most do not test lookups
22+
// TODO: make this even simpler, remove the enrichResolution for tests that do not require it (most tests)
23+
public AnalyzerContext(
24+
Configuration configuration,
25+
EsqlFunctionRegistry functionRegistry,
26+
IndexResolution indexResolution,
27+
EnrichResolution enrichResolution
28+
) {
29+
this(configuration, functionRegistry, indexResolution, IndexResolution.invalid("<none>"), enrichResolution);
30+
}
31+
}

0 commit comments

Comments
 (0)