flex/engines/graph_db/runtime/common/accessors.h (588 lines of code) (raw):

/** 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. */ #ifndef RUNTIME_COMMON_ACCESSORS_H_ #define RUNTIME_COMMON_ACCESSORS_H_ #include "flex/engines/graph_db/database/read_transaction.h" #include "flex/engines/graph_db/runtime/common/columns/edge_columns.h" #include "flex/engines/graph_db/runtime/common/columns/path_columns.h" #include "flex/engines/graph_db/runtime/common/columns/value_columns.h" #include "flex/engines/graph_db/runtime/common/columns/vertex_columns.h" #include "flex/engines/graph_db/runtime/common/context.h" #include "flex/engines/graph_db/runtime/common/graph_interface.h" #include "flex/engines/graph_db/runtime/common/rt_any.h" namespace gs { namespace runtime { class IAccessor { public: virtual ~IAccessor() = default; virtual RTAny eval_path(size_t idx) const = 0; virtual RTAny eval_vertex(label_t label, vid_t v, size_t idx) const { return this->eval_path(idx); } virtual RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx) const { return this->eval_path(idx); } virtual RTAny eval_path(size_t idx, int) const { return this->eval_path(idx); } virtual RTAny eval_vertex(label_t label, vid_t v, size_t idx, int) const { return this->eval_vertex(label, v, idx); } virtual RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx, int) const { return this->eval_edge(label, src, dst, data, idx); } virtual bool is_optional() const { return false; } virtual std::string name() const { return "unknown"; } virtual std::shared_ptr<IContextColumnBuilder> builder() const { return nullptr; } }; class VertexPathAccessor : public IAccessor { public: using elem_t = VertexRecord; VertexPathAccessor(const Context& ctx, int tag) : vertex_col_(*std::dynamic_pointer_cast<IVertexColumn>(ctx.get(tag))) {} bool is_optional() const override { return vertex_col_.is_optional(); } elem_t typed_eval_path(size_t idx) const { return vertex_col_.get_vertex(idx); } RTAny eval_path(size_t idx) const override { return RTAny::from_vertex(typed_eval_path(idx)); } RTAny eval_path(size_t idx, int) const override { if (!vertex_col_.has_value(idx)) { return RTAny(RTAnyType::kNull); } return RTAny::from_vertex(typed_eval_path(idx)); } private: const IVertexColumn& vertex_col_; }; class VertexGIdPathAccessor : public IAccessor { public: using elem_t = int64_t; VertexGIdPathAccessor(const Context& ctx, int tag) : vertex_col_(*std::dynamic_pointer_cast<IVertexColumn>(ctx.get(tag))) {} bool is_optional() const override { return vertex_col_.is_optional(); } elem_t typed_eval_path(size_t idx) const { const auto& v = vertex_col_.get_vertex(idx); return encode_unique_vertex_id(v.label_, v.vid_); } RTAny eval_path(size_t idx) const override { return RTAny::from_int64(typed_eval_path(idx)); } private: const IVertexColumn& vertex_col_; }; template <typename GraphInterface, typename T> class VertexPropertyPathAccessor : public IAccessor { public: using elem_t = T; VertexPropertyPathAccessor(const GraphInterface& graph, const Context& ctx, int tag, const std::string& prop_name) : is_optional_(false), vertex_col_(*std::dynamic_pointer_cast<IVertexColumn>(ctx.get(tag))) { int label_num = graph.schema().vertex_label_num(); property_columns_.resize(label_num); const auto& labels = vertex_col_.get_labels_set(); if (vertex_col_.is_optional()) { is_optional_ = true; } for (auto label : labels) { property_columns_[label] = graph.template GetVertexColumn<T>(label, prop_name); if (property_columns_[label].is_null()) { is_optional_ = true; } } } bool is_optional() const override { return is_optional_; } elem_t typed_eval_path(size_t idx) const { const auto& v = vertex_col_.get_vertex(idx); auto& col = property_columns_[v.label_]; if (!col.is_null()) { return col.get_view(v.vid_); } else { return elem_t(); } } RTAny eval_path(size_t idx) const override { auto val = TypedConverter<T>::from_typed(typed_eval_path(idx)); return val; } RTAny eval_path(size_t idx, int) const override { if (!vertex_col_.has_value(idx)) { return RTAny(RTAnyType::kNull); } const auto& v = vertex_col_.get_vertex(idx); auto& col = property_columns_[v.label_]; if (!col.is_null()) { return TypedConverter<T>::from_typed(col.get_view(v.vid_)); } else { return RTAny(RTAnyType::kNull); } } private: bool is_optional_; const IVertexColumn& vertex_col_; using vertex_column_t = typename GraphInterface::template vertex_column_t<elem_t>; std::vector<vertex_column_t> property_columns_; }; class VertexLabelPathAccessor : public IAccessor { public: using elem_t = int32_t; VertexLabelPathAccessor(const Context& ctx, int tag) : vertex_col_(*std::dynamic_pointer_cast<IVertexColumn>(ctx.get(tag))) {} elem_t typed_eval_path(size_t idx) const { return static_cast<int32_t>(vertex_col_.get_vertex(idx).label_); } RTAny eval_path(size_t idx) const override { return RTAny(static_cast<int32_t>(typed_eval_path(idx))); } private: const IVertexColumn& vertex_col_; }; class VertexLabelVertexAccessor : public IAccessor { public: using elem_t = int64_t; VertexLabelVertexAccessor() {} elem_t typed_eval_vertex(label_t label, vid_t v, size_t idx) const { return static_cast<int64_t>(label); } RTAny eval_path(size_t idx) const override { LOG(FATAL) << "not supposed to reach here..."; return RTAny(); } RTAny eval_vertex(label_t label, vid_t v, size_t idx) const override { return RTAny::from_int64(label); } }; template <typename T> class ContextValueAccessor : public IAccessor { public: using elem_t = T; ContextValueAccessor(const Context& ctx, int tag) : col_(*std::dynamic_pointer_cast<IValueColumn<elem_t>>(ctx.get(tag))) { assert(std::dynamic_pointer_cast<IValueColumn<elem_t>>(ctx.get(tag)) != nullptr); } elem_t typed_eval_path(size_t idx) const { return col_.get_value(idx); } RTAny eval_path(size_t idx) const override { return col_.get_elem(idx); } bool is_optional() const override { return col_.is_optional(); } RTAny eval_path(size_t idx, int) const override { if (!col_.has_value(idx)) { return RTAny(RTAnyType::kNull); } return eval_path(idx); } private: const IValueColumn<elem_t>& col_; }; class VertexIdVertexAccessor : public IAccessor { public: using elem_t = VertexRecord; VertexIdVertexAccessor() {} elem_t typed_eval_vertex(label_t label, vid_t v, size_t idx) const { return VertexRecord{label, v}; } RTAny eval_path(size_t idx) const override { LOG(FATAL) << "not supposed to reach here..."; return RTAny(); } RTAny eval_vertex(label_t label, vid_t v, size_t idx) const override { return RTAny::from_vertex(typed_eval_vertex(label, v, idx)); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, int) const override { if (v == std::numeric_limits<vid_t>::max()) { return RTAny(RTAnyType::kNull); } return RTAny::from_vertex(typed_eval_vertex(label, v, idx)); } }; class VertexGIdVertexAccessor : public IAccessor { public: using elem_t = int64_t; VertexGIdVertexAccessor() {} elem_t typed_eval_vertex(label_t label, vid_t v, size_t idx) const { return encode_unique_vertex_id(label, v); } RTAny eval_path(size_t idx) const override { LOG(FATAL) << "not supposed to reach here..."; return RTAny(); } RTAny eval_vertex(label_t label, vid_t v, size_t idx) const override { return RTAny::from_int64(typed_eval_vertex(label, v, idx)); } }; template <typename GraphInterface, typename T> class VertexPropertyVertexAccessor : public IAccessor { public: using elem_t = T; VertexPropertyVertexAccessor(const GraphInterface& graph, const std::string& prop_name) { int label_num = graph.schema().vertex_label_num(); for (int i = 0; i < label_num; ++i) { property_columns_.emplace_back(graph.template GetVertexColumn<T>( static_cast<label_t>(i), prop_name)); } } elem_t typed_eval_vertex(label_t label, vid_t v, size_t idx) const { if (property_columns_[label].is_null()) { return elem_t(); } return property_columns_[label].get_view(v); } RTAny eval_path(size_t idx) const override { LOG(FATAL) << "not supposed to reach here..."; return RTAny(); } RTAny eval_vertex(label_t label, vid_t v, size_t idx) const override { if (property_columns_[label].is_null()) { return RTAny(); } return TypedConverter<T>::from_typed(property_columns_[label].get_view(v)); } RTAny eval_vertex(label_t label, vid_t v, size_t idx, int) const override { if (property_columns_[label].is_null()) { return RTAny(RTAnyType::kNull); } return TypedConverter<T>::from_typed(property_columns_[label].get_view(v)); } bool is_optional() const override { for (auto col : property_columns_) { if (col.is_null()) { return true; } } return false; } private: using vertex_column_t = typename GraphInterface::template vertex_column_t<elem_t>; std::vector<vertex_column_t> property_columns_; }; class EdgeIdPathAccessor : public IAccessor { public: using elem_t = EdgeRecord; EdgeIdPathAccessor(const Context& ctx, int tag) : edge_col_(*std::dynamic_pointer_cast<IEdgeColumn>(ctx.get(tag))) {} elem_t typed_eval_path(size_t idx) const { return edge_col_.get_edge(idx); } RTAny eval_path(size_t idx) const override { return RTAny::from_edge(typed_eval_path(idx)); } bool is_optional() const override { return edge_col_.is_optional(); } RTAny eval_path(size_t idx, int) const override { if (!edge_col_.has_value(idx)) { return RTAny(RTAnyType::kNull); } return RTAny::from_edge(typed_eval_path(idx)); } private: const IEdgeColumn& edge_col_; }; template <typename GraphInterface, typename T> class EdgePropertyPathAccessor : public IAccessor { public: using elem_t = T; EdgePropertyPathAccessor(const GraphInterface& graph, const std::string& prop_name, const Context& ctx, int tag) : col_(*std::dynamic_pointer_cast<IEdgeColumn>(ctx.get(tag))) {} RTAny eval_path(size_t idx) const override { const auto& e = col_.get_edge(idx); return RTAny(e.prop_); } elem_t typed_eval_path(size_t idx) const { const auto& e = col_.get_edge(idx); elem_t ret = e.prop_.as<elem_t>(); return ret; } bool is_optional() const override { return col_.is_optional(); } RTAny eval_path(size_t idx, int) const override { if (!col_.has_value(idx)) { return RTAny(RTAnyType::kNull); } return eval_path(idx); } private: const IEdgeColumn& col_; }; template <typename GraphInterface, typename T> class MultiPropsEdgePropertyPathAccessor : public IAccessor { public: using elem_t = T; MultiPropsEdgePropertyPathAccessor(const GraphInterface& graph, const std::string& prop_name, const Context& ctx, int tag) : col_(*std::dynamic_pointer_cast<IEdgeColumn>(ctx.get(tag))) { const auto& labels = col_.get_labels(); vertex_label_num_ = graph.schema().vertex_label_num(); edge_label_num_ = graph.schema().edge_label_num(); prop_index_.resize( 2 * vertex_label_num_ * vertex_label_num_ * edge_label_num_, std::numeric_limits<size_t>::max()); for (auto& label : labels) { size_t idx = label.src_label * vertex_label_num_ * edge_label_num_ + label.dst_label * edge_label_num_ + label.edge_label; const auto& names = graph.schema().get_edge_property_names( label.src_label, label.dst_label, label.edge_label); for (size_t i = 0; i < names.size(); ++i) { if (names[i] == prop_name) { prop_index_[idx] = i; break; } } } } RTAny eval_path(size_t idx) const override { const auto& e = col_.get_edge(idx); auto val = e.prop_; auto id = get_index(e.label_triplet_); if (e.prop_.type != RTAnyType::kRecordView) { assert(id == 0); return RTAny(val); } else { auto rv = val.as<RecordView>(); assert(id != std::numeric_limits<size_t>::max()); return RTAny(rv[id]); } } elem_t typed_eval_path(size_t idx) const { const auto& e = col_.get_edge(idx); auto val = e.prop_; auto id = get_index(e.label_triplet_); if (e.prop_.type != RTAnyType::kRecordView) { assert(id == 0); elem_t ret = e.prop_.as<elem_t>(); return ret; } else { auto rv = val.as<RecordView>(); assert(id != std::numeric_limits<size_t>::max()); auto tmp = rv[id]; elem_t ret; ConvertAny<T>::to(tmp, ret); return ret; } } bool is_optional() const override { return col_.is_optional(); } size_t get_index(const LabelTriplet& label) const { size_t idx = label.src_label * vertex_label_num_ * edge_label_num_ + label.dst_label * edge_label_num_ + label.edge_label; return prop_index_[idx]; } RTAny eval_path(size_t idx, int) const override { if (!col_.has_value(idx)) { return RTAny(RTAnyType::kNull); } return eval_path(idx); } private: const IEdgeColumn& col_; std::vector<size_t> prop_index_; size_t vertex_label_num_; size_t edge_label_num_; }; class EdgeLabelPathAccessor : public IAccessor { public: using elem_t = int32_t; EdgeLabelPathAccessor(const Context& ctx, int tag) : col_(*std::dynamic_pointer_cast<IEdgeColumn>(ctx.get(tag))) {} RTAny eval_path(size_t idx) const override { const auto& e = col_.get_edge(idx); return RTAny(static_cast<int32_t>(e.label_triplet_.edge_label)); } elem_t typed_eval_path(size_t idx) const { const auto& e = col_.get_edge(idx); return static_cast<int32_t>(e.label_triplet_.edge_label); } private: const IEdgeColumn& col_; }; template <typename GraphInterface, typename T> class EdgePropertyEdgeAccessor : public IAccessor { public: using elem_t = T; EdgePropertyEdgeAccessor(const GraphInterface& graph, const std::string& name) {} elem_t typed_eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx) const { T ret; ConvertAny<T>::to(data, ret); return ret; } RTAny eval_path(size_t idx) const override { LOG(FATAL) << "not supposed to reach here..."; return RTAny(); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx) const override { return RTAny(data); } }; template <typename GraphInterface, typename T> class MultiPropsEdgePropertyEdgeAccessor : public IAccessor { public: using elem_t = T; MultiPropsEdgePropertyEdgeAccessor(const GraphInterface& graph, const std::string& name) { edge_label_num_ = graph.schema().edge_label_num(); vertex_label_num_ = graph.schema().vertex_label_num(); indexs.resize(2 * vertex_label_num_ * vertex_label_num_ * edge_label_num_, std::numeric_limits<size_t>::max()); for (label_t src_label = 0; src_label < vertex_label_num_; ++src_label) { auto src = graph.schema().get_vertex_label_name(src_label); for (label_t dst_label = 0; dst_label < vertex_label_num_; ++dst_label) { auto dst = graph.schema().get_vertex_label_name(dst_label); for (label_t edge_label = 0; edge_label < edge_label_num_; ++edge_label) { auto edge = graph.schema().get_edge_label_name(edge_label); if (!graph.schema().exist(src, dst, edge)) { continue; } size_t idx = src_label * vertex_label_num_ * edge_label_num_ + dst_label * edge_label_num_ + edge_label; const std::vector<std::string>& names = graph.schema().get_edge_property_names(src_label, dst_label, edge_label); for (size_t i = 0; i < names.size(); ++i) { if (names[i] == name) { indexs[idx] = i; break; } } } } } } elem_t typed_eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx) const { T ret; if (data.type != PropertyType::RecordView()) { assert(get_index(label) == 0); ConvertAny<T>::to(data, ret); } else { auto id = get_index(label); assert(id != std::numeric_limits<size_t>::max()); auto view = data.AsRecordView(); ConvertAny<T>::to(view[id], ret); } return ret; } RTAny eval_path(size_t idx) const override { LOG(FATAL) << "not supposed to reach here..."; return RTAny(); } RTAny eval_edge(const LabelTriplet& label, vid_t src, vid_t dst, const Any& data, size_t idx) const override { return RTAny(typed_eval_edge(label, src, dst, data, idx)); } size_t get_index(const LabelTriplet& label) const { size_t idx = label.src_label * vertex_label_num_ * edge_label_num_ + label.dst_label * edge_label_num_ + label.edge_label; return indexs[idx]; } private: std::vector<size_t> indexs; size_t vertex_label_num_; size_t edge_label_num_; }; template <typename T> class ParamAccessor : public IAccessor { public: using elem_t = T; ParamAccessor(const std::map<std::string, std::string>& params, const std::string& key) { val_ = TypedConverter<T>::typed_from_string(params.at(key)); } T typed_eval_path(size_t) const { return val_; } T typed_eval_vertex(label_t, vid_t, size_t) const { return val_; } T typed_eval_edge(const LabelTriplet&, vid_t, vid_t, const Any&, size_t) const { return val_; } RTAny eval_path(size_t) const override { return TypedConverter<T>::from_typed(val_); } RTAny eval_vertex(label_t, vid_t, size_t) const override { return TypedConverter<T>::from_typed(val_); } RTAny eval_edge(const LabelTriplet&, vid_t, vid_t, const Any&, size_t) const override { return TypedConverter<T>::from_typed(val_); } private: T val_; }; class PathIdPathAccessor : public IAccessor { public: using elem_t = Path; PathIdPathAccessor(const Context& ctx, int tag) : path_col_(*std::dynamic_pointer_cast<IPathColumn>(ctx.get(tag))) {} elem_t typed_eval_path(size_t idx) const { return path_col_.get_path(idx); } RTAny eval_path(size_t idx) const override { return path_col_.get_elem(idx); } private: const IPathColumn& path_col_; }; class PathLenPathAccessor : public IAccessor { public: using elem_t = int32_t; PathLenPathAccessor(const Context& ctx, int tag) : path_col_(*std::dynamic_pointer_cast<IPathColumn>(ctx.get(tag))) {} elem_t typed_eval_path(size_t idx) const { return path_col_.get_path_length(idx); } RTAny eval_path(size_t idx) const override { return RTAny(static_cast<int32_t>(typed_eval_path(idx))); } private: const IPathColumn& path_col_; }; template <typename T> class ConstAccessor : public IAccessor { public: using elem_t = T; ConstAccessor(const T& val) : val_(val) {} T typed_eval_path(size_t) const { return val_; } T typed_eval_vertex(label_t, vid_t, size_t) const { return val_; } T typed_eval_edge(const LabelTriplet&, vid_t, vid_t, const Any&, size_t) const { return val_; } RTAny eval_path(size_t) const override { return TypedConverter<T>::from_typed(val_); } RTAny eval_vertex(label_t, vid_t, size_t) const override { return TypedConverter<T>::from_typed(val_); } RTAny eval_edge(const LabelTriplet&, vid_t, vid_t, const Any&, size_t) const override { return TypedConverter<T>::from_typed(val_); } private: T val_; }; std::shared_ptr<IAccessor> create_context_value_accessor(const Context& ctx, int tag, RTAnyType type); template <typename GraphInterface> std::shared_ptr<IAccessor> create_vertex_property_path_accessor( const GraphInterface& graph, const Context& ctx, int tag, RTAnyType type, const std::string& prop_name); template <typename GraphInterface> std::shared_ptr<IAccessor> create_vertex_property_vertex_accessor( const GraphInterface& graph, RTAnyType type, const std::string& prop_name); std::shared_ptr<IAccessor> create_vertex_label_path_accessor(const Context& ctx, int tag); template <typename GraphInterface> std::shared_ptr<IAccessor> create_edge_property_path_accessor( const GraphInterface& graph, const std::string& prop_name, const Context& ctx, int tag, RTAnyType type); std::shared_ptr<IAccessor> create_edge_label_path_accessor(const Context& ctx, int tag); template <typename GraphInterface> std::shared_ptr<IAccessor> create_edge_property_edge_accessor( const GraphInterface& graph, const std::string& prop_name, RTAnyType type); } // namespace runtime } // namespace gs #endif // RUNTIME_COMMON_ACCESSORS_H_