diff --git a/src/parser/parser.yy b/src/parser/parser.yy
index ad0d856f729db5b5988a0f1f2b7bc2451ec877df..985199ea6569f3f09eb12c2f136645f452bd36a1 100644
--- a/src/parser/parser.yy
+++ b/src/parser/parser.yy
@@ -23,6 +23,7 @@
 #include "common/expression/VariableExpression.h"
 #include "common/expression/CaseExpression.h"
 #include "common/expression/TextSearchExpression.h"
+#include "common/expression/PredicateExpression.h"
 #include "common/expression/ListComprehensionExpression.h"
 #include "common/expression/AggregateExpression.h"
 
@@ -182,6 +183,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL;
 %token KW_LISTENER KW_ELASTICSEARCH
 %token KW_AUTO KW_FUZZY KW_PREFIX KW_REGEXP KW_WILDCARD
 %token KW_TEXT KW_SEARCH KW_CLIENTS KW_SIGN KW_SERVICE KW_TEXT_SEARCH
+%token KW_ANY KW_SINGLE KW_NONE
 
 /* symbols */
 %token L_PAREN R_PAREN L_BRACKET R_BRACKET L_BRACE R_BRACE COMMA
@@ -195,7 +197,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL;
 %token <doubleval> DOUBLE
 %token <strval> STRING VARIABLE LABEL IPV4
 
-%type <strval> name_label unreserved_keyword agg_function
+%type <strval> name_label unreserved_keyword agg_function predicate_name
 %type <expr> expression
 %type <expr> property_expression
 %type <expr> vertex_prop_expression
@@ -215,6 +217,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL;
 %type <expr> subscript_expression
 %type <expr> attribute_expression
 %type <expr> case_expression
+%type <expr> predicate_expression
 %type <expr> list_comprehension_expression
 %type <expr> compound_expression
 %type <expr> aggregate_expression
@@ -453,6 +456,9 @@ unreserved_keyword
     | KW_META               { $$ = new std::string("meta"); }
     | KW_STORAGE            { $$ = new std::string("storage"); }
     | KW_ALL                { $$ = new std::string("all"); }
+    | KW_ANY                { $$ = new std::string("any"); }
+    | KW_SINGLE             { $$ = new std::string("single"); }
+    | KW_NONE               { $$ = new std::string("none"); }
     | KW_SHORTEST           { $$ = new std::string("shortest"); }
     | KW_NOLOOP             { $$ = new std::string("noloop"); }
     | KW_COUNT_DISTINCT     { $$ = new std::string("count_distinct"); }
@@ -627,6 +633,9 @@ expression
     | case_expression {
         $$ = $1;
     }
+    | predicate_expression {
+        $$ = $1;
+    }
     | list_comprehension_expression {
         $$ = $1;
     }
@@ -749,6 +758,24 @@ when_then_list
     }
     ;
 
+predicate_name
+    : KW_ALL                { $$ = new std::string("all"); }
+    | KW_ANY                { $$ = new std::string("any"); }
+    | KW_SINGLE             { $$ = new std::string("single"); }
+    | KW_NONE               { $$ = new std::string("none"); }
+    ;
+
+predicate_expression
+    : predicate_name L_PAREN expression KW_IN expression KW_WHERE expression R_PAREN {
+        if ($3->kind() != Expression::Kind::kLabel) {
+            throw nebula::GraphParser::syntax_error(@3, "The loop variable must be a label in predicate functions");
+        }
+        auto &innerVar = *(static_cast<const LabelExpression *>($3)->name());
+        auto *expr = new PredicateExpression($1, new std::string(innerVar), $5, $7);
+        nebula::graph::ParserUtil::rewritePred(qctx, expr, innerVar);
+        $$ = expr;
+        delete $3;
+    }
 
 list_comprehension_expression
     : L_BRACKET expression KW_IN expression KW_WHERE expression R_BRACKET {
diff --git a/src/parser/scanner.lex b/src/parser/scanner.lex
index bb9a31d9eb9cc7cffaac97c132ee07779602a386..d3e1696c3da25700b2761f8dbd9a4cd3b9eae578 100644
--- a/src/parser/scanner.lex
+++ b/src/parser/scanner.lex
@@ -166,6 +166,9 @@ IP_OCTET                    ([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])
 "COLLATION"                 { return TokenType::KW_COLLATION; }
 "ATOMIC_EDGE"               { return TokenType::KW_ATOMIC_EDGE; }
 "ALL"                       { return TokenType::KW_ALL; }
+"ANY"                       { return TokenType::KW_ANY; }
+"SINGLE"                    { return TokenType::KW_SINGLE; }
+"NONE"                      { return TokenType::KW_NONE; }
 "LEADER"                    { return TokenType::KW_LEADER; }
 "UUID"                      { return TokenType::KW_UUID; }
 "DATA"                      { return TokenType::KW_DATA; }
diff --git a/src/parser/test/ScannerTest.cpp b/src/parser/test/ScannerTest.cpp
index 710e18209705a1c94741157bf45e28f542746253..917c7b5e50e0b26ccd98b2b0cb322679eaa37932 100644
--- a/src/parser/test/ScannerTest.cpp
+++ b/src/parser/test/ScannerTest.cpp
@@ -482,6 +482,12 @@ TEST(Scanner, Basic) {
         CHECK_SEMANTIC_TYPE("STATS", TokenType::KW_STATS),
         CHECK_SEMANTIC_TYPE("Stats", TokenType::KW_STATS),
         CHECK_SEMANTIC_TYPE("stats", TokenType::KW_STATS),
+        CHECK_SEMANTIC_TYPE("ANY", TokenType::KW_ANY),
+        CHECK_SEMANTIC_TYPE("any", TokenType::KW_ANY),
+        CHECK_SEMANTIC_TYPE("SINGLE", TokenType::KW_SINGLE),
+        CHECK_SEMANTIC_TYPE("single", TokenType::KW_SINGLE),
+        CHECK_SEMANTIC_TYPE("NONE", TokenType::KW_NONE),
+        CHECK_SEMANTIC_TYPE("none", TokenType::KW_NONE),
         CHECK_SEMANTIC_TYPE("CASE", TokenType::KW_CASE),
         CHECK_SEMANTIC_TYPE("case", TokenType::KW_CASE),
         CHECK_SEMANTIC_TYPE("WHEN", TokenType::KW_WHEN),
@@ -521,8 +527,8 @@ TEST(Scanner, Basic) {
         CHECK_SEMANTIC_VALUE("0x7FFFFFFFFFFFFFFF", TokenType::INTEGER, 0x7FFFFFFFFFFFFFFFL),
         CHECK_SEMANTIC_VALUE("0x007FFFFFFFFFFFFFFF", TokenType::INTEGER, 0x007FFFFFFFFFFFFFFFL),
         CHECK_SEMANTIC_VALUE("9223372036854775807", TokenType::INTEGER, 9223372036854775807L),
-        CHECK_SEMANTIC_VALUE("00777777777777777777777", TokenType::INTEGER,
-                              00777777777777777777777),
+        CHECK_SEMANTIC_VALUE(
+            "00777777777777777777777", TokenType::INTEGER, 00777777777777777777777),
         CHECK_LEXICAL_ERROR("9223372036854775809"),
         CHECK_LEXICAL_ERROR("0x8000000000000001"),
         CHECK_LEXICAL_ERROR("001000000000000000000001"),
@@ -558,7 +564,6 @@ TEST(Scanner, Basic) {
         CHECK_SEMANTIC_VALUE("\"\\\\\\\\110 \"", TokenType::STRING, "\\\\110 "),
         CHECK_SEMANTIC_VALUE("\"\\\\\\\\\110 \"", TokenType::STRING, "\\\\H "),
 
-
         CHECK_SEMANTIC_VALUE("\"宸辨墍涓嶆锛屽嬁鏂戒簬浜篭"", TokenType::STRING, "宸辨墍涓嶆锛屽嬁鏂戒簬浜�"),
     };
 #undef CHECK_SEMANTIC_TYPE
diff --git a/src/util/ParserUtil.h b/src/util/ParserUtil.h
index 7c2c968b09b58745ec7c38634ebbd6dbf895378c..2301876315fb5841a3def45f5796c91d70b228f5 100644
--- a/src/util/ParserUtil.h
+++ b/src/util/ParserUtil.h
@@ -81,6 +81,50 @@ public:
             lc->setMapping(newMapping);
         }
     }
+
+    static void rewritePred(QueryContext *qctx,
+                            PredicateExpression *pred,
+                            const std::string &oldVarName) {
+        const auto &newVarName = qctx->vctx()->anonVarGen()->getVar();
+        qctx->ectx()->setValue(newVarName, Value());
+        auto rewriter = [&oldVarName, &newVarName](const Expression *expr) {
+            Expression *ret = nullptr;
+            if (expr->kind() == Expression::Kind::kLabel) {
+                auto *label = static_cast<const LabelExpression *>(expr);
+                if (*label->name() == oldVarName) {
+                    ret = new VariableExpression(new std::string(newVarName));
+                } else {
+                    ret = label->clone().release();
+                }
+            } else {
+                DCHECK(expr->kind() == Expression::Kind::kLabelAttribute);
+                auto *la = static_cast<const LabelAttributeExpression *>(expr);
+                if (*la->left()->name() == oldVarName) {
+                    const auto &value = la->right()->value();
+                    ret =
+                        new AttributeExpression(new VariableExpression(new std::string(newVarName)),
+                                                new ConstantExpression(value));
+                } else {
+                    ret = la->clone().release();
+                }
+            }
+            return ret;
+        };
+
+        RewriteMatchLabelVisitor visitor(rewriter);
+
+        pred->setOriginString(new std::string(pred->makeString()));
+        pred->setInnerVar(new std::string(newVarName));
+        Expression *filter = pred->filter();
+        Expression *newFilter = nullptr;
+        if (isLabel(filter)) {
+            newFilter = rewriter(filter);
+        } else {
+            newFilter = filter->clone().release();
+            newFilter->accept(&visitor);
+        }
+        pred->setFilter(newFilter);
+    }
 };
 
 }   // namespace graph
