stalary commented on code in PR #16800:
URL: https://github.com/apache/doris/pull/16800#discussion_r1107884073


##########
fe/fe-core/src/main/java/org/apache/doris/external/elasticsearch/QueryBuilders.java:
##########
@@ -38,6 +59,238 @@
  */
 public final class QueryBuilders {
 
+    /**
+     * Generate dsl from compound expr.
+     **/
+    private static QueryBuilder toCompoundEsDsl(Expr expr, List<Expr> 
notPushDownList,
+            Map<String, String> fieldsContext, boolean likePushdown) {
+        CompoundPredicate compoundPredicate = (CompoundPredicate) expr;
+        switch (compoundPredicate.getOp()) {
+            case AND: {
+                QueryBuilder left = toEsDsl(compoundPredicate.getChild(0), 
notPushDownList, fieldsContext,
+                        likePushdown);
+                QueryBuilder right = toEsDsl(compoundPredicate.getChild(1), 
notPushDownList, fieldsContext,
+                        likePushdown);
+                if (left != null && right != null) {
+                    return QueryBuilders.boolQuery().must(left).must(right);
+                }
+                return null;
+            }
+            case OR: {
+                int beforeSize = notPushDownList.size();
+                QueryBuilder left = toEsDsl(compoundPredicate.getChild(0), 
notPushDownList, fieldsContext,
+                        likePushdown);
+                QueryBuilder right = toEsDsl(compoundPredicate.getChild(1), 
notPushDownList, fieldsContext,
+                        likePushdown);
+                int afterSize = notPushDownList.size();
+                if (left != null && right != null) {
+                    return 
QueryBuilders.boolQuery().should(left).should(right);
+                }
+                // One 'or' association cannot be pushed down and the other 
cannot be pushed down
+                if (afterSize > beforeSize) {
+                    if (left != null) {
+                        // add right if right don't pushdown
+                        notPushDownList.add(compoundPredicate.getChild(0));
+                    } else if (right != null) {
+                        // add left if left don't pushdown
+                        notPushDownList.add(compoundPredicate.getChild(1));
+                    }
+                }
+                return null;
+            }
+            case NOT: {
+                QueryBuilder child = toEsDsl(compoundPredicate.getChild(0), 
notPushDownList, fieldsContext,
+                        likePushdown);
+                if (child != null) {
+                    return QueryBuilders.boolQuery().mustNot(child);
+                }
+                return null;
+            }
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * Get the expr inside the cast.
+     **/
+    private static Expr exprWithoutCast(Expr expr) {
+        if (expr instanceof CastExpr) {
+            return exprWithoutCast(expr.getChild(0));
+        }
+        return expr;
+    }
+
+    public static QueryBuilder toEsDsl(Expr expr) {
+        return toEsDsl(expr, new ArrayList<>(), new HashMap<>(),
+                Boolean.parseBoolean(EsResource.LIKE_PUSH_DOWN_DEFAULT_VALUE));
+    }
+
+    private static QueryBuilder parseBinaryPredicate(Expr expr, TExprOpcode 
opCode, String column) {
+        Object value = toDorisLiteral(expr.getChild(1));
+        switch (opCode) {
+            case EQ:
+            case EQ_FOR_NULL:
+                return QueryBuilders.termQuery(column, value);
+            case NE:
+                return 
QueryBuilders.boolQuery().mustNot(QueryBuilders.termQuery(column, value));
+            case GE:
+                return QueryBuilders.rangeQuery(column).gte(value);
+            case GT:
+                return QueryBuilders.rangeQuery(column).gt(value);
+            case LE:
+                return QueryBuilders.rangeQuery(column).lte(value);
+            case LT:
+                return QueryBuilders.rangeQuery(column).lt(value);
+            default:
+                return null;
+        }
+    }
+
+    private static QueryBuilder parseIsNullPredicate(Expr expr, String column) 
{
+        IsNullPredicate isNullPredicate = (IsNullPredicate) expr;
+        if (isNullPredicate.isNotNull()) {
+            return QueryBuilders.existsQuery(column);
+        }
+        return 
QueryBuilders.boolQuery().mustNot(QueryBuilders.existsQuery(column));
+    }
+
+    private static QueryBuilder parseLikePredicate(Expr expr, String column) {
+        LikePredicate likePredicate = (LikePredicate) expr;
+        if (likePredicate.getOp().equals(Operator.LIKE)) {
+            char[] chars = 
likePredicate.getChild(1).getStringValue().toCharArray();
+            // example of translation :
+            //      abc_123  ===> abc?123
+            //      abc%ykz  ===> abc*123
+            //      %abc123  ===> *abc123
+            //      _abc123  ===> ?abc123
+            //      \\_abc1  ===> \\_abc1
+            //      abc\\_123 ===> abc\\_123
+            //      abc\\%123 ===> abc\\%123
+            // NOTE. user must input sql like 'abc\\_123' or 'abc\\%ykz'
+            for (int i = 0; i < chars.length; i++) {
+                if (chars[i] == '_' || chars[i] == '%') {
+                    if (i == 0) {
+                        chars[i] = (chars[i] == '_') ? '?' : '*';
+                    } else if (chars[i - 1] != '\\') {
+                        chars[i] = (chars[i] == '_') ? '?' : '*';
+                    }
+                }
+            }
+            return QueryBuilders.wildcardQuery(column, new String(chars));
+        } else {
+            return QueryBuilders.wildcardQuery(column, 
likePredicate.getChild(1).getStringValue());
+        }
+    }
+
+    private static QueryBuilder parseInPredicate(Expr expr, String column) {
+        InPredicate inPredicate = (InPredicate) expr;
+        List<Object> values = 
inPredicate.getListChildren().stream().map(QueryBuilders::toDorisLiteral)
+                .collect(Collectors.toList());
+        if (inPredicate.isNotIn()) {
+            return 
QueryBuilders.boolQuery().mustNot(QueryBuilders.termsQuery(column, values));
+        }
+        return QueryBuilders.termsQuery(column, values);
+    }
+
+    private static QueryBuilder parseFunctionCallExpr(Expr expr) {
+        // esquery(k1, '{
+        //        "match_phrase": {
+        //           "k1": "doris on es"
+        //        }
+        //    }');
+        // The first child k1 compatible with expr syntax
+        FunctionCallExpr functionCallExpr = (FunctionCallExpr) expr;
+        if ("esquery".equals(functionCallExpr.getFnName().getFunction())) {
+            String stringValue = functionCallExpr.getChild(1).getStringValue();
+            return new QueryBuilders.EsQueryBuilder(stringValue);
+        }
+        return null;
+    }
+
+    /**
+     * Doris expr to es dsl.
+     **/
+    public static QueryBuilder toEsDsl(Expr expr, List<Expr> notPushDownList, 
Map<String, String> fieldsContext,
+            boolean likePushDown) {
+        if (expr == null) {
+            return null;
+        }
+        // CompoundPredicate, `between` also converted to CompoundPredicate.
+        if (expr instanceof CompoundPredicate) {
+            return toCompoundEsDsl(expr, notPushDownList, fieldsContext, 
likePushDown);
+        }
+        TExprOpcode opCode = expr.getOpcode();
+        String column;
+        Expr leftExpr = expr.getChild(0);
+        // Type transformed cast can not pushdown
+        if (leftExpr instanceof CastExpr) {
+            Expr withoutCastExpr = exprWithoutCast(leftExpr);
+            // pushdown col(float) >= 3
+            if (withoutCastExpr.getType().equals(leftExpr.getType()) || 
(withoutCastExpr.getType().isFloatingPointType()
+                    && leftExpr.getType().isFloatingPointType())) {
+                column = ((SlotRef) withoutCastExpr).getColumnName();
+            } else {
+                notPushDownList.add(expr);
+                return null;
+            }
+        } else if (leftExpr instanceof SlotRef) {
+            column = ((SlotRef) leftExpr).getColumnName();
+        } else {
+            notPushDownList.add(expr);
+            return null;
+        }
+        // Replace col with col.keyword if mapping exist.
+        column = fieldsContext.getOrDefault(column, column);
+        if (expr instanceof BinaryPredicate) {
+            return parseBinaryPredicate(expr, opCode, column);
+        }
+        if (expr instanceof IsNullPredicate) {
+            return parseIsNullPredicate(expr, column);
+        }
+        if (expr instanceof LikePredicate) {
+            if (!likePushDown) {

Review Comment:
   Judge whether push down like



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to