Repository: alibaba/GraphScope (language: python)

Issue:
[BUG] `COUNT DISTINCT` is not supported on Edge
```cypher
MATCH(a)-[b]-(c)
return COUNT (DISTINCT b);
```



Discussion / hints:

Fix patch:
diff --git a/.github/workflows/hqps-db-ci.yml b/.github/workflows/hqps-db-ci.yml
index abf02e3a8840..786973a39c8c 100644
--- a/.github/workflows/hqps-db-ci.yml
+++ b/.github/workflows/hqps-db-ci.yml
@@ -98,6 +98,9 @@ jobs:
         mkdir -p ${INTERACTIVE_WORKSPACE}/data/movies
         cp ${GS_TEST_DIR}/flex/movies/movies_schema.yaml ${INTERACTIVE_WORKSPACE}/data/movies/graph.yaml
         cp ${GS_TEST_DIR}/flex/movies/movies_import.yaml ${INTERACTIVE_WORKSPACE}/data/movies/import.yaml
+        mkdir -p ${INTERACTIVE_WORKSPACE}/data/graph_algo
+        cp ${GITHUB_WORKSPACE}/flex/tests/interactive/graph_algo_test.yaml ${INTERACTIVE_WORKSPACE}/data/graph_algo/graph.yaml
+        cp ${GITHUB_WORKSPACE}/flex/interactive/examples/graph_algo/import.yaml ${INTERACTIVE_WORKSPACE}/data/graph_algo/import.yaml
 
         # load graph
         cd ${GITHUB_WORKSPACE}/flex/build
@@ -105,6 +108,8 @@ jobs:
         GLOG_v=10 ./bin/bulk_loader -g ${INTERACTIVE_WORKSPACE}/data/ldbc/graph.yaml -l ${INTERACTIVE_WORKSPACE}/data/ldbc/import.yaml -d ${INTERACTIVE_WORKSPACE}/data/ldbc/indices/
         export FLEX_DATA_DIR=../interactive/examples/movies
         GLOG_v=10 ./bin/bulk_loader -g ${INTERACTIVE_WORKSPACE}/data/movies/graph.yaml -l ${INTERACTIVE_WORKSPACE}/data/movies/import.yaml -d ${INTERACTIVE_WORKSPACE}/data/movies/indices/
+        export FLEX_DATA_DIR=../interactive/examples/graph_algo
+        GLOG_v=10 ./bin/bulk_loader -g ${INTERACTIVE_WORKSPACE}/data/graph_algo/graph.yaml -l ${INTERACTIVE_WORKSPACE}/data/graph_algo/import.yaml -d ${INTERACTIVE_WORKSPACE}/data/graph_algo/indices/
 
     - name: Test HQPS admin http service
       env: 
@@ -191,4 +196,17 @@ jobs:
         bash hqps_cypher_test.sh ${INTERACTIVE_WORKSPACE} movies \
           ${GITHUB_WORKSPACE}/flex/tests/hqps/engine_config_test.yaml
 
+    - name: Run End-to-End cypher adhoc graph_algo query test
+      env:
+        GS_TEST_DIR: ${{ github.workspace }}/gstest
+        HOME : /home/graphscope/
+        INTERACTIVE_WORKSPACE: /tmp/interactive_workspace
+      run: |
+        cd ${GITHUB_WORKSPACE}/flex/tests/hqps/
+        export ENGINE_TYPE=hiactor
+        # change the default_graph config in ${GS_TEST_DIR}/flex/ldbc-sf01-long-date/engine_config.yaml to graph_algo
+        sed -i 's/default_graph: movies/default_graph: graph_algo/g' ./engine_config_test.yaml
+        bash hqps_cypher_test.sh ${INTERACTIVE_WORKSPACE} graph_algo \
+          ${GITHUB_WORKSPACE}/flex/tests/hqps/engine_config_test.yaml
+
 
diff --git a/docs/flex/interactive/custom_graph_data.md b/docs/flex/interactive/custom_graph_data.md
index 0834a07f91c8..c48bd15c087d 100644
--- a/docs/flex/interactive/custom_graph_data.md
+++ b/docs/flex/interactive/custom_graph_data.md
@@ -206,4 +206,9 @@ bin/gs_interactive service start -g movies
 Note: Stopping a prior service is necessary to start a new service with an alternative graph.
 
 