diff --git a/src/visitor/CollectAllExprsVisitor.cpp b/src/visitor/CollectAllExprsVisitor.cpp
index e1599c1e064b59f5f08886ea9f548be7becd3d37..172f37a978c089bcde2b6fa5f162ad35b68e541c 100644
--- a/src/visitor/CollectAllExprsVisitor.cpp
+++ b/src/visitor/CollectAllExprsVisitor.cpp
@@ -157,6 +157,12 @@ void CollectAllExprsVisitor::visit(ListComprehensionExpression* expr) {
     }
 }
 
+void CollectAllExprsVisitor::visit(PredicateExpression *expr) {
+    collectExpr(expr);
+    expr->collection()->accept(this);
+    expr->filter()->accept(this);
+}
+
 void CollectAllExprsVisitor::visitBinaryExpr(BinaryExpression *expr) {
     collectExpr(expr);
     expr->left()->accept(this);
diff --git a/src/visitor/CollectAllExprsVisitor.h b/src/visitor/CollectAllExprsVisitor.h
index fa6b16c25490bda6b9386f6592cc0badf0d3c264..d421a9cf0acbbdbf766f7258ed1dd8f9bd2a4221 100644
--- a/src/visitor/CollectAllExprsVisitor.h
+++ b/src/visitor/CollectAllExprsVisitor.h
@@ -56,6 +56,7 @@ private:
     void visit(VertexExpression* expr) override;
     void visit(EdgeExpression* expr) override;
     void visit(CaseExpression* expr) override;
+    void visit(PredicateExpression* expr) override;
     void visit(ListComprehensionExpression* expr) override;
 
     void visit(ColumnExpression* expr) override;
diff --git a/src/visitor/DeduceTypeVisitor.cpp b/src/visitor/DeduceTypeVisitor.cpp
index 1bc42b21e942f86acdb26ed2620ac992e47b2ee1..2e77d4716591ed934378f3eff0f4aa6b1593be85 100644
--- a/src/visitor/DeduceTypeVisitor.cpp
+++ b/src/visitor/DeduceTypeVisitor.cpp
@@ -601,6 +601,25 @@ void DeduceTypeVisitor::visit(CaseExpression *expr) {
     type_ = Value::Type::__EMPTY__;
 }
 
+void DeduceTypeVisitor::visit(PredicateExpression *expr) {
+    expr->collection()->accept(this);
+    if (!ok()) return;
+    if (type_ == Value::Type::NULLVALUE || type_ == Value::Type::__EMPTY__) {
+        return;
+    }
+    if (type_ != Value::Type::LIST) {
+        std::stringstream ss;
+        ss << "`" << expr->toString().c_str()
+           << "': Invalid colletion type, expected type of LIST, but was:" << type_;
+        status_ = Status::SemanticError(ss.str());
+        return;
+    }
+    expr->filter()->accept(this);
+    if (!ok()) return;
+
+    type_ = Value::Type::BOOL;
+}
+
 void DeduceTypeVisitor::visit(ListComprehensionExpression *expr) {
     expr->collection()->accept(this);
     if (!ok()) {
diff --git a/src/visitor/DeduceTypeVisitor.h b/src/visitor/DeduceTypeVisitor.h
index fe3e0a9a34bac539cf4014af5b8e104b9fe6d488..a21de5c21a042d3553b3560981757f721fa92763 100644
--- a/src/visitor/DeduceTypeVisitor.h
+++ b/src/visitor/DeduceTypeVisitor.h
@@ -84,6 +84,8 @@ private:
     void visit(PathBuildExpression *expr) override;
     // column expression
     void visit(ColumnExpression * expr) override;
+    // predicate expression
+    void visit(PredicateExpression *expr) override;
     // list comprehension expression
     void visit(ListComprehensionExpression *) override;
 
diff --git a/src/visitor/ExprVisitorImpl.cpp b/src/visitor/ExprVisitorImpl.cpp
index 9f549e99fdfd71eceedd08fec2f12f6503ebd668..0835f769b607bb3fa168611c1dba7a7def7453cf 100644
--- a/src/visitor/ExprVisitorImpl.cpp
+++ b/src/visitor/ExprVisitorImpl.cpp
@@ -145,6 +145,14 @@ void ExprVisitorImpl::visit(PathBuildExpression *expr) {
     }
 }
 
+void ExprVisitorImpl::visit(PredicateExpression *expr) {
+    DCHECK(ok());
+    expr->collection()->accept(this);
+    if (!ok()) return;
+    expr->filter()->accept(this);
+    if (!ok()) return;
+}
+
 void ExprVisitorImpl::visit(ListComprehensionExpression *expr) {
     DCHECK(ok());
     expr->collection()->accept(this);
diff --git a/src/visitor/ExprVisitorImpl.h b/src/visitor/ExprVisitorImpl.h
index 2f24b5d7aad75363834b5a5ebfbb064a18629c79..9660a859ec01056ff1c75ac7994fab57fc503bab 100644
--- a/src/visitor/ExprVisitorImpl.h
+++ b/src/visitor/ExprVisitorImpl.h
@@ -34,6 +34,8 @@ public:
     void visit(CaseExpression *expr) override;
     // path build expression
     void visit(PathBuildExpression *expr) override;
+    // predicate expression
+    void visit(PredicateExpression *expr) override;
     // list comprehension expression
     void visit(ListComprehensionExpression *expr) override;
 
diff --git a/src/visitor/FindAnyExprVisitor.cpp b/src/visitor/FindAnyExprVisitor.cpp
index 6b85c5d618bbbfef7ba807cfa98c001d525410a9..9286e09989d90129fbe786b75fbd3b3c32a09340 100644
--- a/src/visitor/FindAnyExprVisitor.cpp
+++ b/src/visitor/FindAnyExprVisitor.cpp
@@ -87,6 +87,15 @@ void FindAnyExprVisitor::visit(CaseExpression *expr) {
     }
 }
 
+void FindAnyExprVisitor::visit(PredicateExpression *expr) {
+    findExpr(expr);
+    if (found_) return;
+    expr->collection()->accept(this);
+    if (found_) return;
+    expr->filter()->accept(this);
+    if (found_) return;
+}
+
 void FindAnyExprVisitor::visit(ConstantExpression *expr) {
     findExpr(expr);
 }
diff --git a/src/visitor/FindAnyExprVisitor.h b/src/visitor/FindAnyExprVisitor.h
index fb53103b03cabb4f91e2d81476ffec89dbacf8b7..fafb7b3ad5cd066fdbf03818b704ffa87b47097a 100644
--- a/src/visitor/FindAnyExprVisitor.h
+++ b/src/visitor/FindAnyExprVisitor.h
@@ -39,6 +39,7 @@ private:
     void visit(SetExpression* expr) override;
     void visit(MapExpression* expr) override;
     void visit(CaseExpression* expr) override;
+    void visit(PredicateExpression* expr) override;
 
     void visit(ConstantExpression* expr) override;
     void visit(EdgePropertyExpression* expr) override;
diff --git a/src/visitor/FoldConstantExprVisitor.cpp b/src/visitor/FoldConstantExprVisitor.cpp
index a8abe6ac06ea18d434b023b10b5c8387fca5408f..7949b31860f6b15b9c6d11c374d3aab2f57655a8 100644
--- a/src/visitor/FoldConstantExprVisitor.cpp
+++ b/src/visitor/FoldConstantExprVisitor.cpp
@@ -381,5 +381,26 @@ void FoldConstantExprVisitor::visit(ListComprehensionExpression *expr) {
     canBeFolded_ = canBeFolded;
 }
 
+void FoldConstantExprVisitor::visit(PredicateExpression *expr) {
+    bool canBeFolded = true;
+    if (!isConstant(expr->collection())) {
+        expr->collection()->accept(this);
+        if (canBeFolded_) {
+            expr->setCollection(fold(expr->collection()));
+        } else {
+            canBeFolded = false;
+        }
+    }
+    if (!isConstant(expr->filter())) {
+        expr->filter()->accept(this);
+        if (canBeFolded_) {
+            expr->setFilter(fold(expr->filter()));
+        } else {
+            canBeFolded = false;
+        }
+    }
+    canBeFolded_ = canBeFolded;
+}
+
 }   // namespace graph
 }   // namespace nebula
