Skip to content

Commit

Permalink
optimize match var_len_path speed. (TuGraph-family#622)
Browse files Browse the repository at this point in the history
* success part

* 5s verision successful

* fix standard_result.cpp

* fix code format

* fix relp foward different bug

* fix code format

---------

Co-authored-by: lipanpan03 <[email protected]>
  • Loading branch information
ncbd and lipanpan03 authored Aug 20, 2024
1 parent b11ab90 commit 93895a5
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 78 deletions.
13 changes: 12 additions & 1 deletion include/lgraph/lgraph_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,15 @@ namespace lgraph_api {

struct ResultElement;

namespace lgraph_result {
struct Node;
struct Relationship;
}

typedef std::unordered_map<size_t, std::shared_ptr<lgraph_result::Node>> NODEMAP;
typedef std::unordered_map<EdgeUid, std::shared_ptr<lgraph_result::Relationship>,
EdgeUid::Hash> RELPMAP;

/**
* @brief You only initialize the class by Result instance. Record provide some insert method
* to insert data to the record. eg. Insert, InsertVertexByID, InsertEdgeByID.
Expand Down Expand Up @@ -155,7 +164,9 @@ class Record {
* @param txn Trasaction
*/
void Insert(const std::string &fname, const traversal::Path &path,
lgraph_api::Transaction* txn);
lgraph_api::Transaction* txn,
NODEMAP& node_map,
RELPMAP& relp_map);
#endif

/**
Expand Down
16 changes: 16 additions & 0 deletions include/lgraph/lgraph_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,22 @@ struct EdgeUid {
return false;
}
};

struct Hash {
size_t operator()(const EdgeUid& edgeUid) const {
size_t hashValue = 0;
hashValue = std::hash<int64_t>()(edgeUid.eid);
hashValue ^= std::hash<int64_t>()(edgeUid.dst) +
0x9e3779b9 + (hashValue << 6) + (hashValue >> 2);
hashValue ^= std::hash<int64_t>()(edgeUid.lid) +
0x9e3779b9 + (hashValue << 6) + (hashValue >> 2);
hashValue ^= std::hash<int64_t>()(edgeUid.src) +
0x9e3779b9 + (hashValue << 6) + (hashValue >> 2);
hashValue ^= std::hash<int64_t>()(edgeUid.tid) +
0x9e3779b9 + (hashValue << 6) + (hashValue >> 2);
return hashValue;
}
};
};

/** @brief Information about the user. */
Expand Down
16 changes: 12 additions & 4 deletions src/cypher/execution_plan/ops/op_produce_results.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@

#include <regex>
#include "cypher/execution_plan/ops/op.h"
#include "lgraph/lgraph_result.h"
#include "lgraph/lgraph_types.h"
#include "lgraph_api/result_element.h"
#include "resultset/record.h"
#include "server/json_convert.h"
#include "server/bolt_session.h"
Expand All @@ -29,7 +31,9 @@
static void RRecordToURecord(
lgraph_api::Transaction *txn,
const std::vector<std::pair<std::string, lgraph_api::LGraphType>> &header,
const std::shared_ptr<cypher::Record> &record_ptr, lgraph_api::Record &record) {
const std::shared_ptr<cypher::Record> &record_ptr, lgraph_api::Record &record,
lgraph_api::NODEMAP& node_map, lgraph_api::RELPMAP& relp_map
) {
if (header.empty()) {
return;
}
Expand Down Expand Up @@ -157,7 +161,7 @@ static void RRecordToURecord(
}
path.Append(Edge(start, lid, tid, end, eid, forward));
}
record.Insert(header[index].first, path, txn);
record.Insert(header[index].first, path, txn, node_map, relp_map);
continue;
} else {
if (v.constant.array != nullptr || v.constant.map != nullptr) {
Expand Down Expand Up @@ -193,6 +197,8 @@ class ProduceResults : public OpBase {
Resetted,
Consuming,
} state_;
lgraph_api::NODEMAP node_map_;
lgraph_api::RELPMAP relp_map_;

public:
ProduceResults() : OpBase(OpType::PRODUCE_RESULTS, "Produce Results") {
Expand Down Expand Up @@ -295,7 +301,8 @@ class ProduceResults : public OpBase {
}
if (session->streaming_msg.value().type == bolt::BoltMsg::PullN) {
auto record = ctx->result_->MutableRecord();
RRecordToURecord(ctx->txn_.get(), ctx->result_->Header(), child->record, *record);
RRecordToURecord(ctx->txn_.get(), ctx->result_->Header(), child->record,
*record, node_map_, relp_map_);
session->ps.AppendRecords(ctx->result_->BoltRecords());
ctx->result_->ClearRecords();
bool sync = false;
Expand Down Expand Up @@ -328,7 +335,8 @@ class ProduceResults : public OpBase {
auto res = child->Consume(ctx);
if (res != OP_OK) return res;
auto record = ctx->result_->MutableRecord();
RRecordToURecord(ctx->txn_.get(), ctx->result_->Header(), child->record, *record);
RRecordToURecord(ctx->txn_.get(), ctx->result_->Header(),
child->record, *record, node_map_, relp_map_);
return OP_OK;
}
}
Expand Down
77 changes: 47 additions & 30 deletions src/lgraph_api/lgraph_result.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/

#include <memory>
#include "fma-common/string_formatter.h"
#include "lgraph/lgraph_result.h"
#include "lgraph_api/result_element.h"
Expand Down Expand Up @@ -246,56 +246,73 @@ void Record::InsertEdgeByID(const std::string &key, const EdgeUid &uid) {
Result::Result() : row_count_(-1) {}

void Record::Insert(const std::string &key, const traversal::Path &path,
lgraph_api::Transaction *txn) {
lgraph_api::Transaction *txn, lgraph_api::NODEMAP& node_map,
lgraph_api::RELPMAP& relp_map) {
auto core_txn = txn->GetTxn().get();
if (!HasKey(key) || header[key] != LGraphType::PATH) {
throw std::runtime_error(
FMA_FMT("[STANDARD RESULT ERROR] the variable {} is not exist", key));
}
lgraph_result::Path result_path;
if (path.Length() == 0) {
record[key] = std::shared_ptr<ResultElement>(new ResultElement(result_path));
}
lgraph_result::Path* result_path = new lgraph_result::Path();
for (size_t i = 0; i < path.Length(); i++) {
lgraph_result::Node node;
std::shared_ptr<lgraph_result::Node> node;
auto vid = path.GetNthVertex(i).GetId();
auto vit = core_txn->GetVertexIterator(vid);
node.id = vid;
node.label = core_txn->GetVertexLabel(vit);
for (const auto &property : core_txn->GetVertexFields(vit)) {
node.properties[property.first] = property.second;
if (node_map.find(vid) != node_map.end()) {
node = node_map[vid];
} else {
node = std::make_shared<lgraph_result::Node>();
node->id = vid;
node->label = core_txn->GetVertexLabel(vit);
for (const auto &property : core_txn->GetVertexFields(vit)) {
node->properties[property.first] = property.second;
}
node_map[vid] = node;
}
result_path.emplace_back(lgraph_result::PathElement(std::move(node)));
result_path->emplace_back(lgraph_result::PathElement(std::move(node)));
auto edge = path.GetNthEdge(i);
lgraph_result::Relationship repl;
std::shared_ptr<lgraph_result::Relationship> repl;
auto euid = lgraph::EdgeUid(edge.GetSrcVertex().GetId(), edge.GetDstVertex().GetId(),
edge.GetLabelId(), edge.GetTemporalId(), edge.GetEdgeId());
auto eit = core_txn->GetOutEdgeIterator(euid, false);
if (!eit.IsValid()) {
THROW_CODE(InternalError, "invalid euid {} for inserting path record", euid.ToString());
}
repl.id = euid.eid;
repl.src = euid.src;
repl.dst = euid.dst;
repl.label_id = euid.lid;
repl.tid = euid.tid;
repl.label = core_txn->GetEdgeLabel(eit);
repl.forward = ((int64_t)vid == euid.src);
for (const auto &property : core_txn->GetEdgeFields(eit)) {
repl.properties[property.first] = property.second;
if (relp_map.find(euid) != relp_map.end() &&
relp_map[euid]->forward == (((int64_t)vid == euid.src))) {
repl = relp_map[euid];
} else {
repl = std::make_shared<lgraph_result::Relationship>();
repl->id = euid.eid;
repl->src = euid.src;
repl->dst = euid.dst;
repl->label_id = euid.lid;
repl->tid = euid.tid;
repl->label = core_txn->GetEdgeLabel(eit);
repl->forward = ((int64_t)vid == euid.src);
for (const auto &property : core_txn->GetEdgeFields(eit)) {
repl->properties[property.first] = property.second;
}
relp_map[euid] = repl;
}
result_path.emplace_back(lgraph_result::PathElement(std::move(repl)));
result_path->emplace_back(lgraph_result::PathElement(std::move(repl)));
}
lgraph_result::Node node;
std::shared_ptr<lgraph_result::Node> node;
auto vid = path.GetEndVertex().GetId();
auto vit = core_txn->GetVertexIterator(vid);
node.id = vid;
node.label = core_txn->GetVertexLabel(vit);
for (const auto &property : core_txn->GetVertexFields(vit)) {
node.properties[property.first] = property.second;
if (node_map.find(vid) != node_map.end()) {
node = node_map[vid];
} else {
node = std::make_shared<lgraph_result::Node>();
node->id = vid;
node->label = core_txn->GetVertexLabel(vit);
for (const auto &property : core_txn->GetVertexFields(vit)) {
node->properties[property.first] = property.second;
}
node_map[vid] = node;
}
result_path.emplace_back(lgraph_result::PathElement(std::move(node)));
record[key] = std::shared_ptr<ResultElement>(new ResultElement(result_path));
result_path->emplace_back(lgraph_result::PathElement(std::move(node)));
record[key] = std::shared_ptr<ResultElement>(new ResultElement(std::move(result_path)));
length_++;
}

Expand Down
48 changes: 12 additions & 36 deletions src/lgraph_api/result_element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/

#include "lgraph_api/result_element.h"
#include <memory>
#include "lgraph/lgraph_result.h"
#include "server/json_convert.h"
#include "fma-common/string_formatter.h"
Expand Down Expand Up @@ -107,64 +108,37 @@ bolt::Relationship Relationship::ToBolt(int64_t* v_eid) {

PathElement::PathElement(const PathElement &value) {
type_ = value.type_;
if (type_ == LGraphType::NODE) {
v.node = new lgraph_result::Node(*value.v.node);
} else {
v.repl = new Relationship(*value.v.repl);
}
v = value.v;
}

PathElement::PathElement(PathElement &&value) {
type_ = value.type_;
if (type_ == LGraphType::NODE) {
v.node = value.v.node;
value.v.node = nullptr;
} else {
v.repl = value.v.repl;
value.v.repl = nullptr;
}
v = value.v;
}

PathElement &PathElement::operator=(const PathElement &value) {
if (this == &value) return *this;
type_ = value.type_;
if (type_ == LGraphType::NODE) {
delete v.node;
v.node = new Node(*value.v.node);
} else {
delete v.repl;
v.repl = new Relationship(*value.v.repl);
}
v = value.v;
return *this;
}

PathElement &PathElement::operator=(PathElement &&value) {
if (this == &value) return *this;
type_ = value.type_;
if (type_ == LGraphType::NODE) {
v.node = value.v.node;
value.v.node = nullptr;
} else {
v.repl = value.v.repl;
value.v.repl = nullptr;
}
v = value.v;
return *this;
}

nlohmann::json PathElement::ToJson() {
if (type_ == LGraphType::NODE) {
return v.node->ToJson();
return std::get<std::shared_ptr<Node>>(v)->ToJson();
} else {
return v.repl->ToJson();
return std::get<std::shared_ptr<Relationship>>(v)->ToJson();
}
}

PathElement::~PathElement() {
if (type_ == LGraphType::NODE) {
delete v.node;
} else {
delete v.repl;
}
}

} // namespace lgraph_result
Expand Down Expand Up @@ -436,14 +410,16 @@ std::any ResultElement::ToBolt(int64_t* v_eid) {
for (size_t i = 0; i < v.path->size(); i++) {
auto& p = (*v.path)[i];
if (p.type_ == LGraphType::NODE) {
path.nodes.push_back(p.v.node->ToBolt());
path.nodes.push_back(std::get<std::shared_ptr<lgraph_result::Node>>(p.v)->ToBolt());
} else {
// The neo4j python client checks the uniqueness of the edge id.
path.rels.push_back(p.v.repl->ToBoltUnbound(v_eid));
path.rels.push_back(std::get<std::shared_ptr<lgraph_result::Relationship>>(p.v)
->ToBoltUnbound(v_eid));
}
if (i >= 1) {
if (i%2 == 1) {
if (p.v.repl->src == path.nodes.back().id) {
if (std::get<std::shared_ptr<lgraph_result::Relationship>>(p.v)->src
== path.nodes.back().id) {
path.indices.push_back((int)path.rels.size());
} else {
path.indices.push_back(0-(int)path.rels.size());
Expand Down
30 changes: 24 additions & 6 deletions src/lgraph_api/result_element.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include <map>
#include <any>
#include <memory>
#include <variant>
#include "tools/json.hpp"
#include "lgraph/lgraph_types.h"
#include "bolt/graph.h"
Expand Down Expand Up @@ -52,17 +54,22 @@ struct Relationship {
// a new member.
struct PathElement {
lgraph_api::LGraphType type_;
union {
Node *node;
Relationship *repl;
} v;
std::variant<std::shared_ptr<Node>, std::shared_ptr<Relationship>> v;
explicit PathElement(const Node &node) {
type_ = lgraph_api::LGraphType::NODE;
v.node = new Node(node);
v = std::make_shared<Node>(node);
}
explicit PathElement(std::shared_ptr<Node> &&node) {
type_ = lgraph_api::LGraphType::NODE;
v = node;
}
explicit PathElement(const Relationship &repl) {
type_ = lgraph_api::LGraphType::RELATIONSHIP;
v.repl = new Relationship(repl);
v = std::make_shared<Relationship>(repl);
}
explicit PathElement(std::shared_ptr<Relationship> &&repl) {
type_ = lgraph_api::LGraphType::RELATIONSHIP;
v = repl;
}
PathElement(const PathElement &);
PathElement(PathElement &&);
Expand Down Expand Up @@ -121,6 +128,17 @@ struct ResultElement {
v.path = new lgraph_result::Path(data);
}

explicit ResultElement(lgraph_result::Path &&data) {
type_ = LGraphType::PATH;
v.path = new lgraph_result::Path(data);
}

explicit ResultElement(lgraph_result::Path* &&data) {
type_ = LGraphType::PATH;
v.path = data;
data = nullptr;
}

ResultElement(const ResultElement &);
ResultElement(const ResultElement &&);
inline ResultElement &operator=(const ResultElement &);
Expand Down
4 changes: 3 additions & 1 deletion test/test_procedures/standard_result.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ extern "C" LGAPI bool Process(GraphDB &db, const std::string &request, std::stri
using Vertex = lgraph_api::traversal::Vertex;
using Edge = lgraph_api::traversal::Edge;
lgraph_api::traversal::Path p(Vertex(vit.GetId()));
lgraph_api::NODEMAP node_map;
lgraph_api::RELPMAP relp_map;
p.Append(Edge(0, 0, 0, 2, 0, true));
for (auto vit = txn.GetVertexIterator(); vit.IsValid(); vit.Next()) {
auto it = vit.GetInEdgeIterator();
Expand All @@ -68,7 +70,7 @@ extern "C" LGAPI bool Process(GraphDB &db, const std::string &request, std::stri
record->Insert("in_edge", vit1.GetInEdgeIterator());
vit1.Goto(vid2);
record->Insert("out_edge", vit1.GetOutEdgeIterator());
record->Insert("path", p, &txn);
record->Insert("path", p, &txn, node_map, relp_map);
for (auto eit = vit.GetOutEdgeIterator(); eit.IsValid(); eit.Next()) out_num_edges += 1;
edge_num_map["out_num_edges"] = FieldData(out_num_edges);
for (auto eit = vit.GetInEdgeIterator(); eit.IsValid(); eit.Next()) in_num_edges += 1;
Expand Down

0 comments on commit 93895a5

Please sign in to comment.