From a5ee0fad08f3b56fc69884f703cf5d78ac25efa4 Mon Sep 17 00:00:00 2001 From: gvolfing Date: Mon, 11 Mar 2024 19:39:32 +0100 Subject: [PATCH] Enhance planner for edge-id indexing --- .../plan/rewrite/edge_type_index_lookup.hpp | 59 ++++++++++++++++--- src/storage/v2/edge_accessor.cpp | 4 +- src/storage/v2/inmemory/storage.cpp | 10 +++- 3 files changed, 64 insertions(+), 9 deletions(-) diff --git a/src/query/plan/rewrite/edge_type_index_lookup.hpp b/src/query/plan/rewrite/edge_type_index_lookup.hpp index eedf36ae0..deff1f144 100644 --- a/src/query/plan/rewrite/edge_type_index_lookup.hpp +++ b/src/query/plan/rewrite/edge_type_index_lookup.hpp @@ -48,11 +48,26 @@ class EdgeTypeIndexRewriter final : public HierarchicalLogicalOperatorVisitor { bool PreVisit(Filter &op) override { prev_ops_.push_back(&op); + filters_.CollectFilterExpression(op.expression_, *symbol_table_); + return true; } - bool PostVisit(Filter & /*op*/) override { + bool PostVisit(Filter &op) override { prev_ops_.pop_back(); + + ExpressionRemovalResult removal = RemoveExpressions(op.expression_, filter_exprs_for_removal_); + op.expression_ = removal.trimmed_expression; + if (op.expression_) { + Filters leftover_filters; + leftover_filters.CollectFilterExpression(op.expression_, *symbol_table_); + op.all_filters_ = std::move(leftover_filters); + } + + if (!op.expression_) { + SetOnParent(op.input()); + } + return true; } @@ -70,7 +85,7 @@ class EdgeTypeIndexRewriter final : public HierarchicalLogicalOperatorVisitor { bool PostVisit(ScanAll &op) override { prev_ops_.pop_back(); - if (EdgeTypeIndexingPossible()) { + if (EdgeTypeIndexingPossible() || maybe_id_lookup_value_) { SetOnParent(op.input()); } @@ -88,6 +103,25 @@ class EdgeTypeIndexRewriter final : public HierarchicalLogicalOperatorVisitor { edge_type_index_exist = only_one_edge_type ? db_->EdgeTypeIndexExists(op.common_.edge_types.front()) : false; scanall_under_expand_ = only_one_edge_type && expansion_is_named && expdanded_node_not_named; + + const auto &output_symbol = op.common_.edge_symbol; + const auto &modified_symbols = op.ModifiedSymbols(*symbol_table_); + std::unordered_set bound_symbols(modified_symbols.begin(), modified_symbols.end()); + auto are_bound = [&bound_symbols](const auto &used_symbols) { + for (const auto &used_symbol : used_symbols) { + if (!utils::Contains(bound_symbols, used_symbol)) { + return false; + } + } + return true; + }; + + for (const auto &filter : filters_.IdFilters(output_symbol)) { + if (filter.id_filter->is_symbol_in_value_ || !are_bound(filter.used_symbols)) continue; + maybe_id_lookup_value_ = filter.id_filter->value_; + filter_exprs_for_removal_.insert(filter.expression); + filters_.EraseFilter(filter); + } } return true; @@ -96,9 +130,10 @@ class EdgeTypeIndexRewriter final : public HierarchicalLogicalOperatorVisitor { bool PostVisit(Expand &op) override { prev_ops_.pop_back(); - if (EdgeTypeIndexingPossible()) { + if (EdgeTypeIndexingPossible() || maybe_id_lookup_value_) { auto indexed_scan = GenEdgeTypeScan(op); SetOnParent(std::move(indexed_scan)); + return true; } return true; @@ -488,9 +523,12 @@ class EdgeTypeIndexRewriter final : public HierarchicalLogicalOperatorVisitor { std::vector prev_ops_; std::unordered_set cartesian_symbols_; + memgraph::query::Expression *maybe_id_lookup_value_ = nullptr; + bool EdgeTypeIndexingPossible() const { return expand_under_produce_ && scanall_under_expand_ && once_under_scanall_ && edge_type_index_exist; } + bool expand_under_produce_ = false; bool scanall_under_expand_ = false; bool once_under_scanall_ = false; @@ -500,14 +538,21 @@ class EdgeTypeIndexRewriter final : public HierarchicalLogicalOperatorVisitor { throw utils::NotYetImplemented("Operator not yet covered by EdgeTypeIndexRewriter"); } - std::unique_ptr GenEdgeTypeScan(const Expand &expand) { + std::unique_ptr GenEdgeTypeScan(const Expand &expand) { const auto &input = expand.input(); const auto &output_symbol = expand.common_.edge_symbol; const auto &view = expand.view_; - // Extract edge_type from symbol - auto edge_type = expand.common_.edge_types.front(); - return std::make_unique(input, output_symbol, edge_type, view); + if (EdgeTypeIndexingPossible()) { + auto edge_type = expand.common_.edge_types.front(); + return std::make_unique(input, output_symbol, edge_type, view); + } + + if (maybe_id_lookup_value_) { + return std::make_unique(input, output_symbol, maybe_id_lookup_value_, view); + } + + LOG_FATAL("Fatal error while rewriting query plan."); } void SetOnParent(const std::shared_ptr &input) { diff --git a/src/storage/v2/edge_accessor.cpp b/src/storage/v2/edge_accessor.cpp index d03e489d4..95b6f4624 100644 --- a/src/storage/v2/edge_accessor.cpp +++ b/src/storage/v2/edge_accessor.cpp @@ -29,7 +29,9 @@ namespace memgraph::storage { std::optional EdgeAccessor::Create(EdgeRef edge, EdgeTypeId edge_type, Vertex *from_vertex, Vertex *to_vertex, Storage *storage, Transaction *transaction, bool for_deleted) { - return std::nullopt; + // TODO Take the view as well and determine if the + // constructs are visible or not. Checkout VertexAccessor. + return EdgeAccessor(edge, edge_type, from_vertex, to_vertex, storage, transaction, for_deleted); } bool EdgeAccessor::IsDeleted() const { diff --git a/src/storage/v2/inmemory/storage.cpp b/src/storage/v2/inmemory/storage.cpp index 1e4a71b64..129960261 100644 --- a/src/storage/v2/inmemory/storage.cpp +++ b/src/storage/v2/inmemory/storage.cpp @@ -1429,16 +1429,24 @@ EdgesIterable InMemoryStorage::InMemoryAccessor::Edges(EdgeTypeId edge_type, Vie std::optional InMemoryStorage::InMemoryAccessor::FindEdge(Gid gid, View view) { auto *mem_storage = static_cast(storage_); + auto edge_acc = mem_storage->edges_.access(); + auto edge_it = edge_acc.find(gid); + if (edge_it == edge_acc.end()) { + return std::nullopt; + } + auto *edge_ptr = &(*edge_it); + // TODO replace this logic once we have a proper edge struct in place. // This should be only temporary, currently we have to do this whole // lookup through all the vertices, since the edge struct only has a // pointer to it's GID, it has no information whatsoever about the from // and to vertices. auto acc = mem_storage->vertices_.access(); + auto maybe_edge_info = std::invoke([&]() -> std::optional> { for (auto &vertex : acc) { for (auto &edge : vertex.out_edges) { - if (std::get<2>(edge).gid == gid) { + if (std::get<2>(edge).ptr == edge_ptr) { return std::make_tuple(std::get<2>(edge), std::get<0>(edge), &vertex, std::get<1>(edge)); } }