diff --git a/src/visitor/FoldConstantExprVisitor.h b/src/visitor/FoldConstantExprVisitor.h
index 18995604ebcfb659f67c269155595cd128e996a7..532c864ef99c68d15a21594324e3035036fa0789 100644
--- a/src/visitor/FoldConstantExprVisitor.h
+++ b/src/visitor/FoldConstantExprVisitor.h
@@ -64,6 +64,8 @@ public:
     void visit(PathBuildExpression *expr) override;
     // column expression
     void visit(ColumnExpression *expr) override;
+    // predicate expression
+    void visit(PredicateExpression *expr) override;
     // list comprehension expression
     void visit(ListComprehensionExpression *) override;
 
diff --git a/src/visitor/RewriteInputPropVisitor.cpp b/src/visitor/RewriteInputPropVisitor.cpp
index b93635ca7dee09e790417bc523d27aba6d054c56..db4bab96f96922752a0378b7c7fa637e8052bf40 100644
--- a/src/visitor/RewriteInputPropVisitor.cpp
+++ b/src/visitor/RewriteInputPropVisitor.cpp
@@ -271,5 +271,17 @@ void RewriteInputPropVisitor::visit(PathBuildExpression* expr) {
         }
     }
 }
+
+void RewriteInputPropVisitor::visit(PredicateExpression* expr) {
+    expr->collection()->accept(this);
+    if (ok()) {
+        expr->setCollection(result_.release());
+    }
+    expr->filter()->accept(this);
+    if (ok()) {
+        expr->setFilter(result_.release());
+    }
+}
+
 }   // namespace graph
 }   // namespace nebula
