Skip to content

Commit fd66790

Browse files
authored
fix(interactive): Support multiple edge properties and some minor fix (#4438)
As titled.
1 parent f45485f commit fd66790

File tree

13 files changed

+205
-28
lines changed

13 files changed

+205
-28
lines changed

docs/flex/interactive/data_model.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ vertex_type_pair_relations:
4646
Note:
4747
- 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.
4848
- 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.
49-
- Currently we only support at most one property for each edge triplet.
49+
- Multiple edge properties are supported.
5050
- We currently only support `var_char` and `long_text` as the edge property among all string types.
5151
- All implementation related configuration are put under `x_csr_params`.
5252
- `max_vertex_num` limit the number of vertices of this type:

flex/engines/graph_db/runtime/common/columns/edge_columns.cc

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,7 @@ namespace runtime {
2121

2222
std::shared_ptr<IContextColumn> SDSLEdgeColumn::shuffle(
2323
const std::vector<size_t>& offsets) const {
24-
std::vector<PropertyType> sub_types;
25-
if (prop_type_ == PropertyType::kRecordView) {
26-
sub_types = std::dynamic_pointer_cast<TypedColumn<RecordView>>(prop_col_)
27-
->sub_types();
28-
}
29-
SDSLEdgeColumnBuilder builder(dir_, label_, prop_type_, sub_types);
24+
SDSLEdgeColumnBuilder builder(dir_, label_, prop_type_);
3025
size_t new_row_num = offsets.size();
3126
builder.reserve(new_row_num);
3227

@@ -84,8 +79,7 @@ std::shared_ptr<IContextColumn> SDSLEdgeColumn::optional_shuffle(
8479
}
8580

8681
std::shared_ptr<IContextColumn> SDSLEdgeColumnBuilder::finish() {
87-
auto ret =
88-
std::make_shared<SDSLEdgeColumn>(dir_, label_, prop_type_, sub_types_);
82+
auto ret = std::make_shared<SDSLEdgeColumn>(dir_, label_, prop_type_);
8983
ret->edges_.swap(edges_);
9084
// shrink to fit
9185
prop_col_->resize(ret->edges_.size());

flex/engines/graph_db/runtime/common/columns/edge_columns.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ static inline void get_edge_data(EdgePropVecBase* prop, size_t idx,
5858
edge_data.value.day_val =
5959
dynamic_cast<EdgePropVec<Day>*>(prop)->get_view(idx);
6060
} else if (prop->type() == PropertyType::kRecordView) {
61-
// edge_data.type = RTAnyType::kRecordView;
61+
edge_data.type = RTAnyType::kRecordView;
62+
edge_data.value.record_view =
63+
dynamic_cast<EdgePropVec<RecordView>*>(prop)->get_view(idx);
6264
} else {
6365
edge_data.type = RTAnyType::kUnknown;
6466
}
@@ -84,6 +86,9 @@ static inline void set_edge_data(EdgePropVecBase* col, size_t idx,
8486
dynamic_cast<EdgePropVec<Date>*>(col)->set(idx, edge_data.value.date_val);
8587
} else if (edge_data.type == RTAnyType::kDate32) {
8688
dynamic_cast<EdgePropVec<Day>*>(col)->set(idx, edge_data.value.day_val);
89+
} else if (edge_data.type == RTAnyType::kRecordView) {
90+
dynamic_cast<EdgePropVec<RecordView>*>(col)->set(
91+
idx, edge_data.value.record_view);
8792
} else {
8893
// LOG(FATAL) << "not support for " << edge_data.type;
8994
}
@@ -650,13 +655,11 @@ class BDMLEdgeColumn : public IEdgeColumn {
650655
class SDSLEdgeColumnBuilder : public IContextColumnBuilder {
651656
public:
652657
SDSLEdgeColumnBuilder(Direction dir, const LabelTriplet& label,
653-
PropertyType prop_type,
654-
const std::vector<PropertyType>& sub_types = {})
658+
PropertyType prop_type)
655659
: dir_(dir),
656660
label_(label),
657661
prop_type_(prop_type),
658-
prop_col_(EdgePropVecBase::make_edge_prop_vec(prop_type)),
659-
sub_types_(sub_types) {}
662+
prop_col_(EdgePropVecBase::make_edge_prop_vec(prop_type)) {}
660663
~SDSLEdgeColumnBuilder() = default;
661664

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

690692
template <typename T>

flex/engines/graph_db/runtime/common/operators/retrieve/edge_expand.cc

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ Context EdgeExpand::expand_edge_without_predicate(
183183
pt = props[0];
184184
}
185185

186-
SDSLEdgeColumnBuilder builder(Direction::kIn, params.labels[0], pt,
187-
props);
186+
SDSLEdgeColumnBuilder builder(Direction::kIn, params.labels[0], pt);
188187

189188
label_t dst_label = params.labels[0].dst_label;
190189
foreach_vertex(input_vertex_list,
@@ -223,8 +222,7 @@ Context EdgeExpand::expand_edge_without_predicate(
223222
pt = PropertyType::kRecordView;
224223
}
225224

226-
SDSLEdgeColumnBuilder builder(Direction::kOut, params.labels[0], pt,
227-
props);
225+
SDSLEdgeColumnBuilder builder(Direction::kOut, params.labels[0], pt);
228226
label_t src_label = params.labels[0].src_label;
229227
foreach_vertex(input_vertex_list,
230228
[&](size_t index, label_t label, vid_t v) {
@@ -312,7 +310,7 @@ Context EdgeExpand::expand_edge_without_predicate(
312310
if (params.dir == Direction::kOut) {
313311
auto& triplet = labels[0];
314312
SDSLEdgeColumnBuilder builder(Direction::kOut, triplet,
315-
label_props[0].second, props_vec[0]);
313+
label_props[0].second);
316314
foreach_vertex(
317315
input_vertex_list, [&](size_t index, label_t label, vid_t v) {
318316
if (label == triplet.src_label) {
@@ -332,7 +330,7 @@ Context EdgeExpand::expand_edge_without_predicate(
332330
} else if (params.dir == Direction::kIn) {
333331
auto& triplet = labels[0];
334332
SDSLEdgeColumnBuilder builder(Direction::kIn, triplet,
335-
label_props[0].second, props_vec[0]);
333+
label_props[0].second);
336334
foreach_vertex(
337335
input_vertex_list, [&](size_t index, label_t label, vid_t v) {
338336
if (label == triplet.dst_label) {

flex/engines/graph_db/runtime/common/operators/retrieve/edge_expand.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,7 @@ class EdgeExpand {
8383
pt = PropertyType::kRecordView;
8484
}
8585

86-
SDSLEdgeColumnBuilder builder(Direction::kIn, params.labels[0], pt,
87-
props);
86+
SDSLEdgeColumnBuilder builder(Direction::kIn, params.labels[0], pt);
8887

8988
foreach_vertex(input_vertex_list,
9089
[&](size_t index, label_t label, vid_t v) {
@@ -122,8 +121,7 @@ class EdgeExpand {
122121
pt = PropertyType::kRecordView;
123122
}
124123

125-
SDSLEdgeColumnBuilder builder(Direction::kOut, params.labels[0], pt,
126-
props);
124+
SDSLEdgeColumnBuilder builder(Direction::kOut, params.labels[0], pt);
127125

128126
foreach_vertex(input_vertex_list,
129127
[&](size_t index, label_t label, vid_t v) {

flex/engines/graph_db/runtime/common/rt_any.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,8 @@ static void sink_any(const Any& any, common::Value* value) {
693693
value->set_boolean(any.AsBool());
694694
} else if (any.type == PropertyType::Double()) {
695695
value->set_f64(any.AsDouble());
696+
} else if (any.type == PropertyType::Empty()) {
697+
value->mutable_none();
696698
} else {
697699
LOG(FATAL) << "Any value: " << any.to_string()
698700
<< ", type = " << any.type.type_enum;
@@ -987,6 +989,8 @@ std::shared_ptr<EdgePropVecBase> EdgePropVecBase::make_edge_prop_vec(
987989
return std::make_shared<EdgePropVec<bool>>();
988990
} else if (type == PropertyType::Empty()) {
989991
return std::make_shared<EdgePropVec<grape::EmptyType>>();
992+
} else if (type == PropertyType::RecordView()) {
993+
return std::make_shared<EdgePropVec<RecordView>>();
990994
} else {
991995
LOG(FATAL) << "not support for " << type;
992996
return nullptr;

flex/engines/graph_db/runtime/common/rt_any.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ struct EdgeData {
336336
return grape::EmptyType();
337337
} else if constexpr (std::is_same_v<T, Date>) {
338338
return Date(value.i64_val);
339+
} else if constexpr (std::is_same_v<T, RecordView>) {
340+
return value.record_view;
339341
} else {
340342
LOG(FATAL) << "not support for " << typeid(T).name();
341343
}
@@ -366,6 +368,9 @@ struct EdgeData {
366368
} else if constexpr (std::is_same_v<T, Date>) {
367369
type = RTAnyType::kTimestamp;
368370
value.date_val = val;
371+
} else if constexpr (std::is_same_v<T, RecordView>) {
372+
type = RTAnyType::kRecordView;
373+
value.record_view = val;
369374
} else {
370375
LOG(FATAL) << "not support for " << typeid(T).name();
371376
}
@@ -385,14 +390,14 @@ struct EdgeData {
385390
return std::to_string(value.f64_val);
386391
} else if (type == RTAnyType::kBoolValue) {
387392
return value.b_val ? "true" : "false";
388-
} else if (type == RTAnyType::kEmpty) {
389-
return "";
390393
} else if (type == RTAnyType::kDate32) {
391394
return value.day_val.to_string();
392395
} else if (type == RTAnyType::kTimestamp) {
393396
return std::to_string(value.date_val.milli_second);
394397
} else if (type == RTAnyType::kEmpty) {
395398
return "";
399+
} else if (type == RTAnyType::kRecordView) {
400+
return value.record_view.to_string();
396401
} else {
397402
LOG(FATAL) << "Unexpected property type: " << static_cast<int>(type);
398403
return "";
@@ -430,6 +435,10 @@ struct EdgeData {
430435
type = RTAnyType::kTimestamp;
431436
value.date_val = any.value.d;
432437
break;
438+
case impl::PropertyTypeImpl::kRecordView:
439+
type = RTAnyType::kRecordView;
440+
value.record_view = any.value.record_view;
441+
break;
433442
default:
434443
LOG(FATAL) << "Unexpected property type: "
435444
<< static_cast<int>(any.type.type_enum);
@@ -471,6 +480,8 @@ struct EdgeData {
471480
return value.day_val == e.value.day_val;
472481
} else if (type == RTAnyType::kTimestamp) {
473482
return value.date_val == e.value.date_val;
483+
} else if (type == RTAnyType::kRecordView) {
484+
return value.record_view == e.value.record_view;
474485
} else {
475486
return false;
476487
}
@@ -486,6 +497,7 @@ struct EdgeData {
486497
pod_string_view str_val;
487498
Date date_val;
488499
Day day_val;
500+
RecordView record_view;
489501
// todo: make recordview as a pod type
490502
// RecordView record;
491503
} value;

flex/interactive/sdk/python/gs_interactive/tests/conftest.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,91 @@
124124
},
125125
}
126126

127+
modern_graph_multiple_edge_properties = {
128+
"name": "full_graph",
129+
"description": "This is a test graph",
130+
"schema": {
131+
"vertex_types": [
132+
{
133+
"type_name": "person",
134+
"properties": [
135+
{
136+
"property_name": "id",
137+
"property_type": {"primitive_type": "DT_SIGNED_INT64"},
138+
},
139+
{
140+
"property_name": "name",
141+
"property_type": {"string": {"long_text": ""}},
142+
},
143+
{
144+
"property_name": "age",
145+
"property_type": {"primitive_type": "DT_SIGNED_INT32"},
146+
},
147+
],
148+
"primary_keys": ["id"],
149+
},
150+
{
151+
"type_name": "software",
152+
"properties": [
153+
{
154+
"property_name": "id",
155+
"property_type": {"primitive_type": "DT_SIGNED_INT64"},
156+
},
157+
{
158+
"property_name": "name",
159+
"property_type": {"string": {"long_text": ""}},
160+
},
161+
{
162+
"property_name": "lang",
163+
"property_type": {"string": {"long_text": ""}},
164+
},
165+
],
166+
"primary_keys": ["id"],
167+
},
168+
],
169+
"edge_types": [
170+
{
171+
"type_name": "knows",
172+
"vertex_type_pair_relations": [
173+
{
174+
"source_vertex": "person",
175+
"destination_vertex": "person",
176+
"relation": "MANY_TO_MANY",
177+
}
178+
],
179+
"properties": [
180+
{
181+
"property_name": "weight",
182+
"property_type": {"primitive_type": "DT_DOUBLE"},
183+
}
184+
],
185+
"primary_keys": [],
186+
},
187+
{
188+
"type_name": "created",
189+
"vertex_type_pair_relations": [
190+
{
191+
"source_vertex": "person",
192+
"destination_vertex": "software",
193+
"relation": "MANY_TO_MANY",
194+
}
195+
],
196+
"properties": [
197+
{
198+
"property_name": "weight",
199+
"property_type": {"primitive_type": "DT_DOUBLE"},
200+
},
201+
{
202+
"property_name": "since",
203+
"property_type": {"primitive_type": "DT_SIGNED_INT32"},
204+
},
205+
],
206+
"primary_keys": [],
207+
},
208+
],
209+
},
210+
}
211+
127212
modern_graph_vertex_only = {
128213
"name": "vertex_only",
129214
"description": "This is a test graph, only contains vertex",
@@ -895,6 +980,18 @@ def create_modern_graph(interactive_session):
895980
delete_running_graph(interactive_session, graph_id)
896981

897982

983+
@pytest.fixture(scope="function")
984+
def create_modern_graph_multiple_edge_property(interactive_session):
985+
create_graph_request = CreateGraphRequest.from_dict(
986+
modern_graph_multiple_edge_properties
987+
)
988+
resp = interactive_session.create_graph(create_graph_request)
989+
assert resp.is_ok()
990+
graph_id = resp.get_value().graph_id
991+
yield graph_id
992+
delete_running_graph(interactive_session, graph_id)
993+
994+
898995
@pytest.fixture(scope="function")
899996
def create_graph_algo_graph(interactive_session):
900997
create_graph_request = CreateGraphRequest.from_dict(graph_algo_graph)

flex/interactive/sdk/python/gs_interactive/tests/test_robustness.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,3 +432,42 @@ def test_var_char_property(
432432
for record in records:
433433
# all string property in this graph is var char with max_length 2
434434
assert len(record["personName"]) == 2
435+
436+
437+
def test_multiple_edge_property(
438+
interactive_session, neo4j_session, create_modern_graph_multiple_edge_property
439+
):
440+
print("[Test multiple edge property]")
441+
import_data_to_full_modern_graph(
442+
interactive_session, create_modern_graph_multiple_edge_property
443+
)
444+
start_service_on_graph(
445+
interactive_session, create_modern_graph_multiple_edge_property
446+
)
447+
ensure_compiler_schema_ready(
448+
interactive_session, neo4j_session, create_modern_graph_multiple_edge_property
449+
)
450+
result = neo4j_session.run(
451+
"MATCH (n: person)-[e]->(m: software) RETURN e.weight AS weight, e.since AS since ORDER BY weight ASC, since ASC;"
452+
)
453+
records = result.fetch(10)
454+
assert len(records) == 4
455+
expected_result = [
456+
{"weight": 0.2, "since": 2023},
457+
{"weight": 0.4, "since": 2020},
458+
{"weight": 0.4, "since": 2022},
459+
{"weight": 1.0, "since": 2021},
460+
]
461+
462+
for i in range(len(records)):
463+
assert records[i]["weight"] == expected_result[i]["weight"]
464+
assert records[i]["since"] == expected_result[i]["since"]
465+
466+
result = neo4j_session.run(
467+
"MATCH (n: person)-[e]->(m: software) RETURN e ORDER BY e.weight ASC, e.since ASC;"
468+
)
469+
records = result.fetch(10)
470+
assert len(records) == 4
471+
for i in range(len(records)):
472+
assert records[i]["e"]["weight"] == expected_result[i]["weight"]
473+
assert records[i]["e"]["since"] == expected_result[i]["since"]

flex/utils/property/column.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ std::shared_ptr<ColumnBase> CreateColumn(
178178
return std::make_shared<TypedColumn<grape::EmptyType>>(strategy);
179179
} else if (type == PropertyType::kBool) {
180180
return std::make_shared<BoolColumn>(strategy);
181+
} else if (type == PropertyType::kUInt8) {
182+
return std::make_shared<UInt8Column>(strategy);
183+
} else if (type == PropertyType::kUInt16) {
184+
return std::make_shared<UInt16Column>(strategy);
181185
} else if (type == PropertyType::kInt32) {
182186
return std::make_shared<IntColumn>(strategy);
183187
} else if (type == PropertyType::kInt64) {

0 commit comments

Comments
 (0)