Repository: alibaba/GraphScope (language: python)

Issue:
Support extract interval from temporal types in GIE
**Is your feature request related to a problem? Please describe.**

Support extract Year/Month/Day/Hour/Minute/Second etc. from a Date/Time/DateTime type in GIE.


Discussion / hints:

Fix patch:
diff --git a/docs/interactive_engine/neo4j/supported_cypher.md b/docs/interactive_engine/neo4j/supported_cypher.md
index 21261ad9cb65..fc502a149d54 100644
--- a/docs/interactive_engine/neo4j/supported_cypher.md
+++ b/docs/interactive_engine/neo4j/supported_cypher.md
@@ -100,6 +100,7 @@ Note that some Aggregator operators, such as `max()`, we listed here are impleme
 | List | Fold expressions into a single list | [] | [] | <input type="checkbox" disabled checked /> |   |
 | Labels | Get label name of a vertex type | labels() | labels() | <input type="checkbox" disabled checked /> |   |
 | Type | Get label name of an edge type | type() | type() | <input type="checkbox" disabled checked /> |   |
+| Extract | Get interval value from a temporal type | \<temporal\>.\<interval\> | \<temporal\>.\<interval\> | <input type="checkbox" disabled checked /> |   |
 
 
 
diff --git a/flex/codegen/src/graph_types.h b/flex/codegen/src/graph_types.h
index 7f5a44525b34..60fbd1820df3 100644
--- a/flex/codegen/src/graph_types.h
+++ b/flex/codegen/src/graph_types.h
@@ -40,9 +40,9 @@ enum class DataType {
   kVertexId = 8,
   kEdgeId = 9,
   kLength = 10,
-  kTime = 11,
-  kDate = 12,
-  kDateTime = 13,
+  kDate = 11,
+  kTime = 12,
+  kTimeStamp = 13,
   kLabelId = 14
 };
 