diff --git a/src/visitor/RewriteInputPropVisitor.h b/src/visitor/RewriteInputPropVisitor.h
index a15a94797ebf9fabdedf1733fc83e2c8924a0513..8f649c8d930d59d1f958ecf8bbf7673258e5d520 100644
--- a/src/visitor/RewriteInputPropVisitor.h
+++ b/src/visitor/RewriteInputPropVisitor.h
@@ -76,6 +76,8 @@ private:
     void visit(PathBuildExpression *expr) override;
     // column expression
     void visit(ColumnExpression* expr) override;
+    // predicate expression
+    void visit(PredicateExpression *) override;
     // list comprehension expression
     void visit(ListComprehensionExpression *) override;
 
diff --git a/src/visitor/RewriteLabelAttrVisitor.cpp b/src/visitor/RewriteLabelAttrVisitor.cpp
index e44cf2c290f79bf37ec3a3d5fa1017806fa93045..5719d67869f5f59520c706b45ae043d11babcd46 100644
--- a/src/visitor/RewriteLabelAttrVisitor.cpp
+++ b/src/visitor/RewriteLabelAttrVisitor.cpp
@@ -145,6 +145,21 @@ void RewriteLabelAttrVisitor::visit(ListComprehensionExpression* expr) {
     }
 }
 
