Skip to content

Commit

Permalink
fix(interactive): Support multiple edge properties and some minor fix (
Browse files Browse the repository at this point in the history
…#4438)

As titled.
  • Loading branch information
zhanglei1949 authored Jan 22, 2025
1 parent f45485f commit fd66790
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 28 deletions.
2 changes: 1 addition & 1 deletion docs/flex/interactive/data_model.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ vertex_type_pair_relations:
Note:
- A single edge type can have multiple `vertex_type_pair_relations`. For instance, a "knows" edge might connect one person to another, symbolizing their friendship. Alternatively, it could associate a person with a skill, indicating their proficiency in that skill.
- The permissible relations include: `ONE_TO_ONE`, `ONE_TO_MANY`, `MANY_TO_ONE`, and `MANY_TO_MANY`. These relations can be utilized by the optimizer to generate more efficient execution plans.
- Currently we only support at most one property for each edge triplet.
- Multiple edge properties are supported.
- We currently only support `var_char` and `long_text` as the edge property among all string types.
- All implementation related configuration are put under `x_csr_params`.
- `max_vertex_num` limit the number of vertices of this type:
Expand Down
10 changes: 2 additions & 8 deletions flex/engines/graph_db/runtime/common/columns/edge_columns.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,7 @@ namespace runtime {

std::shared_ptr<IContextColumn> SDSLEdgeColumn::shuffle(
const std::vector<size_t>& offsets) const {
std::vector<PropertyType> sub_types;
if (prop_type_ == PropertyType::kRecordView) {
sub_types = std::dynamic_pointer_cast<TypedColumn<RecordView>>(prop_col_)
->sub_types();
}
SDSLEdgeColumnBuilder builder(dir_, label_, prop_type_, sub_types);
SDSLEdgeColumnBuilder builder(dir_, label_, prop_type_);
size_t new_row_num = offsets.size();
builder.reserve(new_row_num);

Expand Down Expand Up @@ -84,8 +79,7 @@ std::shared_ptr<IContextColumn> SDSLEdgeColumn::optional_shuffle(
}

std::shared_ptr<IContextColumn> SDSLEdgeColumnBuilder::finish() {
auto ret =
std::make_shared<SDSLEdgeColumn>(dir_, label_, prop_type_, sub_types_);
auto ret = std::make_shared<SDSLEdgeColumn>(dir_, label_, prop_type_);
ret->edges_.swap(edges_);
// shrink to fit
prop_col_->resize(ret->edges_.size());
Expand Down
14 changes: 8 additions & 6 deletions flex/engines/graph_db/runtime/common/columns/edge_columns.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ static inline void get_edge_data(EdgePropVecBase* prop, size_t idx,
edge_data.value.day_val =
dynamic_cast<EdgePropVec<Day>*>(prop)->get_view(idx);
} else if (prop->type() == PropertyType::kRecordView) {
// edge_data.type = RTAnyType::kRecordView;
edge_data.type = RTAnyType::kRecordView;
edge_data.value.record_view =
dynamic_cast<EdgePropVec<RecordView>*>(prop)->get_view(idx);
} else {
edge_data.type = RTAnyType::kUnknown;
}
Expand All @@ -84,6 +86,9 @@ static inline void set_edge_data(EdgePropVecBase* col, size_t idx,
dynamic_cast<EdgePropVec<Date>*>(col)->set(idx, edge_data.value.date_val);
} else if (edge_data.type == RTAnyType::kDate32) {
dynamic_cast<EdgePropVec<Day>*>(col)->set(idx, edge_data.value.day_val);
} else if (edge_data.type == RTAnyType::kRecordView) {
dynamic_cast<EdgePropVec<RecordView>*>(col)->set(
idx, edge_data.value.record_view);
} else {
// LOG(FATAL) << "not support for " << edge_data.type;
}
Expand Down Expand Up @@ -650,13 +655,11 @@ class BDMLEdgeColumn : public IEdgeColumn {
class SDSLEdgeColumnBuilder : public IContextColumnBuilder {
public:
SDSLEdgeColumnBuilder(Direction dir, const LabelTriplet& label,
PropertyType prop_type,
const std::vector<PropertyType>& sub_types = {})
PropertyType prop_type)
: dir_(dir),
label_(label),
prop_type_(prop_type),
prop_col_(EdgePropVecBase::make_edge_prop_vec(prop_type)),
sub_types_(sub_types) {}
prop_col_(EdgePropVecBase::make_edge_prop_vec(prop_type)) {}
~SDSLEdgeColumnBuilder() = default;

void reserve(size_t size) override { edges_.reserve(size); }
Expand Down Expand Up @@ -684,7 +687,6 @@ class SDSLEdgeColumnBuilder : public IContextColumnBuilder {
std::vector<std::pair<vid_t, vid_t>> edges_;
PropertyType prop_type_;
std::shared_ptr<EdgePropVecBase> prop_col_;
std::vector<PropertyType> sub_types_;
};

template <typename T>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,7 @@ Context EdgeExpand::expand_edge_without_predicate(
pt = props[0];
}

SDSLEdgeColumnBuilder builder(Direction::kIn, params.labels[0], pt,
props);
SDSLEdgeColumnBuilder builder(Direction::kIn, params.labels[0], pt);

label_t dst_label = params.labels[0].dst_label;
foreach_vertex(input_vertex_list,
Expand Down Expand Up @@ -223,8 +222,7 @@ Context EdgeExpand::expand_edge_without_predicate(
pt = PropertyType::kRecordView;
}

SDSLEdgeColumnBuilder builder(Direction::kOut, params.labels[0], pt,
props);
SDSLEdgeColumnBuilder builder(Direction::kOut, params.labels[0], pt);
label_t src_label = params.labels[0].src_label;
foreach_vertex(input_vertex_list,
[&](size_t index, label_t label, vid_t v) {
Expand Down Expand Up @@ -312,7 +310,7 @@ Context EdgeExpand::expand_edge_without_predicate(
if (params.dir == Direction::kOut) {
auto& triplet = labels[0];
SDSLEdgeColumnBuilder builder(Direction::kOut, triplet,
label_props[0].second, props_vec[0]);
label_props[0].second);
foreach_vertex(
input_vertex_list, [&](size_t index, label_t label, vid_t v) {
if (label == triplet.src_label) {
Expand All @@ -332,7 +330,7 @@ Context EdgeExpand::expand_edge_without_predicate(
} else if (params.dir == Direction::kIn) {
auto& triplet = labels[0];
SDSLEdgeColumnBuilder builder(Direction::kIn, triplet,
label_props[0].second, props_vec[0]);
label_props[0].second);
foreach_vertex(
input_vertex_list, [&](size_t index, label_t label, vid_t v) {
if (label == triplet.dst_label) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ class EdgeExpand {
pt = PropertyType::kRecordView;
}

SDSLEdgeColumnBuilder builder(Direction::kIn, params.labels[0], pt,
props);
SDSLEdgeColumnBuilder builder(Direction::kIn, params.labels[0], pt);

foreach_vertex(input_vertex_list,
[&](size_t index, label_t label, vid_t v) {
Expand Down Expand Up @@ -122,8 +121,7 @@ class EdgeExpand {
pt = PropertyType::kRecordView;
}

SDSLEdgeColumnBuilder builder(Direction::kOut, params.labels[0], pt,
props);
SDSLEdgeColumnBuilder builder(Direction::kOut, params.labels[0], pt);

foreach_vertex(input_vertex_list,
[&](size_t index, label_t label, vid_t v) {
Expand Down
4 changes: 4 additions & 0 deletions flex/engines/graph_db/runtime/common/rt_any.cc
Original file line number Diff line number Diff line change
Expand Up @@ -693,6 +693,8 @@ static void sink_any(const Any& any, common::Value* value) {
value->set_boolean(any.AsBool());
} else if (any.type == PropertyType::Double()) {
value->set_f64(any.AsDouble());
} else if (any.type == PropertyType::Empty()) {
value->mutable_none();
} else {
LOG(FATAL) << "Any value: " << any.to_string()
<< ", type = " << any.type.type_enum;
Expand Down Expand Up @@ -987,6 +989,8 @@ std::shared_ptr<EdgePropVecBase> EdgePropVecBase::make_edge_prop_vec(
return std::make_shared<EdgePropVec<bool>>();
} else if (type == PropertyType::Empty()) {
return std::make_shared<EdgePropVec<grape::EmptyType>>();
} else if (type == PropertyType::RecordView()) {
return std::make_shared<EdgePropVec<RecordView>>();
} else {
LOG(FATAL) << "not support for " << type;
return nullptr;
Expand Down
16 changes: 14 additions & 2 deletions flex/engines/graph_db/runtime/common/rt_any.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,8 @@ struct EdgeData {
return grape::EmptyType();
} else if constexpr (std::is_same_v<T, Date>) {
return Date(value.i64_val);
} else if constexpr (std::is_same_v<T, RecordView>) {
return value.record_view;
} else {
LOG(FATAL) << "not support for " << typeid(T).name();
}
Expand Down Expand Up @@ -366,6 +368,9 @@ struct EdgeData {
} else if constexpr (std::is_same_v<T, Date>) {
type = RTAnyType::kTimestamp;
value.date_val = val;
} else if constexpr (std::is_same_v<T, RecordView>) {
type = RTAnyType::kRecordView;
value.record_view = val;
} else {
LOG(FATAL) << "not support for " << typeid(T).name();
}
Expand All @@ -385,14 +390,14 @@ struct EdgeData {
return std::to_string(value.f64_val);
} else if (type == RTAnyType::kBoolValue) {
return value.b_val ? "true" : "false";
} else if (type == RTAnyType::kEmpty) {
return "";
} else if (type == RTAnyType::kDate32) {
return value.day_val.to_string();
} else if (type == RTAnyType::kTimestamp) {
return std::to_string(value.date_val.milli_second);
} else if (type == RTAnyType::kEmpty) {
return "";
} else if (type == RTAnyType::kRecordView) {
return value.record_view.to_string();
} else {
LOG(FATAL) << "Unexpected property type: " << static_cast<int>(type);
return "";
Expand Down Expand Up @@ -430,6 +435,10 @@ struct EdgeData {
type = RTAnyType::kTimestamp;
value.date_val = any.value.d;
break;
case impl::PropertyTypeImpl::kRecordView:
type = RTAnyType::kRecordView;
value.record_view = any.value.record_view;
break;
default:
LOG(FATAL) << "Unexpected property type: "
<< static_cast<int>(any.type.type_enum);
Expand Down Expand Up @@ -471,6 +480,8 @@ struct EdgeData {
return value.day_val == e.value.day_val;
} else if (type == RTAnyType::kTimestamp) {
return value.date_val == e.value.date_val;
} else if (type == RTAnyType::kRecordView) {
return value.record_view == e.value.record_view;
} else {
return false;
}
Expand All @@ -486,6 +497,7 @@ struct EdgeData {
pod_string_view str_val;
Date date_val;
Day day_val;
RecordView record_view;
// todo: make recordview as a pod type
// RecordView record;
} value;
Expand Down
97 changes: 97 additions & 0 deletions flex/interactive/sdk/python/gs_interactive/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,91 @@
},
}

modern_graph_multiple_edge_properties = {
"name": "full_graph",
"description": "This is a test graph",
"schema": {
"vertex_types": [
{
"type_name": "person",
"properties": [
{
"property_name": "id",
"property_type": {"primitive_type": "DT_SIGNED_INT64"},
},
{
"property_name": "name",
"property_type": {"string": {"long_text": ""}},
},
{
"property_name": "age",
"property_type": {"primitive_type": "DT_SIGNED_INT32"},
},
],
"primary_keys": ["id"],
},
{
"type_name": "software",
"properties": [
{
"property_name": "id",
"property_type": {"primitive_type": "DT_SIGNED_INT64"},
},
{
"property_name": "name",
"property_type": {"string": {"long_text": ""}},
},
{
"property_name": "lang",
"property_type": {"string": {"long_text": ""}},
},
],
"primary_keys": ["id"],
},
],
"edge_types": [
{
"type_name": "knows",
"vertex_type_pair_relations": [
{
"source_vertex": "person",
"destination_vertex": "person",
"relation": "MANY_TO_MANY",
}
],
"properties": [
{
"property_name": "weight",
"property_type": {"primitive_type": "DT_DOUBLE"},
}
],
"primary_keys": [],
},
{
"type_name": "created",
"vertex_type_pair_relations": [
{
"source_vertex": "person",
"destination_vertex": "software",
"relation": "MANY_TO_MANY",
}
],
"properties": [
{
"property_name": "weight",
"property_type": {"primitive_type": "DT_DOUBLE"},
},
{
"property_name": "since",
"property_type": {"primitive_type": "DT_SIGNED_INT32"},
},
],
"primary_keys": [],
},
],
},
}

modern_graph_vertex_only = {
"name": "vertex_only",
"description": "This is a test graph, only contains vertex",
Expand Down Expand Up @@ -895,6 +980,18 @@ def create_modern_graph(interactive_session):
delete_running_graph(interactive_session, graph_id)


@pytest.fixture(scope="function")
def create_modern_graph_multiple_edge_property(interactive_session):
create_graph_request = CreateGraphRequest.from_dict(
modern_graph_multiple_edge_properties
)
resp = interactive_session.create_graph(create_graph_request)
assert resp.is_ok()
graph_id = resp.get_value().graph_id
yield graph_id
delete_running_graph(interactive_session, graph_id)


@pytest.fixture(scope="function")
def create_graph_algo_graph(interactive_session):
create_graph_request = CreateGraphRequest.from_dict(graph_algo_graph)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -432,3 +432,42 @@ def test_var_char_property(
for record in records:
# all string property in this graph is var char with max_length 2
assert len(record["personName"]) == 2


def test_multiple_edge_property(
interactive_session, neo4j_session, create_modern_graph_multiple_edge_property
):
print("[Test multiple edge property]")
import_data_to_full_modern_graph(
interactive_session, create_modern_graph_multiple_edge_property
)
start_service_on_graph(
interactive_session, create_modern_graph_multiple_edge_property
)
ensure_compiler_schema_ready(
interactive_session, neo4j_session, create_modern_graph_multiple_edge_property
)
result = neo4j_session.run(
"MATCH (n: person)-[e]->(m: software) RETURN e.weight AS weight, e.since AS since ORDER BY weight ASC, since ASC;"
)
records = result.fetch(10)
assert len(records) == 4
expected_result = [
{"weight": 0.2, "since": 2023},
{"weight": 0.4, "since": 2020},
{"weight": 0.4, "since": 2022},
{"weight": 1.0, "since": 2021},
]

for i in range(len(records)):
assert records[i]["weight"] == expected_result[i]["weight"]
assert records[i]["since"] == expected_result[i]["since"]

result = neo4j_session.run(
"MATCH (n: person)-[e]->(m: software) RETURN e ORDER BY e.weight ASC, e.since ASC;"
)
records = result.fetch(10)
assert len(records) == 4
for i in range(len(records)):
assert records[i]["e"]["weight"] == expected_result[i]["weight"]
assert records[i]["e"]["since"] == expected_result[i]["since"]
4 changes: 4 additions & 0 deletions flex/utils/property/column.cc
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ std::shared_ptr<ColumnBase> CreateColumn(
return std::make_shared<TypedColumn<grape::EmptyType>>(strategy);
} else if (type == PropertyType::kBool) {
return std::make_shared<BoolColumn>(strategy);
} else if (type == PropertyType::kUInt8) {
return std::make_shared<UInt8Column>(strategy);
} else if (type == PropertyType::kUInt16) {
return std::make_shared<UInt16Column>(strategy);
} else if (type == PropertyType::kInt32) {
return std::make_shared<IntColumn>(strategy);
} else if (type == PropertyType::kInt64) {
Expand Down
2 changes: 2 additions & 0 deletions flex/utils/property/column.h
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,8 @@ class TypedColumn<RecordView> : public ColumnBase {
};

using BoolColumn = TypedColumn<bool>;
using UInt8Column = TypedColumn<uint8_t>;
using UInt16Column = TypedColumn<uint16_t>;
using IntColumn = TypedColumn<int32_t>;
using UIntColumn = TypedColumn<uint32_t>;
using LongColumn = TypedColumn<int64_t>;
Expand Down
Loading

0 comments on commit fd66790

Please sign in to comment.