-Now you can move to [Stored Procedure](./stored_procedures) to explore querying via stored procedures.
\ No newline at end of file
+Now you can move to [Stored Procedure](./stored_procedures) to explore querying via stored procedures.
+
+
+## Try other graphs
+
+In addition to `movies` graph, we have also prepared the `graph_algo` graph. You can find the raw CSV files, graph.yaml, and import.yaml in the `./examples/graph_algo/` directory. You can import the `graph_algo` graph just like importing the `movies` graph.
\ No newline at end of file
diff --git a/flex/codegen/src/codegen_utils.h b/flex/codegen/src/codegen_utils.h
index 33e560becd6f..ba0cf9c310e6 100644
--- a/flex/codegen/src/codegen_utils.h
+++ b/flex/codegen/src/codegen_utils.h
@@ -200,9 +200,17 @@ static codegen::ParamConst variable_to_param_const(const common::Variable& var,
                                                    BuildingContext& ctx) {
   codegen::ParamConst param_const;
   if (var.has_property()) {
-    param_const.var_name = var.property().key().name();
-    param_const.type =
-        common_data_type_pb_2_data_type(var.node_type().data_type());
+    auto& var_property = var.property();
+    if (var_property.has_label()) {
+      param_const.var_name = "label";
+      param_const.type = codegen::DataType::kLabelId;
+    } else if (var_property.has_key()) {
+      param_const.var_name = var.property().key().name();
+      param_const.type =
+          common_data_type_pb_2_data_type(var.node_type().data_type());
+    } else {
+      LOG(FATAL) << "Unexpected property type";
+    }
   } else if (var.has_tag()) {
     // check is vertex or is edge from node_type
     if (var.has_node_type()) {
diff --git a/flex/codegen/src/hqps/hqps_expr_builder.h b/flex/codegen/src/hqps/hqps_expr_builder.h
index b8ad4e408bed..5e37b1c2a108 100644
--- a/flex/codegen/src/hqps/hqps_expr_builder.h
+++ b/flex/codegen/src/hqps/hqps_expr_builder.h
@@ -62,9 +62,19 @@ static std::pair<int32_t, std::string> variable_to_tag_id_property_selector(
   }
   int real_tag_ind = ctx.GetTagInd(tag_id);
   if (var.has_property()) {
-    std::string prop_name = var.property().key().name();
-    std::string prop_type = data_type_2_string(
-        common_data_type_pb_2_data_type(var.node_type().data_type()));
+    auto var_property = var.property();
+    std::string prop_name, prop_type;
+    if (var_property.has_label()) {
+      prop_name = "label";
+      prop_type = data_type_2_string(codegen::DataType::kLabelId);
+    } else if (var_property.has_key()) {
+      prop_name = var.property().key().name();
+      prop_type = data_type_2_string(
+          common_data_type_pb_2_data_type(var.node_type().data_type()));
+    } else {
+      LOG(FATAL) << "Unexpected property type: " << var.DebugString();
+    }
+
     boost::format formater(PROPERTY_SELECTOR);
     formater % prop_type % prop_name;
 
@@ -267,28 +277,7 @@ class ExprBuilder {
     VLOG(10) << "Adding expr of size: " << size;
     for (auto i = 0; i < size;) {
       auto expr = expr_ops[i];
-      if (expr.has_var() && expr.var().property().has_label()) {
-        VLOG(10) << "Found label in expr, skip this check";
-        int j = i;
-        for (; j < size; ++j) {
-          if (expr_ops[j].item_case() == common::ExprOpr::kBrace &&
-              expr_ops[j].brace() ==
-                  common::ExprOpr::Brace::ExprOpr_Brace_RIGHT_BRACE) {
-            VLOG(10) << "Found right brace at ind: " << j
-                     << ", started at: " << i;
-            AddExprOpr(std::string("true"));
-            AddExprOpr(expr_ops[j]);
-            i = j + 1;
-            break;
-          }
-        }
-        if (j == size) {
-          LOG(WARNING) << "no right brace found" << j << "size: " << size;
-          // just add true, since the current expresion has no other expr_ops
-          AddExprOpr(std::string("true"));
-          i = j;
-        }
-      } else if (expr.has_extract()) {
+      if (expr.has_extract()) {
         // special case for extract
         auto extract = expr.extract();
         if (i + 1 >= size) {
diff --git a/flex/codegen/src/hqps/hqps_sort_builder.h b/flex/codegen/src/hqps/hqps_sort_builder.h
index 58824266fdfb..26ba2b5d525f 100644
--- a/flex/codegen/src/hqps/hqps_sort_builder.h
+++ b/flex/codegen/src/hqps/hqps_sort_builder.h
@@ -54,10 +54,26 @@ std::string sort_pair_pb_to_order_pair(
   auto real_key_tag_id = ctx.GetTagInd(pair.key().tag().id());
   CHECK(pair.key().node_type().type_case() == common::IrDataType::kDataType)
       << "sort ordering pair only support primitive";
-  sort_prop_type =
-      single_common_data_type_pb_2_str(pair.key().node_type().data_type());
-  // the type of sorted property.
-  sort_prop_name = pair.key().property().key().name();
+  if (pair.key().has_property()) {
+    auto sort_property = pair.key().property();
+    if (sort_property.has_label()) {
+      sort_prop_name = "label";
+      sort_prop_type = data_type_2_string(codegen::DataType::kLabelId);
+    } else if (sort_property.has_key()) {
+      sort_prop_name = pair.key().property().key().name();
+      sort_prop_type =
+          single_common_data_type_pb_2_str(pair.key().node_type().data_type());
+    } else {
+      throw std::runtime_error("Unknown sort property type" +
+                               sort_property.DebugString());
+    }
+  } else if (pair.key().has_tag()) {
+    sort_prop_name = "";
+    sort_prop_type =
+        single_common_data_type_pb_2_str(pair.key().node_type().data_type());
+  } else {
+    throw std::runtime_error("Unknown sort property type" + pair.DebugString());
+  }
 
   boost::format formater(ORDERING_PAIR_TEMPLATE_STR);
   formater % sort_order_str % real_key_tag_id % sort_prop_type % sort_prop_name;
diff --git a/flex/engines/hqps_db/core/operator/edge_expand.h b/flex/engines/hqps_db/core/operator/edge_expand.h
index c22428519d10..1cfd6ec246ce 100644
--- a/flex/engines/hqps_db/core/operator/edge_expand.h
+++ b/flex/engines/hqps_db/core/operator/edge_expand.h
@@ -918,13 +918,17 @@ class EdgeExpand {
         auto cur_src_label = label_vec[i];
         // for all this type of vertices, emplace back subgraph
         auto& real_sub_graphs = label_to_subgraphs[cur_src_label];
-        for (auto j = 0; j < real_sub_graphs.size(); ++j) {
-          for (auto k = 0; k < vertices.size(); ++k) {
-            if (label_indices[k] != i) {
-              continue;
-            }
-            grouped_edge_iters[k].emplace_back(
-                real_sub_graphs[j].get_edges(vertices[k]));
+        for (auto k = 0; k < vertices.size(); ++k) {
+          if (label_indices[k] != i) {
+            continue;
+          }
+
+          for (auto j = 0; j < real_sub_graphs.size(); ++j) {
+            auto cur_edges = real_sub_graphs[j].get_edges(vertices[k]);
+            VLOG(10) << "vid index: " << k << " label ind: " << i
+                     << " cur label: " << gs::to_string(cur_src_label)
+                     << " real subgraphs:[" << j << "]: " << cur_edges.Size();
+            grouped_edge_iters[k].emplace_back(cur_edges);
           }
         }
       }
@@ -1306,7 +1310,8 @@ class EdgeExpand {
     auto prop_names = state.prop_names_;
     auto& cur_set = state.cur_vertex_set_;
     VLOG(10) << "[EdgeExpandESingleLabelSrcImpl]" << prop_names.size()
-             << ", set size: " << cur_set.Size();
+             << ", set size: " << cur_set.Size()
+             << ", direction: " << gs::to_string(state.direction_);
     for (auto v : prop_names) {
       VLOG(10) << "prop:" << v;
     }
diff --git a/flex/engines/hqps_db/core/operator/project.h b/flex/engines/hqps_db/core/operator/project.h
index a2b48655761c..a314b3a5cd07 100644
--- a/flex/engines/hqps_db/core/operator/project.h
+++ b/flex/engines/hqps_db/core/operator/project.h
@@ -298,6 +298,7 @@ class ProjectOp {
   static auto apply_single_project_impl(
       const GRAPH_INTERFACE& graph, NODE_T& node, const std::string& prop_name,
       const std::vector<size_t>& repeat_array) {
+    LOG(INFO) << "[Single project on labelKey]" << demangle(node);
     auto size = node.Size();
     auto label_vec = node.GetLabelVec();
     std::vector<T> res_prop_vec;
diff --git a/flex/engines/hqps_db/core/operator/sink.h b/flex/engines/hqps_db/core/operator/sink.h
index 3321819318b9..64bafef763da 100644
--- a/flex/engines/hqps_db/core/operator/sink.h
+++ b/flex/engines/hqps_db/core/operator/sink.h
@@ -208,6 +208,12 @@ void set_any_to_common_value(const Any& any, common::Value* value) {
 }
 
 // set edge value
+void set_edge_property(results::Edge* edge, const std::string& prop_name,
+                       const std::tuple<int32_t>& value) {
+  auto prop = edge->add_properties();
+  prop->mutable_value()->set_i64(std::get<0>(value));
+  prop->mutable_key()->set_name(prop_name);
+}
 
 void set_edge_property(results::Edge* edge, const std::string& prop_name,
                        const std::tuple<int64_t>& value) {
@@ -240,8 +246,17 @@ void set_edge_property(results::Edge* edge, const std::string& prop_name,
   prop->mutable_key()->set_name(prop_name);
 }
 
+// set grape::EmptyType
+void set_edge_property(results::Edge* edge, const std::string& prop_name,
+                       const std::tuple<grape::EmptyType>& value) {
+  // just skip
+}
+
 void set_edge_property(results::Edge* edge, const std::string& prop_name,
                        const Any& value) {
+  if (value.type == PropertyType::kEmpty) {
+    return;
+  }
   auto prop = edge->add_properties();
   set_any_to_common_value(value, prop->mutable_value());
   prop->mutable_key()->set_name(prop_name);
@@ -250,6 +265,8 @@ void set_edge_property(results::Edge* edge, const std::string& prop_name,
 template <typename GRAPH_INTERFACE>
 class SinkOp {
  public:
+  using vid_t = typename GRAPH_INTERFACE::vertex_id_t;
+  using label_id_t = typename GRAPH_INTERFACE::label_id_t;
   // sink current context to results_pb defined in results.proto
   // return results::CollectiveResults
   template <typename CTX_HEAD_T, int cur_alias, int base_tag,
@@ -375,7 +392,7 @@ class SinkOp {
         new_col->mutable_name_or_id()->set_id(tag_id);
         auto vertex =
             new_col->mutable_entry()->mutable_element()->mutable_vertex();
-        vertex->set_id(vids[i]);
+        vertex->set_id(encode_unique_vertex_id(label, vids[i]));
         if (bitset.get_bit(i)) {
           label = labels[0];
         } else {
@@ -390,7 +407,7 @@ class SinkOp {
           if (column_ptr) {
             auto new_prop = vertex->add_properties();
             new_prop->mutable_key()->set_name(prop_names[label][j]);
-            set_any_to_common_value(column_ptr->get(i),
+            set_any_to_common_value(column_ptr->get(vids[i]),
                                     new_prop->mutable_value());
           }
         }
@@ -420,8 +437,7 @@ class SinkOp {
           new_col->mutable_name_or_id()->set_id(tag_id);
           auto vertex =
               new_col->mutable_entry()->mutable_element()->mutable_vertex();
-          vertex->set_id(vids[i]);
-          vertex->mutable_label()->set_id(label);
+          vertex->set_id(encode_unique_vertex_id(label, vids[i]));
           vertex->mutable_label()->set_id(label);
           // set properties.
           auto columns = column_ptrs[label];
@@ -431,7 +447,7 @@ class SinkOp {
             if (column_ptr) {
               auto new_prop = vertex->add_properties();
               new_prop->mutable_key()->set_name(prop_names[label][j]);
-              set_any_to_common_value(column_ptr->get(i),
+              set_any_to_common_value(column_ptr->get(vids[i]),
                                       new_prop->mutable_value());
             }
           }
@@ -466,16 +482,15 @@ class SinkOp {
         new_col->mutable_name_or_id()->set_id(tag_id);
         auto vertex =
             new_col->mutable_entry()->mutable_element()->mutable_vertex();
-        vertex->set_id(vids[i]);
+        vertex->set_id(encode_unique_vertex_id(label, vids[i]));
         vertex->mutable_label()->set_id(label);
         for (auto j = 0; j < column_ptrs.size(); ++j) {
           auto& column_ptr = column_ptrs[j];
           // Only set non-none properties.
           if (column_ptr) {
             auto new_prop = vertex->add_properties();
-            VLOG(10) << "col:" << j << "PropName: " << prop_names[j];
             new_prop->mutable_key()->set_name(prop_names[j]);
-            set_any_to_common_value(column_ptr->get(i),
+            set_any_to_common_value(column_ptr->get(vids[i]),
                                     new_prop->mutable_value());
           }
         }
@@ -499,7 +514,7 @@ class SinkOp {
           new_col->mutable_name_or_id()->set_id(tag_id);
           auto vertex =
               new_col->mutable_entry()->mutable_element()->mutable_vertex();
-          vertex->set_id(vids[i]);
+          vertex->set_id(encode_unique_vertex_id(label, vids[i]));
           vertex->mutable_label()->set_id(label);
           for (auto j = 0; j < column_ptrs.size(); ++j) {
             auto& column_ptr = column_ptrs[j];
@@ -507,7 +522,7 @@ class SinkOp {
             if (column_ptr) {
               auto new_prop = vertex->add_properties();
               new_prop->mutable_key()->set_name(prop_names[j]);
-              set_any_to_common_value(column_ptr->get(i),
+              set_any_to_common_value(column_ptr->get(vids[i]),
                                       new_prop->mutable_value());
             }
           }
@@ -736,7 +751,7 @@ class SinkOp {
     auto vertices_vec = vertex_set.GetVertices();
     auto labels_vec = vertex_set.GetLabels();
     auto& bitsets = vertex_set.GetBitsets();
-    CHECK(vertices_vec.size() == labels_vec.size());
+    CHECK(bitsets.size() == labels_vec.size());
     std::vector<std::vector<std::string>> prop_names;
     for (auto i = 0; i < labels_vec.size(); ++i) {
       prop_names.emplace_back(schema.get_vertex_property_names(labels_vec[i]));
@@ -754,6 +769,7 @@ class SinkOp {
     }
 
     label_t label;
+    size_t label_vec_ind;
     if (repeat_offsets.empty()) {
       CHECK(vertex_set.Size() == results_vec.results_size())
           << "size neq " << vertex_set.Size() << " "
@@ -770,25 +786,25 @@ class SinkOp {
         new_col->mutable_name_or_id()->set_id(tag_id);
         auto mutable_vertex =
             new_col->mutable_entry()->mutable_element()->mutable_vertex();
-        mutable_vertex->set_id(vertices_vec[i]);
-
         // todo: set properties.
         for (auto j = 0; j < bitsets.size(); ++j) {
           if (bitsets[j].get_bit(i)) {
             label = labels_vec[j];
+            label_vec_ind = j;
             break;
           }
         }
         mutable_vertex->mutable_label()->set_id(label);
+        mutable_vertex->set_id(encode_unique_vertex_id(label, vertices_vec[i]));
         // label must be set
-        auto columns = column_ptrs[label];
-        for (auto j = 0; j < columns.size(); ++j) {
-          auto& column_ptr = columns[j];
+        auto cur_column_ptrs = column_ptrs[label_vec_ind];
+        for (auto j = 0; j < cur_column_ptrs.size(); ++j) {
+          auto& column_ptr = cur_column_ptrs[j];
           // Only set non-none properties.
           if (column_ptr) {
             auto new_prop = mutable_vertex->add_properties();
-            new_prop->mutable_key()->set_name(prop_names[label][j]);
-            set_any_to_common_value(column_ptr->get(i),
+            new_prop->mutable_key()->set_name(prop_names[label_vec_ind][j]);
+            set_any_to_common_value(column_ptr->get(vertices_vec[i]),
                                     new_prop->mutable_value());
           }
         }
@@ -804,23 +820,25 @@ class SinkOp {
           new_col->mutable_name_or_id()->set_id(tag_id);
           auto mutable_vertex =
               new_col->mutable_entry()->mutable_element()->mutable_vertex();
-          mutable_vertex->set_id(vertices_vec[i]);
           for (auto j = 0; j < bitsets.size(); ++j) {
             if (bitsets[j].get_bit(i)) {
               label = labels_vec[j];
+              label_vec_ind = j;
               break;
             }
           }
           mutable_vertex->mutable_label()->set_id(label);
+          mutable_vertex->set_id(
+              encode_unique_vertex_id(label, vertices_vec[i]));
           // label must be set
-          auto columns = column_ptrs[label];
-          for (auto j = 0; j < columns.size(); ++j) {
-            auto& column_ptr = columns[j];
+          auto cur_column_ptrs = column_ptrs[label_vec_ind];
+          for (auto j = 0; j < cur_column_ptrs.size(); ++j) {
+            auto& column_ptr = cur_column_ptrs[j];
             // Only set non-none properties.
             if (column_ptr) {
               auto new_prop = mutable_vertex->add_properties();
-              new_prop->mutable_key()->set_name(prop_names[label][j]);
-              set_any_to_common_value(column_ptr->get(i),
+              new_prop->mutable_key()->set_name(prop_names[label_vec_ind][j]);
+              set_any_to_common_value(column_ptr->get(vertices_vec[i]),
                                       new_prop->mutable_value());
             }
           }
@@ -843,7 +861,6 @@ class SinkOp {
       auto iter = edge_set.begin();
       auto end_iter = edge_set.end();
       for (auto i = 0; i < results_vec.results_size(); ++i) {
-        // auto& row = results_vec[i];
         auto row = results_vec.mutable_results(i);
         CHECK(row->record().columns_size() == Ind)
             << "record column size: " << row->record().columns_size()
@@ -854,8 +871,17 @@ class SinkOp {
         auto mutable_edge =
             new_col->mutable_entry()->mutable_element()->mutable_edge();
         CHECK(iter != end_iter);
-        mutable_edge->set_src_id(iter.GetSrc());
-        mutable_edge->set_dst_id(iter.GetDst());
+        auto unique_edge_label = generate_edge_label_id(
+            iter.GetSrcLabel(), iter.GetDstLabel(), iter.GetEdgeLabel());
+        mutable_edge->mutable_label()->set_id(unique_edge_label);
+        mutable_edge->set_id(encode_unique_edge_id(unique_edge_label, i));
+        mutable_edge->set_src_id(
+            encode_unique_vertex_id(iter.GetSrcLabel(), iter.GetSrc()));
+        mutable_edge->mutable_src_label()->set_id(iter.GetSrcLabel());
+        mutable_edge->set_dst_id(
+            encode_unique_vertex_id(iter.GetDstLabel(), iter.GetDst()));
+        mutable_edge->mutable_dst_label()->set_id(iter.GetDstLabel());
+
         auto prop_names = iter.GetPropNames();
         if (prop_names.size() > 0) {
           set_edge_property(mutable_edge, prop_names[0], iter.GetData());
@@ -871,7 +897,6 @@ class SinkOp {
       for (auto i = 0; i < repeat_offsets.size(); ++i) {
         CHECK(iter != end_iter);
         for (auto j = 0; j < repeat_offsets[i]; ++j) {
-          // auto& row = results_vec[i];
           auto row = results_vec.mutable_results(cur_ind++);
           CHECK(row->record().columns_size() == Ind)
               << "record column size: " << row->record().columns_size()
@@ -881,8 +906,17 @@ class SinkOp {
           new_col->mutable_name_or_id()->set_id(tag_id);
           auto mutable_edge =
               new_col->mutable_entry()->mutable_element()->mutable_edge();
-          mutable_edge->set_src_id(iter.GetSrc());
-          mutable_edge->set_dst_id(iter.GetDst());
+          auto unique_edge_label = generate_edge_label_id(
+              iter.GetSrcLabel(), iter.GetDstLabel(), iter.GetEdgeLabel());
+          mutable_edge->mutable_label()->set_id(unique_edge_label);
+          mutable_edge->set_id(
+              encode_unique_edge_id(unique_edge_label, cur_ind - 1));
+          mutable_edge->set_src_id(
+              encode_unique_vertex_id(iter.GetSrcLabel(), iter.GetSrc()));
+          mutable_edge->mutable_src_label()->set_id(iter.GetSrcLabel());
+          mutable_edge->set_dst_id(
+              encode_unique_vertex_id(iter.GetDstLabel(), iter.GetDst()));
+          mutable_edge->mutable_dst_label()->set_id(iter.GetDstLabel());
           auto prop_names = iter.GetPropNames();
           if (prop_names.size() > 0) {
             set_edge_property(mutable_edge, prop_names[0], iter.GetData());
@@ -957,7 +991,38 @@ class SinkOp {
       mutable_path.add_path()->mutable_vertex()->set_id(vertices[i]);
     }
   }
-};  // namespace gs
+
+  static vid_t encode_unique_vertex_id(label_id_t label_id, vid_t vid) {
+    // encode label_id and vid to a unique vid
+    vid_t unique_vid = label_id;
+    static constexpr int num_bits = sizeof(vid_t) * 8 - sizeof(label_id_t) * 8;
+    unique_vid = unique_vid << num_bits;
+    unique_vid = unique_vid | vid;
+    return unique_vid;
+  }
+
+  static int64_t encode_unique_edge_id(label_id_t label_id, size_t index) {
+    // encode label_id and vid to a unique vid
+    int64_t unique_edge_id = label_id;
+    static constexpr int num_bits =
+        sizeof(int64_t) * 8 - sizeof(label_id_t) * 8;
+    unique_edge_id = unique_edge_id << num_bits;
+    unique_edge_id = unique_edge_id | index;
+    return unique_edge_id;
+  }
+
+  static label_id_t generate_edge_label_id(label_id_t src_label_id,
+                                           label_id_t dst_label_id,
+                                           label_id_t edge_label_id) {
+    label_id_t unique_edge_label_id = src_label_id;
+    static constexpr int num_bits = sizeof(label_id_t) * 8;
+    unique_edge_label_id = unique_edge_label_id << num_bits;
+    unique_edge_label_id = unique_edge_label_id | dst_label_id;
+    unique_edge_label_id = unique_edge_label_id << num_bits;
+    unique_edge_label_id = unique_edge_label_id | edge_label_id;
+    return unique_edge_label_id;
+  }
+};
 }  // namespace gs
 
 #endif  // ENGINES_HQPS_ENGINE_OPERATOR_SINK_H_
diff --git a/flex/engines/hqps_db/core/operator/sort.h b/flex/engines/hqps_db/core/operator/sort.h
index 43dd74d20c3c..bff03c5e6e05 100644
--- a/flex/engines/hqps_db/core/operator/sort.h
+++ b/flex/engines/hqps_db/core/operator/sort.h
@@ -401,9 +401,9 @@ class SortOp {
       const ORDER_PAIR& ordering_pair,
       const FlatEdgeSet<VID_T, LabelT, EDATA_T>& set,
       const GRAPH_INTERFACE& graph) {
-    return FlatEdgeSetPropGetter<
-        ORDER_PAIR::tag_id,
-        typename FlatEdgeSet<VID_T, LabelT, EDATA_T>::index_ele_tuple_t>();
+    return create_prop_getter_impl<ORDER_PAIR::tag_id,
+                                   typename ORDER_PAIR::prop_t>(
+        set, graph, ordering_pair.name);
   }
 
   template <typename ORDER_PAIR, size_t N, typename GI, typename VID_T,
@@ -412,10 +412,9 @@ class SortOp {
       const ORDER_PAIR& ordering_pair,
       const GeneralEdgeSet<N, GI, VID_T, LabelT, EDATA_T...>& set,
       const GRAPH_INTERFACE& graph) {
-    return GeneralEdgeSetPropGetter<
-        ORDER_PAIR::tag_id,
-        typename GeneralEdgeSet<N, GI, VID_T, LabelT,
-                                EDATA_T...>::index_ele_tuple_t>();
+    return create_prop_getter_impl<ORDER_PAIR::tag_id,
+                                   typename ORDER_PAIR::prop_t>(
+        set, graph, ordering_pair.name);
   }
 
   template <typename ORDER_PAIR, typename T>
diff --git a/flex/engines/hqps_db/core/params.h b/flex/engines/hqps_db/core/params.h
index b6bd8136ed5e..c2f9d58d574b 100644
--- a/flex/engines/hqps_db/core/params.h
+++ b/flex/engines/hqps_db/core/params.h
@@ -225,31 +225,31 @@ struct InnerIdProperty {
   InnerIdProperty() = default;
 };
 
-template <typename label_id_t, int _tag_id = -1>
-struct LabelKeyProperty {
-  using prop_t = label_id_t;
-  static constexpr int tag_id = _tag_id;
-  std::string name;
-  LabelKeyProperty(std::string&& n) : name(std::move(n)){};
-};
-
 // Denote the length of a path
 struct LengthKey {
   using length_data_type = int32_t;
 };
 
-struct LabelKey {
-  using label_data_type = uint8_t;
-  int32_t label_id;
-  LabelKey() = default;
-  LabelKey(label_data_type id) : label_id(id) {}
-};
+inline bool operator<(const LabelKey& lhs, const LabelKey& rhs) {
+  return lhs.label_id < rhs.label_id;
+}
 
-template <typename T>
-struct is_label_key_prop : std::false_type {};
+inline bool operator==(const LabelKey& lhs, const LabelKey& rhs) {
+  return lhs.label_id == rhs.label_id;
+}
+
+inline bool operator!=(const LabelKey& lhs, const LabelKey& rhs) {
+  return lhs.label_id != rhs.label_id;
+}
 
-template <typename T, int tag_id>
-struct is_label_key_prop<LabelKeyProperty<T, tag_id>> : std::true_type {};
+inline bool operator>(const LabelKey& lhs, const LabelKey& rhs) {
+  return lhs.label_id > rhs.label_id;
+}
+
+// overload hash_value for LabelKey
+inline std::size_t hash_value(const LabelKey& key) {
+  return std::hash<int32_t>()(key.label_id);
+}
 
 // static constexpr size_t dist_col = 0;
 
diff --git a/flex/engines/hqps_db/core/utils/hqps_utils.h b/flex/engines/hqps_db/core/utils/hqps_utils.h
index 49b77202cbdc..dd70b115afb5 100644
--- a/flex/engines/hqps_db/core/utils/hqps_utils.h
+++ b/flex/engines/hqps_db/core/utils/hqps_utils.h
@@ -36,7 +36,6 @@
 namespace gs {
 
 // demangle a c++ variable's class name
-
 template <typename T>
 std::string demangle(const T& t) {
   int status;
@@ -199,6 +198,18 @@ bool operator>(const WithProxy<T>& lhs, const std::array<T, N>& rhs) {
   return rhs.end() != std::find(rhs.begin(), rhs.end(), lhs.t_);
 }
 
+template <size_t N, typename std::enable_if<(N > 0)>::type* = nullptr>
+bool operator>(const WithProxy<LabelKey>& lhs,
+               const std::array<int64_t, N>& rhs) {
+  return rhs.end() != std::find(rhs.begin(), rhs.end(), lhs.t_.label_id);
+}
+
+template <size_t N, typename std::enable_if<(N == 0)>::type* = nullptr>
+bool operator>(const WithProxy<LabelKey>& lhs,
+               const std::array<int64_t, N>& rhs) {
+  return false;
+}
+
 template <
     typename T, size_t N,
     typename std::enable_if<std::is_pod_v<T> && (N == 0)>::type* = nullptr>
diff --git a/flex/engines/hqps_db/core/utils/keyed.h b/flex/engines/hqps_db/core/utils/keyed.h
index 78f9539a5285..a386a991a33c 100644
--- a/flex/engines/hqps_db/core/utils/keyed.h
+++ b/flex/engines/hqps_db/core/utils/keyed.h
@@ -179,7 +179,8 @@ struct KeyedAggT<GI, RowVertexSet<LabelT, VID_T, T...>, AggFunc::COUNT_DISTINCT,
                  std::integer_sequence<int32_t, tag_id>> {
   using agg_res_t = Collection<size_t>;
   // build a counter array.
-  using aggregate_res_builder_t = DistinctCountBuilder<1, tag_id, VID_T>;
+  using vertex_set_t = RowVertexSet<LabelT, VID_T, T...>;
+  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, vertex_set_t>;
 
   static aggregate_res_builder_t create_agg_builder(
       const RowVertexSet<LabelT, VID_T, T...>& set, const GI& graph,
@@ -211,7 +212,8 @@ struct KeyedAggT<GI, TwoLabelVertexSet<VID_T, LabelT, T...>,
                  std::integer_sequence<int32_t, tag_id>> {
   using agg_res_t = Collection<size_t>;
   // build a counter array.
-  using aggregate_res_builder_t = DistinctCountBuilder<2, tag_id, VID_T>;
+  using vertex_set_t = TwoLabelVertexSet<VID_T, LabelT, T...>;
+  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, vertex_set_t>;
 
   static aggregate_res_builder_t create_agg_builder(
       const TwoLabelVertexSet<VID_T, LabelT, T...>& set, const GI& graph,
@@ -384,6 +386,21 @@ struct KeyedAggT<GI, UnTypedEdgeSet<VID_T, LabelT, typename GI::sub_graph_t>,
   }
 };
 
+template <typename GI, typename VID_T, typename LabelT, typename SET_T,
+          int tag_id>
+struct KeyedAggT<GI, SingleLabelEdgeSet<VID_T, LabelT, SET_T>, AggFunc::COUNT,
+                 std::tuple<grape::EmptyType>,
+                 std::integer_sequence<int32_t, tag_id>> {
+  using agg_res_t = Collection<size_t>;
+  using aggregate_res_builder_t = CountBuilder<tag_id>;
+
+  static aggregate_res_builder_t create_agg_builder(
+      const SingleLabelEdgeSet<VID_T, LabelT, SET_T>& set, const GI& graph,
+      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
+    return CountBuilder<tag_id>();
+  }
+};
+
 template <typename GI, typename VID_T, typename LabelT, typename EDATA_T,
           int tag_id>
 struct KeyedAggT<GI, FlatEdgeSet<VID_T, LabelT, EDATA_T>, AggFunc::COUNT,
@@ -399,6 +416,55 @@ struct KeyedAggT<GI, FlatEdgeSet<VID_T, LabelT, EDATA_T>, AggFunc::COUNT,
   }
 };
 
+// COUNT DISTINCT for EdgeSets.
+template <typename GI, typename VID_T, typename LabelT, int tag_id>
+struct KeyedAggT<GI, UnTypedEdgeSet<VID_T, LabelT, typename GI::sub_graph_t>,
+                 AggFunc::COUNT_DISTINCT, std::tuple<grape::EmptyType>,
+                 std::integer_sequence<int32_t, tag_id>> {
+  using agg_res_t = Collection<size_t>;
+  using edge_set_t = UnTypedEdgeSet<VID_T, LabelT, typename GI::sub_graph_t>;
+  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, edge_set_t>;
+
+  static aggregate_res_builder_t create_agg_builder(
+      const UnTypedEdgeSet<VID_T, LabelT, typename GI::sub_graph_t>& set,
+      const GI& graph,
+      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
+    return aggregate_res_builder_t(set);
+  }
+};
+
+template <typename GI, typename VID_T, typename LabelT, typename SET_T,
+          int tag_id>
+struct KeyedAggT<GI, SingleLabelEdgeSet<VID_T, LabelT, SET_T>,
+                 AggFunc::COUNT_DISTINCT, std::tuple<grape::EmptyType>,
+                 std::integer_sequence<int32_t, tag_id>> {
+  using agg_res_t = Collection<size_t>;
+  using edge_set_t = SingleLabelEdgeSet<VID_T, LabelT, SET_T>;
+  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, edge_set_t>;
+
+  static aggregate_res_builder_t create_agg_builder(
+      const SingleLabelEdgeSet<VID_T, LabelT, SET_T>& set, const GI& graph,
+      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
+    return aggregate_res_builder_t(set);
+  }
+};
+
+template <typename GI, typename VID_T, typename LabelT, typename EDATA_T,
+          int tag_id>
+struct KeyedAggT<GI, FlatEdgeSet<VID_T, LabelT, EDATA_T>,
+                 AggFunc::COUNT_DISTINCT, std::tuple<grape::EmptyType>,
+                 std::integer_sequence<int32_t, tag_id>> {
+  using agg_res_t = Collection<size_t>;
+  using edge_set_t = FlatEdgeSet<VID_T, LabelT, EDATA_T>;
+  using aggregate_res_builder_t = DistinctCountBuilder<tag_id, edge_set_t>;
+
+  static aggregate_res_builder_t create_agg_builder(
+      const FlatEdgeSet<VID_T, LabelT, EDATA_T>& set, const GI& graph,
+      std::tuple<PropertySelector<grape::EmptyType>>& selectors) {
+    return aggregate_res_builder_t(set);
+  }
+};
+
 template <typename LabelT, typename KEY_T, typename VID_T, typename... T,
           typename ELE, typename DATA>
 static inline auto insert_into_builder_v2_impl(
diff --git a/flex/engines/hqps_db/core/utils/props.h b/flex/engines/hqps_db/core/utils/props.h
index 5ef63881b8a5..9af20be89c78 100644
--- a/flex/engines/hqps_db/core/utils/props.h
+++ b/flex/engines/hqps_db/core/utils/props.h
@@ -189,6 +189,54 @@ class InnerIdGetter {
   const std::vector<VID_T>& vids_;
 };
 
+template <int tag_id>
+class VertexLabelGetter {
+ public:
+  VertexLabelGetter(const std::vector<LabelKey>&& label_keys)
+      : label_keys(std::move(label_keys)) {}
+
+  template <typename IND_ELE>
+  LabelKey get_view(const IND_ELE& ele) const {
+    auto index_ = std::get<0>(ele);
+    if (index_ >= label_keys.size()) {
+      LOG(FATAL) << "index out of range";
+    }
+    return label_keys[index_];
+  }
+
+  template <typename ALL_ELE_T>
+  inline auto get_from_all_element(const ALL_ELE_T& all_ele) const {
+    return get_view(gs::get_from_tuple<tag_id>(all_ele));
+  }
+
+ private:
+  std::vector<LabelKey> label_keys;
+};
+
+template <int tag_id>
+class EdgeLabelGetter {
+ public:
+  EdgeLabelGetter(const std::vector<LabelKey>&& label_keys)
+      : label_keys(std::move(label_keys)) {}
+
+  template <typename IND_ELE>
+  LabelKey get_view(const IND_ELE& ele) const {
+    auto index_ = std::get<0>(ele);
+    if (index_ >= label_keys.size()) {
+      LOG(FATAL) << "index out of range";
+    }
+    return label_keys[index_];
+  }
+
+  template <typename ALL_ELE_T>
+  inline auto get_from_all_element(const ALL_ELE_T& all_ele) const {
+    return get_view(gs::get_from_tuple<tag_id>(all_ele));
+  }
+
+ private:
+  std::vector<LabelKey> label_keys;
+};
+
 template <int tag_id, typename VID_T, typename... DATA_T>
 class InnerIdDataGetter {
  public:
@@ -281,6 +329,32 @@ class CollectionPropGetter {
   std::tuple<size_t, T> ind_ele_;
 };
 
+// Specialize for LabelKey
+template <int tag_id>
+class CollectionPropGetter<tag_id, LabelKey> {
+ public:
+  CollectionPropGetter() {}
+
+  inline auto get_view(const std::tuple<size_t, LabelKey>& ele) const {
+    return std::get<1>(ele).label_id;
+  }
+
+  inline auto get_view() const { return std::get<1>(ind_ele_); }
+
+  template <typename ALL_ELE_T>
+  inline auto get_from_all_element(const ALL_ELE_T& all_ele) const {
+    return get_view(gs::get_from_tuple<tag_id>(all_ele));
+  }
+
+  template <typename ALL_IND_ELE_T>
+  inline void set_ind_ele(const ALL_IND_ELE_T& ind_ele) {
+    ind_ele_ = ind_ele;
+  }
+
+ private:
+  std::tuple<size_t, LabelKey> ind_ele_;
+};
+
 // specialize for collection with only one column
 template <int tag_id, typename T>
 class CollectionPropGetter<tag_id, std::tuple<T>> {
@@ -560,11 +634,35 @@ static auto get_dist_prop_getter(
   }
 }
 
+///////////////////// Get LabelKey Property for VertexSet
+template <int tag_id, typename prop_t, typename GRAPH_INTERFACE,
+          typename NODE_T,
+          typename std::enable_if<(std::is_same_v<prop_t, LabelKey> &&
+                                   NODE_T::is_vertex_set)>::type* = nullptr>
+static auto create_prop_getter_impl(const NODE_T& set,
+                                    const GRAPH_INTERFACE& graph,
+                                    const std::string& prop_name) {
+  auto label_vec = set.GetLabelVec();
+  return VertexLabelGetter<tag_id>(std::move(label_vec));
+}
+
+template <int tag_id, typename prop_t, typename GRAPH_INTERFACE,
+          typename NODE_T,
+          typename std::enable_if<(std::is_same_v<prop_t, LabelKey> &&
+                                   NODE_T::is_edge_set)>::type* = nullptr>
+static auto create_prop_getter_impl(const NODE_T& set,
+                                    const GRAPH_INTERFACE& graph,
+                                    const std::string& prop_name) {
+  auto label_vec = set.GetLabelVec();
+  return EdgeLabelGetter<tag_id>(std::move(label_vec));
+}
+
 // get for common properties for two_vertex_set
-template <
-    int tag_id, typename prop_t, typename GRAPH_INTERFACE, typename LabelT,
-    typename VID_T, typename... T,
-    typename std::enable_if<!std::is_same_v<prop_t, Dist>>::type* = nullptr>
+template <int tag_id, typename prop_t, typename GRAPH_INTERFACE,
+          typename LabelT, typename VID_T, typename... T,
+          typename std::enable_if<(!std::is_same_v<prop_t, Dist> &&
+                                   !std::is_same_v<prop_t, LabelKey>)>::type* =
+              nullptr>
 static auto create_prop_getter_impl(
     const RowVertexSetImpl<LabelT, VID_T, T...>& set,
     const GRAPH_INTERFACE& graph, const std::string& prop_name) {
@@ -610,7 +708,9 @@ static auto create_prop_getter_impl(
 
 // get for common properties for two_label_vertex_set
 template <int tag_id, typename prop_t, typename GRAPH_INTERFACE, typename VID_T,
-          typename LabelT, typename... T>
+          typename LabelT, typename... T,
+          typename std::enable_if<!(std::is_same_v<prop_t, LabelKey>)>::type* =
+              nullptr>
 static auto create_prop_getter_impl(
     const TwoLabelVertexSetImpl<VID_T, LabelT, T...>& set,
     const GRAPH_INTERFACE& graph, const std::string& prop_name) {
@@ -631,10 +731,11 @@ static auto create_prop_getter_impl(
 }
 
 // get for common properties for keyed_row_vertex_set
-template <
-    int tag_id, typename prop_t, typename GRAPH_INTERFACE, typename LabelT,
-    typename KEY_T, typename VID_T, typename... T,
-    typename std::enable_if<!std::is_same_v<prop_t, Dist>>::type* = nullptr>
+template <int tag_id, typename prop_t, typename GRAPH_INTERFACE,
+          typename LabelT, typename KEY_T, typename VID_T, typename... T,
+          typename std::enable_if<(!std::is_same_v<prop_t, Dist> &&
+                                   !std::is_same_v<prop_t, LabelKey>)>::type* =
+              nullptr>
 static auto create_prop_getter_impl(
     const KeyedRowVertexSetImpl<LabelT, KEY_T, VID_T, T...>& set,
     const GRAPH_INTERFACE& graph, const std::string& prop_name) {
@@ -653,7 +754,9 @@ static auto create_prop_getter_impl(
 
 // get for common properties for keyed_row_vertex_set
 template <int tag_id, typename prop_t, typename GRAPH_INTERFACE,
-          typename LabelT, typename VID_T, typename... SET_T>
+          typename LabelT, typename VID_T, typename... SET_T,
+          typename std::enable_if<!(std::is_same_v<prop_t, LabelKey>)>::type* =
+              nullptr>
 static auto create_prop_getter_impl(
     const GeneralVertexSet<VID_T, LabelT, SET_T...>& set,
     const GRAPH_INTERFACE& graph, const std::string& prop_name) {
@@ -675,7 +778,9 @@ static auto create_prop_getter_impl(
 
 // get for common properties for FlatEdgeSet
 template <int tag_id, typename prop_t, typename GRAPH_INTERFACE, typename VID_T,
-          typename LabelT, typename EDATA_T>
+          typename LabelT, typename EDATA_T,
+          typename std::enable_if<!(std::is_same_v<prop_t, LabelKey>)>::type* =
+              nullptr>
 static auto create_prop_getter_impl(
     const FlatEdgeSet<VID_T, LabelT, EDATA_T>& set,
     const GRAPH_INTERFACE& graph, const std::string& prop_name) {
@@ -686,7 +791,9 @@ static auto create_prop_getter_impl(
 
 // get for common properties for Single label edge set.
 template <int tag_id, typename prop_t, typename GRAPH_INTERFACE, typename VID_T,
-          typename LabelT, typename EDATA_T>
+          typename LabelT, typename EDATA_T,
+          typename std::enable_if<!(std::is_same_v<prop_t, LabelKey>)>::type* =
+              nullptr>
 static auto create_prop_getter_impl(
     const SingleLabelEdgeSet<VID_T, LabelT, EDATA_T>& set,
     const GRAPH_INTERFACE& graph, const std::string& prop_name) {
@@ -698,7 +805,9 @@ static auto create_prop_getter_impl(
 
 // get for common properties for GeneralEdgeSet
 template <int tag_id, typename prop_t, size_t N, typename GI, typename VID_T,
-          typename LabelT, typename... EDATA_T>
+          typename LabelT, typename... EDATA_T,
+          typename std::enable_if<!(std::is_same_v<prop_t, LabelKey>)>::type* =
+              nullptr>
 static auto create_prop_getter_impl(
     const GeneralEdgeSet<N, GI, VID_T, LabelT, EDATA_T...>& set,
     const GI& graph, const std::string& prop_name) {
diff --git a/flex/engines/hqps_db/database/adj_list.h b/flex/engines/hqps_db/database/adj_list.h
index 0c42432c69fe..39384d37599c 100644
--- a/flex/engines/hqps_db/database/adj_list.h
+++ b/flex/engines/hqps_db/database/adj_list.h
@@ -95,6 +95,7 @@ class SubGraph {
     return iterator(label_triplet_, nullptr, &prop_names_);
   }
 
+  // here the src, dst, refer the src, dst of the csr, not the direction.
   label_id_t GetSrcLabel() const { return label_triplet_[0]; }
   label_id_t GetEdgeLabel() const { return label_triplet_[2]; }
   label_id_t GetDstLabel() const { return label_triplet_[1]; }
@@ -205,26 +206,27 @@ class Adj<T> {
 };
 
 template <>
-class Adj<> {
+class Adj<grape::EmptyType> {
  public:
   Adj() = default;
   ~Adj() = default;
 
-  Adj(const Adj<>& other) : neighbor_(other.neighbor_), prop_(other.prop_) {}
-  Adj(Adj<>&& other)
+  Adj(const Adj<grape::EmptyType>& other)
+      : neighbor_(other.neighbor_), prop_(other.prop_) {}
+  Adj(Adj<grape::EmptyType>&& other)
       : neighbor_(other.neighbor_), prop_(std::move(other.prop_)) {}
 
-  inline Adj<>& operator=(const Adj<>& from) {
+  inline Adj<grape::EmptyType>& operator=(const Adj<grape::EmptyType>& from) {
     this->neighbor_ = from.neighbor_;
     this->prop_ = from.prop_;
     return *this;
   }
 
   vid_t neighbor() const { return neighbor_; }
-  const std::tuple<>& properties() const { return prop_; }
+  const std::tuple<grape::EmptyType>& properties() const { return prop_; }
 
   vid_t neighbor_;
-  std::tuple<> prop_;
+  std::tuple<grape::EmptyType> prop_;
 };
 
 template <typename... T>
@@ -358,7 +360,7 @@ class AdjList<T> {
 };
 
 template <>
-class AdjList<> {
+class AdjList<grape::EmptyType> {
   using nbr_t = MutableNbr<grape::EmptyType>;
   class Iterator {
    public:
@@ -389,8 +391,8 @@ class AdjList<> {
 
     vid_t neighbor() const { return cur_.neighbor(); }
 
-    const Adj<>& operator*() const { return cur_; }
-    const Adj<>* operator->() const { return &cur_; }
+    const Adj<grape::EmptyType>& operator*() const { return cur_; }
+    const Adj<grape::EmptyType>* operator->() const { return &cur_; }
 
     Iterator& operator++() {
       if (begin0_ < end0_) {
@@ -424,7 +426,7 @@ class AdjList<> {
     }
 
    private:
-    Adj<> cur_;
+    Adj<grape::EmptyType> cur_;
     const nbr_t *begin0_, *begin1_;
     const nbr_t *end0_, *end1_;
   };
@@ -438,11 +440,11 @@ class AdjList<> {
   AdjList(const slice_t& slice0, const slice_t& slice1)
       : slice0_(slice0), slice1_(slice1) {}
 
-  AdjList(AdjList<>&& adj_list)
+  AdjList(AdjList<grape::EmptyType>&& adj_list)
       : slice0_(std::move(adj_list.slice0_)),
         slice1_(std::move(adj_list.slice1_)) {}
 
-  AdjList(const AdjList<>& adj_list)
+  AdjList(const AdjList<grape::EmptyType>& adj_list)
       : slice0_(adj_list.slice0_), slice1_(adj_list.slice1_) {}
 
   Iterator begin() const {
@@ -454,7 +456,7 @@ class AdjList<> {
   }
   size_t size() const { return slice0_.size() + slice1_.size(); }
 
-  AdjList<>& operator=(const AdjList<>& other) {
+  AdjList<grape::EmptyType>& operator=(const AdjList<grape::EmptyType>& other) {
     slice0_ = other.slice0_;
     slice1_ = other.slice1_;
     return *this;
@@ -548,7 +550,7 @@ class AdjListArray<T> {
 };
 
 template <>
-class AdjListArray<> {
+class AdjListArray<grape::EmptyType> {
  public:
   using csr_base_t = MutableCsrBase;
   using typed_csr_base_t = MutableCsr<grape::EmptyType>;
@@ -559,9 +561,12 @@ class AdjListArray<> {
     slices_.reserve(vids.size());
     const typed_csr_base_t* casted_csr =
         dynamic_cast<const typed_csr_base_t*>(csr);
-    for (auto v : vids) {
-      auto edges = casted_csr->get_edges(v);
-      slices_.emplace_back(std::make_pair(casted_csr->get_edges(v), slice_t()));
+    if (casted_csr) {
+      for (auto v : vids) {
+        auto edges = casted_csr->get_edges(v);
+        slices_.emplace_back(
+            std::make_pair(casted_csr->get_edges(v), slice_t()));
+      }
     }
   }
 
@@ -575,31 +580,41 @@ class AdjListArray<> {
         dynamic_cast<const typed_csr_base_t*>(csr1);
 
     for (auto v : vids) {
-      slices_.emplace_back(
-          std::make_pair(casted_csr0->get_edges(v), casted_csr1->get_edges(v)));
+      if (casted_csr0 && casted_csr1) {
+        slices_.emplace_back(std::make_pair(casted_csr0->get_edges(v),
+                                            casted_csr1->get_edges(v)));
+      } else if (casted_csr0 && !casted_csr1) {
+        slices_.emplace_back(
+            std::make_pair(casted_csr0->get_edges(v), slice_t()));
+      } else if (!casted_csr0 && casted_csr1) {
+        slices_.emplace_back(
+            std::make_pair(slice_t(), casted_csr1->get_edges(v)));
+      } else {
+        slices_.emplace_back(std::make_pair(slice_t(), slice_t()));
+      }
     }
   }
   // move constructor
-  AdjListArray(AdjListArray<>&& adj_list)
+  AdjListArray(AdjListArray<grape::EmptyType>&& adj_list)
       : slices_(std::move(adj_list.slices_)), flag_(adj_list.flag_) {}
 
   size_t size() const { return slices_.size(); }
 
   void resize(size_t new_size) { slices_.resize(new_size); }
 
-  void set(size_t i, const AdjList<>& slice) {
+  void set(size_t i, const AdjList<grape::EmptyType>& slice) {
     slices_[i] = std::make_pair(slice.slice0(), slice.slice1());
   }
 
-  AdjList<> get(size_t i) const {
+  AdjList<grape::EmptyType> get(size_t i) const {
     if (flag_) {
-      return AdjList<>(slices_[i].first, slices_[i].second);
+      return AdjList<grape::EmptyType>(slices_[i].first, slices_[i].second);
     } else {
-      return AdjList<>(slices_[i].first);
+      return AdjList<grape::EmptyType>(slices_[i].first);
     }
   }
 
-  void swap(AdjListArray<>& adj_list) {
+  void swap(AdjListArray<grape::EmptyType>& adj_list) {
     this->slices_.swap(adj_list.slices_);
     bool tmp_flag = flag_;
     flag_ = adj_list.flag_;
diff --git a/flex/engines/hqps_db/database/mutable_csr_interface.h b/flex/engines/hqps_db/database/mutable_csr_interface.h
index d2d6999b895a..92e7d41ed924 100644
--- a/flex/engines/hqps_db/database/mutable_csr_interface.h
+++ b/flex/engines/hqps_db/database/mutable_csr_interface.h
@@ -508,15 +508,15 @@ class MutableCSRInterface {
           csr, {src_label_id, dst_label_id, edge_label_id}, prop_names}};
     } else if (direction_str == "in" || direction_str == "In" ||
                direction_str == "IN") {
-      csr = db_session_.graph().get_ie_csr(src_label_id, dst_label_id,
+      csr = db_session_.graph().get_ie_csr(dst_label_id, src_label_id,
                                            edge_label_id);
       return std::vector<sub_graph_t>{sub_graph_t{
-          csr, {src_label_id, dst_label_id, edge_label_id}, prop_names}};
+          csr, {dst_label_id, src_label_id, edge_label_id}, prop_names}};
     } else if (direction_str == "both" || direction_str == "Both" ||
                direction_str == "BOTH") {
       csr = db_session_.graph().get_oe_csr(src_label_id, dst_label_id,
                                            edge_label_id);
-      other_csr = db_session_.graph().get_ie_csr(src_label_id, dst_label_id,
+      other_csr = db_session_.graph().get_ie_csr(dst_label_id, src_label_id,
                                                  edge_label_id);
       return std::vector<sub_graph_t>{
           sub_graph_t{
@@ -797,6 +797,9 @@ class MutableCSRInterface {
       const label_t& label_id, const std::string& prop_name) const {
     using column_t = std::shared_ptr<TypedRefColumn<T>>;
     column_t column;
+    if constexpr (std::is_same_v<T, LabelKey>) {
+      return std::make_shared<TypedRefColumn<LabelKey>>(label_id);
+    }
     if (prop_name == "id" || prop_name == "ID" || prop_name == "Id") {
       column = std::dynamic_pointer_cast<TypedRefColumn<T>>(
           db_session_.get_vertex_id_column(label_id));
@@ -816,6 +819,8 @@ class MutableCSRInterface {
       const label_t& label_id, const std::string& prop_name) const {
     if (prop_name == "id" || prop_name == "ID" || prop_name == "Id") {
       return db_session_.get_vertex_id_column(label_id);
+    } else if (prop_name == "Label" || prop_name == "LabelKey") {
+      return std::make_shared<TypedRefColumn<LabelKey>>(label_id);
     } else {
       return create_ref_column(
           db_session_.get_vertex_property_column(label_id, prop_name));
diff --git a/flex/engines/hqps_db/structures/collection.h b/flex/engines/hqps_db/structures/collection.h
index 1997266111f9..f2f307a12d65 100644
--- a/flex/engines/hqps_db/structures/collection.h
+++ b/flex/engines/hqps_db/structures/collection.h
@@ -52,6 +52,10 @@ class TwoLabelVertexSetImpl;
 template <typename VID_T, typename LabelT, typename... T>
 class TwoLabelVertexSetImplBuilder;
 
+// untypedEdgeSet
+template <typename VID_T, typename LabelT, typename SUB_GRAPH_T>
+class UnTypedEdgeSet;
+
 template <typename T>
 class Collection;
 
@@ -423,14 +427,58 @@ class CountBuilder {
   std::vector<size_t> vec_;
 };
 
-template <size_t num_labels, int tag_id, typename T>
+template <int tag_id, typename T, typename Enable = void>
 class DistinctCountBuilder;
 
+// Count the distinct edges of UntypedEdgeSet.
+// We assume each edge  in UnTypeEdgeSet  is unique, so just count the index of
+// index_ele_tuple_t.
+template <int tag_id, typename EDGE_SET_T>
+class DistinctCountBuilder<
+    tag_id, EDGE_SET_T,
+    typename std::enable_if<(EDGE_SET_T::is_edge_set)>::type> {
+ public:
+  using edge_set_t = EDGE_SET_T;
+  using index_ele_t = typename edge_set_t::index_ele_tuple_t;
+  DistinctCountBuilder(const edge_set_t& edge_set) {
+    edges_num_ = edge_set.Size();
+  }
+
+  template <typename ELE_TUPLE_T, typename DATA_TUPLE>
+  void insert(size_t ind, const ELE_TUPLE_T& tuple, const DATA_TUPLE& data) {
+    auto& cur_ind_ele = gs::get_from_tuple<tag_id>(tuple);
+    while (vec_.size() <= ind) {
+      vec_.emplace_back(grape::Bitset(edges_num_));
+    }
+    auto& cur_bitset = vec_[ind];
+    auto cur_ind = std::get<0>(cur_ind_ele);
+    if (cur_ind < edges_num_) {
+      cur_bitset.set_bit(cur_ind);
+    } else {
+      LOG(FATAL) << "Invalid edge index: " << cur_ind
+                 << ", edges num: " << edges_num_;
+    }
+  }
+
+  Collection<size_t> Build() {
+    std::vector<size_t> res;
+    res.reserve(vec_.size());
+    for (auto& bitset : vec_) {
+      res.emplace_back(bitset.count());
+    }
+    return Collection<size_t>(std::move(res));
+  }
+
+ private:
+  std::vector<grape::Bitset> vec_;
+  size_t edges_num_;
+};
+
 // count the distinct number of recieved elements.
-template <int tag_id, typename T>
-class DistinctCountBuilder<1, tag_id, T> {
+template <int tag_id, typename LabelT, typename VID_T, typename... T>
+class DistinctCountBuilder<tag_id, RowVertexSetImpl<LabelT, VID_T, T...>> {
  public:
-  DistinctCountBuilder(const std::vector<T>& vertices) {
+  DistinctCountBuilder(const std::vector<VID_T>& vertices) {
     // find out the range of vertices inside vector, and use a bitset to count
     for (auto v : vertices) {
       min_v = std::min(min_v, v);
@@ -446,7 +494,7 @@ class DistinctCountBuilder<1, tag_id, T> {
         std::is_same_v<
             std::tuple_element_t<1, std::remove_const_t<std::remove_reference_t<
                                         decltype(cur_ind_ele)>>>,
-            T>,
+            VID_T>,
         "Type not match");
     while (vec_.size() <= ind) {
       vec_.emplace_back(grape::Bitset(range_size));
@@ -469,15 +517,15 @@ class DistinctCountBuilder<1, tag_id, T> {
 
  private:
   std::vector<grape::Bitset> vec_;
-  T min_v, max_v, range_size;
+  VID_T min_v, max_v, range_size;
 };
 
 // specialization for DistinctCountBuilder for num_labels=2
-template <int tag_id, typename T>
-class DistinctCountBuilder<2, tag_id, T> {
+template <int tag_id, typename VID_T, typename LabelT, typename... T>
+class DistinctCountBuilder<tag_id, TwoLabelVertexSetImpl<VID_T, LabelT, T...>> {
  public:
   DistinctCountBuilder(const grape::Bitset& bitset,
-                       const std::vector<T>& vids) {
+                       const std::vector<VID_T>& vids) {
     // find out the range of vertices inside vector, and use a bitset to count
     for (auto i = 0; i < vids.size(); ++i) {
       auto v = vids[i];
@@ -502,7 +550,7 @@ class DistinctCountBuilder<2, tag_id, T> {
         std::is_same_v<
             std::tuple_element_t<2, std::remove_const_t<std::remove_reference_t<
                                         decltype(cur_ind_ele)>>>,
-            T>,
+            VID_T>,
         "Type not match");
     auto label_ind = std::get<1>(cur_ind_ele);
     while (vec_[label_ind].size() <= ind) {
@@ -530,7 +578,7 @@ class DistinctCountBuilder<2, tag_id, T> {
 
  private:
   std::array<std::vector<grape::Bitset>, 2> vec_;
-  std::array<T, 2> min_v, max_v, range_size;
+  std::array<VID_T, 2> min_v, max_v, range_size;
 };
 
 template <typename T, int tag_id>
diff --git a/flex/engines/hqps_db/structures/multi_edge_set/flat_edge_set.h b/flex/engines/hqps_db/structures/multi_edge_set/flat_edge_set.h
index 8c3b2b0c0e3c..bae2d05eb32f 100644
--- a/flex/engines/hqps_db/structures/multi_edge_set/flat_edge_set.h
+++ b/flex/engines/hqps_db/structures/multi_edge_set/flat_edge_set.h
@@ -81,18 +81,20 @@ class FlatEdgeSetBuilder {
   Direction direction_;
 };
 
-template <typename VID_T, typename EDATA_T>
+template <typename VID_T, typename LabelT, typename EDATA_T>
 class FlatEdgeSetIter {
  public:
   using ele_tuple_t = std::tuple<VID_T, VID_T, EDATA_T>;
-  using self_type_t = FlatEdgeSetIter<VID_T, EDATA_T>;
+  using self_type_t = FlatEdgeSetIter<VID_T, LabelT, EDATA_T>;
   using index_ele_tuple_t = std::tuple<size_t, ele_tuple_t>;
   using data_tuple_t = ele_tuple_t;
   FlatEdgeSetIter(const std::vector<ele_tuple_t>& vec, size_t ind,
                   const std::vector<uint8_t>& label_triplet_ind,
+                  const std::vector<std::array<LabelT, 3>>& label_triplet,
                   const std::vector<std::vector<std::string>>& prop_names)
       : vec_(vec),
         ind_(ind),
+        label_triplet_(label_triplet),
         label_triplet_ind_(label_triplet_ind),
         prop_names_(prop_names) {}
 
@@ -101,11 +103,22 @@ class FlatEdgeSetIter {
   index_ele_tuple_t GetIndexElement() const {
     return std::make_tuple(ind_, GetElement());
   }
+  LabelT GetEdgeLabel() const {
+    return label_triplet_[label_triplet_ind_[ind_]][2];
+  }
 
   VID_T GetSrc() const { return std::get<0>(vec_[ind_]); }
 
+  LabelT GetSrcLabel() const {
+    return label_triplet_[label_triplet_ind_[ind_]][0];
+  }
+
   VID_T GetDst() const { return std::get<1>(vec_[ind_]); }
 
+  LabelT GetDstLabel() const {
+    return label_triplet_[label_triplet_ind_[ind_]][1];
+  }
+
   const EDATA_T& GetData() const { return std::get<2>(vec_[ind_]); }
 
   const std::vector<std::string>& GetPropNames() const {
@@ -138,6 +151,7 @@ class FlatEdgeSetIter {
  private:
   const std::vector<ele_tuple_t>& vec_;
   const std::vector<uint8_t>& label_triplet_ind_;
+  const std::vector<std::array<LabelT, 3>>& label_triplet_;
   const std::vector<std::vector<std::string>>& prop_names_;
   size_t ind_;
 };
@@ -148,7 +162,7 @@ class FlatEdgeSet {
  public:
   using ele_tuple_t = std::tuple<VID_T, VID_T, EDATA_T>;
   using index_ele_tuple_t = std::tuple<size_t, ele_tuple_t>;
-  using iterator = FlatEdgeSetIter<VID_T, EDATA_T>;
+  using iterator = FlatEdgeSetIter<VID_T, LabelT, EDATA_T>;
   using self_type_t = FlatEdgeSet<VID_T, LabelT, EDATA_T>;
   using flat_t = self_type_t;
   using data_tuple_t = ele_tuple_t;
@@ -181,11 +195,12 @@ class FlatEdgeSet {
   }
 
   iterator begin() const {
-    return iterator(vec_, 0, label_triplet_ind_, prop_names_);
+    return iterator(vec_, 0, label_triplet_ind_, label_triplet_, prop_names_);
   }
 
   iterator end() const {
-    return iterator(vec_, vec_.size(), label_triplet_ind_, prop_names_);
+    return iterator(vec_, vec_.size(), label_triplet_ind_, label_triplet_,
+                    prop_names_);
   }
 
   std::vector<LabelKey> GetLabelVec() const {
@@ -201,7 +216,7 @@ class FlatEdgeSet {
   template <size_t col_ind, typename... index_ele_tuple_t_>
   flat_t Flat(
       std::vector<std::tuple<index_ele_tuple_t_...>>& index_ele_tuple) const {
-    std::vector<std::tuple<VID_T, VID_T, std::tuple<EDATA_T>>> res;
+    std::vector<ele_tuple_t> res;
     std::vector<uint8_t> label_triplet_ind;
     res.reserve(index_ele_tuple.size());
     label_triplet_ind.reserve(index_ele_tuple.size());
@@ -211,8 +226,9 @@ class FlatEdgeSet {
       label_triplet_ind.emplace_back(
           label_triplet_ind_[std::get<0>(cur_ind_ele)]);
     }
-    return FlatEdgeSet(std::move(res), label_triplet_, prop_names_,
-                       std::move(label_triplet_ind), direction_);
+    auto copied_label_triplet = label_triplet_;
+    return FlatEdgeSet(std::move(res), std::move(copied_label_triplet),
+                       prop_names_, std::move(label_triplet_ind), direction_);
   }
 
   void fillBuiltinPropsImpl(std::vector<EDATA_T>& tuples,
@@ -376,6 +392,19 @@ class FlatEdgeSet {
                        direction_);
   }
 
+  void SubSetWithIndices(std::vector<size_t>& indices) {
+    std::vector<ele_tuple_t> res_vec;
+    std::vector<uint8_t> res_label_triplet_ind;
+    res_vec.reserve(indices.size());
+    res_label_triplet_ind.reserve(indices.size());
+    for (auto i = 0; i < indices.size(); ++i) {
+      res_vec.emplace_back(vec_[indices[i]]);
+      res_label_triplet_ind.emplace_back(label_triplet_ind_[indices[i]]);
+    }
+    vec_.swap(res_vec);
+    label_triplet_ind_.swap(res_label_triplet_ind);
+  }
+
   void Repeat(std::vector<offset_t>& cur_offset,
               std::vector<offset_t>& repeat_vec) {
     CHECK(cur_offset.size() == repeat_vec.size());
@@ -454,19 +483,28 @@ class SingleLabelEdgeSetIter {
   using index_ele_tuple_t = std::tuple<size_t, ele_tuple_t>;
   using data_tuple_t = ele_tuple_t;
   SingleLabelEdgeSetIter(const std::vector<ele_tuple_t>& vec, size_t ind,
+                         const std::array<LabelT, 3>& label_triplet,
                          const std::vector<std::string>& prop_names)
-      : vec_(vec), ind_(ind), prop_names_(prop_names) {}
+      : vec_(vec),
+        ind_(ind),
+        label_triplet_(label_triplet),
+        prop_names_(prop_names) {}
 
   ele_tuple_t GetElement() const { return vec_[ind_]; }
 
   index_ele_tuple_t GetIndexElement() const {
     return std::make_tuple(ind_, GetElement());
   }
+  LabelT GetEdgeLabel() const { return label_triplet_[2]; }
 
   VID_T GetSrc() const { return std::get<0>(vec_[ind_]); }
 
+  LabelT GetSrcLabel() const { return label_triplet_[0]; }
+
   VID_T GetDst() const { return std::get<1>(vec_[ind_]); }
 
+  LabelT GetDstLabel() const { return label_triplet_[1]; }
+
   const EDATA_T& GetData() const { return std::get<2>(vec_[ind_]); }
 
   const std::vector<std::string>& GetPropNames() const { return prop_names_; }
@@ -496,6 +534,7 @@ class SingleLabelEdgeSetIter {
 
  private:
   const std::vector<ele_tuple_t>& vec_;
+  const std::array<LabelT, 3>& label_triplet_;
   const std::vector<std::string>& prop_names_;
   size_t ind_;
 };
@@ -526,9 +565,13 @@ class SingleLabelEdgeSet {
         prop_names_(prop_names),
         direction_(direction) {}
 
-  iterator begin() const { return iterator(vec_, 0, prop_names_); }
+  iterator begin() const {
+    return iterator(vec_, 0, label_triplet_, prop_names_);
+  }
 
-  iterator end() const { return iterator(vec_, vec_.size(), prop_names_); }
+  iterator end() const {
+    return iterator(vec_, vec_.size(), label_triplet_, prop_names_);
+  }
 
   std::vector<LabelKey> GetLabelVec() const {
     std::vector<LabelKey> res;
@@ -682,6 +725,15 @@ class SingleLabelEdgeSet {
     vec_.swap(res_vec);
   }
 
+  void SubSetWithIndices(std::vector<size_t>& indices) {
+    std::vector<ele_tuple_t> res_vec;
+    res_vec.reserve(indices.size());
+    for (auto i = 0; i < indices.size(); ++i) {
+      res_vec.emplace_back(vec_[indices[i]]);
+    }
+    vec_.swap(res_vec);
+  }
+
   builder_t CreateBuilder() const {
     return builder_t(label_triplet_, prop_names_, direction_);
   }
diff --git a/flex/engines/hqps_db/structures/multi_edge_set/general_edge_set.h b/flex/engines/hqps_db/structures/multi_edge_set/general_edge_set.h
index ded75b8f09a8..7ea975d9acbf 100644
--- a/flex/engines/hqps_db/structures/multi_edge_set/general_edge_set.h
+++ b/flex/engines/hqps_db/structures/multi_edge_set/general_edge_set.h
@@ -155,7 +155,7 @@ class GeneralEdgeSetBuilder<2, GI, VID_T, LabelT, std::tuple<grape::EmptyType>,
   const grape::Bitset& bitset_;
   Direction direction_;
 };
-template <typename GI, typename VID_T, typename... T>
+template <typename GI, typename VID_T, typename LabelT, typename... T>
 class GeneralEdgeSetIter {
  public:
   using adj_list_array_t = typename GI::template adj_list_array_t<T...>;
@@ -164,11 +164,20 @@ class GeneralEdgeSetIter {
   using ele_tuple_t = std::tuple<VID_T, adj_list_iterator>;
   using data_tuple_t = ele_tuple_t;
   using index_ele_tuple_t = std::tuple<size_t, VID_T, adj_list_iterator>;
-  using self_type_t = GeneralEdgeSetIter<GI, VID_T, T...>;
+  using self_type_t = GeneralEdgeSetIter<GI, VID_T, LabelT, T...>;
 
   GeneralEdgeSetIter(const std::vector<VID_T>& vids,
-                     const adj_list_array_t& adj_lists, size_t ind)
-      : vids_(vids), adj_lists_(adj_lists), ind_(ind) {
+                     const adj_list_array_t& adj_lists,
+                     const grape::Bitset& bitsets,
+                     const std::array<LabelT, 2>& src_labels, LabelT dst_label,
+                     LabelT edge_label, size_t ind)
+      : vids_(vids),
+        adj_lists_(adj_lists),
+        bitsets_(bitsets),
+        src_labels_(src_labels),
+        dst_label_(dst_label),
+        edge_label_(edge_label),
+        ind_(ind) {
     if (ind_ == 0) {
       probe_next_valid_adj();
     }
@@ -178,13 +187,31 @@ class GeneralEdgeSetIter {
   GeneralEdgeSetIter(const self_type_t& other)
       : vids_(other.vids_),
         adj_lists_(other.adj_lists_),
+        bitsets_(other.bitsets_),
+        src_labels_(other.src_labels_),
+        dst_label_(other.dst_label_),
+        edge_label_(other.edge_label_),
         ind_(other.ind_),
         cur_adj_list_(other.cur_adj_list_),
         begin_(other.begin_),
         end_(other.end_) {}
 
+  inline LabelT GetEdgeLabel() const { return edge_label_; }
+
   inline VID_T GetSrc() const { return vids_[ind_]; }
+
+  inline LabelT GetSrcLabel() const {
+    if (bitsets_.get_bit(ind_)) {
+      return src_labels_[0];
+    } else {
+      return src_labels_[1];
+    }
+  }
+
   inline VID_T GetDst() const { return begin_.neighbor(); }
+
+  inline LabelT GetDstLabel() const { return dst_label_; }
+
   inline const std::tuple<T...>& GetData() const { return begin_.properties(); }
 
   ele_tuple_t GetElement() const { return ele_tuple_t(GetSrc(), begin_); }
@@ -239,12 +266,16 @@ class GeneralEdgeSetIter {
   const std::vector<VID_T>& vids_;
   const adj_list_array_t& adj_lists_;
   adj_list_t cur_adj_list_;
+  const grape::Bitset& bitsets_;
   adj_list_iterator begin_, end_;
+  const std::array<LabelT, 2>& src_labels_;
+  LabelT dst_label_;
+  LabelT edge_label_;
   size_t ind_;
 };
 
-template <typename GI, typename VID_T>
-class GeneralEdgeSetIter<GI, VID_T, grape::EmptyType> {
+template <typename GI, typename VID_T, typename LabelT>
+class GeneralEdgeSetIter<GI, VID_T, LabelT, grape::EmptyType> {
  public:
   using adj_list_array_t = typename GI::template adj_list_array_t<>;
   using adj_list_t = typename GI::template adj_list_t<>;
@@ -252,11 +283,20 @@ class GeneralEdgeSetIter<GI, VID_T, grape::EmptyType> {
   using ele_tuple_t = std::tuple<VID_T, adj_list_iterator>;
   using data_tuple_t = ele_tuple_t;
   using index_ele_tuple_t = std::tuple<size_t, VID_T, adj_list_iterator>;
-  using self_type_t = GeneralEdgeSetIter<GI, VID_T, grape::EmptyType>;
+  using self_type_t = GeneralEdgeSetIter<GI, VID_T, LabelT, grape::EmptyType>;
 
   GeneralEdgeSetIter(const std::vector<VID_T>& vids,
-                     const adj_list_array_t& adj_lists, size_t ind)
-      : vids_(vids), adj_lists_(adj_lists), ind_(ind) {
+                     const adj_list_array_t& adj_lists,
+                     const grape::Bitset& bitsets,
+                     const std::array<LabelT, 2>& src_labels, LabelT dst_label,
+                     LabelT edge_label, size_t ind)
+      : vids_(vids),
+        adj_lists_(adj_lists),
+        bitsets_(bitsets),
+        src_labels_(src_labels),
+        dst_label_(dst_label),
+        edge_label_(edge_label),
+        ind_(ind) {
     if (ind_ == 0) {
       probe_next_valid_adj();
     }
@@ -266,13 +306,31 @@ class GeneralEdgeSetIter<GI, VID_T, grape::EmptyType> {
   GeneralEdgeSetIter(const self_type_t& other)
       : vids_(other.vids_),
         adj_lists_(other.adj_lists_),
+        bitsets_(other.bitsets_),
+        src_labels_(other.src_labels_),
+        dst_label_(other.dst_label_),
+        edge_label_(other.edge_label_),
         ind_(other.ind_),
         cur_adj_list_(other.cur_adj_list_),
         begin_(other.begin_),
         end_(other.end_) {}
 
+  inline LabelT GetEdgeLabel() const { return edge_label_; }
+
   inline VID_T GetSrc() const { return vids_[ind_]; }
+
+  inline LabelT GetSrcLabel() const {
+    if (bitsets_.get_bit(ind_)) {
+      return src_labels_[0];
+    } else {
+      return src_labels_[1];
+    }
+  }
+
   inline VID_T GetDst() const { return begin_.neighbor(); }
+
+  inline LabelT GetDstLabel() const { return dst_label_; }
+
   inline const std::tuple<grape::EmptyType> GetData() const {
     return std::make_tuple(grape::EmptyType());
   }
@@ -328,7 +386,11 @@ class GeneralEdgeSetIter<GI, VID_T, grape::EmptyType> {
  private:
   const std::vector<VID_T>& vids_;
   const adj_list_array_t& adj_lists_;
-  adj_list_t cur_adj_list_;
+  const grape::Bitset& bitsets_;
+  const std::array<LabelT, 2>& src_labels_;
+  LabelT dst_label_;
+  LabelT edge_label_;
+  const adj_list_t cur_adj_list_;
   adj_list_iterator begin_, end_;
   size_t ind_;
 };
@@ -393,7 +455,7 @@ class GeneralEdgeSet<2, GI, VID_T, LabelT, std::tuple<T...>, std::tuple<T...>> {
   using self_type_t =
       GeneralEdgeSet<2, GI, VID_T, LabelT, std::tuple<T...>, std::tuple<T...>>;
 
-  using iterator = GeneralEdgeSetIter<GI, VID_T, T...>;
+  using iterator = GeneralEdgeSetIter<GI, VID_T, LabelT, T...>;
   using builder_t = GeneralEdgeSetBuilder<2, GI, VID_T, LabelT,
                                           std::tuple<T...>, std::tuple<T...>>;
   GeneralEdgeSet(std::vector<VID_T>&& vids, adj_list_array_t&& adj_lists,
@@ -424,13 +486,20 @@ class GeneralEdgeSet<2, GI, VID_T, LabelT, std::tuple<T...>, std::tuple<T...>> {
     bitsets_.swap(other.bitsets_);
   }
 
-  iterator begin() const { return iterator(vids_, adj_lists_, 0); }
+  iterator begin() const {
+    return iterator(vids_, adj_lists_, bitsets_, src_labels_, dst_label_,
+                    edge_label_, 0);
+  }
 
-  iterator end() const { return iterator(vids_, adj_lists_, vids_.size()); }
+  iterator end() const {
+    return iterator(vids_, adj_lists_, bitsets_, src_labels_, dst_label_,
+                    edge_label_, vids_.size());
+  }
 
   const std::vector<std::string>& GetPropNames() const { return prop_names_; }
 
   std::vector<LabelKey> GetLabelVec() const {
+    VLOG(1) << "GetLabelVec for general edge set.";
     std::vector<LabelKey> res;
     res.reserve(Size());
     for (auto i = 0; i < Size(); ++i) {
@@ -594,7 +663,7 @@ class GeneralEdgeSet<2, GI, VID_T, LabelT, std::tuple<grape::EmptyType>,
   using data_tuple_t = ele_tuple_t;
   using index_ele_tuple_t = std::tuple<size_t, VID_T, adj_list_iter_t>;
 
-  using iterator = GeneralEdgeSetIter<GI, VID_T, grape::EmptyType>;
+  using iterator = GeneralEdgeSetIter<GI, VID_T, LabelT, grape::EmptyType>;
   using builder_t =
       GeneralEdgeSetBuilder<2, GI, VID_T, LabelT, std::tuple<grape::EmptyType>,
                             std::tuple<grape::EmptyType>>;
@@ -625,6 +694,7 @@ class GeneralEdgeSet<2, GI, VID_T, LabelT, std::tuple<grape::EmptyType>,
 
   std::vector<LabelKey> GetLabelVec() const {
     std::vector<LabelKey> res;
+    VLOG(1) << "GetLabelVec for general edge set.";
     res.reserve(Size());
     for (auto i = 0; i < Size(); ++i) {
       res.emplace_back(edge_label_);
diff --git a/flex/engines/hqps_db/structures/multi_edge_set/untyped_edge_set.h b/flex/engines/hqps_db/structures/multi_edge_set/untyped_edge_set.h
index 3e948edf93a0..6f92146c065d 100644
--- a/flex/engines/hqps_db/structures/multi_edge_set/untyped_edge_set.h
+++ b/flex/engines/hqps_db/structures/multi_edge_set/untyped_edge_set.h
@@ -45,7 +45,8 @@ class UnTypedEdgeSetIter {
       : src_vertices_(src_v),
         adj_lists_(std::move(adj_lists)),
         vid_ind_(ind),
-        iter_ind_(0) {
+        iter_ind_(0),
+        cur_ind_(0) {
     LOG(INFO) << "UnTypedEdgeSetIter init,size: " << adj_lists_.size()
               << ", vertices size: " << src_vertices_.size();
     if (vid_ind_ != src_vertices_.size()) {
@@ -71,6 +72,8 @@ class UnTypedEdgeSetIter {
     }
   }
 
+  inline LabelT GetEdgeLabel() const { return cur_iter_.GetEdgeLabel(); }
+
   inline VID_T GetSrc() const { return src_vertices_[vid_ind_]; }
   inline VID_T GetDst() const { return cur_iter_.GetDstId(); }
 
@@ -88,10 +91,11 @@ class UnTypedEdgeSetIter {
 
   // Make sure this okay.
   inline index_ele_tuple_t GetIndexElement() const {
-    return std::make_tuple(vid_ind_, GetSrc(), GetDst(), GetData());
+    return std::make_tuple(cur_ind_, GetSrc(), GetDst(), GetData());
   }
 
   inline const self_type_t& operator++() {
+    ++cur_ind_;
     cur_iter_.Next();
     if (cur_iter_.IsValid()) {
       return *this;
@@ -144,6 +148,7 @@ class UnTypedEdgeSetIter {
   }
 
   size_t vid_ind_, iter_ind_;
+  size_t cur_ind_;
   edge_iter_t cur_iter_;
   const std::vector<vid_t>& src_vertices_;
   std::vector<std::vector<edge_iter_t>> adj_lists_;
@@ -199,6 +204,7 @@ class UnTypedEdgeSet {
   std::vector<LabelKey> GetLabelVec() const {
     std::vector<LabelKey> res;
     res.reserve(Size());
+    VLOG(1) << "GetLabelVec for UntypedEdgeSet, size: " << Size();
     for (auto i = 0; i < src_vertices_.size(); ++i) {
       auto label_ind = label_indices_[i];
       auto label = src_labels_[label_ind];
@@ -232,7 +238,6 @@ class UnTypedEdgeSet {
   template <typename PropT>
   std::vector<PropT> getProperties(const PropNameArray<PropT>& prop_names,
                                    const std::vector<offset_t>& repeat_array) {
-    //
     std::vector<PropT> tmp_prop_vec;
     size_t sum = 0;
     {
@@ -273,12 +278,15 @@ class UnTypedEdgeSet {
     auto v_labels = get_v_opt.v_labels_;
     auto v_labels_vec = array_to_vec(v_labels);
     // if v_labels_vec is null or empty, return all vertices
-    if (v_opt == VOpt::Start) {
+    if ((v_opt == VOpt::Start && direction_ == Direction::Out) ||
+        (v_opt == VOpt::End && direction_ == Direction::In)) {
       if (v_labels_vec.empty()) {
         v_labels_vec = src_labels_;
       }
       return getSrcVertices(v_labels_vec);
-    } else if (v_opt == VOpt::End || v_opt == VOpt::Other) {
+    } else if ((v_opt == VOpt::Start && direction_ == Direction::In) ||
+               (v_opt == VOpt::End && direction_ == Direction::Out) ||
+               (v_opt == VOpt::Other)) {
       auto dst_label_set = get_dst_label_set();
       if (v_labels_vec.empty()) {
         v_labels_vec =
@@ -398,6 +406,7 @@ class UnTypedEdgeSet {
             typename std::enable_if<Fs == -1>::type* = nullptr>
   auto ProjectWithRepeatArray(const std::vector<size_t>& repeat_array,
                               KeyAlias<tag_id, Fs>& key_alias) const {
+    LOG(INFO) << "Project UntypedEdgeSet to FlatEdgeSet";
     using dst_ele_tuple_t = std::tuple<VID_T, VID_T, Any>;
     CHECK(repeat_array.size() == Size());
     size_t real_size = 0;
@@ -423,8 +432,6 @@ class UnTypedEdgeSet {
       auto& cur_edge_iters = edge_iters[i];
       auto src_label_ind = label_indices_[i];
       auto src_label = src_labels_[src_label_ind];
-      auto cur_triplets_vec = edge_label_triplets[src_label_ind];
-      CHECK(cur_triplets_vec.size() == cur_edge_iters.size());
 
       for (auto j = 0; j < cur_edge_iters.size(); ++j) {
         auto& cur_iter = cur_edge_iters[j];
@@ -510,14 +517,17 @@ class UnTypedEdgeSet {
 
   std::vector<std::vector<std::array<LabelT, 3>>> get_edge_triplets() const {
     std::vector<std::vector<std::array<LabelT, 3>>> ret;
-    for (auto iter : adj_lists_) {
-      auto& sub_graphs = iter.second;
+    for (auto src_label_ind = 0; src_label_ind < src_labels_.size();
+         ++src_label_ind) {
+      auto src_label = src_labels_[src_label_ind];
       std::vector<std::array<LabelT, 3>> tmp;
-      for (auto i = 0; i < sub_graphs.size(); ++i) {
-        auto& sub_graph = sub_graphs[i];
-        tmp.emplace_back(std::array<LabelT, 3>({sub_graph.GetSrcLabel(),
-                                                sub_graph.GetDstLabel(),
-                                                sub_graph.GetEdgeLabel()}));
+      if (adj_lists_.find(src_label) != adj_lists_.end()) {
+        auto& sub_graphs = adj_lists_.at(src_label);
+        for (auto& sub_graph : sub_graphs) {
+          tmp.emplace_back(std::array<LabelT, 3>({sub_graph.GetSrcLabel(),
+                                                  sub_graph.GetDstLabel(),
+                                                  sub_graph.GetEdgeLabel()}));
+        }
       }
       ret.emplace_back(std::move(tmp));
     }
diff --git a/flex/engines/hqps_db/structures/multi_vertex_set/general_vertex_set.h b/flex/engines/hqps_db/structures/multi_vertex_set/general_vertex_set.h
index 30933d3f9205..710f5d17d0a5 100644
--- a/flex/engines/hqps_db/structures/multi_vertex_set/general_vertex_set.h
+++ b/flex/engines/hqps_db/structures/multi_vertex_set/general_vertex_set.h
@@ -78,7 +78,7 @@ auto general_project_vertices_impl(
             break;
           }
         } else {
-          if (expr(std::get<0>(eles))) {
+          if (std::apply(expr, eles)) {
             res_bitsets[label_id].set_bit(res_vec.size());
             res_vec.push_back(old_vec[i]);
             break;
@@ -162,7 +162,7 @@ auto general_project_vertices_impl(
             break;
           }
         } else {
-          if (expr(std::get<0>(eles))) {
+          if (std::apply(expr, eles)) {
             res_bitsets[label_id].set_bit(res_vec.size());
             res_vec.push_back(old_vec[i]);
             res_data_vec.push_back(old_data_vec[i]);
diff --git a/flex/interactive/bin/gs_interactive b/flex/interactive/bin/gs_interactive
index 1e5c2772f4a9..4fcec9b1a41e 100755
--- a/flex/interactive/bin/gs_interactive
+++ b/flex/interactive/bin/gs_interactive
@@ -2125,8 +2125,4 @@ while [[ $# -gt 0 ]]; do
     exit 1
     ;;
   esac
-done
-
-
-
-
+done
\ No newline at end of file
diff --git a/flex/interactive/docker/README.md b/flex/interactive/docker/README.md
index ba94c11ec681..69af971facac 100644
--- a/flex/interactive/docker/README.md
+++ b/flex/interactive/docker/README.md
@@ -9,7 +9,7 @@ docker build -f interactive-base.Dockerfile -t interactive-base .
 ## Build Runtime Image with latest GraphScope
 
 ```bash
-docker build -f interactive-base.Dockerfile --target final_image -t interactive .
+docker build -f interactive-runtime.Dockerfile --target final_image -t interactive .
 ```
 
 ## Tag the image
diff --git a/flex/interactive/examples/graph_algo/0_count_paper.cypher b/flex/interactive/examples/graph_algo/0_count_paper.cypher
new file mode 100644
index 000000000000..4289037a286c
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/0_count_paper.cypher
@@ -0,0 +1,4 @@
+MATCH (p:Paper)-[:WorkOn]->(:Algorithm)-[:Belong]->(ca:Category)
+WITH distinct ca, count(p) as paperCount
+RETURN ca.category, paperCount
+ORDER BY paperCount desc;
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/1_challenge_strategy.cypher b/flex/interactive/examples/graph_algo/1_challenge_strategy.cypher
new file mode 100644
index 000000000000..04a9a7cfc617
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/1_challenge_strategy.cypher
@@ -0,0 +1,6 @@
+MATCH (ca:Category)<-[:Belong]-(a:Algorithm),
+       (a)<-[:WorkOn]-(p:Paper)-[:Use]->(s:Strategy),
+       (s)-[:ApplyOn]->(ch:Challenge)
+WITH ca, ch, count(p) AS num
+RETURN ca.category AS category, ch.challenge AS challenge, num
+ORDER BY num DESC LIMIT 5;
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/2_get_edge_type.cypher b/flex/interactive/examples/graph_algo/2_get_edge_type.cypher
new file mode 100644
index 000000000000..f0126e21c2b2
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/2_get_edge_type.cypher
@@ -0,0 +1,1 @@
+MATCH(c: CCFField)<-[e]-(p:Paper) return type(e) As edgeType ORDER BY edgeType ASC LIMIT 10;
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/3_get_distinct_edge_type.cypher b/flex/interactive/examples/graph_algo/3_get_distinct_edge_type.cypher
new file mode 100644
index 000000000000..44ffcb3da538
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/3_get_distinct_edge_type.cypher
@@ -0,0 +1,1 @@
+MATCH(v)-[e]-() return distinct type(e) AS edgeType order by edgeType ASC;
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/4_filter_edge.cypher b/flex/interactive/examples/graph_algo/4_filter_edge.cypher
new file mode 100644
index 000000000000..bde3745b429c
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/4_filter_edge.cypher
@@ -0,0 +1,1 @@
+MATCH(c: CCFField)<-[e]-(p:Paper) where type(e) = 6 return type(e) As edgeType ORDER BY edgeType ASC LIMIT 10;
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/5.cypher b/flex/interactive/examples/graph_algo/5.cypher
new file mode 100644
index 000000000000..7cd3be3b552e
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/5.cypher
@@ -0,0 +1,4 @@
+MATCH (p:Paper)-[:Resolve]->(ch:Challenge),
+              (p1:Paper)-[:Resolve]->(ch),
+               (p)-[c:Citation]->(p1)
+RETURN COUNT(distinct c);
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/6.cypher b/flex/interactive/examples/graph_algo/6.cypher
new file mode 100644
index 000000000000..c1e472f179cf
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/6.cypher
@@ -0,0 +1,6 @@
+MATCH (p:Paper)-[:Resolve]->(ch:Challenge),
+              (p1:Paper)-[:Resolve]->(ch),
+               (p)-[c:Citation]->(p1)
+WITH DISTINCT p, c, p1
+WITH p.id As paperId, p1.id As citationId
+RETURN paperId, citationId ORDER BY paperId ASC, citationId ASC;
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/7.cypher b/flex/interactive/examples/graph_algo/7.cypher
new file mode 100644
index 000000000000..65453aa90967
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/7.cypher
@@ -0,0 +1,5 @@
+MATCH (p:Paper)-[:HasField]->(c:CCFField),
+              (p1:Paper)-[:HasField]->(c),
+               (p)-[b:Citation]-(p1)
+WITH distinct p, p1
+RETURN p.CCFField, p1.CCFField;
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/8.cypher b/flex/interactive/examples/graph_algo/8.cypher
new file mode 100644
index 000000000000..4478008fb744
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/8.cypher
@@ -0,0 +1,5 @@
+MATCH (p:Paper)-[:HasField]->(f1:CCFField),
+              (p1:Paper)-[:HasField]->(f2:CCFField),
+               (p)-[c:Citation]->(p1)
+WHERE f1.id = 0 AND f2.id <> f1.id
+RETURN distinct p, p1;
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/9.cypher b/flex/interactive/examples/graph_algo/9.cypher
new file mode 100644
index 000000000000..7a490274710e
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/9.cypher
@@ -0,0 +1,4 @@
+MATCH (p:Paper)-[:Resolve]->(ch:Challenge),
+              (p1:Paper)-[:Resolve]->(ch),
+               (p)-[c:Citation]-(p1)
+RETURN COUNT(distinct p, p1);
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/Algorithm.csv b/flex/interactive/examples/graph_algo/Algorithm.csv
new file mode 100644
index 000000000000..e7189ce3de99
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Algorithm.csv
@@ -0,0 +1,28 @@
+id|algorithm
+0|PageRank
+1|Personalized PageRank
+2|Degree Centrality
+3|Betweenness Centrality
+4|Closeness Centrality
+5|Local Clustering Coefficient
+6|Louvain
+7|Label Propagation
+8|Minimum Cut/Max Flow
+9|Connected Components
+10|Cosine Similarity
+11|Jaccard Similarity
+12|SimRank
+13|K-Core Decomposition
+14|K-Truss
+15|K-Clique
+16|K-ECC
+17|Triangle Counting
+18|Subgraph Matching
+19|BFS
+20|DFS
+21|Topological Sort
+22|Single Source Shortest Path
+23|Minimum Spanning Tree
+24|Cycle Detection
+25|Maximum Independent Set
+26|Color
diff --git a/flex/interactive/examples/graph_algo/Algorithm_Belong_Topic.csv b/flex/interactive/examples/graph_algo/Algorithm_Belong_Topic.csv
new file mode 100644
index 000000000000..0155e6feea69
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Algorithm_Belong_Topic.csv
@@ -0,0 +1,28 @@
+start|end
+0|0
+1|0
+2|0
+3|0
+4|0
+5|1
+6|1
+7|1
+8|1
+9|1
+10|2
+11|2
+12|2
+13|3
+14|3
+15|3
+16|3
+17|4
+18|4
+19|5
+20|5
+21|5
+22|5
+23|5
+24|5
+25|6
+26|6
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/Algorithm_Target_Challenge.csv b/flex/interactive/examples/graph_algo/Algorithm_Target_Challenge.csv
new file mode 100644
index 000000000000..dabe4ebd3681
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Algorithm_Target_Challenge.csv
@@ -0,0 +1,52 @@
+start|end|number
+0|1|6
+0|2|1
+0|3|3
+1|0|1
+1|1|1
+1|2|2
+3|1|1
+3|2|4
+3|3|1
+4|2|2
+6|0|2
+6|1|2
+6|2|3
+7|1|1
+7|2|1
+8|1|3
+8|2|2
+9|0|1
+9|1|2
+9|2|2
+11|1|1
+12|2|1
+12|0|1
+13|1|3
+13|2|3
+14|1|3
+14|0|1
+14|2|2
+15|0|2
+15|1|3
+15|2|4
+15|3|2
+19|0|2
+19|1|3
+19|2|2
+22|0|4
+22|1|12
+22|2|3
+22|3|1
+23|2|2
+23|1|3
+24|1|2
+17|0|4
+17|1|2
+18|0|3
+18|1|5
+18|2|3
+25|2|1
+26|1|1
+26|2|5
+26|3|1
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/CCFField.csv b/flex/interactive/examples/graph_algo/CCFField.csv
new file mode 100644
index 000000000000..2844f7558165
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/CCFField.csv
@@ -0,0 +1,10 @@
+id|field
+0|数据库/数据挖掘/内容检索
+1|计算机体系结构/并行与分布计算/存储系统
+2|计算机科学理论
+3|人工智能
+4|交叉/综合/新兴
+5|计算机网络
+6|信息系统
+7|软件工程/系统软件/程序设计语言
+8|计算机图形学与多媒体
diff --git a/flex/interactive/examples/graph_algo/Challenge.csv b/flex/interactive/examples/graph_algo/Challenge.csv
new file mode 100644
index 000000000000..d1aa4ec473fd
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Challenge.csv
@@ -0,0 +1,5 @@
+id|challenge
+0|Load Balance
+1|Communication Overhead
+2|Parallelism
+3|Bandwidth
diff --git a/flex/interactive/examples/graph_algo/Paper.csv b/flex/interactive/examples/graph_algo/Paper.csv
new file mode 100644
index 000000000000..60a1396a5580
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Paper.csv
@@ -0,0 +1,103 @@
+id|conference|CCF Rank|CCF field|year|paper
+0|Information Sciences|B|数据库/数据挖掘/内容检索|2022|Distributed PageRank computation with improved round complexities.
+1|ICASSP|B|计算机图形学与多媒体|2021|Provably Fast Asynchronous And Distributed Algorithms For Pagerank Centrality Computation.
+2|ICML|A|人工智能|2020|Improved Communication Cost in Distributed PageRank computation - A Theoretical Study.
+3|AAAI|A|人工智能|2019|Distributed PageRank computation: An Improved Theoretical Study.
+4|TCS|B|计算机科学理论|2015|Fast Distributed PageRank computation.
+5|USENIX ATC|A|计算机体系结构/并行与分布计算/存储系统|2018|Accelerating PageRank using Partition-Centric Processing
+6|COMAD|A|计算机体系结构/并行与分布计算/存储系统|2014|Subgraph Rank: PageRank for Subgraph-Centric Distributed Graph Processing
+7|KAIS|B|数据库/数据挖掘/内容检索|2019|PPR-partitioning: a Distributed graph partitioning algorithm based on the personalized PageRank vectors in vertex-centric systems.
+8|WWW|A|交叉/综合/新兴|2019|Distributed Algorithms for Fully Personalized PageRank in Large Graphs.
+9|SIGMOD|A|数据库/数据挖掘/内容检索|2017|Distributed Algorithms on Exact Personalized PageRank.
+10|INFOCOM|A|计算机网络|2020|Simple and Fast Distributed Computation of Betweenness Centrality.
+11|PPoPP|A|计算机体系结构/并行与分布计算/存储系统|2019|A round-efficient Distributed betweenness Centrality algorithm.
+12|TPDS|A|计算机体系结构/并行与分布计算/存储系统|2018|Parallel Algorithm for Incremental Betweenness Centrality in Large Graphs.
+13|TCS|B|计算机科学理论|2017|On the distribution of betweenness centrality in random trees.
+14|ICDCS|B|计算机体系结构/并行与分布计算/存储系统|2017|Distributively Computing Random Walk Betweenness Centrality in Linear Time.
+15|ICDCS|B|计算机体系结构/并行与分布计算/存储系统|2016|Nearly Optimal Distributed Algorithm for Computing Betweenness Centrality.
+16|CN|B|计算机网络|2013|DACCER:Distributed Assessment of the Closeness Centrality Ranking in complex networks.
+17|CLUSTER|B|计算机体系结构/并行与分布计算/存储系统|2013|STREAMER: A Distributed framework for incremental closeness centrality computation.
+18|TJSC|C|计算机体系结构/并行与分布计算/存储系统|2022|Scalable distributed Louvain algorithm for community detection in large graphs
+19|IPDPS|B|计算机体系结构/并行与分布计算/存储系统|2018|Distributed Louvain Algorithm for Graph Community Detection
+20|DASC|/|/|2018|Parallelizing Louvain Algorithm: Distributed Memory Challenges
+21|CLUSTER|B|计算机体系结构/并行与分布计算/存储系统|2018|A Scalable Distributed Louvain Algorithm for Large-scale Graph Community Detection
+22|HPEC|/|/|2019|Distributed Direction-Optimizing Label Propagation for Community Detection
+23|Concurrency and Computation|C|计算机体系结构/并行与分布计算/存储系统|2019|Parallel and distributed core label propagation with graph coloring
+24|TC|A|计算机体系结构/并行与分布计算/存储系统|2022|Distributed Detection of Minimum Cuts in Wireless Multi-Hop Networks
+25|JNCA|C|计算机网络|2019|A Distributed Evolutionary algorithm for detecting minimum vertex cuts for wireless ad hoc and sensor networks
+26|DISC|/|/|2013| Distributed Minimum Cut Approximation
+27|IPDPS|B|计算机体系结构/并行与分布计算/存储系统|2020|Communication-Efficient Jaccard similarity for High-Performance Distributed Genome Comparisons
+28|VLDBJ|A|数据库/数据挖掘/内容检索|2020|DISK: A Distributed Framework for Single-Source SimRank with Accuracy Guarantee
+29|VLDB|A|数据库/数据挖掘/内容检索|2022|Distributed D-core Decomposition over Large Directed Graphs
+30|JPDC|B|计算机体系结构/并行与分布计算/存储系统|2021|Distributed approximate k-core decomposition and min-max edge orientation: Breaking the diameter barrier
+31|BigData|C|交叉/综合/新兴|2017|A distributed k-core decomposition algorithm on spark
+32|TPDS|A|计算机体系结构/并行与分布计算/存储系统|2013|Distributed k-Core Decomposition
+33|TPDS|A|计算机体系结构/并行与分布计算/存储系统|2022|Efficient Distributed Approaches to Core Maintenance on Large Dynamic Graphs
+34|BigData|C|交叉/综合/新兴|2014|Distributed algorithms for k-truss decomposition
+35|TC|A|计算机体系结构/并行与分布计算/存储系统|2023|Exploring Truss Maintenance in Fully Dynamic Graphs: A Mixed Structure-Based Approach
+36|IS|B|信息系统|2019|KTMiner: Distributed k-truss detection in big graphs
+37|SIGMOD|A|数据库/数据挖掘/内容检索|2014|Efficient Cohesive Subgraphs Detection in Parallel
+38|PODC|B|计算机体系结构/并行与分布计算/存储系统|2022|Deterministic Near-Optimal Distributed Listing of Cliques
+39|TKDE|A|数据库/数据挖掘/内容检索|2021|Efficient Distributed k-Clique Mining for Large Networks Using MapReduce
+40|SODA|A|计算机科学理论|2021|Tight Distributed Listing of Cliques
+41|PODC|B|计算机体系结构/并行与分布计算/存储系统|2020|On Distributed Listing of Cliques
+42|ICALP|B|计算机科学理论|2019|Distributed Detection of Cliques in Dynamic Networks
+43|SEKE|C|软件工程/系统软件/程序设计语言|2018|A Formal Approach for Distributed Computing of Maximal Cliques in Dynamic Networks
+44|TSC|A|软件工程/系统软件/程序设计语言|2016|Distributed Maximal Clique Computation and Management
+45|IJUFKS|C|人工智能|2015|Finding Maximum Clique in Stochastic Graphs Using Distributed Learning Automata
+46|MSN|C|计算机网络|2015|Distributed Algorithms for Maximum Clique in Wireless Networks
+47|ICPP|B|计算机体系结构/并行与分布计算/存储系统|2015|PDTL: Parallel and Distributed triangle listing for Massive Graphs.
+48|TC|A|计算机体系结构/并行与分布计算/存储系统|2022|Svelto: High-Level Synthesis of Multi-Threaded Accelerators for Graph Analytics
+49|SC|A|计算机体系结构/并行与分布计算/存储系统|2021|TriPoll: Computing Surveys of Triangles in Massive-Scale Temporal Graphs with Metadata
+50|TPDS|A|计算机体系结构/并行与分布计算/存储系统|2020|TRUST: Triangle Counting Reloaded on GPUs
+51|TPDS|A|计算机体系结构/并行与分布计算/存储系统|2022|A Block-Based Triangle Counting Algorithm on Heterogeneous Environments
+52|VLDBJ|A|数据库/数据挖掘/内容检索|2022|G-thinker: a general distributed framework for finding qualified subgraphs in a big graph with load balancing
+53|VLDBJ|A|数据库/数据挖掘/内容检索|2017|Path-based holistic detection plan for multiple patterns in distributed graph frameworks
+54|VLDBJ|A|数据库/数据挖掘/内容检索|2016|Efficient distributed subgraph similarity matching
+55|ICDE|A|数据库/数据挖掘/内容检索|2019|BENU: Distributed Subgraph Enumeration with Backtracking-Based Framework
+56|ICDE|A|数据库/数据挖掘/内容检索|2019|Improving Distributed Subgraph Matching Algorithm on Timely Dataflow
+57|EuroSys|A|计算机体系结构/并行与分布计算/存储系统|2018|G-Miner: an efficient task-oriented graph mining system
+58|JPDC|B|计算机体系结构/并行与分布计算/存储系统|2018|Exploiting social network graph characteristics for efficient BFS on heterogeneous chips
+59|JPDC|B|计算机体系结构/并行与分布计算/存储系统|2016|Silent self-stabilizing BFS tree algorithms revisited
+60|JPDC|B|计算机体系结构/并行与分布计算/存储系统|2015|Solutions to the st-connectivity problem using a GPU-based_istributed BFS.
+61|TPDS|A|计算机体系结构/并行与分布计算/存储系统|2015|BFS-4K: An Efficient Implementation of BFS for Kepler GPU Architectures.
+62|TOS|A|计算机体系结构/并行与分布计算/存储系统|2020|TH-DPMS: Design and Implementation of an RDMA-enabled Distributed Persistent Memory Storage System
+63|PPoPP|A|计算机体系结构/并行与分布计算/存储系统|2022|Scaling Graph Traversal to 281 Trillion Edges with 40 Million Cores
+64|DC|C|计算机体系结构/并行与分布计算/存储系统|2022|Single-source shortest paths in the CONGEST model with improved bounds
+65|SODA|A|计算机科学理论|2022|Universally-Optimal Distributed Shortest Paths and Transshipment via Graph-Based {\(\mathscr{l}\)}\({}_{\mbox{1}}\)-Oblivious Routing
+66|STOC|A|计算机科学理论|2022|Undirected (1+\emph{{\(\epsilon\)}})-shortest paths via minor-aggregates: near-optimal deterministic parallel and distributed algorithms
+67|SICOMP|A|计算机科学理论|2021|Near-Optimal Approximate Shortest Paths and Transshipment in Distributed and Streaming Models
+68|SICOMP|A|计算机科学理论|2021|A Deterministic Almost-Tight Distributed Algorithm for Approximating Single-Source Shortest Paths
+69|PODC|B|计算机体系结构/并行与分布计算/存储系统|2021|Brief Announcement: An Improved Distributed Approximate Single Source Shortest Paths Algorithm
+70|JACM|A|交叉/综合/新兴|2020|Distributed Exact Shortest Paths in Sublinear Time
+71|FOCS|A|计算机科学理论 |2018|A Faster Distributed Single-Source Shortest Paths Algorithm
+72|PPoPP|A|计算机体系结构/并行与分布计算/存储系统 |2016|DSMR: a shared and distributed memory algorithm for single-source shortest path problem
+73|SC|A|计算机体系结构/并行与分布计算/存储系统 |2022|Scaling Graph 500 SSSP to 140 Trillion Edges with over 40 Million Cores
+74|SIGMOD|A|数据库/数据挖掘/内容检索|2020|Distributed Processing of k Shortest Path Queries over Dynamic Road Networks
+75|TKDE|A|数据库/数据挖掘/内容检索|2022|Distributed Multimodal Path Queries
+76|TPDS|A|计算机体系结构/并行与分布计算/存储系统 |2017|Scalable Single Source Shortest Path Algorithms for Massively Parallel Systems
+77|VLDBJ|A|数据库/数据挖掘/内容检索|2017|Distributed shortest path query processing on dynamic road networks
+78|TPDS|A|计算机体系结构/并行与分布计算/存储系统 |2022|A Parallel Algorithm Template for Updating Single-Source Shortest Paths in Large-Scale Dynamic Networks
+79|STOC|A|计算机科学理论|2023|Maximum Length-Constrained Flows and Disjoint Paths: Distributed Deterministic and Fast
+80|JPDC|B|计算机体系结构/并行与分布计算/存储系统|2022|A fast parallel max-flow algorithm
+81|SICOMP|A|计算机科学理论 |2018|Near-Optimal Distributed Maximum Flow
+82|DC|C|计算机体系结构/并行与分布计算/存储系统|2023|A distributed algorithm for directed minimum-weight spanning tree
+83|DC|C|计算机体系结构/并行与分布计算/存储系统|2021|Broadcast and minimum spanning tree with o(m) messages in the asynchronous CONGEST model.
+84|STOC|B|计算机科学理论 |2017|A Time- and Message-Optimal Distributed Algorithm for Minimum Spanning Trees
+85|PODC|B|计算机体系结构/并行与分布计算/存储系统|2019|Distributed Minimum Degree Spanning Trees
+86|SIGMOD|A|数据库/数据挖掘/内容检索|2021|Fast Parallel Algorithms for Euclidean Minimum Spanning Tree and Hierarchical Spatial Clustering
+87|ISAAC|C|计算机科学理论 |2021|Lower Bounds for Induced Cycle Detection in Distributed Computing
+88|SPAA|B|计算机体系结构/并行与分布计算/存储系统|2017|Distributed Detection of Cycles
+89|TAC|B|人工智能|2023|A Scalable Distributed Dynamical Systems Approach to Learn the Strongly Connected Components and Diameter of Networks
+90|IPDPS|B|计算机体系结构/并行与分布计算/存储系统|2022|Communication-efficient Massively Distributed Connected Components
+91|DPD|C|数据库/数据挖掘/内容检索|2018|Distributed computing connected components with linear communication cost
+92|TPDS|A|计算机体系结构/并行与分布计算/存储系统|2017|Fast Connected Components Computation in Large Graphs by Vertex Pruning
+93|TPDS|A|计算机体系结构/并行与分布计算/存储系统|2017|An Adaptive Parallel Algorithm for Computing Connected Components
+94|TON|A|计算机网络|2016|Distributed Greedy Approximation to Maximum Weighted Independent Set for Scheduling With Fading Channels
+95|IA3|/|/|2020|Distributed Memory Graph Coloring Algorithms for Multiple GPUs
+96|IEEE CLOUD|C|交叉/综合/新兴|2020|A distributed large graph coloring algorithm on Giraph
+97|AE|/|/|2015|A Distributed Hybrid Algorithm for the Graph Coloring Problem
+98|SICOMP|A|计算机体系结构/并行与分布计算/存储系统|2014|Distributed (Delta+1)-Coloring in Linear (in Delta) Time
+99|TPDS|A|计算机体系结构/并行与分布计算/存储系统|2019|Vertex Coloring with Communication Constraints in Synchronous Broadcast Networks
+100|TPDS|A|计算机体系结构/并行与分布计算/存储系统|2018|A Parallel Complex Coloring Algorithm for Scheduling of Input-Queued Switches
+101|SC|A|计算机体系结构/并行与分布计算/存储系统 |2011|Parallel breadth-first search on distributed memory systems
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/Paper_Citation_Paper.csv b/flex/interactive/examples/graph_algo/Paper_Citation_Paper.csv
new file mode 100644
index 000000000000..a13c20201732
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Paper_Citation_Paper.csv
@@ -0,0 +1,75 @@
+start|end
+0|4
+0|8
+0|9
+0|3
+2|4
+2|9
+2|3
+3|4
+7|9
+8|9
+8|4
+10|15
+11|14
+11|15
+14|15
+14|81
+14|4
+18|20
+25|26
+24|26
+28|3
+29|32
+29|31
+30|32
+31|32
+34|32
+35|34
+36|34
+36|37
+38|40
+38|41
+40|41
+50|101
+50|47
+52|57
+63|101
+64|71
+64|68
+65|67
+65|71
+65|70
+66|67
+66|64
+66|71
+66|68
+67|70
+67|71
+67|68
+68|70
+68|26
+69|67
+69|70
+69|71
+70|26
+71|70
+71|81
+71|26
+71|68
+71|84
+74|70
+74|71
+75|77
+77|70
+77|71
+77|74
+83|70
+79|81
+82|26
+83|84
+84|68
+87|40
+87|41
+90|101
+99|98
diff --git a/flex/interactive/examples/graph_algo/Paper_HasField_CCFField.csv b/flex/interactive/examples/graph_algo/Paper_HasField_CCFField.csv
new file mode 100644
index 000000000000..77b9f96ca906
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Paper_HasField_CCFField.csv
@@ -0,0 +1,98 @@
+start|end
+0|0
+1|8
+2|3
+3|3
+4|2
+5|1
+6|1
+7|0
+8|4
+9|0
+10|5
+11|1
+12|1
+13|2
+14|1
+15|1
+16|5
+17|1
+18|1
+19|1
+21|1
+23|1
+24|1
+25|5
+27|1
+28|0
+29|0
+30|1
+31|4
+32|1
+33|1
+34|4
+35|1
+36|6
+37|0
+38|1
+39|0
+40|2
+41|1
+42|2
+43|7
+44|7
+45|3
+46|5
+47|1
+48|1
+49|1
+50|1
+51|1
+52|0
+53|0
+54|0
+55|0
+56|0
+57|1
+58|1
+59|1
+60|1
+61|1
+62|1
+63|1
+64|1
+65|2
+66|2
+67|2
+68|2
+69|1
+70|4
+71|2
+72|1
+73|1
+74|0
+75|0
+76|1
+77|0
+78|1
+79|2
+80|1
+81|2
+82|1
+83|1
+84|2
+85|1
+86|0
+87|2
+88|1
+89|3
+90|1
+91|0
+92|1
+93|1
+94|5
+96|4
+98|1
+99|1
+100|1
+101|1
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/Paper_Resolve_Challenge.csv b/flex/interactive/examples/graph_algo/Paper_Resolve_Challenge.csv
new file mode 100644
index 000000000000..ad99523a4ec4
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Paper_Resolve_Challenge.csv
@@ -0,0 +1,124 @@
+start|end
+0|1
+0|3
+1|1
+1|2
+2|3
+3|1
+3|3
+4|1
+5|2
+6|1
+7|2
+8|2
+8|0
+9|1
+10|2
+11|1
+12|2
+13|2
+14|2
+15|3
+16|2
+17|2
+18|0
+18|1
+18|2
+19|2
+19|1
+20|0
+21|0
+22|1
+23|2
+24|1
+25|2
+26|1
+27|1
+28|2
+29|1
+29|2
+30|1
+31|2
+32|1
+32|2
+33|2
+34|1
+35|1
+36|0
+37|1
+38|0
+38|1
+39|2
+40|1
+41|3
+42|3
+43|2
+44|0
+45|2
+46|1
+46|2
+47|0
+48|0
+49|1
+50|0
+51|0
+52|0
+52|1
+52|2
+53|1
+54|0
+54|1
+55|1
+56|2
+57|0
+57|1
+57|2
+58|2
+59|1
+59|2
+60|1
+60|2
+61|0
+62|0
+63|1
+64|1
+65|1
+66|1
+67|1
+68|1
+69|1
+70|3
+71|1
+72|0
+73|0
+73|1
+74|0
+75|2
+76|0
+76|1
+77|0
+77|1
+78|0
+79|2
+81|1
+82|1
+83|2
+84|1
+85|1
+85|2
+87|1
+88|1
+89|2
+90|1
+91|1
+91|2
+92|2
+93|0
+94|1
+95|1
+96|2
+97|2
+98|2
+99|3
+100|2
+101|2
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/Paper_Use_Strategy.csv b/flex/interactive/examples/graph_algo/Paper_Use_Strategy.csv
new file mode 100644
index 000000000000..2180c802b360
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Paper_Use_Strategy.csv
@@ -0,0 +1,126 @@
+start|end
+47|0
+44|0
+72|0
+76|0
+77|0
+8|0
+74|0
+50|0
+38|0
+61|1
+93|1
+62|1
+78|1
+48|1
+73|2
+32|3
+34|3
+19|3
+39|3
+30|3
+63|3
+29|3
+32|4
+37|4
+5|4
+76|5
+49|5
+101|6
+77|6
+69|6
+38|6
+90|6
+77|7
+69|7
+73|7
+32|8
+34|8
+19|4
+21|4
+39|8
+29|8
+33|8
+58|9
+8|9
+1|9
+83|9
+49|9
+42|10
+41|10
+2|11
+0|15
+0|13
+1|3
+3|13
+4|13
+6|4
+7|14
+9|4
+10|14
+11|13
+12|14
+13|14
+14|14
+15|15
+16|14
+17|14
+18|4
+18|0
+20|4
+21|0
+22|5
+23|14
+24|3
+25|14
+26|13
+27|13
+28|14
+31|14
+35|3
+36|0
+40|3
+43|14
+45|14
+46|14
+51|4
+51|0
+52|4
+52|1
+53|3
+54|0
+54|13
+55|13
+56|14
+57|4
+59|14
+59|13
+60|13
+60|14
+64|13
+65|13
+66|13
+67|13
+68|7
+70|15
+71|14
+75|14
+79|14
+81|13
+82|13
+84|13
+85|13
+85|14
+87|13
+88|13
+89|14
+91|4
+92|13
+94|13
+95|3
+96|13
+97|13
+98|13
+99|15
+100|13
+101|13
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/Paper_WorkOn_Algorithm.csv b/flex/interactive/examples/graph_algo/Paper_WorkOn_Algorithm.csv
new file mode 100644
index 000000000000..75a9da5b7add
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Paper_WorkOn_Algorithm.csv
@@ -0,0 +1,103 @@
+start|end
+0|0
+1|0
+2|0
+3|0
+4|0
+5|0
+6|0
+7|1
+8|1
+9|1
+10|3
+11|3
+12|3
+13|3
+14|3
+15|3
+16|4
+17|4
+18|6
+19|6
+20|6
+21|6
+22|7
+23|7
+24|8
+25|8
+26|8
+27|11
+28|12
+29|13
+30|13
+31|13
+32|13
+33|13
+34|14
+35|14
+36|14
+37|14
+38|15
+39|15
+40|15
+41|15
+42|15
+43|15
+44|15
+45|15
+46|15
+47|17
+48|17
+49|17
+50|17
+51|17
+52|18
+53|18
+54|18
+55|18
+56|18
+57|18
+58|19
+59|19
+60|19
+61|19
+62|19
+63|19
+64|22
+65|22
+66|22
+67|22
+68|22
+69|22
+70|22
+71|22
+72|22
+73|22
+74|22
+75|22
+76|22
+77|22
+78|22
+79|8
+80|8
+81|8
+82|23
+83|23
+84|23
+85|23
+86|23
+87|24
+88|24
+89|9
+90|9
+91|9
+92|9
+93|9
+94|25
+95|26
+96|26
+97|26
+98|26
+99|26
+100|26
+101|19
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/Strategy.csv b/flex/interactive/examples/graph_algo/Strategy.csv
new file mode 100644
index 000000000000..40e6dbc258e6
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Strategy.csv
@@ -0,0 +1,17 @@
+id|strategy
+0|Partition
+1|Scheduling
+2|Dense Representation
+3|Communication Pruning
+4|Subgraph-Centric
+5|Combination of Push and Pull Model
+6|Aggregation
+7|Navigation
+8|Local Computation
+9|Asynchronous
+10|Pruning
+11|Segmentation
+12|Other (Load Balance)
+13|Other (Communication Overhead)
+14|Other (Parallelism)
+15|Other (Bandwidth)
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/Strategy_ApplyOn_Challenge.csv b/flex/interactive/examples/graph_algo/Strategy_ApplyOn_Challenge.csv
new file mode 100644
index 000000000000..54cbaf823c2c
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Strategy_ApplyOn_Challenge.csv
@@ -0,0 +1,17 @@
+start|end
+0|0
+1|0
+12|0
+3|1
+4|1
+5|1
+6|1
+7|1
+13|1
+8|2
+9|2
+14|2
+10|3
+11|3
+2|3
+15|3
\ No newline at end of file
diff --git a/flex/interactive/examples/graph_algo/Topic.csv b/flex/interactive/examples/graph_algo/Topic.csv
new file mode 100644
index 000000000000..47fc74d189d0
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/Topic.csv
@@ -0,0 +1,8 @@
+id|category
+0|Centrality
+1|Clustering
+2|Similarity
+3|Cohesive_Subgraph
+4|Pattern Matching
+5|Traversal
+6|Other
diff --git a/flex/interactive/examples/graph_algo/graph.yaml b/flex/interactive/examples/graph_algo/graph.yaml
new file mode 100644
index 000000000000..0148bc0a7f3d
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/graph.yaml
@@ -0,0 +1,120 @@
+name: graph_algo
+schema:
+  vertex_types:
+    - type_name: Paper
+      properties:
+        - property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_name: conference
+          property_type:
+            primitive_type: DT_STRING
+        - property_name: CCFRank
+          property_type:
+            primitive_type: DT_STRING
+        - property_name: CCFField
+          property_type:
+            primitive_type: DT_STRING
+        - property_name: year
+          property_type:
+            primitive_type: DT_SIGNED_INT32
+        - property_name: paper
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+    - type_name: Challenge
+      properties:
+        - property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_name: challenge
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+    - type_name: Topic
+      properties:
+        - property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_name: category
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+    - type_name: Algorithm
+      properties:
+        - property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_name: algorithm
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+    - type_name: Strategy
+      properties:
+        - property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_name: strategy
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+    - type_name: CCFField
+      properties:
+        - property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_name: field
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+  edge_types:
+    - type_name: WorkOn
+      vertex_type_pair_relations:
+        - source_vertex: Paper
+          destination_vertex: Algorithm
+          relation: MANY_TO_ONE
+    - type_name: Resolve
+      vertex_type_pair_relations:
+        - source_vertex: Paper
+          destination_vertex: Challenge
+          relation: MANY_TO_MANY
+    - type_name: Target
+      vertex_type_pair_relations:
+        - source_vertex: Algorithm
+          destination_vertex: Challenge
+          relation: MANY_TO_MANY
+      properties:
+        - property_name: number
+          property_type:
+            primitive_type: DT_SIGNED_INT32
+    - type_name: Belong
+      vertex_type_pair_relations:
+        - source_vertex: Algorithm
+          destination_vertex: Topic
+          relation: MANY_TO_ONE
+    - type_name: Use
+      vertex_type_pair_relations:
+        - source_vertex: Paper
+          destination_vertex: Strategy
+          relation: MANY_TO_MANY
+    - type_name: ApplyOn
+      vertex_type_pair_relations:
+        - source_vertex: Strategy
+          destination_vertex: Challenge
+          relation: MANY_TO_ONE
+    - type_name: HasField
+      vertex_type_pair_relations:
+        - source_vertex: Paper
+          destination_vertex: CCFField
+          relation: MANY_TO_MANY
+    - type_name: Citation
+      vertex_type_pair_relations:
+        - source_vertex: Paper
+          destination_vertex: Paper
+          relation: MANY_TO_MANY
diff --git a/flex/interactive/examples/graph_algo/import.yaml b/flex/interactive/examples/graph_algo/import.yaml
new file mode 100644
index 000000000000..4c7d65b37a1d
--- /dev/null
+++ b/flex/interactive/examples/graph_algo/import.yaml
@@ -0,0 +1,94 @@
+graph: graph_algo
+loading_config:
+  data_source:
+    scheme: file  # file, oss, s3, hdfs; only file is supported now
+#    location: /home/graphscope/graph_algo/
+  import_option: init # append, overwrite, only init is supported now
+  format:
+    type: csv
+    metadata:
+      delimiter: '|'  # other loading configuration places here
+      header_row: true # whether to use the first row as the header
+      quoting: false
+      quote_char: '"'
+      double_quote: true
+      escape_char: '\'
+      escaping: false
+      block_size: 4MB
+      batch_reader: false
+vertex_mappings:
+  - type_name: Paper  # must align with the schema
+    inputs:
+      - Paper.csv
+  - type_name: Challenge
+    inputs:
+      - Challenge.csv
+  - type_name: Topic
+    inputs:
+      - Topic.csv
+  - type_name: Algorithm
+    inputs:
+      - Algorithm.csv
+  - type_name: Strategy
+    inputs:
+      - Strategy.csv
+  - type_name: CCFField
+    inputs:
+      - CCFField.csv
+edge_mappings:
+  - type_triplet:
+      edge: WorkOn
+      source_vertex:  Paper
+      destination_vertex:  Algorithm
+    inputs:
+      - Paper_WorkOn_Algorithm.csv
+  - type_triplet:
+      edge: Resolve
+      source_vertex:  Paper
+      destination_vertex:  Challenge
+    inputs:
+      - Paper_Resolve_Challenge.csv
+  - type_triplet: 
+      edge: Target
+      source_vertex:  Algorithm
+      destination_vertex:  Challenge
+    source_vertex_mappings:
+      - column:
+          index: 0
+          name: id
+    destination_vertex_mappings:
+      - column:
+          index: 1
+          name: id
+    inputs:
+      - Algorithm_Target_Challenge.csv
+  - type_triplet: 
+      edge: Belong
+      source_vertex:  Algorithm
+      destination_vertex:  Topic
+    inputs:
+      - Algorithm_Belong_Topic.csv
+  - type_triplet:
+      edge: Use
+      source_vertex:  Paper
+      destination_vertex:  Strategy
+    inputs:
+      - Paper_Use_Strategy.csv
+  - type_triplet:
+      edge: ApplyOn
+      source_vertex:  Strategy
+      destination_vertex:  Challenge
+    inputs:
+      - Strategy_ApplyOn_Challenge.csv
+  - type_triplet:
+      edge: HasField
+      source_vertex:  Paper
+      destination_vertex:  CCFField
+    inputs:
+      - Paper_HasField_CCFField.csv
+  - type_triplet:
+      edge: Citation
+      source_vertex:  Paper
+      destination_vertex:  Paper
+    inputs:
+      - Paper_Citation_Paper.csv
diff --git a/flex/interactive/examples/movies/REVIEWED.csv b/flex/interactive/examples/movies/REVIEWED.csv
index 829aff494856..497396b717fa 100644
--- a/flex/interactive/examples/movies/REVIEWED.csv
+++ b/flex/interactive/examples/movies/REVIEWED.csv
@@ -1,5 +1,4 @@
 start|end|rating|summary
-
 169|105|95|An amazing journey
 171|105|100|A perfect movie
 173|105|90|Unforgettable
diff --git a/flex/utils/id_indexer.h b/flex/utils/id_indexer.h
index fd7d4ee17924..a22cb1a426ed 100644
--- a/flex/utils/id_indexer.h
+++ b/flex/utils/id_indexer.h
@@ -319,7 +319,9 @@ class LFIndexer {
   }
 
   bool get_index(const Any& oid, INDEX_T& ret) const {
-    assert(oid.type == get_type());
+    if (oid.type != get_type()) {
+      return false;
+    }
     size_t index =
         hash_policy_.index_for_hash(hasher_(oid), num_slots_minus_one_);
     static constexpr INDEX_T sentinel = std::numeric_limits<INDEX_T>::max();
diff --git a/flex/utils/property/column.h b/flex/utils/property/column.h
index 1810289ed1cf..75ac2dce8e48 100644
--- a/flex/utils/property/column.h
+++ b/flex/utils/property/column.h
@@ -515,6 +515,24 @@ class TypedRefColumn : public RefColumnBase {
   StorageStrategy strategy_;
 };
 
+template <>
+class TypedRefColumn<LabelKey> : public RefColumnBase {
+ public:
+  TypedRefColumn(LabelKey label_key) : label_key_(label_key) {}
+
+  ~TypedRefColumn() {}
+
+  inline LabelKey get_view(size_t index) const { return label_key_; }
+
+  Any get(size_t index) const override {
+    LOG(ERROR) << "LabelKeyColumn does not support get() to Any";
+    return Any();
+  }
+
+ private:
+  LabelKey label_key_;
+};
+
 }  // namespace gs
 
 #endif  // GRAPHSCOPE_PROPERTY_COLUMN_H_
diff --git a/flex/utils/property/types.h b/flex/utils/property/types.h
index 8ac36222ff98..93ba705889b2 100644
--- a/flex/utils/property/types.h
+++ b/flex/utils/property/types.h
@@ -116,6 +116,21 @@ struct Date {
   int64_t milli_second;
 };
 
+struct LabelKey {
+  using label_data_type = uint8_t;
+  int32_t label_id;
+  LabelKey() = default;
+  LabelKey(label_data_type id) : label_id(id) {}
+  LabelKey(LabelKey&&) = default;
+  LabelKey(const LabelKey&) = default;
+
+  // operator=
+  LabelKey& operator=(const LabelKey& other) {
+    label_id = other.label_id;
+    return *this;
+  }
+};
+
 union AnyValue {
   AnyValue() {}
   ~AnyValue() {}
@@ -795,7 +810,19 @@ grape::OutArchive& operator>>(grape::OutArchive& out_archive,
 
 }  // namespace gs
 
+namespace boost {
+// override boost hash function for EmptyType
+inline std::size_t hash_value(const grape::EmptyType& value) { return 0; }
+}  // namespace boost
+
 namespace std {
+inline bool operator==(const grape::EmptyType& a, const grape::EmptyType& b) {
+  return true;
+}
+
+inline bool operator!=(const grape::EmptyType& a, const grape::EmptyType& b) {
+  return false;
+}
 
 inline ostream& operator<<(ostream& os, const gs::Date& dt) {
   os << dt.to_string();
diff --git a/interactive_engine/compiler/pom.xml b/interactive_engine/compiler/pom.xml
index 590a7928cccf..9deae4b90f2a 100644
--- a/interactive_engine/compiler/pom.xml
+++ b/interactive_engine/compiler/pom.xml
@@ -254,6 +254,7 @@
                         <exclude>**/SimpleMatchTest.java</exclude>
                         <exclude>**/IrPatternTest.java</exclude>
                         <exclude>**/MovieTest.java</exclude>
+                        <exclude>**/GraphAlgoTest.java</exclude>
                     </excludes>
                 </configuration>
             </plugin>
diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/client/HttpExecutionClient.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/client/HttpExecutionClient.java
index 97efb753bb04..55b1a6949191 100644
--- a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/client/HttpExecutionClient.java
+++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/common/client/HttpExecutionClient.java
@@ -80,14 +80,26 @@ public void submit(
                             .sendAsync(httpRequest, HttpResponse.BodyHandlers.ofByteArray())
                             .orTimeout(timeoutConfig.getChannelTimeoutMS(), TimeUnit.MILLISECONDS)
                             .whenComplete(
-                                    (bytes, exception) -> {
+                                    (response, exception) -> {
                                         if (exception != null) {
                                             listener.onError(exception);
                                         }
                                         try {
+                                            // if response is not 200
+                                            if (response.statusCode() != 200) {
+                                                // parse String from response.body()
+                                                String errorMessage = new String(response.body());
+                                                listener.onError(
+                                                        new RuntimeException(
+                                                                "Query execution failed: response"
+                                                                        + " status code is "
+                                                                        + response.statusCode()
+                                                                        + ", error message: "
+                                                                        + errorMessage));
+                                            }
                                             IrResult.CollectiveResults results =
                                                     IrResult.CollectiveResults.parseFrom(
-                                                            bytes.body());
+                                                            response.body());
                                             for (IrResult.Results irResult :
                                                     results.getResultsList()) {
                                                 listener.onNext(irResult.getRecord());
diff --git a/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/graphAlgo/GraphAlgoQueries.java b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/graphAlgo/GraphAlgoQueries.java
new file mode 100644
index 000000000000..c5b76f50f643
--- /dev/null
+++ b/interactive_engine/compiler/src/main/java/com/alibaba/graphscope/cypher/integration/suite/graphAlgo/GraphAlgoQueries.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2020 Alibaba Group Holding Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.graphscope.cypher.integration.suite.graphAlgo;
+
+import com.alibaba.graphscope.cypher.integration.suite.QueryContext;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class GraphAlgoQueries {
+
+    public static QueryContext get_graph_algo_test1() {
+        String query =
+                "MATCH (p:Paper)-[:WorkOn]->(:Algorithm)-[:Belong]->(ca:Topic)\n"
+                        + "WITH distinct ca, count(p) as paperCount\n"
+                        + "RETURN ca.category, paperCount\n "
+                        + "ORDER BY paperCount desc;";
+        List<String> expected =
+                Arrays.asList(
+                        "Record<{category: \"Traversal\", paperCount: 29}>",
+                        "Record<{category: \"Cohesive_Subgraph\", paperCount:" + " 18}>",
+                        "Record<{category: \"Centrality\", paperCount: 18}>",
+                        "Record<{category: \"Clustering\", paperCount: 17}>",
+                        "Record<{category: \"Pattern Matching\", paperCount: 11}>",
+                        "Record<{category: \"Other\", paperCount: 7}>",
+                        "Record<{category: \"Similarity\", paperCount: 2}>");
+        return new QueryContext(query, expected);
+    }
+
+    public static QueryContext get_graph_algo_test2() {
+        String query =
+                "MATCH (ca:Topic)<-[:Belong]-(a:Algorithm),\n"
+                        + "(a)<-[:WorkOn]-(p:Paper)-[:Use]->(s:Strategy),\n"
+                        + "(s)-[:ApplyOn]->(ch:Challenge)\n"
+                        + "WITH ca, ch, count(p) AS num \n"
+                        + "RETURN ca.category AS category, ch.challenge AS challenge, num\n"
+                        + "ORDER BY num DESC LIMIT 5;";
+        List<String> expected =
+                Arrays.asList(
+                        "Record<{category: \"Traversal\", challenge: \"Communication Overhead\","
+                                + " num: 21}>",
+                        "Record<{category: \"Clustering\", challenge: \"Communication Overhead\","
+                                + " num: 12}>",
+                        "Record<{category: \"Cohesive_Subgraph\", challenge:"
+                                + " \"Communication Overhead\", num: 10}>",
+                        "Record<{category: \"Centrality\", challenge:"
+                                + " \"Parallelism\", num: 9}>",
+                        "Record<{category: \"Cohesive_Subgraph\", challenge: \"Parallelism\", num:"
+                                + " 9}>");
+        return new QueryContext(query, expected);
+    }
+
+    public static QueryContext get_graph_algo_test3() {
+        String query =
+                "MATCH(c: CCFField)<-[e]-(p:Paper) return type(e) As edgeType ORDER BY edgeType ASC"
+                        + " LIMIT 10;";
+        List<String> expected =
+                Arrays.asList(
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>");
+        return new QueryContext(query, expected);
+    }
+
+    public static QueryContext get_graph_algo_test4() {
+        String query = "MATCH(v)-[e]-() return distinct type(e) AS edgeType order by edgeType ASC;";
+        List<String> expected =
+                Arrays.asList(
+                        "Record<{edgeType: \"WorkOn\"}>",
+                        "Record<{edgeType: \"Resolve\"}>",
+                        "Record<{edgeType: \"Target\"}>",
+                        "Record<{edgeType: \"Belong\"}>",
+                        "Record<{edgeType: \"Use\"}>",
+                        "Record<{edgeType: \"ApplyOn\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"Citation\"}>");
+        return new QueryContext(query, expected);
+    }
+
+    public static QueryContext get_graph_algo_test5() {
+        String query =
+                "MATCH(c: CCFField)<-[e]-(p:Paper) where type(e) = 6 return type(e) As edgeType"
+                        + " ORDER BY edgeType ASC LIMIT 10;";
+        List<String> expected =
+                Arrays.asList(
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>",
+                        "Record<{edgeType: \"HasField\"}>");
+        return new QueryContext(query, expected);
+    }
+
+    public static QueryContext get_graph_algo_test6() {
+        String query =
+                "MATCH (p:Paper)-[:Resolve]->(ch:Challenge),\n"
+                        + "(p1:Paper)-[:Resolve]->(ch),\n"
+                        + "(p)-[c:Citation]->(p1) \n"
+                        + "RETURN COUNT(distinct c) AS count;";
+        List<String> expected = Arrays.asList("Record<{count: 38}>");
+        return new QueryContext(query, expected);
+    }
+
+    public static QueryContext get_graph_algo_test7() {
+
+        String query =
+                "MATCH (p:Paper)-[:Resolve]->(ch:Challenge),\n"
+                    + "      (p1:Paper)-[:Resolve]->(ch),\n"
+                    + "       (p)-[c:Citation]->(p1)\n"
+                    + "WITH DISTINCT p, c, p1\n"
+                    + "WITH p.id As paperId, p1.id As citationId\n"
+                    + "RETURN paperId, citationId ORDER BY paperId ASC, citationId ASC LIMIT 5;";
+
+        List<String> expected =
+                Arrays.asList(
+                        "Record<{paperId: 0, citationId: 3}>",
+                        "Record<{paperId: 0, citationId: 4}>",
+                        "Record<{paperId: 0, citationId: 9}>",
+                        "Record<{paperId: 2, citationId: 3}>",
+                        "Record<{paperId: 3, citationId: 4}>");
+        return new QueryContext(query, expected);
+    }
+}


Test patch:
diff --git a/flex/tests/hqps/hqps_cypher_test.sh b/flex/tests/hqps/hqps_cypher_test.sh
index e32da4080099..d295ca4e0fa7 100644
--- a/flex/tests/hqps/hqps_cypher_test.sh
+++ b/flex/tests/hqps/hqps_cypher_test.sh
@@ -34,7 +34,7 @@ if [ ! -d ${INTERACTIVE_WORKSPACE} ]; then
   exit 1
 fi
 # check graph is ldbc or movies
-if [ ${GRAPH_NAME} != "ldbc" ] && [ ${GRAPH_NAME} != "movies" ]; then
+if [ ${GRAPH_NAME} != "ldbc" ] && [ ${GRAPH_NAME} != "movies" ] && [ ${GRAPH_NAME} != "graph_algo" ]; then
   echo "GRAPH_NAME: ${GRAPH_NAME} not supported, use movies or ldbc"
   exit 1
 fi
@@ -148,6 +148,16 @@ run_movie_test(){
   popd
 }
 
+run_graph_algo_test(){
+  echo "run graph_algo test"
+  pushd ${GIE_HOME}/compiler
+  cmd="mvn test -Dtest=com.alibaba.graphscope.cypher.integration.graphAlgo.GraphAlgoTest"
+  echo "Start graph_algo test: ${cmd}"
+  ${cmd}
+  info "Finish graph_algo test"
+  popd
+}
+
 kill_service
 start_engine_service
 start_compiler_service
@@ -155,12 +165,12 @@ start_compiler_service
 if [ "${GRAPH_NAME}" == "ldbc" ]; then
   run_ldbc_test
   run_simple_test
-else
+elif [ "${GRAPH_NAME}" == "movies" ]; then
   run_movie_test
+elif [ "${GRAPH_NAME}" == "graph_algo" ]; then
+  run_graph_algo_test
+else
+  echo "GRAPH_NAME: ${GRAPH_NAME} not supported, use movies, ldbc or graph_algo"
 fi
 
 kill_service
-
-
-
-
diff --git a/flex/tests/interactive/graph_algo_test.yaml b/flex/tests/interactive/graph_algo_test.yaml
new file mode 100644
index 000000000000..adebb1d52696
--- /dev/null
+++ b/flex/tests/interactive/graph_algo_test.yaml
@@ -0,0 +1,152 @@
+name: graph_algo
+store_type: mutable_csr
+schema:
+  vertex_types:
+    - type_id: 0
+      type_name: Paper
+      properties:
+        - property_id: 0
+          property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_id: 1
+          property_name: conference
+          property_type:
+            primitive_type: DT_STRING
+        - property_id: 2
+          property_name: CCFRank
+          property_type:
+            primitive_type: DT_STRING
+        - property_id: 3
+          property_name: CCFField
+          property_type:
+            primitive_type: DT_STRING
+        - property_id: 4
+          property_name: year
+          property_type:
+            primitive_type: DT_SIGNED_INT32
+        - property_id: 5
+          property_name: paper
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+    - type_id: 1
+      type_name: Challenge
+      properties:
+        - property_id: 0
+          property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_id: 1
+          property_name: challenge
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+    - type_id: 2
+      type_name: Topic
+      properties:
+        - property_id: 0
+          property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_id: 1
+          property_name: category
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+    - type_id: 3
+      type_name: Algorithm
+      properties:
+        - property_id: 0
+          property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_id: 1
+          property_name: algorithm
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+    - type_id: 4
+      type_name: Strategy
+      properties:
+        - property_id: 0
+          property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_id: 1
+          property_name: strategy
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+    - type_id: 5
+      type_name: CCFField
+      properties:
+        - property_id: 0
+          property_name: id
+          property_type:
+            primitive_type: DT_SIGNED_INT64
+        - property_id: 1
+          property_name: field
+          property_type:
+            primitive_type: DT_STRING
+      primary_keys:
+        - id
+  edge_types:
+    - type_id: 0
+      type_name: WorkOn
+      vertex_type_pair_relations:
+        - source_vertex: Paper
+          destination_vertex: Algorithm
+          relation: MANY_TO_ONE
+    - type_id: 1
+      type_name: Resolve
+      vertex_type_pair_relations:
+        - source_vertex: Paper
+          destination_vertex: Challenge
+          relation: MANY_TO_MANY
+    - type_id: 2
+      type_name: Target
+      vertex_type_pair_relations:
+        - source_vertex: Algorithm
+          destination_vertex: Challenge
+          relation: MANY_TO_MANY
+      properties:
+        - property_id: 0
+          property_name: number
+          property_type:
+            primitive_type: DT_SIGNED_INT32
+    - type_id: 3
+      type_name: Belong
+      vertex_type_pair_relations:
+        - source_vertex: Algorithm
+          destination_vertex: Topic
+          relation: MANY_TO_ONE
+    - type_id: 4
+      type_name: Use
+      vertex_type_pair_relations:
+        - source_vertex: Paper
+          destination_vertex: Strategy
+          relation: MANY_TO_MANY
+    - type_id: 5
+      type_name: ApplyOn
+      vertex_type_pair_relations:
+        - source_vertex: Strategy
+          destination_vertex: Challenge
+          relation: MANY_TO_ONE
+    - type_id: 6
+      type_name: HasField
+      vertex_type_pair_relations:
+        - source_vertex: Paper
+          destination_vertex: CCFField
+          relation: MANY_TO_MANY
+    - type_id: 7
+      type_name: Citation
+      vertex_type_pair_relations:
+        - source_vertex: Paper
+          destination_vertex: Paper
+          relation: MANY_TO_MANY
\ No newline at end of file
diff --git a/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/graphAlgo/GraphAlgoTest.java b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/graphAlgo/GraphAlgoTest.java
new file mode 100644
index 000000000000..f60c4a113536
--- /dev/null
+++ b/interactive_engine/compiler/src/test/java/com/alibaba/graphscope/cypher/integration/graphAlgo/GraphAlgoTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 Alibaba Group Holding Limited.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.graphscope.cypher.integration.graphAlgo;
+
+import com.alibaba.graphscope.cypher.integration.suite.QueryContext;
+import com.alibaba.graphscope.cypher.integration.suite.graphAlgo.GraphAlgoQueries;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.neo4j.driver.GraphDatabase;
+import org.neo4j.driver.Result;
+import org.neo4j.driver.Session;
+
+public class GraphAlgoTest {
+
+    private static Session session;
+
+    @BeforeClass
+    public static void beforeClass() {
+        String neo4jServerUrl =
+                System.getProperty("neo4j.bolt.server.url", "neo4j://localhost:7687");
+        session = GraphDatabase.driver(neo4jServerUrl).session();
+    }
+
+    @Test
+    public void run_graph_query1_test() {
+        QueryContext testQuery = GraphAlgoQueries.get_graph_algo_test1();
+        Result result = session.run(testQuery.getQuery());
+        Assert.assertEquals(testQuery.getExpectedResult().toString(), result.list().toString());
+    }
+
+    @Test
+    public void run_graph_query2_test() {
+        QueryContext testQuery = GraphAlgoQueries.get_graph_algo_test2();
+        Result result = session.run(testQuery.getQuery());
+        Assert.assertEquals(testQuery.getExpectedResult().toString(), result.list().toString());
+    }
+
+    @Test
+    public void run_graph_query3_test() {
+        QueryContext testQuery = GraphAlgoQueries.get_graph_algo_test3();
+        Result result = session.run(testQuery.getQuery());
+        Assert.assertEquals(testQuery.getExpectedResult().toString(), result.list().toString());
+    }
+
+    @Test
+    public void run_graph_query4_test() {
+        QueryContext testQuery = GraphAlgoQueries.get_graph_algo_test4();
+        Result result = session.run(testQuery.getQuery());
+        Assert.assertEquals(testQuery.getExpectedResult().toString(), result.list().toString());
+    }
+
+    @Test
+    public void run_graph_query5_test() {
+        QueryContext testQuery = GraphAlgoQueries.get_graph_algo_test5();
+        Result result = session.run(testQuery.getQuery());
+        Assert.assertEquals(testQuery.getExpectedResult().toString(), result.list().toString());
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        if (session != null) {
+            session.close();
+        }
+    }
+}