+void RewriteLabelAttrVisitor::visit(PredicateExpression* expr) {
+    if (isLabelAttrExpr(expr->collection())) {
+        auto newExpr = static_cast<LabelAttributeExpression*>(expr->collection());
+        expr->setCollection(createExpr(newExpr));
+    } else {
+        expr->collection()->accept(this);
+    }
+    if (isLabelAttrExpr(expr->filter())) {
+        auto newExpr = static_cast<LabelAttributeExpression*>(expr->filter());
+        expr->setFilter(createExpr(newExpr));
+    } else {
+        expr->filter()->accept(this);
+    }
+}
+
 void RewriteLabelAttrVisitor::visitBinaryExpr(BinaryExpression* expr) {
     if (isLabelAttrExpr(expr->left())) {
         auto left = static_cast<const LabelAttributeExpression*>(expr->left());
diff --git a/src/visitor/RewriteLabelAttrVisitor.h b/src/visitor/RewriteLabelAttrVisitor.h
index 2ca5030348130bf0725ec242a27af7d7863afbbd..6ac46e6dd5d78b3e6d3d14bbfc15367429b87f4a 100644
--- a/src/visitor/RewriteLabelAttrVisitor.h
+++ b/src/visitor/RewriteLabelAttrVisitor.h
@@ -33,6 +33,7 @@ private:
     void visit(SetExpression *expr) override;
     void visit(MapExpression *expr) override;
     void visit(CaseExpression *) override;
+    void visit(PredicateExpression *) override;
     void visit(ListComprehensionExpression *) override;
     void visit(ConstantExpression *) override {}
     void visit(LabelExpression *) override {}
diff --git a/src/visitor/RewriteMatchLabelVisitor.cpp b/src/visitor/RewriteMatchLabelVisitor.cpp
index 3782f177961b7da3bd025504c95c490a7f08e9d9..a0d24c1867a7e0aa8fda2065de75f23c6dc634a6 100644
--- a/src/visitor/RewriteMatchLabelVisitor.cpp
+++ b/src/visitor/RewriteMatchLabelVisitor.cpp
@@ -143,6 +143,19 @@ void RewriteMatchLabelVisitor::visit(ListComprehensionExpression *expr) {
     }
 }
 
+void RewriteMatchLabelVisitor::visit(PredicateExpression *expr) {
+    if (isLabel(expr->collection())) {
+        expr->setCollection(rewriter_(expr));
+    } else {
+        expr->collection()->accept(this);
+    }
+    if (isLabel(expr->filter())) {
+        expr->setFilter(rewriter_(expr));
+    } else {
+        expr->filter()->accept(this);
+    }
+}
+
 void RewriteMatchLabelVisitor::visitBinaryExpr(BinaryExpression *expr) {
     if (isLabel(expr->left())) {
         expr->setLeft(rewriter_(expr->left()));
diff --git a/src/visitor/RewriteMatchLabelVisitor.h b/src/visitor/RewriteMatchLabelVisitor.h
index 1775c05b9f7b8428a8862e7dd6c432fec00a59e6..0b57d26a9b834e1b45c78c2f1f8201fe66dc5644 100644
--- a/src/visitor/RewriteMatchLabelVisitor.h
+++ b/src/visitor/RewriteMatchLabelVisitor.h
@@ -60,6 +60,7 @@ private:
     void visit(VertexExpression*) override {}
     void visit(EdgeExpression*) override {}
     void visit(ColumnExpression*) override {}
+    void visit(PredicateExpression *) override;
     void visit(ListComprehensionExpression*) override;
 
     void visitBinaryExpr(BinaryExpression *) override;
diff --git a/src/visitor/RewriteSymExprVisitor.cpp b/src/visitor/RewriteSymExprVisitor.cpp
index 892c1fd5908f381db5ae8029b0b925383f6cc4f3..345c62fb51b05401c5c8bebcd83a6ad7e84f6bee 100644
--- a/src/visitor/RewriteSymExprVisitor.cpp
+++ b/src/visitor/RewriteSymExprVisitor.cpp
@@ -287,5 +287,16 @@ void RewriteSymExprVisitor::visit(ListComprehensionExpression *expr) {
     }
 }
 
+void RewriteSymExprVisitor::visit(PredicateExpression *expr) {
+    expr->collection()->accept(this);
+    if (expr_) {
+        expr->setCollection(expr_.release());
+    }
+    expr->filter()->accept(this);
+    if (expr_) {
+        expr->setFilter(expr_.release());
+    }
+}
+
 }   // namespace graph
 }   // namespace nebula
