Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 6 additions & 0 deletions docs/changelog/137395.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 137395
summary: Fix attribute only in full text function not found
area: ES|QL
type: bug
issues:
- 137396
Original file line number Diff line number Diff line change
Expand Up @@ -1253,3 +1253,22 @@ FROM airports
airport_code:keyword | name:text | city:keyword | country:keyword | location:geo_point | city_boundary:geo_shape
LTN | London Luton | Luton | United Kingdom | POINT(-0.376227267397439 51.8802952570969) | POLYGON((-0.5059 51.9006, -0.4225 51.8545, -0.3499 51.8787, -0.3856 51.9157, -0.4191 51.9123, -0.4263 51.9267, -0.4857 51.9227, -0.4823 51.9078, -0.5059 51.9006))
;

lookupJoinExpressionOnRightFieldNotAnywhereElse
required_capability: join_lookup_v12
required_capability: lookup_join_with_full_text_function

FROM multi_column_joinable
| RENAME id_int AS id_left
| LOOKUP JOIN multi_column_joinable_lookup ON id_int == id_left AND MATCH(other1, "beta")
| WHERE other2 IS NOT NULL
| KEEP id_left, name_str, extra1, other2
| SORT id_left, name_str, extra1, other2
;

warning:Line 3:3: evaluation of [LOOKUP JOIN multi_column_joinable_lookup ON id_int == id_left AND MATCH(other1, \"beta\")] failed, treating result as null. Only first 20 failures recorded.
warning:Line 3:3: java.lang.IllegalArgumentException: LOOKUP JOIN encountered multi-value

id_left:integer | name_str:keyword | extra1:keyword | other2:integer
1 | Alice | foo | 2000
;
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ public static PreAnalysisResult resolveFieldNames(LogicalPlan parsed, boolean ha
referencesBuilder.get().addAll(enrichRefs);
} else if (p instanceof LookupJoin join) {
joinRefs.addAll(join.config().leftFields());
if (join.config().joinOnConditions() != null) {
joinRefs.addAll(join.config().joinOnConditions().references());
}
if (keepRefs.isEmpty()) {
// No KEEP commands after the JOIN, so we need to mark this index for "*" field resolution
wildcardJoinIndices.add(((UnresolvedRelation) join.right()).indexPattern().indexPattern());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package org.elasticsearch.xpack.esql.analysis;

import org.elasticsearch.TransportVersion;
import org.elasticsearch.index.IndexMode;
import org.elasticsearch.inference.TaskType;
import org.elasticsearch.test.ESTestCase;
Expand Down Expand Up @@ -156,6 +157,17 @@ public static LogicalPlan analyze(String query, Analyzer analyzer) {
return analyzed;
}

public static LogicalPlan analyze(String query, TransportVersion transportVersion) {
Analyzer baseAnalyzer = expandedDefaultAnalyzer();
if (baseAnalyzer.context() instanceof MutableAnalyzerContext mutableContext) {
try (var restore = mutableContext.setTemporaryTransportVersionOnOrAfter(transportVersion)) {
return analyze(query, baseAnalyzer);
}
} else {
throw new UnsupportedOperationException("Analyzer Context is not mutable");
}
}

private static final Pattern indexFromPattern = Pattern.compile("(?i)FROM\\s+([\\w-]+)");

private static String indexFromQuery(String query) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5561,6 +5561,43 @@ public void testSubqueryWithFullTextFunctionInMainQuery() {
assertEquals("sample_data", subqueryIndex.indexPattern());
}

public void testLookupJoinOnFieldNotAnywhereElse() {
assumeTrue(
"requires LOOKUP JOIN ON boolean expression capability",
EsqlCapabilities.Cap.LOOKUP_JOIN_WITH_FULL_TEXT_FUNCTION.isEnabled()
);

String query = "FROM test | LOOKUP JOIN languages_lookup "
+ "ON languages == language_code AND MATCH(language_name, \"English\")"
+ "| KEEP languages";

LogicalPlan analyzedPlan = analyze(query, Analyzer.ESQL_LOOKUP_JOIN_FULL_TEXT_FUNCTION);

Limit limit = as(analyzedPlan, Limit.class);
assertThat(limit.limit(), instanceOf(Literal.class));
assertEquals(1000, as(limit.limit(), Literal.class).value());

EsqlProject project = as(limit.child(), EsqlProject.class);
assertEquals(1, project.projections().size());

LookupJoin lookupJoin = as(project.child(), LookupJoin.class);

// Verify join condition contains MATCH function
assertThat(lookupJoin.config().joinOnConditions(), notNullValue());
Expression joinCondition = lookupJoin.config().joinOnConditions();
// Check that the join condition contains a MATCH function (it should be an AND expression)
assertThat(joinCondition.toString(), containsString("MATCH"));

// Verify left relation is test index
EsRelation leftRelation = as(lookupJoin.left(), EsRelation.class);
assertEquals("test", leftRelation.indexPattern());

// Verify right relation is languages_lookup with LOOKUP mode
EsRelation rightRelation = as(lookupJoin.right(), EsRelation.class);
assertEquals("languages_lookup", rightRelation.indexPattern());
assertEquals(IndexMode.LOOKUP, rightRelation.indexMode());
}

private void verifyNameAndTypeAndMultiTypeEsField(
String actualName,
DataType actualType,
Expand Down