Bläddra i källkod

Allow filtering null on enrich fields (ESQL-1467)

The current resolver assumes that the enrich fields are not nullable;
however, they can be. This leads to a bug where we optimize away the
`is_null` or not `is_null` filters on enrich fields and return
unexpected results.
Nhat Nguyen 2 år sedan
förälder
incheckning
972ab7d217

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

@@ -33,6 +33,7 @@ import org.elasticsearch.xpack.ql.expression.Expressions;
 import org.elasticsearch.xpack.ql.expression.FieldAttribute;
 import org.elasticsearch.xpack.ql.expression.Literal;
 import org.elasticsearch.xpack.ql.expression.NamedExpression;
+import org.elasticsearch.xpack.ql.expression.Nullability;
 import org.elasticsearch.xpack.ql.expression.ReferenceAttribute;
 import org.elasticsearch.xpack.ql.expression.UnresolvedAttribute;
 import org.elasticsearch.xpack.ql.expression.UnresolvedStar;
@@ -286,7 +287,7 @@ public class Analyzer extends ParameterizedRuleExecutor<LogicalPlan, AnalyzerCon
                 }
                 return new UnresolvedAttribute(source, enrichFieldName, null, msg);
             } else {
-                return new ReferenceAttribute(source, enrichFieldName, mappedField.dataType());
+                return new ReferenceAttribute(source, enrichFieldName, mappedField.dataType(), null, Nullability.TRUE, null, false);
             }
         }
     }

+ 17 - 0
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java

@@ -1082,6 +1082,23 @@ public class LogicalPlanOptimizerTests extends ESTestCase {
         as(topN.child(), Enrich.class);
     }
 
+    public void testEnrichNotNullFilter() {
+        LogicalPlan plan = optimizedPlan("""
+            from test
+            | eval x = to_string(languages)
+            | enrich languages_idx on x
+            | where not is_null(language_name)
+            | limit 10
+            """);
+        var limit = as(plan, Limit.class);
+        var filter = as(limit.child(), Filter.class);
+        var enrich = as(filter.child(), Enrich.class);
+        assertTrue(enrich.policyName().resolved());
+        assertThat(enrich.policyName().fold(), is(BytesRefs.toBytesRef("languages_idx")));
+        var eval = as(enrich.child(), Eval.class);
+        as(eval.child(), EsRelation.class);
+    }
+
     /**
      * Expects
      * EsqlProject[[a{r}#3, last_name{f}#9]]