diff --git a/src/visitor/RewriteSymExprVisitor.h b/src/visitor/RewriteSymExprVisitor.h
index 6e14c56fa589c9da5f7f147dcc7173c04868ef97..76c2ef73f0aee9083a1d9b9a38f3bae9200808e0 100644
--- a/src/visitor/RewriteSymExprVisitor.h
+++ b/src/visitor/RewriteSymExprVisitor.h
@@ -71,6 +71,8 @@ public:
     void visit(PathBuildExpression *expr) override;
     // column expression
     void visit(ColumnExpression *expr) override;
+    // predicate expression
+    void visit(PredicateExpression *expr) override;
     // list comprehension expression
     void visit(ListComprehensionExpression *expr) override;
 
diff --git a/tests/tck/features/expression/predicate.feature b/tests/tck/features/expression/predicate.feature
new file mode 100644
index 0000000000000000000000000000000000000000..836a511679c7deb675eef31a889ff56d6a49f4f0
--- /dev/null
+++ b/tests/tck/features/expression/predicate.feature
@@ -0,0 +1,76 @@
+# Copyright (c) 2020 vesoft inc. All rights reserved.
+#
+# This source code is licensed under Apache 2.0 License,
+# attached with Common Clause Condition 1.0, found in the LICENSES directory.
+@jie
+Feature: Predicate
+
+  Scenario: yield a predicate
+    Given a graph with space named "nba"
+    When executing query:
+      """
+      YIELD all(n IN range(1, 5) WHERE n > 2) AS r
+      """
+    Then the result should be, in any order:
+      | r     |
+      | False |
+    When executing query:
+      """
+      YIELD any(n IN [1, 2, 3, 4, 5] WHERE n > 2) AS r
+      """
+    Then the result should be, in any order:
+      | r    |
+      | True |
+    When executing query:
+      """
+      YIELD single(n IN range(1, 5) WHERE n == 3) AS r
+      """
+    Then the result should be, in any order:
+      | r    |
+      | True |
+    When executing query:
+      """
+      YIELD none(n IN range(1, 3) WHERE n == 0) AS r
+      """
+    Then the result should be, in any order:
+      | r    |
+      | True |
+
+  Scenario: use a predicate in GO
+    Given a graph with space named "nba"
+    When executing query:
+      """
+      GO FROM "Tony Parker" OVER like
+      WHERE any(x IN [5,  10] WHERE like.likeness + $$.player.age + x > 100)
+      YIELD like._dst AS id, like.likeness AS likeness
+      """
+    Then the result should be, in any order:
+      | id                  | likeness |
+      | "LaMarcus Aldridge" | 90       |
+      | "Manu Ginobili"     | 95       |
+      | "Tim Duncan"        | 95       |
+
+  Scenario: use a predicate in MATCH
+    Given a graph with space named "nba"
+    When executing query:
+      """
+      MATCH p = (n:player{name:"LeBron James"})<-[:like]-(m)
+      RETURN nodes(p)[0].name AS n1, nodes(p)[1].name AS n2,
+      all(n IN nodes(p) WHERE n.name NOT STARTS WITH "D") AS b
+      """
+    Then the result should be, in any order:
+      | n1             | n2                | b     |
+      | "LeBron James" | "Carmelo Anthony" | True  |
+      | "LeBron James" | "Chris Paul"      | True  |
+      | "LeBron James" | "Danny Green"     | False |
+      | "LeBron James" | "Dejounte Murray" | False |
+      | "LeBron James" | "Dwyane Wade"     | False |
+      | "LeBron James" | "Kyrie Irving"    | True  |
+    When executing query:
+      """
+      MATCH p = (n:player{name:"LeBron James"})-[:like]->(m)
+      RETURN single(n IN nodes(p) WHERE n.age > 40) as b
+      """
+    Then the result should be, in any order:
+      | b    |
+      | True |