This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch branch-4.0
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/branch-4.0 by this push:
     new 63dec157b34 branch-4.0: [fix](search) fix mow support for search 
function #56927 (#56980)
63dec157b34 is described below

commit 63dec157b34f19ef6157496a60e4cd251fedd4c0
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Oct 16 10:05:58 2025 +0800

    branch-4.0: [fix](search) fix mow support for search function #56927 
(#56980)
    
    Cherry-picked from #56927
    
    Co-authored-by: Jack <[email protected]>
---
 .../nereids/rules/analysis/CheckSearchUsage.java   | 29 ++++++--
 .../suites/search/test_search_mow_support.groovy   | 78 ++++++++++++++++++++++
 2 files changed, 101 insertions(+), 6 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckSearchUsage.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckSearchUsage.java
index 0fd66ef0618..40fc84e41f2 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckSearchUsage.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/CheckSearchUsage.java
@@ -30,6 +30,8 @@ import 
org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
 import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
 
 import com.google.common.collect.ImmutableList;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 import java.util.List;
 
@@ -39,15 +41,16 @@ import java.util.List;
  * Must run in analysis phase before search() gets optimized away.
  */
 public class CheckSearchUsage implements AnalysisRuleFactory {
+    private static final Logger LOG = 
LogManager.getLogger(CheckSearchUsage.class);
 
     @Override
     public List<Rule> buildRules() {
         return ImmutableList.of(
-            any().thenApply(ctx -> {
-                Plan plan = ctx.root;
-                checkPlanRecursively(plan);
-                return plan;
-            }).toRule(RuleType.CHECK_SEARCH_USAGE)
+                any().thenApply(ctx -> {
+                    Plan plan = ctx.root;
+                    checkPlanRecursively(plan);
+                    return plan;
+                }).toRule(RuleType.CHECK_SEARCH_USAGE)
         );
     }
 
@@ -93,9 +96,10 @@ public class CheckSearchUsage implements AnalysisRuleFactory 
{
     }
 
     private void validateSearchUsage(Plan plan) {
+        LOG.debug("validateSearchUsage: {}", plan.treeString());
         if (plan instanceof LogicalFilter) {
             Plan child = plan.child(0);
-            if (!(child instanceof LogicalOlapScan)) {
+            if (!isSingleTableScanPipeline(child)) {
                 throw new AnalysisException("search() predicate only supports 
filtering directly on a single "
                         + "table scan; remove joins, subqueries, or additional 
operators between search() "
                         + "and the target table");
@@ -127,4 +131,17 @@ public class CheckSearchUsage implements 
AnalysisRuleFactory {
         }
         return false;
     }
+
+    private boolean isSingleTableScanPipeline(Plan plan) {
+        Plan current = plan;
+        while (true) {
+            if (current instanceof LogicalOlapScan) {
+                return true;
+            }
+            if (current.arity() != 1) {
+                return false;
+            }
+            current = current.child(0);
+        }
+    }
 }
diff --git a/regression-test/suites/search/test_search_mow_support.groovy 
b/regression-test/suites/search/test_search_mow_support.groovy
new file mode 100644
index 00000000000..ce759ad99c9
--- /dev/null
+++ b/regression-test/suites/search/test_search_mow_support.groovy
@@ -0,0 +1,78 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+suite("test_search_mow_support") {
+    def tableName = "search_mow_support_tbl"
+    sql "DROP TABLE IF EXISTS ${tableName}"
+
+    sql """
+        CREATE TABLE ${tableName} (
+            k1 BIGINT,
+            title VARCHAR(256),
+            desc_text TEXT,
+            INDEX idx_title (title) USING INVERTED PROPERTIES("parser" = 
"english")
+        ) ENGINE=OLAP
+        UNIQUE KEY(k1)
+        DISTRIBUTED BY HASH(k1) BUCKETS 1
+        PROPERTIES (
+            "replication_allocation" = "tag.location.default: 1",
+            "enable_unique_key_merge_on_write" = "true"
+        )
+    """
+
+    // initial rows
+    sql """
+        INSERT INTO ${tableName} VALUES
+        (1, 'Rainbowman', 'first version'),
+        (2, 'Other Title', 'unrelated row'),
+        (3, 'Rainbowman Story', 'should not match exact search')
+    """
+
+    // update existing key to exercise delete bitmap handling
+    sql """
+        INSERT INTO ${tableName} VALUES
+        (1, 'Rainbowman', 'updated version'),
+        (4, 'rainbowman lowercase', 'case variants')
+    """
+
+    sql "SET enable_common_expr_pushdown = true"
+    sql "SET enable_common_expr_pushdown_for_inverted_index = true"
+
+    def exactCount = sql """
+        SELECT /*+SET_VAR(enable_inverted_index_query=true) */ count(*)
+        FROM ${tableName}
+        WHERE search('title:ALL("Rainbowman")')
+    """
+    assert exactCount[0][0] == 3
+
+    def exactRows = sql """
+        SELECT /*+SET_VAR(enable_inverted_index_query=true) */ k1, title
+        FROM ${tableName}
+        WHERE search('title:ALL("Rainbowman")')
+        ORDER BY k1
+    """
+    assert exactRows.size() == 3
+    assert exactRows[0][0] == 1
+    assert exactRows[0][1] == 'Rainbowman'
+
+    def anyCount = sql """
+        SELECT /*+SET_VAR(enable_inverted_index_query=true) */ count(*)
+        FROM ${tableName}
+        WHERE search('title:ANY("rainbowman")')
+    """
+    assert anyCount[0][0] == 3
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to