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_