@@ -78,8 +78,12 @@ static codegen::DataType common_data_type_pb_2_data_type(
     return codegen::DataType::kInt32Array;
   case common::DataType::BOOLEAN:
     return codegen::DataType::kBoolean;
-  case common::DataType::DATE:
+  case common::DataType::DATE32:
     return codegen::DataType::kDate;
+  case common::DataType::TIME32:
+    return codegen::DataType::kTime;
+  case common::DataType::TIMESTAMP:
+    return codegen::DataType::kTimeStamp;
   default:
     // LOG(FATAL) << "unknown data type";
     throw std::runtime_error(
@@ -106,11 +110,10 @@ static std::string single_common_data_type_pb_2_str(
     return "std::vector<int64_t>";
   case common::DataType::INT32_ARRAY:
     return "std::vector<int32_t>";
-  case common::DataType::DATE:
+  case common::DataType::DATE32:
     return "Date";
+    // TODO: support time32 and timestamp
   default:
-    // LOG(FATAL) << "unknown data type";
-    // return "";
     throw std::runtime_error(
         "unknown data type when convert common data type to string:" +
         std::to_string(static_cast<int>(data_type)));
diff --git a/flex/codegen/src/hqps/hqps_expr_builder.h b/flex/codegen/src/hqps/hqps_expr_builder.h
index ea1570cd2b5b..b8ad4e408bed 100644
--- a/flex/codegen/src/hqps/hqps_expr_builder.h
+++ b/flex/codegen/src/hqps/hqps_expr_builder.h
@@ -111,7 +111,7 @@ static std::string logical_to_str(const common::Logical& logical) {
   case common::Logical::WITHIN:
     return "< WithIn > ";
   case common::Logical::ISNULL:
-    return "IsNull";
+    return "NONE ==";  // Convert
   default:
     throw std::runtime_error("unknown logical");
   }
@@ -284,10 +284,21 @@ class ExprBuilder {
         }
         if (j == size) {
           LOG(WARNING) << "no right brace found" << j << "size: " << size;
-          // just add true, since the current expresion has no other expr_oprs
+          // just add true, since the current expresion has no other expr_ops
           AddExprOpr(std::string("true"));
           i = j;
         }
+      } else if (expr.has_extract()) {
+        // special case for extract
+        auto extract = expr.extract();
+        if (i + 1 >= size) {
+          throw std::runtime_error("extract must have a following var/expr");
+        } else if (expr_ops[i + 1].item_case() != common::ExprOpr::kVar) {
+          throw std::runtime_error("extract must have a following var/expr");
+        } else {
+          AddExtractOpr(extract, expr_ops[i + 1]);
+          i += 2;
+        }
       } else {
         AddExprOpr(expr_ops[i]);
         ++i;
@@ -398,28 +409,8 @@ class ExprBuilder {
     }
 
     case common::ExprOpr::kExtract: {
-      auto extract = opr.extract();
-      auto interval = extract.interval();
-      auto data_time = extract.data_time();
-      CHECK(data_time.operators_size() == 1)
-          << "Currently only support one var in extract";
-      auto expr_opr = data_time.operators(0);
-      CHECK(expr_opr.item_case() == common::ExprOpr::kVar)
-          << "Currently only support var in extract";
-      auto expr_var = expr_opr.var();
-      auto param_const = variable_to_param_const(expr_var, ctx_);
-      make_var_name_unique(param_const);
-      func_call_vars_.push_back(param_const);
-
-      boost::format formater(EXTRACT_TEMPLATE_STR);
-      formater % interval_to_str(interval) % param_const.var_name;
-      auto extract_node_str = formater.str();
-      expr_nodes_.emplace_back(extract_node_str);
-
-      tag_selectors_.emplace_back(
-          variable_to_tag_id_property_selector(ctx_, expr_var));
-      VLOG(10) << "extract opr: " << extract_node_str;
-      break;
+      LOG(FATAL) << "Should not reach here, Extract op should be handled "
+                    "separately";
     }
 
     default:
@@ -428,6 +419,28 @@ class ExprBuilder {
     }
   }
 
+  // Add extract operator with var. Currently not support extract on a compicate
+  // expression.
+  void AddExtractOpr(const common::Extract& extract_opr,
+                     const common::ExprOpr& expr_opr) {
+    CHECK(expr_opr.item_case() == common::ExprOpr::kVar)
+        << "Currently only support var in extract";
+    auto interval = extract_opr.interval();
+    auto expr_var = expr_opr.var();
+    auto param_const = variable_to_param_const(expr_var, ctx_);
+    make_var_name_unique(param_const);
+    func_call_vars_.push_back(param_const);
+
+    boost::format formater(EXTRACT_TEMPLATE_STR);
+    formater % interval_to_str(interval) % param_const.var_name;
+    auto extract_node_str = formater.str();
+    expr_nodes_.emplace_back(extract_node_str);
+
+    tag_selectors_.emplace_back(
+        variable_to_tag_id_property_selector(ctx_, expr_var));
+    VLOG(10) << "extract opr: " << extract_node_str;
+  }
+
   // get expr nodes
   const std::vector<std::string>& GetExprNodes() const { return expr_nodes_; }
 
diff --git a/flex/engines/hqps_db/core/null_record.h b/flex/engines/hqps_db/core/null_record.h
index 5784736c052f..371d4616982e 100644
--- a/flex/engines/hqps_db/core/null_record.h
+++ b/flex/engines/hqps_db/core/null_record.h
@@ -88,10 +88,20 @@ bool operator==(const T& lhs, const None& rhs) {
   return IsNull(lhs);
 }
 
+template <typename T>
+bool operator==(const None& lhs, const T& rhs) {
+  return IsNull(rhs);
+}
+
 template <typename T>
 bool operator!=(const T& lhs, const None& rhs) {
   return !IsNull(lhs);
 }
+
+template <typename T>
+bool operator!=(const None& lhs, const T& rhs) {
+  return !IsNull(rhs);
+}
 }  // namespace gs
 
 #endif  // ENGINES_HQPS_ENGINE_NULL_RECORD_H_
\ No newline at end of file
diff --git a/flex/engines/hqps_db/core/sync_engine.h b/flex/engines/hqps_db/core/sync_engine.h
index 8975a9b7174b..2a21fde4d2d1 100644
--- a/flex/engines/hqps_db/core/sync_engine.h
+++ b/flex/engines/hqps_db/core/sync_engine.h
@@ -684,7 +684,7 @@ class SyncEngine : public BaseEngine {
   template <
       int... in_col_id, typename CTX_HEAD_T, int cur_alias, int base_tag,
       typename... CTX_PREV, typename EXPR, typename... SELECTOR,
-      typename std::enable_if<((sizeof...(in_col_id) > 1) &&
+      typename std::enable_if<((sizeof...(in_col_id) >= 1) &&
                                (sizeof...(in_col_id) ==
                                 sizeof...(SELECTOR)))>::type* = nullptr,
       typename RES_T = Context<CTX_HEAD_T, cur_alias, base_tag, CTX_PREV...>>
diff --git a/interactive_engine/common/src/main/java/com/alibaba/graphscope/groot/common/schema/wrapper/DataType.java b/interactive_engine/common/src/main/java/com/alibaba/graphscope/groot/common/schema/wrapper/DataType.java
index acd61616ed92..33d52ffa0431 100644
--- a/interactive_engine/common/src/main/java/com/alibaba/graphscope/groot/common/schema/wrapper/DataType.java
+++ b/interactive_engine/common/src/main/java/com/alibaba/graphscope/groot/common/schema/wrapper/DataType.java
@@ -35,7 +35,9 @@ public enum DataType {
     DOUBLE_LIST(13),
     STRING_LIST(14),
     BYTES_LIST(15),
-    DATE(16);
+    DATE(16), // represent DATE32
+    TIME32(17),
+    TIMESTAMP(18);
 
     private final byte type;
 
diff --git a/interactive_engine/common/src/main/java/com/alibaba/graphscope/groot/common/util/IrSchemaParser.java b/interactive_engine/common/src/main/java/com/alibaba/graphscope/groot/common/util/IrSchemaParser.java
index bdcedca48c1d..d3ef0202aeb9 100644
--- a/interactive_engine/common/src/main/java/com/alibaba/graphscope/groot/common/util/IrSchemaParser.java
+++ b/interactive_engine/common/src/main/java/com/alibaba/graphscope/groot/common/util/IrSchemaParser.java
@@ -146,6 +146,10 @@ private int getDataTypeId(DataType dataType) {
                 return 9;
             case DATE:
                 return 12;
+            case TIME32:
+                return 13;
+            case TIMESTAMP:
+                return 14;
             default:
                 throw new UnsupportedOperationException(
                         "convert from DataType " + dataType + " to ir core is unsupported yet");
diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/GraphOptTable.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/GraphOptTable.java
index d47111c41906..439fde816177 100644
--- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/GraphOptTable.java
+++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/GraphOptTable.java
@@ -125,8 +125,11 @@ private RelDataType deriveType(GraphProperty property) {
             case DOUBLE:
                 return typeFactory.createSqlType(SqlTypeName.DOUBLE);
             case DATE:
-                return typeFactory.createSqlType(
-                        SqlTypeName.DATE); // todo: support Time and DateTime in GraphSchema
+                return typeFactory.createSqlType(SqlTypeName.DATE);
+            case TIME32:
+                return typeFactory.createSqlType(SqlTypeName.TIME);
+            case TIMESTAMP:
+                return typeFactory.createSqlType(SqlTypeName.TIMESTAMP);
             default:
                 throw new UnsupportedOperationException(
                         "type " + property.getDataType().name() + " not supported");
diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/Utils.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/Utils.java
index 07f3f7f8aac0..86868c7dd8e8 100644
--- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/Utils.java
+++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/meta/schema/Utils.java
@@ -161,15 +161,14 @@ public static DataType toDataType(Object type) {
                         return DataType.STRING;
                     case "DT_DATE32":
                         return DataType.DATE;
+                    case "DT_TIME32":
+                        return DataType.TIME32;
+                    case "TIMESTAMP":
+                        return DataType.TIMESTAMP;
                     default:
                         throw new UnsupportedOperationException(
                                 "unsupported primitive type: " + value);
                 }
-            } else if ((value = typeMap.get("date")) instanceof Map) {
-                Object format = ((Map) value).get("date_format");
-                if (format != null && format.toString().equals("DF_YYYY_MM_DD")) {
-                    return DataType.DATE;
-                }
             }
         }
         throw new UnsupportedOperationException("unsupported type: " + type);
@@ -275,6 +274,10 @@ public static final DataType toDataType(int ordinal) {
                 return DataType.STRING_LIST;
             case 12:
                 return DataType.DATE;
+            case 13:
+                return DataType.TIME32;
+            case 14:
+                return DataType.TIMESTAMP;
             default:
                 throw new UnsupportedOperationException(
                         "convert from ir core type " + ordinal + " to DataType is unsupported yet");
diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/RexToProtoConverter.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/RexToProtoConverter.java
index 3e57e4e77d3f..d290a6fd3fd3 100644
--- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/RexToProtoConverter.java
+++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/RexToProtoConverter.java
@@ -24,6 +24,7 @@
 import com.alibaba.graphscope.gaia.proto.OuterExpression;
 import com.google.common.base.Preconditions;
 
+import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.*;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlOperator;
@@ -106,63 +107,81 @@ private OuterExpression.Expression visitExtract(RexCall call) {
         Preconditions.checkArgument(
                 operands.size() == 2 && operands.get(0) instanceof RexLiteral,
                 "'EXTRACT' operator has invalid operands " + operands);
-        OuterExpression.Expression.Builder exprBuilder = OuterExpression.Expression.newBuilder();
-        exprBuilder.addOperators(
+        OuterExpression.Expression.Builder builder = OuterExpression.Expression.newBuilder();
+        builder.addOperators(
                 OuterExpression.ExprOpr.newBuilder()
                         .setExtract(
                                 OuterExpression.Extract.newBuilder()
                                         .setInterval(
-                                                Utils.protoInterval((RexLiteral) operands.get(0)))
-                                        .setDataTime(operands.get(1).accept(this)))
+                                                Utils.protoInterval((RexLiteral) operands.get(0))))
                         .setNodeType(Utils.protoIrDataType(call.getType(), isColumnId)));
-        return exprBuilder.build();
+        SqlOperator operator = call.getOperator();
+        RexNode operand = operands.get(1);
+        boolean needBrace = needBrace(operator, operand);
+        if (needBrace) {
+            builder.addOperators(
+                    OuterExpression.ExprOpr.newBuilder()
+                            .setBrace(OuterExpression.ExprOpr.Brace.LEFT_BRACE));
+        }
+        builder.addAllOperators(operand.accept(this).getOperatorsList());
+        if (needBrace) {
+            builder.addOperators(
+                    OuterExpression.ExprOpr.newBuilder()
+                            .setBrace(OuterExpression.ExprOpr.Brace.RIGHT_BRACE));
+        }
+        return builder.build();
     }
 
     private OuterExpression.Expression visitUnaryOperator(RexCall call) {
         SqlOperator operator = call.getOperator();
         RexNode operand = call.getOperands().get(0);
         switch (operator.getKind()) {
-                // convert IS_NULL to unary call: IS_NULL(XX)
-            case IS_NULL:
-                return visitIsNullOperator(operand);
                 // convert IS_NOT_NULL to NOT(IS_NULL(XX))
             case IS_NOT_NULL:
                 return OuterExpression.Expression.newBuilder()
-                        .addOperators(Utils.protoOperator(GraphStdOperatorTable.NOT))
+                        .addOperators(
+                                Utils.protoOperator(GraphStdOperatorTable.NOT).toBuilder()
+                                        .setNodeType(
+                                                Utils.protoIrDataType(call.getType(), isColumnId)))
                         .addOperators(
                                 OuterExpression.ExprOpr.newBuilder()
                                         .setBrace(OuterExpression.ExprOpr.Brace.LEFT_BRACE))
-                        .addAllOperators(visitIsNullOperator(operand).getOperatorsList())
+                        .addAllOperators(
+                                visitUnaryOperator(
+                                                GraphStdOperatorTable.IS_NULL,
+                                                operand,
+                                                call.getType())
+                                        .getOperatorsList())
                         .addOperators(
                                 OuterExpression.ExprOpr.newBuilder()
                                         .setBrace(OuterExpression.ExprOpr.Brace.RIGHT_BRACE))
                         .build();
+            case IS_NULL:
             case NOT:
             default:
-                return OuterExpression.Expression.newBuilder()
-                        .addOperators(Utils.protoOperator(operator))
-                        .addOperators(
-                                OuterExpression.ExprOpr.newBuilder()
-                                        .setBrace(OuterExpression.ExprOpr.Brace.LEFT_BRACE))
-                        .addAllOperators(operand.accept(this).getOperatorsList())
-                        .addOperators(
-                                OuterExpression.ExprOpr.newBuilder()
-                                        .setBrace(OuterExpression.ExprOpr.Brace.RIGHT_BRACE))
-                        .build();
+                return visitUnaryOperator(operator, operand, call.getType());
         }
     }
 
-    private OuterExpression.Expression visitIsNullOperator(RexNode operand) {
-        return OuterExpression.Expression.newBuilder()
-                .addOperators(Utils.protoOperator(GraphStdOperatorTable.IS_NULL))
-                .addOperators(
-                        OuterExpression.ExprOpr.newBuilder()
-                                .setBrace(OuterExpression.ExprOpr.Brace.LEFT_BRACE))
-                .addAllOperators(operand.accept(this).getOperatorsList())
-                .addOperators(
-                        OuterExpression.ExprOpr.newBuilder()
-                                .setBrace(OuterExpression.ExprOpr.Brace.RIGHT_BRACE))
-                .build();
+    private OuterExpression.Expression visitUnaryOperator(
+            SqlOperator operator, RexNode operand, RelDataType dataType) {
+        OuterExpression.Expression.Builder builder = OuterExpression.Expression.newBuilder();
+        builder.addOperators(
+                Utils.protoOperator(operator).toBuilder()
+                        .setNodeType(Utils.protoIrDataType(dataType, isColumnId)));
+        boolean needBrace = needBrace(operator, operand);
+        if (needBrace) {
+            builder.addOperators(
+                    OuterExpression.ExprOpr.newBuilder()
+                            .setBrace(OuterExpression.ExprOpr.Brace.LEFT_BRACE));
+        }
+        builder.addAllOperators(operand.accept(this).getOperatorsList());
+        if (needBrace) {
+            builder.addOperators(
+                    OuterExpression.ExprOpr.newBuilder()
+                            .setBrace(OuterExpression.ExprOpr.Brace.RIGHT_BRACE));
+        }
+        return builder.build();
     }
 
     private OuterExpression.Expression visitBinaryOperator(RexCall call) {
diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java
index 1245a82bb6d6..04e0dcb68b7a 100644
--- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java
+++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/ir/runtime/proto/Utils.java
@@ -229,7 +229,11 @@ public static final Common.DataType protoBasicDataType(RelDataType basicType) {
                                         + " is unsupported yet");
                 }
             case DATE:
-                return Common.DataType.DATE;
+                return Common.DataType.DATE32;
+            case TIME:
+                return Common.DataType.TIME32;
+            case TIMESTAMP:
+                return Common.DataType.TIMESTAMP;
             default:
                 throw new UnsupportedOperationException(
                         "basic type " + basicType.getSqlTypeName() + " is unsupported yet");
diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java
index 7b394d2df623..6b437462f46e 100644
--- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java
+++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/result/CypherRecordParser.java
@@ -27,12 +27,12 @@
 
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeField;
+import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.NotImplementedException;
 import org.checkerframework.checker.nullness.qual.Nullable;
 import org.neo4j.values.AnyValue;
-import org.neo4j.values.storable.BooleanValue;
-import org.neo4j.values.storable.Values;
+import org.neo4j.values.storable.*;
 import org.neo4j.values.virtual.MapValue;
 import org.neo4j.values.virtual.NodeValue;
 import org.neo4j.values.virtual.RelationshipValue;
@@ -40,6 +40,7 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.time.ZoneOffset;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -221,6 +222,22 @@ protected AnyValue parseValue(Common.Value value, @Nullable RelDataType dataType
                 return Values.stringArray(value.getStrArray().getItemList().toArray(String[]::new));
             case NONE:
                 return Values.NO_VALUE;
+            case DATE:
+                Preconditions.checkArgument(
+                        dataType.getSqlTypeName() == SqlTypeName.DATE,
+                        "date32 value should have date type");
+                return DateValue.epochDate(value.getDate().getItem());
+            case TIME:
+                Preconditions.checkArgument(
+                        dataType.getSqlTypeName() == SqlTypeName.TIME,
+                        "time32 value should have time type");
+                return TimeValue.time(value.getTime().getItem() * 1000_000L, ZoneOffset.UTC);
+            case TIMESTAMP:
+                Preconditions.checkArgument(
+                        dataType.getSqlTypeName() == SqlTypeName.TIMESTAMP,
+                        "timestamp value should have timestamp type");
+                return DateTimeValue.ofEpochMillis(
+                        Values.longValue(value.getTimestamp().getItem()));
             default:
                 throw new NotImplementedException(value.getItemCase() + " is unsupported yet");
         }
diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/integration/suite/pattern/PatternQueryTest.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/integration/suite/pattern/PatternQueryTest.java
index 26fd2857cbfd..d6578865b045 100644
--- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/integration/suite/pattern/PatternQueryTest.java
+++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/gremlin/integration/suite/pattern/PatternQueryTest.java
@@ -20,7 +20,6 @@
 import com.alibaba.graphscope.gremlin.plugin.traversal.IrCustomizedTraversal;
 
 import org.apache.tinkerpop.gremlin.process.AbstractGremlinProcessTest;
-import org.apache.tinkerpop.gremlin.process.traversal.P;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.structure.Vertex;
 import org.junit.Assert;
@@ -63,21 +62,21 @@ public abstract class PatternQueryTest extends AbstractGremlinProcessTest {
     public void run_pattern_1_test() {
         Traversal<Vertex, Long> traversal = this.get_pattern_1_test();
         this.printTraversalForm(traversal);
-        Assert.assertEquals(155633L, traversal.next().longValue());
+        Assert.assertEquals(240390L, traversal.next().longValue());
     }
 
     @Test
     public void run_pattern_2_test() {
         Traversal<Vertex, Long> traversal = this.get_pattern_2_test();
         this.printTraversalForm(traversal);
-        Assert.assertEquals(55488L, traversal.next().longValue());
+        Assert.assertEquals(118209L, traversal.next().longValue());
     }
 
     @Test
     public void run_pattern_3_test() {
         Traversal<Vertex, Long> traversal = this.get_pattern_3_test();
         this.printTraversalForm(traversal);
-        Assert.assertEquals(568408L, traversal.next().longValue());
+        Assert.assertEquals(1247146L, traversal.next().longValue());
     }
 
     @Test
@@ -91,7 +90,7 @@ public void run_pattern_4_test() {
     public void run_pattern_5_test() {
         Traversal<Vertex, Long> traversal = this.get_pattern_5_test();
         this.printTraversalForm(traversal);
-        Assert.assertEquals(16291L, traversal.next().longValue());
+        Assert.assertEquals(5596L, traversal.next().longValue());
     }
 
     @Test
@@ -105,14 +104,14 @@ public void run_pattern_6_test() {
     public void run_pattern_7_test() {
         Traversal<Vertex, Long> traversal = this.get_pattern_7_test();
         this.printTraversalForm(traversal);
-        Assert.assertEquals(2944L, traversal.next().longValue());
+        Assert.assertEquals(20858L, traversal.next().longValue());
     }
 
     @Test
     public void run_pattern_8_test() {
         Traversal<Vertex, Long> traversal = this.get_pattern_8_test();
         this.printTraversalForm(traversal);
-        Assert.assertEquals(782347L, traversal.next().longValue());
+        Assert.assertEquals(1247146L, traversal.next().longValue());
     }
 
     @Test
@@ -126,7 +125,7 @@ public void run_pattern_9_test() {
     public void run_pattern_10_test() {
         Traversal<Vertex, Long> traversal = this.get_pattern_10_test();
         this.printTraversalForm(traversal);
-        Assert.assertEquals(3019L, traversal.next().longValue());
+        Assert.assertEquals(11547L, traversal.next().longValue());
     }
 
     @Test
@@ -154,7 +153,7 @@ public void run_pattern_13_test() {
     public void run_pattern_14_test() {
         Traversal<Vertex, Long> traversal = this.get_pattern_14_test();
         this.printTraversalForm(traversal);
-        Assert.assertEquals(55488L, traversal.next().longValue());
+        Assert.assertEquals(118209L, traversal.next().longValue());
     }
 
     @Test
@@ -177,12 +176,7 @@ public static class Traversals extends PatternQueryTest {
         @Override
         public Traversal<Vertex, Long> get_pattern_1_test() {
             return g.V().match(
-                            __.as("a").out("KNOWS").as("b"),
-                            __.as("b")
-                                    .outE("KNOWS")
-                                    .has("creationDate", P.gt(20120101000000000L))
-                                    .inV()
-                                    .as("c"))
+                            __.as("a").out("KNOWS").as("b"), __.as("b").outE("KNOWS").inV().as("c"))
                     .count();
         }
 
@@ -193,7 +187,7 @@ public Traversal<Vertex, Long> get_pattern_2_test() {
                             __.as("a").out("KNOWS").as("b"),
                             __.as("b")
                                     .hasLabel("PERSON")
-                                    .has("creationDate", P.gt(20120101000000000L))
+                                    .has("gender", "male")
                                     .out("KNOWS")
                                     .as("c"))
                     .count();
@@ -207,9 +201,8 @@ public Traversal<Vertex, Long> get_pattern_3_test() {
                             __.as("b").out("KNOWS").as("c"),
                             __.as("c")
                                     .hasLabel("PERSON")
-                                    .has("creationDate", P.gt(20120101000000000L))
+                                    .has("gender", "male")
                                     .outE("KNOWS")
-                                    .has("creationDate", P.gt(20120601000000000L))
                                     .inV()
                                     .as("d"))
                     .count();
@@ -229,21 +222,9 @@ public Traversal<Vertex, Long> get_pattern_4_test() {
         @Override
         public Traversal<Vertex, Long> get_pattern_5_test() {
             return g.V().match(
-                            __.as("a")
-                                    .outE("KNOWS")
-                                    .has("creationDate", P.gt(20110101000000000L))
-                                    .inV()
-                                    .as("b"),
-                            __.as("b")
-                                    .outE("KNOWS")
-                                    .has("creationDate", P.gt(20110101000000000L))
-                                    .inV()
-                                    .as("c"),
-                            __.as("a")
-                                    .outE("KNOWS")
-                                    .has("creationDate", P.gt(20110101000000000L))
-                                    .inV()
-                                    .as("c"))
+                            __.as("a").has("gender", "male").out("KNOWS").as("b"),
+                            __.as("b").has("gender", "female").out("KNOWS").as("c"),
+                            __.as("a").out("KNOWS").as("c"))
                     .count();
         }
 
@@ -264,19 +245,10 @@ public Traversal<Vertex, Long> get_pattern_6_test() {
         public Traversal<Vertex, Long> get_pattern_7_test() {
             return g.V().match(
                             __.as("a").out("KNOWS").as("b"),
-                            __.as("b")
-                                    .has("creationDate", P.gt(20120101000000000L))
-                                    .outE("KNOWS")
-                                    .has("creationDate", P.gt(20120201000000000L))
-                                    .inV()
-                                    .as("c"),
+                            __.as("b").has("gender", "male").outE("KNOWS").inV().as("c"),
                             __.as("a").out("KNOWS").as("c"),
                             __.as("c").out("KNOWS").as("d"),
-                            __.as("b")
-                                    .outE("KNOWS")
-                                    .has("creationDate", P.gt(20120301000000000L))
-                                    .inV()
-                                    .as("d"))
+                            __.as("b").outE("KNOWS").inV().as("d"))
                     .count();
         }
 
@@ -290,7 +262,7 @@ public Traversal<Vertex, Long> get_pattern_8_test() {
                             ((IrCustomizedTraversal)
                                             __.as("c")
                                                     .hasLabel("PERSON")
-                                                    .has("creationDate", P.gt(20120101000000000L))
+                                                    .has("gender", "male")
                                                     .out("1..2", "KNOWS"))
                                     .endV()
                                     .as("d"))
@@ -316,10 +288,7 @@ public Traversal<Vertex, Long> get_pattern_10_test() {
                                     .endV()
                                     .as("b"),
                             ((IrCustomizedTraversal)
-                                            __.as("b")
-                                                    .has("creationDate", P.gt(20120101000000000L))
-                                                    .outE("KNOWS")
-                                                    .has("creationDate", P.gt(20120601000000000L)))
+                                            __.as("b").has("gender", "female").outE("KNOWS"))
                                     .inV()
                                     .as("c"),
                             ((IrCustomizedTraversal) __.as("a").out("1..2", "KNOWS"))
@@ -357,10 +326,7 @@ public Traversal<Vertex, Long> get_pattern_13_test() {
         public Traversal<Vertex, Long> get_pattern_14_test() {
             return g.V().match(
                             __.as("a").out("KNOWS").as("b"),
-                            __.as("b")
-                                    .hasLabel("PERSON")
-                                    .has("creationDate", P.gt(20120101000000000L))
-                                    .as("b"),
+                            __.as("b").hasLabel("PERSON").has("gender", "male").as("b"),
                             __.as("b").out("KNOWS").as("c"))
                     .count();
         }
diff --git a/interactive_engine/executor/common/dyn_type/src/object.rs b/interactive_engine/executor/common/dyn_type/src/object.rs
index 51ca9d763f74..b15db7c25ef0 100644
--- a/interactive_engine/executor/common/dyn_type/src/object.rs
+++ b/interactive_engine/executor/common/dyn_type/src/object.rs
@@ -437,6 +437,53 @@ impl DateTimeFormats {
         }
     }
 
+    // the date32 is stored as YYYYMMDD, e.g., 20100102
+    pub fn from_date32(date32: i32) -> Result<Self, CastError> {
+        NaiveDate::from_ymd_opt(date32 / 10000, ((date32 % 10000) / 100) as u32, (date32 % 100) as u32)
+            .map(|d| DateTimeFormats::Date(d))
+            .ok_or(CastError::new::<DateTimeFormats>(RawType::Integer))
+    }
+
+    // the time32 is stored HHMMSSsss, e.g., 121314100
+    pub fn from_time32(time32: i32) -> Result<Self, CastError> {
+        NaiveTime::from_hms_milli_opt(
+            (time32 / 10000000) as u32,
+            ((time32 % 10000000) / 100000) as u32,
+            ((time32 % 100000) / 1000) as u32,
+            (time32 % 1000) as u32,
+        )
+        .map(|t| DateTimeFormats::Time(t))
+        .ok_or(CastError::new::<DateTimeFormats>(RawType::Integer))
+    }
+
+    pub fn from_timestamp_millis(timestamp: i64) -> Result<Self, CastError> {
+        NaiveDateTime::from_timestamp_millis(timestamp)
+            .map(|dt| DateTimeFormats::DateTime(dt))
+            .ok_or(CastError::new::<DateTimeFormats>(RawType::Long))
+    }
+
+    // we pre-assume some date/time/datetime formats according to ISO formats.
+    pub fn from_str(str: &str) -> Result<Self, CastError> {
+        // `1996-12-19`
+        if let Ok(date) = NaiveDate::parse_from_str(str, "%Y-%m-%d") {
+            Ok(DateTimeFormats::Date(date))
+        }
+        // `16:39:57.123`
+        else if let Ok(time) = NaiveTime::parse_from_str(str, "%H:%M:%S%.f") {
+            Ok(DateTimeFormats::Time(time))
+        }
+        // `1996-12-19 16:39:57.123`
+        else if let Ok(dt) = NaiveDateTime::parse_from_str(str, "%Y-%m-%d %H:%M:%S%.f") {
+            Ok(DateTimeFormats::DateTime(dt))
+        }
+        // `1996-12-19T16:39:57.123+08:00`
+        else if let Ok(dt) = DateTime::parse_from_rfc3339(str) {
+            Ok(DateTimeFormats::DateTimeWithTz(dt))
+        } else {
+            Err(CastError::new::<DateTimeFormats>(RawType::String))
+        }
+    }
+
     #[inline]
     pub fn as_date(&self) -> Result<NaiveDate, CastError> {
         match self {
@@ -1526,6 +1573,12 @@ impl From<DateTime<FixedOffset>> for Object {
     }
 }
 
+impl From<DateTimeFormats> for Object {
+    fn from(date_time_formats: DateTimeFormats) -> Self {
+        Object::DateFormat(date_time_formats)
+    }
+}
+
 pub enum OwnedOrRef<'a, T> {
     Owned(T),
     Ref(&'a T),
diff --git a/interactive_engine/executor/ir/common/Cargo.toml b/interactive_engine/executor/ir/common/Cargo.toml
index 606c6fe31da6..bb20818ca0d0 100644
--- a/interactive_engine/executor/ir/common/Cargo.toml
+++ b/interactive_engine/executor/ir/common/Cargo.toml
@@ -9,6 +9,7 @@ pegasus_common = { path = "../../engine/pegasus/common" }
 prost = "0.11"
 serde = { version = "1.0", features = ["derive"] }
 tonic = "0.8"
+chrono = "0.4"
 
 [build-dependencies]
 prost-build = "0.11"
diff --git a/interactive_engine/executor/ir/common/src/utils.rs b/interactive_engine/executor/ir/common/src/utils.rs
index b6e807331a7f..e8ab4cc53dd3 100644
--- a/interactive_engine/executor/ir/common/src/utils.rs
+++ b/interactive_engine/executor/ir/common/src/utils.rs
@@ -18,7 +18,8 @@ use std::convert::{TryFrom, TryInto};
 use std::fmt;
 use std::ops::Deref;
 
-use dyn_type::{Object, Primitives};
+use chrono::Timelike;
+use dyn_type::{DateTimeFormats, Object, Primitives};
 
 use crate::error::ParsePbError;
 use crate::generated::algebra as pb;
@@ -329,6 +330,15 @@ impl TryFrom<common_pb::Value> for Object {
                     }
                     Ok(vec.into())
                 }
+                Date(date) => {
+                    Ok((DateTimeFormats::from_date32(date.item).map_err(|e| format!("{:?}", e))?).into())
+                }
+                Time(time) => {
+                    Ok((DateTimeFormats::from_time32(time.item).map_err(|e| format!("{:?}", e))?).into())
+                }
+                Timestamp(timestamp) => Ok((DateTimeFormats::from_timestamp_millis(timestamp.item)
+                    .map_err(|e| format!("{:?}", e))?)
+                .into()),
             };
         }
 
@@ -582,6 +592,28 @@ impl From<Object> for common_pb::Value {
                 common_pb::value::Item::PairArray(common_pb::PairArray { item: pairs })
             }
             Object::None => common_pb::value::Item::None(common_pb::None {}),
+            Object::DateFormat(datetime_formats) => match datetime_formats {
+                DateTimeFormats::Date(date) => common_pb::value::Item::Date(common_pb::Date32 {
+                    // convert to days since from 1970-01-01
+                    item: (date
+                        .and_hms_opt(0, 0, 0)
+                        .unwrap() // can savely unwrap since it is valid hour/min/sec
+                        .timestamp()
+                        / 86400) as i32,
+                }),
+                DateTimeFormats::Time(time) => common_pb::value::Item::Time(common_pb::Time32 {
+                    // convert to milliseconds past midnight
+                    item: (time.hour() as i32 * 3600 + time.minute() as i32 * 60 + time.second() as i32)
+                        * 1000
+                        + time.nanosecond() as i32 / 1000_000,
+                }),
+                DateTimeFormats::DateTime(dt) => {
+                    common_pb::value::Item::Timestamp(common_pb::Timestamp { item: dt.timestamp_millis() })
+                }
+                DateTimeFormats::DateTimeWithTz(dt) => {
+                    common_pb::value::Item::Timestamp(common_pb::Timestamp { item: dt.timestamp_millis() })
+                }
+            },
             _ => unimplemented!(),
         };
 
diff --git a/interactive_engine/executor/ir/graph_proxy/Cargo.toml b/interactive_engine/executor/ir/graph_proxy/Cargo.toml
index ecf0a02a2fdf..6775437bf84c 100644
--- a/interactive_engine/executor/ir/graph_proxy/Cargo.toml
+++ b/interactive_engine/executor/ir/graph_proxy/Cargo.toml
@@ -17,6 +17,7 @@ pegasus = { path = "../../engine/pegasus/pegasus" }
 pegasus_common = { path = "../../engine/pegasus/common" }
 ahash = "0.8"
 rand = "0.8.5"
+chrono = "0.4"
 
 [features]
 default = []
diff --git a/interactive_engine/executor/ir/graph_proxy/src/adapters/csr_store/read_graph.rs b/interactive_engine/executor/ir/graph_proxy/src/adapters/csr_store/read_graph.rs
index c638bf93d964..217095f85148 100644
--- a/interactive_engine/executor/ir/graph_proxy/src/adapters/csr_store/read_graph.rs
+++ b/interactive_engine/executor/ir/graph_proxy/src/adapters/csr_store/read_graph.rs
@@ -18,7 +18,7 @@ use std::fmt;
 use std::sync::Arc;
 
 use ahash::HashMap;
-use dyn_type::{BorrowObject, Object, Primitives};
+use dyn_type::{BorrowObject, DateTimeFormats, Object, Primitives};
 use ir_common::{KeyId, LabelId, NameOrId};
 use mcsr::columns::RefItem;
 use mcsr::date::Date;
@@ -296,7 +296,7 @@ impl Details for LazyVertexDetails {
             } else {
                 self.inner
                     .get_property(key)
-                    .map(|prop| PropertyValue::Borrowed(to_borrow_object(prop)))
+                    .map(|prop| to_property_value(prop))
             }
         } else {
             info!("Have not support getting property by prop_id in exp_store yet");
@@ -360,7 +360,7 @@ impl Details for LazyEdgeDetails {
         if let NameOrId::Str(key) = key {
             self.inner
                 .get_property(key)
-                .map(|prop| PropertyValue::Borrowed(to_borrow_object(prop)))
+                .map(|prop| to_property_value(prop))
         } else {
             info!("Have not support getting property by prop_id in experiments store yet");
             None
@@ -392,44 +392,62 @@ fn to_object<'a>(ref_item: RefItem<'a>) -> Object {
         RefItem::Int64(v) => Object::Primitive(Primitives::Long(*v)),
         RefItem::UInt64(v) => Object::Primitive(Primitives::Long(i64::try_from(*v).unwrap())),
         RefItem::Double(v) => Object::Primitive(Primitives::Float(*v)),
-        RefItem::Date(v) => Object::Primitive(Primitives::Long(encode_date(v))),
-        RefItem::DateTime(v) => Object::Primitive(Primitives::Long(encode_datetime(v))),
+        RefItem::Date(v) => {
+            if let Some(date) = encode_date(v) {
+                Object::DateFormat(DateTimeFormats::Date(date))
+            } else {
+                Object::None
+            }
+        }
+        RefItem::DateTime(v) => {
+            if let Some(date_time) = encode_datetime(v) {
+                Object::DateFormat(DateTimeFormats::DateTime(date_time))
+            } else {
+                Object::None
+            }
+        }
         RefItem::String(v) => Object::String(v.clone()),
         _ => Object::None,
     }
 }
 
 #[inline]
-fn to_borrow_object<'a>(ref_item: RefItem<'a>) -> BorrowObject<'a> {
+fn to_property_value<'a>(ref_item: RefItem<'a>) -> PropertyValue {
     match ref_item {
-        RefItem::Int32(v) => BorrowObject::Primitive(Primitives::Integer(*v)),
-        RefItem::UInt32(v) => BorrowObject::Primitive(Primitives::Integer(i32::try_from(*v).unwrap())),
-        RefItem::Int64(v) => BorrowObject::Primitive(Primitives::Long(*v)),
-        RefItem::UInt64(v) => BorrowObject::Primitive(Primitives::Long(i64::try_from(*v).unwrap())),
-        RefItem::Double(v) => BorrowObject::Primitive(Primitives::Float(*v)),
-        RefItem::Date(v) => BorrowObject::Primitive(Primitives::Long(encode_date(v))),
-        RefItem::DateTime(v) => BorrowObject::Primitive(Primitives::Long(encode_datetime(v))),
-        RefItem::String(v) => BorrowObject::String(v),
-        _ => BorrowObject::None,
+        RefItem::Int32(v) => BorrowObject::Primitive(Primitives::Integer(*v)).into(),
+        RefItem::UInt32(v) => {
+            BorrowObject::Primitive(Primitives::Integer(i32::try_from(*v).unwrap())).into()
+        }
+        RefItem::Int64(v) => BorrowObject::Primitive(Primitives::Long(*v)).into(),
+        RefItem::UInt64(v) => BorrowObject::Primitive(Primitives::Long(i64::try_from(*v).unwrap())).into(),
+        RefItem::Double(v) => BorrowObject::Primitive(Primitives::Float(*v)).into(),
+        RefItem::Date(v) => {
+            if let Some(date) = encode_date(v) {
+                Object::DateFormat(DateTimeFormats::Date(date)).into()
+            } else {
+                BorrowObject::None.into()
+            }
+        }
+        RefItem::DateTime(v) => {
+            if let Some(date_time) = encode_datetime(v) {
+                Object::DateFormat(DateTimeFormats::DateTime(date_time)).into()
+            } else {
+                BorrowObject::None.into()
+            }
+        }
+        RefItem::String(v) => BorrowObject::String(v).into(),
+        _ => BorrowObject::None.into(),
     }
 }
 
 #[inline]
-fn encode_date(date: &Date) -> i64 {
-    date.year() as i64 * 10000000000000
-        + date.month() as i64 * 100000000000
-        + date.day() as i64 * 1000000000
+fn encode_date(date: &Date) -> Option<chrono::NaiveDate> {
+    chrono::NaiveDate::from_ymd_opt(date.year(), date.month(), date.day())
 }
 
 #[inline]
-fn encode_datetime(datetime: &DateTime) -> i64 {
-    datetime.year() as i64 * 10000000000000
-        + datetime.month() as i64 * 100000000000
-        + datetime.day() as i64 * 1000000000
-        + datetime.hour() as i64 * 10000000
-        + datetime.minute() as i64 * 100000
-        + datetime.second() as i64 * 1000
-        + datetime.millisecond() as i64
+fn encode_datetime(datetime: &DateTime) -> Option<chrono::NaiveDateTime> {
+    chrono::NaiveDateTime::from_timestamp_millis(datetime.to_i64())
 }
 
 #[inline]
diff --git a/interactive_engine/executor/ir/graph_proxy/src/apis/graph/element/property.rs b/interactive_engine/executor/ir/graph_proxy/src/apis/graph/element/property.rs
index 5df5cb4fcf8a..715dbb10a53b 100644
--- a/interactive_engine/executor/ir/graph_proxy/src/apis/graph/element/property.rs
+++ b/interactive_engine/executor/ir/graph_proxy/src/apis/graph/element/property.rs
@@ -114,6 +114,18 @@ impl<'a> PropertyValue<'a> {
     }
 }
 
+impl<'a> From<BorrowObject<'a>> for PropertyValue<'a> {
+    fn from(value: BorrowObject<'a>) -> Self {
+        PropertyValue::Borrowed(value)
+    }
+}
+
+impl<'a> From<Object> for PropertyValue<'a> {
+    fn from(value: Object) -> Self {
+        PropertyValue::Owned(value)
+    }
+}
+
 pub trait Details: std::fmt::Debug + Send + Sync + AsAny {
     /// Get a property with given key
     fn get_property(&self, key: &NameOrId) -> Option<PropertyValue>;
diff --git a/interactive_engine/executor/ir/graph_proxy/src/utils/expr/eval.rs b/interactive_engine/executor/ir/graph_proxy/src/utils/expr/eval.rs
index 631e07016745..3fe3320b7dec 100644
--- a/interactive_engine/executor/ir/graph_proxy/src/utils/expr/eval.rs
+++ b/interactive_engine/executor/ir/graph_proxy/src/utils/expr/eval.rs
@@ -54,11 +54,17 @@ pub enum Operand {
     VarMap(Vec<Operand>),
 }
 
+#[derive(Debug, Clone)]
+pub enum Function {
+    Extract(common_pb::extract::Interval),
+}
+
 /// An inner representation of `common_pb::ExprOpr` for one-shot translation of `common_pb::ExprOpr`.
 #[derive(Debug, Clone)]
 pub(crate) enum InnerOpr {
     Logical(common_pb::Logical),
     Arith(common_pb::Arithmetic),
+    Function(Function),
     Operand(Operand),
 }
 
@@ -68,6 +74,7 @@ impl ToString for InnerOpr {
             InnerOpr::Logical(logical) => format!("{:?}", logical),
             InnerOpr::Arith(arith) => format!("{:?}", arith),
             InnerOpr::Operand(item) => format!("{:?}", item),
+            InnerOpr::Function(func) => format!("{:?}", func),
         }
     }
 }
@@ -160,6 +167,52 @@ fn apply_arith<'a>(
     })
 }
 
+pub(crate) fn apply_function<'a>(
+    function: &Function, a: BorrowObject<'a>, _b_opt: Option<BorrowObject<'a>>,
+) -> ExprEvalResult<Object> {
+    use common_pb::extract::Interval;
+    match function {
+        Function::Extract(interval) => match interval {
+            Interval::Year => Ok(a
+                .as_date_format()?
+                .year()
+                .ok_or(ExprEvalError::GetNoneFromContext)?
+                .into()),
+            Interval::Month => Ok((a
+                .as_date_format()?
+                .month()
+                .ok_or(ExprEvalError::GetNoneFromContext)? as i32)
+                .into()),
+            Interval::Day => Ok((a
+                .as_date_format()?
+                .day()
+                .ok_or(ExprEvalError::GetNoneFromContext)? as i32)
+                .into()),
+            Interval::Hour => Ok((a
+                .as_date_format()?
+                .hour()
+                .ok_or(ExprEvalError::GetNoneFromContext)? as i32)
+                .into()),
+            Interval::Minute => Ok((a
+                .as_date_format()?
+                .minute()
+                .ok_or(ExprEvalError::GetNoneFromContext)? as i32)
+                .into()),
+            Interval::Second => Ok((a
+                .as_date_format()?
+                .second()
+                .ok_or(ExprEvalError::GetNoneFromContext)? as i32)
+                .into()),
+            Interval::Millisecond => Ok((a
+                .as_date_format()?
+                .millisecond()
+                .ok_or(ExprEvalError::GetNoneFromContext)?
+                as i32)
+                .into()),
+        },
+    }
+}
+
 pub(crate) fn apply_logical<'a>(
     logical: &common_pb::Logical, a: BorrowObject<'a>, b_opt: Option<BorrowObject<'a>>,
 ) -> ExprEvalResult<Object> {
@@ -220,14 +273,17 @@ impl Evaluator {
             let first = _first.unwrap();
             let second = _second.unwrap();
             if let InnerOpr::Logical(logical) = second {
-                let first = match first.eval(context) {
-                    Ok(first) => Ok(first),
-                    Err(err) => match err {
-                        ExprEvalError::GetNoneFromContext => Ok(Object::None),
-                        _ => Err(err),
-                    },
-                };
+                let mut first = first.eval(context);
+                if common_pb::Logical::Isnull.eq(logical) {
+                    match first {
+                        Err(ExprEvalError::GetNoneFromContext) => first = Ok(Object::None),
+                        _ => {}
+                    }
+                }
                 Ok(apply_logical(logical, first?.as_borrow(), None)?)
+            } else if let InnerOpr::Function(function) = second {
+                let first = first.eval(context)?;
+                Ok(apply_function(function, first.as_borrow(), None)?)
             } else {
                 if !second.is_operand() {
                     Err(ExprEvalError::MissingOperands(second.into()))
@@ -240,8 +296,8 @@ impl Evaluator {
             let second = _second.unwrap();
             let third = _third.unwrap();
             if let InnerOpr::Logical(logical) = third {
-                // to deal with two unary operators cases, e.g., !(!true), !(a isNull) etc.
-                if common_pb::Logical::Not.eq(logical) || common_pb::Logical::Isnull.eq(logical) {
+                if third.is_unary() {
+                    // to deal with two unary operators cases, e.g., !(!true), !(isNull(a)),isNull(extract(a)) etc.
                     if let InnerOpr::Logical(inner_logical) = second {
                         let mut inner_first = first.eval(context);
                         if common_pb::Logical::Isnull.eq(inner_logical) {
@@ -258,11 +314,17 @@ impl Evaluator {
                             }
                         }
                         return Ok(apply_logical(logical, first?.as_borrow(), None)?);
+                    } else if let InnerOpr::Function(function) = second {
+                        let inner_first = first.eval(context)?;
+                        return Ok(apply_function(function, inner_first.as_borrow(), None)?);
+                    } else {
+                        return Err(ExprEvalError::OtherErr("invalid expression".to_string()));
                     }
+                } else {
+                    let a = first.eval(context)?;
+                    let b = second.eval(context)?;
+                    Ok(apply_logical(logical, a.as_borrow(), Some(b.as_borrow()))?)
                 }
-                let a = first.eval(context)?;
-                let b = second.eval(context)?;
-                Ok(apply_logical(logical, a.as_borrow(), Some(b.as_borrow()))?)
             } else if let InnerOpr::Arith(arith) = third {
                 let a = first.eval(context)?;
                 let b = second.eval(context)?;
@@ -360,7 +422,17 @@ impl Evaluate for Evaluator {
                                 }
                             }
                         }
-
+                        InnerOpr::Function(function) => {
+                            if opr.is_unary() {
+                                apply_function(function, first?.as_borrow(), None)
+                            } else {
+                                if let Some(second) = stack.pop() {
+                                    apply_function(function, second?.as_borrow(), Some(first?.as_borrow()))
+                                } else {
+                                    Err(ExprEvalError::OtherErr("invalid expression".to_string()))
+                                }
+                            }
+                        }
                         InnerOpr::Arith(arith) => {
                             if let Some(second) = stack.pop() {
                                 apply_arith(arith, second?.as_borrow(), first?.as_borrow())
@@ -484,6 +556,9 @@ impl TryFrom<common_pb::ExprOpr> for InnerOpr {
                 Arith(arith) => {
                     Ok(Self::Arith(unsafe { std::mem::transmute::<_, common_pb::Arithmetic>(*arith) }))
                 }
+                Extract(extract) => Ok(Self::Function(Function::Extract(unsafe {
+                    std::mem::transmute::<_, common_pb::extract::Interval>(extract.interval)
+                }))),
                 _ => Ok(Self::Operand(unit.clone().try_into()?)),
             }
         } else {
@@ -616,11 +691,25 @@ impl InnerOpr {
             _ => false,
         }
     }
+
+    pub fn is_unary(&self) -> bool {
+        match self {
+            InnerOpr::Logical(logical) => match logical {
+                common_pb::Logical::Not | common_pb::Logical::Isnull => true,
+                _ => false,
+            },
+            InnerOpr::Function(function) => match function {
+                Function::Extract(_) => true,
+            },
+            _ => false,
+        }
+    }
 }
 
 #[cfg(test)]
 mod tests {
     use ahash::HashMap;
+    use dyn_type::DateTimeFormats;
     use ir_common::expr_parse::str_to_expr_pb;
 
     use super::*;
@@ -995,4 +1084,153 @@ mod tests {
             assert_eq!(eval.eval::<_, Vertices>(Some(&ctxt)).unwrap(), expected);
         }
     }
+
+    fn prepare_context_with_date() -> Vertices {
+        let map1: HashMap<NameOrId, Object> = vec![
+            (
+                NameOrId::from("date1".to_string()),
+                (DateTimeFormats::from_str("2020-08-08").unwrap()).into(),
+            ),
+            (
+                NameOrId::from("date2".to_string()),
+                chrono::NaiveDate::from_ymd_opt(2020, 8, 8)
+                    .unwrap()
+                    .into(),
+            ),
+            (
+                NameOrId::from("time1".to_string()),
+                (DateTimeFormats::from_str("10:11:12.100").unwrap()).into(),
+            ),
+            (
+                NameOrId::from("time2".to_string()),
+                chrono::NaiveTime::from_hms_milli_opt(10, 11, 12, 100)
+                    .unwrap()
+                    .into(),
+            ),
+            (
+                NameOrId::from("datetime1".to_string()),
+                (DateTimeFormats::from_str("2020-08-08T23:11:12.100-11:00").unwrap()).into(),
+            ),
+            (
+                NameOrId::from("datetime2".to_string()),
+                (DateTimeFormats::from_str("2020-08-09 10:11:12.100").unwrap()).into(),
+            ),
+            (
+                NameOrId::from("datetime3".to_string()),
+                chrono::NaiveDateTime::from_timestamp_millis(1602324610100)
+                    .unwrap()
+                    .into(),
+            ), // 2020-10-10 10:10:10
+        ]
+        .into_iter()
+        .collect();
+        Vertices { vec: vec![Vertex::new(1, Some(9.into()), DynDetails::new(map1))] }
+    }
+
+    fn prepare_extract(expr_str: &str, interval: common_pb::extract::Interval) -> common_pb::Expression {
+        let mut operators = str_to_expr_pb(expr_str.to_string())
+            .unwrap()
+            .operators;
+        let extract_opr = common_pb::ExprOpr {
+            node_type: None,
+            item: Some(common_pb::expr_opr::Item::Extract(common_pb::Extract {
+                interval: interval as i32,
+            })),
+        };
+        operators.push(extract_opr);
+        common_pb::Expression { operators }
+    }
+
+    #[test]
+    fn test_eval_extract() {
+        let ctxt = prepare_context_with_date();
+        let cases = vec![
+            // date1: "2020-08-08"
+            prepare_extract("@0.date1", common_pb::extract::Interval::Year),
+            prepare_extract("@0.date1", common_pb::extract::Interval::Month),
+            prepare_extract("@0.date1", common_pb::extract::Interval::Day),
+            // date2: 20200808
+            prepare_extract("@0.date2", common_pb::extract::Interval::Year),
+            prepare_extract("@0.date2", common_pb::extract::Interval::Month),
+            prepare_extract("@0.date2", common_pb::extract::Interval::Day),
+            // time1: "10:11:12.100"
+            prepare_extract("@0.time1", common_pb::extract::Interval::Hour),
+            prepare_extract("@0.time1", common_pb::extract::Interval::Minute),
+            prepare_extract("@0.time1", common_pb::extract::Interval::Second),
+            prepare_extract("@0.time1", common_pb::extract::Interval::Millisecond),
+            // time2: 101112100
+            prepare_extract("@0.time2", common_pb::extract::Interval::Hour),
+            prepare_extract("@0.time2", common_pb::extract::Interval::Minute),
+            prepare_extract("@0.time2", common_pb::extract::Interval::Second),
+            prepare_extract("@0.time2", common_pb::extract::Interval::Millisecond),
+            // datetime1: "2020-08-08T23:11:12.100-11:00"
+            prepare_extract("@0.datetime1", common_pb::extract::Interval::Year),
+            prepare_extract("@0.datetime1", common_pb::extract::Interval::Month),
+            prepare_extract("@0.datetime1", common_pb::extract::Interval::Day),
+            prepare_extract("@0.datetime1", common_pb::extract::Interval::Hour),
+            prepare_extract("@0.datetime1", common_pb::extract::Interval::Minute),
+            prepare_extract("@0.datetime1", common_pb::extract::Interval::Second),
+            prepare_extract("@0.datetime1", common_pb::extract::Interval::Millisecond),
+            // datetime2: "2020-08-09 10:11:12.100"
+            prepare_extract("@0.datetime2", common_pb::extract::Interval::Year),
+            prepare_extract("@0.datetime2", common_pb::extract::Interval::Month),
+            prepare_extract("@0.datetime2", common_pb::extract::Interval::Day),
+            prepare_extract("@0.datetime2", common_pb::extract::Interval::Hour),
+            prepare_extract("@0.datetime2", common_pb::extract::Interval::Minute),
+            prepare_extract("@0.datetime2", common_pb::extract::Interval::Second),
+            prepare_extract("@0.datetime2", common_pb::extract::Interval::Millisecond),
+            // datetime3: 1602324610100, i.e., 2020-10-10 10:10:10
+            prepare_extract("@0.datetime3", common_pb::extract::Interval::Year),
+            prepare_extract("@0.datetime3", common_pb::extract::Interval::Month),
+            prepare_extract("@0.datetime3", common_pb::extract::Interval::Day),
+            prepare_extract("@0.datetime3", common_pb::extract::Interval::Hour),
+            prepare_extract("@0.datetime3", common_pb::extract::Interval::Minute),
+            prepare_extract("@0.datetime3", common_pb::extract::Interval::Second),
+            prepare_extract("@0.datetime3", common_pb::extract::Interval::Millisecond),
+        ];
+
+        let expected = vec![
+            object!(2020),
+            object!(8),
+            object!(8),
+            object!(2020),
+            object!(8),
+            object!(8),
+            object!(10),
+            object!(11),
+            object!(12),
+            object!(100),
+            object!(10),
+            object!(11),
+            object!(12),
+            object!(100),
+            object!(2020),
+            object!(8),
+            object!(8),
+            object!(23),
+            object!(11),
+            object!(12),
+            object!(100),
+            object!(2020),
+            object!(8),
+            object!(9),
+            object!(10),
+            object!(11),
+            object!(12),
+            object!(100),
+            object!(2020),
+            object!(10),
+            object!(10),
+            object!(10),
+            object!(10),
+            object!(10),
+            object!(100),
+        ];
+
+        for (case, expected) in cases.into_iter().zip(expected.into_iter()) {
+            let eval = Evaluator::try_from(case).unwrap();
+            println!("{:?}", eval.eval::<_, Vertices>(Some(&ctxt)).unwrap());
+            assert_eq!(eval.eval::<_, Vertices>(Some(&ctxt)).unwrap(), expected);
+        }
+    }
 }
diff --git a/interactive_engine/executor/ir/proto/common.proto b/interactive_engine/executor/ir/proto/common.proto
index 1c87785c8a53..034c6581f74a 100644
--- a/interactive_engine/executor/ir/proto/common.proto
+++ b/interactive_engine/executor/ir/proto/common.proto
@@ -55,6 +55,21 @@ message NameOrId {
   }
 }
 
+message Date32 {
+  // int32 days since 1970-01-01
+  int32 item = 1;
+}
+
+message Time32 {
+  // int32 milliseconds past midnight
+  int32 item = 1;
+}
+
+message Timestamp {
+  // int64 milliseconds since 1970-01-01 00:00:00.000000 (in an unspecified timezone)
+  int64 item = 1;
+}
+
 message Value {
   oneof item {
     bool  boolean     = 2;
@@ -69,6 +84,9 @@ message Value {
     StringArray str_array    = 11;
     PairArray pair_array     = 12;
     None  none               = 13;
+    Date32 date              = 14;
+    Time32 time              = 15;
+    Timestamp timestamp      = 16;
   }
 }
 
@@ -85,5 +103,7 @@ enum DataType {
   STRING_ARRAY = 9;
   PAIR_ARRAY = 10;
   NONE = 11;
-  DATE = 12; // todo: define `DATE` as message structure which contains date_format 
+  DATE32 = 12;
+  TIME32 = 13;
+  TIMESTAMP = 14;
 }
diff --git a/interactive_engine/executor/ir/proto/expr.proto b/interactive_engine/executor/ir/proto/expr.proto
index fcaae8e745f9..afb6fe8c845f 100644
--- a/interactive_engine/executor/ir/proto/expr.proto
+++ b/interactive_engine/executor/ir/proto/expr.proto
@@ -149,10 +149,9 @@ message Extract {
     HOUR = 3;
     MINUTE = 4;
     SECOND = 5;
+    MILLISECOND = 6;
   }
-
   Interval interval = 1;
-  Expression data_time = 2;
 }
 
 // An operator of expression is one of Logical, Arithmetic, Const and Variable.
diff --git a/interactive_engine/executor/ir/runtime/src/process/operator/map/project.rs b/interactive_engine/executor/ir/runtime/src/process/operator/map/project.rs
index 8fb38c81cad1..d84ab27a0138 100644
--- a/interactive_engine/executor/ir/runtime/src/process/operator/map/project.rs
+++ b/interactive_engine/executor/ir/runtime/src/process/operator/map/project.rs
@@ -170,7 +170,7 @@ mod tests {
     use dyn_type::Object;
     use graph_proxy::apis::{DynDetails, GraphElement, Vertex};
     use ir_common::expr_parse::str_to_expr_pb;
-    use ir_common::generated::physical as pb;
+    use ir_common::generated::{common as common_pb, physical as pb};
     use ir_common::NameOrId;
     use pegasus::api::{Map, Sink};
     use pegasus::result::ResultStream;
@@ -181,7 +181,8 @@ mod tests {
     use crate::process::operator::map::FilterMapFuncGen;
     use crate::process::operator::tests::{
         init_source, init_source_with_multi_tags, init_source_with_tag, init_vertex1, init_vertex2,
-        to_expr_var_pb, to_expr_vars_pb, PERSON_LABEL, TAG_A, TAG_B, TAG_C, TAG_D, TAG_E,
+        to_expr_var_pb, to_expr_vars_pb, to_var_pb, PERSON_LABEL, TAG_A, TAG_B, TAG_C, TAG_D, TAG_E, TAG_F,
+        TAG_G,
     };
     use crate::process::record::Record;
 
@@ -815,4 +816,112 @@ mod tests {
             assert!(true)
         }
     }
+
+    #[test]
+    fn project_extract_from_date_test() {
+        // 2010-01-02
+        let date_obj = Object::DateFormat(dyn_type::DateTimeFormats::from_date32(20100102).unwrap());
+        // 12:34:56.100
+        let time_obj = Object::DateFormat(dyn_type::DateTimeFormats::from_time32(123456100).unwrap());
+        // 2020-10-10 10:10:10
+        let datetime_obj =
+            Object::DateFormat(dyn_type::DateTimeFormats::from_timestamp_millis(1602324610100).unwrap());
+        let mut r1 = Record::new(date_obj.clone(), Some(TAG_A.into()));
+        r1.append(time_obj, Some(TAG_B.into()));
+        r1.append(datetime_obj, Some(TAG_C.into()));
+
+        let extract_date_year_opr = common_pb::ExprOpr {
+            node_type: None,
+            item: Some(common_pb::expr_opr::Item::Extract(common_pb::Extract {
+                interval: common_pb::extract::Interval::Year as i32,
+            })),
+        };
+
+        let extract_time_hour_opr = common_pb::ExprOpr {
+            node_type: None,
+            item: Some(common_pb::expr_opr::Item::Extract(common_pb::Extract {
+                interval: common_pb::extract::Interval::Hour as i32,
+            })),
+        };
+
+        let extract_datetime_month_opr = common_pb::ExprOpr {
+            node_type: None,
+            item: Some(common_pb::expr_opr::Item::Extract(common_pb::Extract {
+                interval: common_pb::extract::Interval::Month as i32,
+            })),
+        };
+
+        let extract_datetime_minute_opr = common_pb::ExprOpr {
+            node_type: None,
+            item: Some(common_pb::expr_opr::Item::Extract(common_pb::Extract {
+                interval: common_pb::extract::Interval::Minute as i32,
+            })),
+        };
+
+        let tag_a_opr = common_pb::ExprOpr {
+            node_type: None,
+            item: Some(common_pb::expr_opr::Item::Var(to_var_pb(Some(TAG_A.into()), None))),
+        };
+        let tag_b_opr = common_pb::ExprOpr {
+            node_type: None,
+            item: Some(common_pb::expr_opr::Item::Var(to_var_pb(Some(TAG_B.into()), None))),
+        };
+        let tag_c_opr = common_pb::ExprOpr {
+            node_type: None,
+            item: Some(common_pb::expr_opr::Item::Var(to_var_pb(Some(TAG_C.into()), None))),
+        };
+
+        let expr1 = common_pb::Expression { operators: vec![extract_date_year_opr, tag_a_opr] };
+
+        let expr2 = common_pb::Expression { operators: vec![extract_time_hour_opr, tag_b_opr] };
+
+        let expr3 =
+            common_pb::Expression { operators: vec![extract_datetime_month_opr, tag_c_opr.clone()] };
+
+        let expr4 =
+            common_pb::Expression { operators: vec![extract_datetime_minute_opr, tag_c_opr.clone()] };
+
+        let source = vec![r1];
+        // To project: year of 2010-01-02, hour of 12:34:56.100, month of 2020-10-10 10:10:10, and minute of 2020-10-10 10:10:10
+        let project_opr_pb = pb::Project {
+            mappings: vec![
+                pb::project::ExprAlias { expr: Some(expr1), alias: Some(TAG_D.into()) },
+                pb::project::ExprAlias { expr: Some(expr2), alias: Some(TAG_E.into()) },
+                pb::project::ExprAlias { expr: Some(expr3), alias: Some(TAG_F.into()) },
+                pb::project::ExprAlias { expr: Some(expr4), alias: Some(TAG_G.into()) },
+            ],
+            is_append: true,
+        };
+
+        let mut result = project_test(source, project_opr_pb);
+        let expected_results = vec![object!(2010), object!(12), object!(10), object!(10)];
+        let mut results = vec![];
+        while let Some(Ok(res)) = result.next() {
+            let year = res
+                .get(Some(TAG_D))
+                .unwrap()
+                .as_object()
+                .unwrap();
+            let hour = res
+                .get(Some(TAG_E))
+                .unwrap()
+                .as_object()
+                .unwrap();
+            let month = res
+                .get(Some(TAG_F))
+                .unwrap()
+                .as_object()
+                .unwrap();
+            let minute = res
+                .get(Some(TAG_G))
+                .unwrap()
+                .as_object()
+                .unwrap();
+            results.push(year.clone());
+            results.push(hour.clone());
+            results.push(month.clone());
+            results.push(minute.clone());
+        }
+        assert_eq!(results, expected_results);
+    }
 }
diff --git a/interactive_engine/executor/ir/runtime/src/process/operator/mod.rs b/interactive_engine/executor/ir/runtime/src/process/operator/mod.rs
index 50486014d7d7..7a4496e0697e 100644
--- a/interactive_engine/executor/ir/runtime/src/process/operator/mod.rs
+++ b/interactive_engine/executor/ir/runtime/src/process/operator/mod.rs
@@ -187,6 +187,8 @@ pub(crate) mod tests {
     pub const TAG_C: KeyId = 2;
     pub const TAG_D: KeyId = 3;
     pub const TAG_E: KeyId = 4;
+    pub const TAG_F: KeyId = 5;
+    pub const TAG_G: KeyId = 6;
 
     pub const PERSON_LABEL: LabelId = 0;
 
diff --git a/interactive_engine/executor/ir/runtime/src/router.rs b/interactive_engine/executor/ir/runtime/src/router.rs
index c7a05cb71f93..be1ff3c83345 100644
--- a/interactive_engine/executor/ir/runtime/src/router.rs
+++ b/interactive_engine/executor/ir/runtime/src/router.rs
@@ -57,11 +57,10 @@ impl<P: PartitionInfo, C: ClusterInfo> Router for DefaultRouter<P, C> {
     type C = C;
     fn route(&self, data: PartitionKeyId) -> GraphProxyResult<WorkerId> {
         let partition_id = self.partition_info.get_partition_id(&data)?;
-        debug!("route partition id: {:?}", partition_id);
         let server_id = self
             .partition_info
             .get_server_id(partition_id)?;
-        debug!("route server id: {:?}", partition_id);
+        trace!("route partition id {:?}, server id: {:?}", partition_id, server_id);
         let servers_num = self.cluster_info.get_server_num()?;
         let magic_num = (data as u32) / servers_num;
         let workers_num = self.cluster_info.get_local_worker_num()?;


Test patch:
diff --git a/flex/tests/hqps/match_query.h b/flex/tests/hqps/match_query.h
index 6b424c99151d..e41c81a650d6 100644
--- a/flex/tests/hqps/match_query.h
+++ b/flex/tests/hqps/match_query.h
@@ -644,7 +644,6 @@ struct MatchQuery11Expr1 {
  private:
 };
 
-// Auto generated query class definition
 class MatchQuery11 : public HqpsAppBase<gs::MutableCSRInterface> {
  public:
   using Engine = SyncEngine<gs::MutableCSRInterface>;
@@ -744,5 +743,63 @@ class MatchQuery11 : public HqpsAppBase<gs::MutableCSRInterface> {
   }
 };
 
+struct MatchQuery12Expr0 {
+ public:
+  using result_t = bool;
+  MatchQuery12Expr0() {}
+
+  inline auto operator()(Date var0) const {
+    return gs::DateTimeExtractor<Interval::MONTH>::extract(var0) == 7;
+  }
+
+ private:
+};
+
+struct MatchQuery12Expr1 {
+ public:
+  using result_t = int64_t;
+  MatchQuery12Expr1() {}
+
+  inline auto operator()(Date var1) const {
+    return gs::DateTimeExtractor<Interval::MONTH>::extract(var1);
+  }
+
+ private:
+};
+
+class MatchQuery12 : public HqpsAppBase<gs::MutableCSRInterface> {
+ public:
+  using Engine = SyncEngine<gs::MutableCSRInterface>;
+  using label_id_t = typename gs::MutableCSRInterface::label_id_t;
+  using vertex_id_t = typename gs::MutableCSRInterface::vertex_id_t;
+  // Query function for query class
+  results::CollectiveResults Query(const gs::MutableCSRInterface& graph) const {
+    auto ctx0 = Engine::template ScanVertex<gs::AppendOpt::Persist>(
+        graph, 1, Filter<TruePredicate>());
+
+    auto ctx1 = Engine::Project<PROJ_TO_NEW>(
+        graph, std::move(ctx0),
+        std::tuple{gs::make_mapper_with_variable<INPUT_COL_ID(0)>(
+            gs::PropertySelector<Date>("birthday"))});
+    auto expr0 = gs::make_filter(MatchQuery12Expr0(),
+                                 gs::PropertySelector<Date>("None"));
+    auto ctx2 = Engine::template Select<INPUT_COL_ID(0)>(graph, std::move(ctx1),
+                                                         std::move(expr0));
+
+    auto ctx3 = Engine::Project<PROJ_TO_NEW>(
+        graph, std::move(ctx2),
+        std::tuple{gs::make_mapper_with_expr<0>(
+            MatchQuery12Expr1(), gs::PropertySelector<Date>("None"))});
+    return Engine::Sink(ctx3, std::array<int32_t, 1>{2});
+  }
+  // Wrapper query function for query class
+  results::CollectiveResults Query(const gs::MutableCSRInterface& graph,
+                                   Decoder& decoder) const override {
+    // decoding params from decoder, and call real query func
+
+    return Query(graph);
+  }
+};
+
 }  // namespace gs
 #endif  // TESTS_HQPS_MATCH_QUERY_H_
\ No newline at end of file
diff --git a/flex/tests/hqps/query_test.cc b/flex/tests/hqps/query_test.cc
index f59c5a73e8d9..8351574c699e 100644
--- a/flex/tests/hqps/query_test.cc
+++ b/flex/tests/hqps/query_test.cc
@@ -211,7 +211,20 @@ int main(int argc, char** argv) {
 
     gs::MutableCSRInterface graph(sess);
     query.Query(graph, input);
-    LOG(INFO) << "Finish MatchQuery10 test";
+    LOG(INFO) << "Finish MatchQuery11 test";
+  }
+
+  {
+    gs::MatchQuery12 query;
+    std::vector<char> encoder_array;
+    gs::Encoder input_encoder(encoder_array);
+    std::vector<char> output_array;
+    gs::Encoder output(output_array);
+    gs::Decoder input(encoder_array.data(), encoder_array.size());
+
+    gs::MutableCSRInterface graph(sess);
+    query.Query(graph, input);
+    LOG(INFO) << "Finish MatchQuery12 test";
   }
 
   LOG(INFO) << "Finish context test.";
diff --git a/interactive_engine/compiler/src/test/resources/config/modern/graph.yaml b/interactive_engine/compiler/src/test/resources/config/modern/graph.yaml
index 23df4e758bde..7da7efa31252 100644
--- a/interactive_engine/compiler/src/test/resources/config/modern/graph.yaml
+++ b/interactive_engine/compiler/src/test/resources/config/modern/graph.yaml
@@ -46,8 +46,7 @@ schema:
         - property_id: 3
           property_name: creationDate
           property_type:
-            date:
-              date_format: DF_YYYY_MM_DD
+            primitive_type: DT_DATE32
       primary_keys:
         - id
   edge_types: