Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2ffa01f
Full Text Functions support for Lookup Join
julian-elastic Oct 7, 2025
b139388
Update docs/changelog/136104.yaml
julian-elastic Oct 7, 2025
f018cac
Merge branch 'main' into rightFTF
julian-elastic Oct 10, 2025
3095216
Add new UTs, fix failing UTs
julian-elastic Oct 10, 2025
124f2fa
Bugfix, add UTs for all FTFs
julian-elastic Oct 10, 2025
4d524e2
Fix failing UT
julian-elastic Oct 10, 2025
65351c7
Merge branch 'main' into rightFTF
julian-elastic Oct 10, 2025
965d801
Minor fixes
julian-elastic Oct 10, 2025
b467ea8
Bugfix
julian-elastic Oct 10, 2025
868cca1
Merge branch 'main' into rightFTF
julian-elastic Oct 13, 2025
a1c0989
Perf Improvements
julian-elastic Oct 13, 2025
c69f5bf
Merge branch 'main' into rightFTF
julian-elastic Oct 13, 2025
4d4a049
Address code review comments
julian-elastic Oct 16, 2025
49296aa
Merge branch 'main' into rightFTF
julian-elastic Oct 16, 2025
895b948
Add more UTs
julian-elastic Oct 16, 2025
6917da2
Fix failing UT
julian-elastic Oct 16, 2025
7ba0ed1
Add a new transport version
julian-elastic Oct 16, 2025
e7d3751
Merge branch 'main' into rightFTF
julian-elastic Oct 16, 2025
b2f44e4
Address code review comments
julian-elastic Oct 17, 2025
8bca38a
Allow for Mutable Analyzer Context for testing purposes
julian-elastic Oct 20, 2025
a9b1ceb
Fix transport version
julian-elastic Oct 20, 2025
b8254c1
Merge branch 'main' into rightFTF
julian-elastic Oct 20, 2025
5b99f18
Fix failing UT
julian-elastic Oct 20, 2025
45dbf66
Merge branch 'main' into rightFTF
julian-elastic Oct 23, 2025
520fc04
Merge branch 'main' into rightFTF
julian-elastic Oct 23, 2025
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/136104.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 136104
summary: Add support for Full Text Functions and Lucene pushable conditions on fields from the Lookup Index for Lookup Join
area: ES|QL
type: enhancement
issues: [ ]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
9201000
2 changes: 1 addition & 1 deletion server/src/main/resources/transport/upper_bounds/9.3.csv
Original file line number Diff line number Diff line change
@@ -1 +1 @@
inference_cached_tokens,9200000
esql_lookup_join_full_text_function,9201000
Original file line number Diff line number Diff line change
Expand Up @@ -861,11 +861,22 @@ private Map<String, Object> lookupExplosion(
}
}
if (lookupEntries != lookupEntriesToKeep) {
// add a filter to reduce the number of matches
// we add both a Lucene pushable filter and a non-pushable filter
// this is to make sure that even if there are non-pushable filters the pushable filters is still applied
query.append(" | WHERE ABS(filter_key) > -1 AND filter_key < ").append(lookupEntriesToKeep);

boolean applyAsExpressionJoinFilter = expressionBasedJoin && randomBoolean();
// we randomly add the filter after the join or as part of the join
// in both cases we should have the same amount of results
if (applyAsExpressionJoinFilter == false) {
// add a filter after the join to reduce the number of matches
// we add both a Lucene pushable filter and a non-pushable filter
// this is to make sure that even if there are non-pushable filters the pushable filters is still applied
query.append(" | WHERE ABS(filter_key) > -1 AND filter_key < ").append(lookupEntriesToKeep);
} else {
// apply the filter as part of the join
// then we filter out the rows that do not match the filter after
// so the number of rows is the same as in the field based join case
// and can get the same number of rows for verification purposes
query.append(" AND filter_key < ").append(lookupEntriesToKeep);
query.append(" | WHERE filter_key IS NOT NULL ");
}
}
query.append(" | STATS COUNT(location) | LIMIT 100\"}");
return responseAsMap(query(query.toString(), null));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,7 @@ private void testLookupJoinFieldLevelSecurityHelper(boolean useExpressionJoin) t
ResponseException error = expectThrows(ResponseException.class, () -> runESQLCommand("fls_user4_1", query));
assertThat(error.getResponse().getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST));
if (useExpressionJoin) {
assertThat(error.getMessage(), containsString("Unsupported join filter expression:value_left == value"));
assertThat(error.getMessage(), containsString("Unknown column [value], did you mean [value_left]?"));
} else {
assertThat(error.getMessage(), containsString("Unknown column [value] in right side of join"));
}
Expand Down Expand Up @@ -902,7 +902,7 @@ private void testLookupJoinFieldLevelSecurityOnAliasHelper(boolean useExpression
ResponseException error = expectThrows(ResponseException.class, () -> runESQLCommand("fls_user4_1_alias", query));
assertThat(error.getResponse().getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_BAD_REQUEST));
if (useExpressionJoin) {
assertThat(error.getMessage(), containsString("Unsupported join filter expression:value_left == value"));
assertThat(error.getMessage(), containsString("Unknown column [value], did you mean [value_left]?"));
} else {
assertThat(error.getMessage(), containsString("Unknown column [value] in right side of join"));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ public class CsvTestsDataLoader {
private static final TestDataset DATE_NANOS_UNION_TYPES = new TestDataset("date_nanos_union_types");
private static final TestDataset COUNTRIES_BBOX = new TestDataset("countries_bbox");
private static final TestDataset COUNTRIES_BBOX_WEB = new TestDataset("countries_bbox_web");
private static final TestDataset AIRPORT_CITY_BOUNDARIES = new TestDataset("airport_city_boundaries");
private static final TestDataset AIRPORT_CITY_BOUNDARIES = new TestDataset("airport_city_boundaries").withSetting(
"lookup-settings.json"
);
private static final TestDataset CARTESIAN_MULTIPOLYGONS = new TestDataset("cartesian_multipolygons");
private static final TestDataset CARTESIAN_MULTIPOLYGONS_NO_DOC_VALUES = new TestDataset("cartesian_multipolygons_no_doc_values")
.withData("cartesian_multipolygons.csv");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@
import org.elasticsearch.xcontent.XContentType;
import org.elasticsearch.xcontent.json.JsonXContent;
import org.elasticsearch.xpack.esql.action.EsqlQueryResponse;
import org.elasticsearch.xpack.esql.analysis.AnalyzerContext;
import org.elasticsearch.xpack.esql.analysis.AnalyzerSettings;
import org.elasticsearch.xpack.esql.analysis.EnrichResolution;
import org.elasticsearch.xpack.esql.analysis.MutableAnalyzerContext;
import org.elasticsearch.xpack.esql.analysis.Verifier;
import org.elasticsearch.xpack.esql.core.expression.Alias;
import org.elasticsearch.xpack.esql.core.expression.Attribute;
Expand Down Expand Up @@ -449,7 +449,7 @@ public static TransportVersion randomMinimumVersion() {
}

// TODO: make this even simpler, remove the enrichResolution for tests that do not require it (most tests)
public static AnalyzerContext testAnalyzerContext(
public static MutableAnalyzerContext testAnalyzerContext(
Configuration configuration,
EsqlFunctionRegistry functionRegistry,
Map<IndexPattern, IndexResolution> indexResolutions,
Expand All @@ -462,15 +462,15 @@ public static AnalyzerContext testAnalyzerContext(
/**
* Analyzer context for a random (but compatible) minimum transport version.
*/
public static AnalyzerContext testAnalyzerContext(
public static MutableAnalyzerContext testAnalyzerContext(
Configuration configuration,
EsqlFunctionRegistry functionRegistry,
Map<IndexPattern, IndexResolution> indexResolutions,
Map<String, IndexResolution> lookupResolution,
EnrichResolution enrichResolution,
InferenceResolution inferenceResolution
) {
return new AnalyzerContext(
return new MutableAnalyzerContext(
configuration,
functionRegistry,
indexResolutions,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

package org.elasticsearch.xpack.esql.analysis;

import org.elasticsearch.TransportVersion;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.TransportVersionUtils;
import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry;
import org.elasticsearch.xpack.esql.index.IndexResolution;
import org.elasticsearch.xpack.esql.inference.InferenceResolution;
import org.elasticsearch.xpack.esql.plan.IndexPattern;
import org.elasticsearch.xpack.esql.session.Configuration;

import java.util.Map;

/**
* A mutable version of AnalyzerContext that allows temporarily changing the transport version.
* This is useful for testing scenarios where different transport versions need to be tested.
*/
public class MutableAnalyzerContext extends AnalyzerContext {
private TransportVersion currentVersion;

public MutableAnalyzerContext(
Configuration configuration,
EsqlFunctionRegistry functionRegistry,
Map<IndexPattern, IndexResolution> indexResolution,
Map<String, IndexResolution> lookupResolution,
EnrichResolution enrichResolution,
InferenceResolution inferenceResolution,
TransportVersion minimumVersion
) {
super(configuration, functionRegistry, indexResolution, lookupResolution, enrichResolution, inferenceResolution, minimumVersion);
this.currentVersion = minimumVersion;
}

@Override
public TransportVersion minimumVersion() {
return currentVersion;
}

/**
* Temporarily set the transport version to a random version between the passed-in version and the latest,
* and return an AutoCloseable to restore it.
* Usage:
* try (var restore = context.setTemporaryTransportVersionOnOrAfter(minVersion)) {...}
*/
public RestoreTransportVersion setTemporaryTransportVersionOnOrAfter(TransportVersion minVersion) {
TransportVersion oldVersion = this.currentVersion;
// Set to a random version between minVersion and current
this.currentVersion = TransportVersionUtils.randomVersionBetween(ESTestCase.random(), minVersion, TransportVersion.current());
return new RestoreTransportVersion(oldVersion);
}

/**
* AutoCloseable that restores the original transport version when closed.
*/
public class RestoreTransportVersion implements AutoCloseable {
private final TransportVersion originalVersion;

private RestoreTransportVersion(TransportVersion originalVersion) {
this.originalVersion = originalVersion;
}

@Override
public void close() {
MutableAnalyzerContext.this.currentVersion = originalVersion;
}
}
}
Loading