diff --git a/src/query/db_accessor.hpp b/src/query/db_accessor.hpp index a9d299309..b80fb0fe3 100644 --- a/src/query/db_accessor.hpp +++ b/src/query/db_accessor.hpp @@ -445,13 +445,13 @@ class DbAccessor final { std::vector ClearLabelIndexStats() { return accessor_->ClearLabelIndexStats(); } - std::vector> DeleteIndexStatsForLabels( + std::vector> DeleteLabelPropertyIndexStats( const std::span labels) { - return accessor_->DeleteIndexStatsForLabels(labels); + return accessor_->DeleteLabelPropertyIndexStats(labels); } - std::vector DeleteLabelIndexStatsForLabels(const std::span labels) { - return accessor_->DeleteLabelIndexStatsForLabels(labels); + std::vector DeleteLabelIndexStats(const std::span labels) { + return accessor_->DeleteLabelIndexStats(labels); } void SetIndexStats(const storage::LabelId &label, const storage::LabelIndexStats &stats) { diff --git a/src/query/frontend/semantic/symbol_generator.cpp b/src/query/frontend/semantic/symbol_generator.cpp index 613f94df4..cde169675 100644 --- a/src/query/frontend/semantic/symbol_generator.cpp +++ b/src/query/frontend/semantic/symbol_generator.cpp @@ -167,10 +167,11 @@ bool SymbolGenerator::PreVisit(SingleQuery &) { // Union bool SymbolGenerator::PreVisit(CypherUnion &) { - auto scope = scopes_.back(); - scopes_.back() = Scope(); + auto next_scope = Scope(); + next_scope.curr_return_names = scopes_.back().curr_return_names; - scopes_.back().curr_return_names = scope.curr_return_names; + scopes_.pop_back(); + scopes_.push_back(next_scope); return true; } diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp index 15b5164a0..60e7647d6 100644 --- a/src/query/interpreter.cpp +++ b/src/query/interpreter.cpp @@ -57,7 +57,6 @@ #include "spdlog/spdlog.h" #include "storage/v2/edge.hpp" #include "storage/v2/id_types.hpp" -#include "storage/v2/indices.hpp" #include "storage/v2/isolation_level.hpp" #include "storage/v2/property_value.hpp" #include "storage/v2/storage_mode.hpp" @@ -1526,91 +1525,110 @@ std::vector> AnalyzeGraphQueryHandler::AnalyzeGraphCreat std::map vertex_degree_counter; auto view = storage::View::OLD; - // Preprocess labels in label indexes to avoid later checks + auto erase_not_specified_label_indices = [&labels, execution_db_accessor](auto &index_info) { + if (labels[0] != kAsterisk) { + for (auto it = index_info.cbegin(); it != index_info.cend();) { + if (std::find(labels.begin(), labels.end(), execution_db_accessor->LabelToName(*it)) == labels.end()) { + it = index_info.erase(it); + } else { + ++it; + } + } + } + }; + + auto erase_not_specified_label_property_indices = [&labels, execution_db_accessor](auto &index_info) { + if (labels[0] != kAsterisk) { + for (auto it = index_info.cbegin(); it != index_info.cend();) { + if (std::find(labels.begin(), labels.end(), execution_db_accessor->LabelToName(it->first)) == labels.end()) { + it = index_info.erase(it); + } else { + ++it; + } + } + } + }; + + auto populate_label_stats = [execution_db_accessor, view](auto index_info) { + std::vector> label_stats; + label_stats.reserve(index_info.size()); + std::for_each(index_info.begin(), index_info.end(), + [execution_db_accessor, view, &label_stats](const storage::LabelId &label_id) { + auto vertices = execution_db_accessor->Vertices(view, label_id); + uint64_t no_vertices{0}; + uint64_t total_degree{0}; + std::for_each(vertices.begin(), vertices.end(), + [&total_degree, &no_vertices, &view](const auto &vertex) { + no_vertices++; + total_degree += *vertex.OutDegree(view) + *vertex.InDegree(view); + }); + + auto average_degree = + no_vertices > 0 ? static_cast(total_degree) / static_cast(no_vertices) : 0; + auto index_stats = storage::LabelIndexStats{.count = no_vertices, .avg_degree = average_degree}; + execution_db_accessor->SetIndexStats(label_id, index_stats); + label_stats.emplace_back(std::make_pair(label_id, index_stats)); + }); + + return label_stats; + }; + + auto populate_label_property_stats = [&label_property_counter, &vertex_degree_counter, execution_db_accessor, + view](auto &index_info) { + // Iterate over all label property indexed vertices + std::for_each( + index_info.begin(), index_info.end(), + [execution_db_accessor, &label_property_counter, &vertex_degree_counter, view](const LPIndex &index_info) { + auto vertices = execution_db_accessor->Vertices(view, index_info.first, index_info.second); + std::for_each(vertices.begin(), vertices.end(), + [&index_info, &label_property_counter, &vertex_degree_counter, &view](const auto &vertex) { + label_property_counter[index_info][*vertex.GetProperty(view, index_info.second)]++; + vertex_degree_counter[index_info] += *vertex.OutDegree(view) + *vertex.InDegree(view); + }); + }); + + std::vector> label_property_stats; + label_property_stats.reserve(label_property_counter.size()); + std::for_each( + label_property_counter.begin(), label_property_counter.end(), + [execution_db_accessor, &vertex_degree_counter, &label_property_stats](const auto &counter_entry) { + const auto &[label_property, values_map] = counter_entry; + // Extract info + uint64_t count_property_value = std::accumulate( + values_map.begin(), values_map.end(), 0, + [](uint64_t prev_value, const auto &prop_value_count) { return prev_value + prop_value_count.second; }); + // num_distinc_values will never be 0 + double avg_group_size = static_cast(count_property_value) / static_cast(values_map.size()); + double chi_squared_stat = std::accumulate( + values_map.begin(), values_map.end(), 0.0, [avg_group_size](double prev_result, const auto &value_entry) { + return prev_result + utils::ChiSquaredValue(value_entry.second, avg_group_size); + }); + + double average_degree = count_property_value > 0 + ? static_cast(vertex_degree_counter[label_property]) / + static_cast(count_property_value) + : 0; + + auto index_stats = + storage::LabelPropertyIndexStats{.count = count_property_value, + .distinct_values_count = static_cast(values_map.size()), + .statistic = chi_squared_stat, + .avg_group_size = avg_group_size, + .avg_degree = average_degree}; + execution_db_accessor->SetIndexStats(label_property.first, label_property.second, index_stats); + label_property_stats.push_back(std::make_pair(label_property, index_stats)); + }); + + return label_property_stats; + }; + std::vector label_indices_info = execution_db_accessor->ListAllIndices().label; - if (labels[0] != kAsterisk) { - for (auto it = label_indices_info.cbegin(); it != label_indices_info.cend();) { - if (std::find(labels.begin(), labels.end(), execution_db_accessor->LabelToName(*it)) == labels.end()) { - it = label_indices_info.erase(it); - } else { - ++it; - } - } - } + erase_not_specified_label_indices(label_indices_info); + auto label_stats = populate_label_stats(label_indices_info); - // Preprocess labels in label property indexes to avoid later checks std::vector label_property_indices_info = execution_db_accessor->ListAllIndices().label_property; - if (labels[0] != kAsterisk) { - for (auto it = label_property_indices_info.cbegin(); it != label_property_indices_info.cend();) { - if (std::find(labels.begin(), labels.end(), execution_db_accessor->LabelToName(it->first)) == labels.end()) { - it = label_property_indices_info.erase(it); - } else { - ++it; - } - } - } - - std::vector> label_stats; - // Iterate over all label indexed vertices - std::for_each(label_indices_info.begin(), label_indices_info.end(), - [execution_db_accessor, view, &label_stats](const storage::LabelId &index_info) { - auto vertices = execution_db_accessor->Vertices(storage::View::OLD, index_info); - int64_t no_vertices = 0; - auto total_degree = 0; - std::for_each(vertices.begin(), vertices.end(), - [&total_degree, &no_vertices, &view](const auto &vertex) { - no_vertices++; - total_degree += *vertex.OutDegree(view) + *vertex.InDegree(view); - }); - - auto average_degree = - no_vertices > 0 ? static_cast(total_degree) / static_cast(no_vertices) : 0; - auto index_stats = storage::LabelIndexStats{.count = no_vertices, .avg_degree = average_degree}; - execution_db_accessor->SetIndexStats(index_info, index_stats); - label_stats.emplace_back(std::make_pair(index_info, index_stats)); - }); - - // Iterate over all label property indexed vertices - std::for_each( - label_property_indices_info.begin(), label_property_indices_info.end(), - [execution_db_accessor, &label_property_counter, &vertex_degree_counter, view](const LPIndex &index_info) { - auto vertices = execution_db_accessor->Vertices(view, index_info.first, index_info.second); - std::for_each(vertices.begin(), vertices.end(), - [&index_info, &label_property_counter, &vertex_degree_counter, &view](const auto &vertex) { - label_property_counter[index_info][*vertex.GetProperty(view, index_info.second)]++; - vertex_degree_counter[index_info] += *vertex.OutDegree(view) + *vertex.InDegree(view); - }); - }); - - std::vector> label_property_stats; - std::for_each( - label_property_counter.begin(), label_property_counter.end(), - [execution_db_accessor, &vertex_degree_counter, &label_property_stats](const auto &counter_entry) { - const auto &[label_property, values_map] = counter_entry; - // Extract info - int64_t count_property_value = std::accumulate( - values_map.begin(), values_map.end(), 0, - [](int64_t prev_value, const auto &prop_value_count) { return prev_value + prop_value_count.second; }); - // num_distinc_values will never be 0 - double avg_group_size = static_cast(count_property_value) / static_cast(values_map.size()); - double chi_squared_stat = std::accumulate( - values_map.begin(), values_map.end(), 0.0, [avg_group_size](double prev_result, const auto &value_entry) { - return prev_result + utils::ChiSquaredValue(value_entry.second, avg_group_size); - }); - - double average_degree = count_property_value > 0 ? static_cast(vertex_degree_counter[label_property]) / - static_cast(count_property_value) - : 0; - - auto index_stats = - storage::LabelPropertyIndexStats{.count = count_property_value, - .distinct_values_count = static_cast(values_map.size()), - .statistic = chi_squared_stat, - .avg_group_size = avg_group_size, - .avg_degree = average_degree}; - execution_db_accessor->SetIndexStats(label_property.first, label_property.second, index_stats); - label_property_stats.push_back(std::make_pair(label_property, index_stats)); - }); + erase_not_specified_label_property_indices(label_property_indices_info); + auto label_property_stats = populate_label_property_stats(label_property_indices_info); std::vector> results; results.reserve(label_stats.size() + label_property_stats.size()); @@ -1621,7 +1639,7 @@ std::vector> AnalyzeGraphQueryHandler::AnalyzeGraphCreat result.emplace_back(execution_db_accessor->LabelToName(stat_entry.first)); result.emplace_back(TypedValue()); - result.emplace_back(stat_entry.second.count); + result.emplace_back(static_cast(stat_entry.second.count)); result.emplace_back(TypedValue()); result.emplace_back(TypedValue()); result.emplace_back(TypedValue()); @@ -1636,8 +1654,8 @@ std::vector> AnalyzeGraphQueryHandler::AnalyzeGraphCreat result.emplace_back(execution_db_accessor->LabelToName(stat_entry.first.first)); result.emplace_back(execution_db_accessor->PropertyToName(stat_entry.first.second)); - result.emplace_back(stat_entry.second.count); - result.emplace_back(stat_entry.second.distinct_values_count); + result.emplace_back(static_cast(stat_entry.second.count)); + result.emplace_back(static_cast(stat_entry.second.distinct_values_count)); result.emplace_back(stat_entry.second.avg_group_size); result.emplace_back(stat_entry.second.statistic); result.emplace_back(stat_entry.second.avg_degree); @@ -1655,11 +1673,12 @@ std::vector> AnalyzeGraphQueryHandler::AnalyzeGraphDelet label_prop_results = execution_db_accessor->ClearLabelPropertyIndexStats(); label_results = execution_db_accessor->ClearLabelIndexStats(); } else { - label_prop_results = execution_db_accessor->DeleteIndexStatsForLabels(labels); - label_results = execution_db_accessor->DeleteLabelIndexStatsForLabels(labels); + label_prop_results = execution_db_accessor->DeleteLabelPropertyIndexStats(labels); + label_results = execution_db_accessor->DeleteLabelIndexStats(labels); } std::vector> results; + results.reserve(label_prop_results.size() + label_results.size()); std::transform(label_prop_results.begin(), label_prop_results.end(), std::back_inserter(results), [execution_db_accessor](const auto &label_property_index) { return std::vector{ diff --git a/src/query/plan/cost_estimator.hpp b/src/query/plan/cost_estimator.hpp index 4940f939a..3169d2e2f 100644 --- a/src/query/plan/cost_estimator.hpp +++ b/src/query/plan/cost_estimator.hpp @@ -16,6 +16,7 @@ #include "query/plan/operator.hpp" #include "query/typed_value.hpp" #include "utils/algorithm.hpp" +#include "utils/math.hpp" namespace memgraph::query::plan { @@ -25,7 +26,7 @@ namespace memgraph::query::plan { * how to do expands and other types of Cypher manipulations. */ struct SymbolStatistics { - int64_t cardinality; + uint64_t count; double degree; }; @@ -288,11 +289,11 @@ class CostEstimator : public HierarchicalLogicalOperatorVisitor { auto stats = GetStatsFor(symbol); if (stats.has_value()) { scope.symbol_stats[symbol.name()] = - SymbolStatistics{.cardinality = stats.value().cardinality, .degree = stats.value().degree}; + SymbolStatistics{.count = stats.value().count, .degree = stats.value().degree}; } } - scopes_.push_back(scope); + scopes_.push_back(std::move(scope)); return true; } @@ -301,9 +302,9 @@ class CostEstimator : public HierarchicalLogicalOperatorVisitor { op.input_->Accept(*this); // Estimate cost on the subquery branch independently, use a copy - auto last_scope = scopes_.back(); + auto &last_scope = scopes_.back(); double subquery_cost = EstimateCostOnBranch(&op.subquery_, last_scope); - subquery_cost = subquery_cost != 0 ? subquery_cost : 1; + subquery_cost = !utils::ApproxEqualDecimal(subquery_cost, 0.0) ? subquery_cost : 1; cardinality_ *= subquery_cost; IncrementCost(CostParam::kSubquery); @@ -387,12 +388,10 @@ class CostEstimator : public HierarchicalLogicalOperatorVisitor { template void SaveStatsFor(const Symbol &symbol, T index_stats) { scopes_.back().symbol_stats[symbol.name()] = SymbolStatistics{ - .cardinality = index_stats.count, + .count = index_stats.count, .degree = index_stats.avg_degree, }; } - - void DeleteStatsFor(const Symbol &symbol) { scopes_.back().symbol_stats.erase(symbol.name()); } }; /** Returns the estimated cost of the given plan. */ diff --git a/src/storage/v2/indices.cpp b/src/storage/v2/indices.cpp index 295cc1fb7..596631899 100644 --- a/src/storage/v2/indices.cpp +++ b/src/storage/v2/indices.cpp @@ -498,7 +498,7 @@ std::vector LabelIndex::ClearIndexStats() { return deleted_indexes; } -std::vector LabelIndex::DeleteIndexStatsForLabel(const storage::LabelId &label) { +std::vector LabelIndex::DeleteIndexStats(const storage::LabelId &label) { std::vector deleted_indexes; for (auto it = stats_.cbegin(); it != stats_.cend();) { if (it->first == label) { @@ -848,8 +848,7 @@ int64_t LabelPropertyIndex::ApproximateVertexCount(LabelId label, PropertyId pro /* Iterate over all property-label pairs and deletes if label from the index is equal to label parameter. */ -std::vector> LabelPropertyIndex::DeleteIndexStatsForLabel( - const storage::LabelId &label) { +std::vector> LabelPropertyIndex::DeleteIndexStats(const storage::LabelId &label) { std::vector> deleted_indexes; for (auto it = stats_.cbegin(); it != stats_.cend();) { if (it->first.first == label) { @@ -871,14 +870,14 @@ std::vector> LabelPropertyIndex::ClearIndexStats( return deleted_indexes; } -void LabelPropertyIndex::SetIndexStats(const storage::LabelId &label, const storage::PropertyId &property, +void LabelPropertyIndex::SetIndexStats(const std::pair &key, const storage::LabelPropertyIndexStats &stats) { - stats_[{label, property}] = stats; + stats_[key] = stats; } std::optional LabelPropertyIndex::GetIndexStats( - const storage::LabelId &label, const storage::PropertyId &property) const { - if (auto it = stats_.find({label, property}); it != stats_.end()) { + const std::pair &key) const { + if (auto it = stats_.find(key); it != stats_.end()) { return it->second; } return {}; diff --git a/src/storage/v2/indices.hpp b/src/storage/v2/indices.hpp index 6406bd6dd..b5dc28114 100644 --- a/src/storage/v2/indices.hpp +++ b/src/storage/v2/indices.hpp @@ -32,7 +32,7 @@ using ParalellizedIndexCreationInfo = std::pair> /*vertex_recovery_info*/, uint64_t /*thread_count*/>; struct LabelIndexStats { - int64_t count; + uint64_t count; double avg_degree; }; @@ -135,7 +135,7 @@ class LabelIndex { std::vector ClearIndexStats(); - std::vector DeleteIndexStatsForLabel(const storage::LabelId &label); + std::vector DeleteIndexStats(const storage::LabelId &label); void Clear() { index_.clear(); } @@ -150,7 +150,7 @@ class LabelIndex { }; struct LabelPropertyIndexStats { - int64_t count, distinct_values_count; + uint64_t count, distinct_values_count; double statistic, avg_group_size, avg_degree; }; @@ -263,13 +263,13 @@ class LabelPropertyIndex { std::vector> ClearIndexStats(); - std::vector> DeleteIndexStatsForLabel(const storage::LabelId &label); + std::vector> DeleteIndexStats(const storage::LabelId &label); - void SetIndexStats(const storage::LabelId &label, const storage::PropertyId &property, + void SetIndexStats(const std::pair &key, const storage::LabelPropertyIndexStats &stats); - std::optional GetIndexStats(const storage::LabelId &label, - const storage::PropertyId &property) const; + std::optional GetIndexStats( + const std::pair &key) const; void Clear() { index_.clear(); } diff --git a/src/storage/v2/storage.hpp b/src/storage/v2/storage.hpp index 49c6a5a3f..207ee5290 100644 --- a/src/storage/v2/storage.hpp +++ b/src/storage/v2/storage.hpp @@ -267,51 +267,66 @@ class Storage final { return storage_->indices_.label_property_index.ApproximateVertexCount(label, property, lower, upper); } + template + std::optional GetIndexStatsForIndex(TIndex &index, TIndexKey &&key) const { + return index.GetIndexStats(key); + } + std::optional GetIndexStats(const storage::LabelId &label) const { - return storage_->indices_.label_index.GetIndexStats(label); + return GetIndexStatsForIndex(storage_->indices_.label_index, label); } std::optional GetIndexStats(const storage::LabelId &label, const storage::PropertyId &property) const { - return storage_->indices_.label_property_index.GetIndexStats(label, property); + return GetIndexStatsForIndex(storage_->indices_.label_property_index, + std::make_pair(label, property)); } - std::vector> ClearLabelPropertyIndexStats() { - return storage_->indices_.label_property_index.ClearIndexStats(); - } - - std::vector ClearLabelIndexStats() { return storage_->indices_.label_index.ClearIndexStats(); } - - std::vector> DeleteIndexStatsForLabels(const std::span labels) { - std::vector> deleted_indexes; - std::for_each(labels.begin(), labels.end(), [this, &deleted_indexes](const auto &label_str) { - std::vector> loc_results = - storage_->indices_.label_property_index.DeleteIndexStatsForLabel(NameToLabel(label_str)); - deleted_indexes.insert(deleted_indexes.end(), std::make_move_iterator(loc_results.begin()), - std::make_move_iterator(loc_results.end())); - }); - return deleted_indexes; - } - - std::vector DeleteLabelIndexStatsForLabels(const std::span labels) { - std::vector deleted_indexes; - std::for_each(labels.begin(), labels.end(), [this, &deleted_indexes](const auto &label_str) { - std::vector loc_results = - storage_->indices_.label_index.DeleteIndexStatsForLabel(NameToLabel(label_str)); - deleted_indexes.insert(deleted_indexes.end(), std::make_move_iterator(loc_results.begin()), - std::make_move_iterator(loc_results.end())); - }); - - return deleted_indexes; + template + void SetIndexStatsForIndex(TIndex &index, TIndexKey &&key, TIndexStats &stats) const { + index.SetIndexStats(key, stats); } void SetIndexStats(const storage::LabelId &label, const LabelIndexStats &stats) { - storage_->indices_.label_index.SetIndexStats(label, stats); + SetIndexStatsForIndex(storage_->indices_.label_index, label, stats); } void SetIndexStats(const storage::LabelId &label, const storage::PropertyId &property, const LabelPropertyIndexStats &stats) { - storage_->indices_.label_property_index.SetIndexStats(label, property, stats); + SetIndexStatsForIndex(storage_->indices_.label_property_index, std::make_pair(label, property), stats); + } + + template + std::vector ClearIndexStatsForIndex(TIndex &index) const { + return index.ClearIndexStats(); + } + + std::vector> ClearLabelPropertyIndexStats() { + return ClearIndexStatsForIndex>(storage_->indices_.label_property_index); + } + + std::vector ClearLabelIndexStats() { + return ClearIndexStatsForIndex(storage_->indices_.label_index); + } + + template + std::vector DeleteIndexStatsForIndex(TIndex &index, const std::span labels) { + std::vector deleted_indexes; + + for (const auto &label : labels) { + std::vector loc_results = index.DeleteIndexStats(NameToLabel(label)); + deleted_indexes.insert(deleted_indexes.end(), std::make_move_iterator(loc_results.begin()), + std::make_move_iterator(loc_results.end())); + } + return deleted_indexes; + } + + std::vector> DeleteLabelPropertyIndexStats(const std::span labels) { + return DeleteIndexStatsForIndex>(storage_->indices_.label_property_index, labels); + } + + std::vector DeleteLabelIndexStats(const std::span labels) { + return DeleteIndexStatsForIndex(storage_->indices_.label_index, labels); } /// @return Accessor to the deleted vertex if a deletion took place, std::nullopt otherwise diff --git a/tests/e2e/analyze_graph/optimize_indexes.py b/tests/e2e/analyze_graph/optimize_indexes.py index f92c051f0..be6a72c1e 100644 --- a/tests/e2e/analyze_graph/optimize_indexes.py +++ b/tests/e2e/analyze_graph/optimize_indexes.py @@ -14,9 +14,7 @@ import sys import pytest from common import connect, execute_and_fetch_all, memgraph - -class OptimizeIndexesConstants: - QUERY_PLAN = "QUERY PLAN" +QUERY_PLAN = "QUERY PLAN" # E2E tests for checking query semantic @@ -308,7 +306,7 @@ def test_given_supernode_when_expanding_then_expand_other_way_around(memgraph): ] result_without_analysis = list(memgraph.execute_and_fetch(query)) - result_without_analysis = [x[OptimizeIndexesConstants.QUERY_PLAN] for x in result_without_analysis] + result_without_analysis = [x[QUERY_PLAN] for x in result_without_analysis] assert expected_explain == result_without_analysis memgraph.execute("analyze graph;") @@ -319,7 +317,7 @@ def test_given_supernode_when_expanding_then_expand_other_way_around(memgraph): ] result_with_analysis = list(memgraph.execute_and_fetch(query)) - result_with_analysis = [x[OptimizeIndexesConstants.QUERY_PLAN] for x in result_with_analysis] + result_with_analysis = [x[QUERY_PLAN] for x in result_with_analysis] assert expected_explain == result_with_analysis @@ -363,7 +361,7 @@ def test_given_supernode_when_subquery_then_carry_information_to_subquery(memgra ] result_without_analysis = list(memgraph.execute_and_fetch(query)) - result_without_analysis = [x[OptimizeIndexesConstants.QUERY_PLAN] for x in result_without_analysis] + result_without_analysis = [x[QUERY_PLAN] for x in result_without_analysis] assert expected_explain == result_without_analysis memgraph.execute("analyze graph;") @@ -373,7 +371,7 @@ def test_given_supernode_when_subquery_then_carry_information_to_subquery(memgra for x in expected_explain ] result_with_analysis = list(memgraph.execute_and_fetch(query)) - result_with_analysis = [x[OptimizeIndexesConstants.QUERY_PLAN] for x in result_with_analysis] + result_with_analysis = [x[QUERY_PLAN] for x in result_with_analysis] assert expected_explain == result_with_analysis @@ -435,7 +433,7 @@ def test_given_supernode_when_subquery_and_union_then_carry_information(memgraph ] result_without_analysis = list(memgraph.execute_and_fetch(query)) - result_without_analysis = [x[OptimizeIndexesConstants.QUERY_PLAN] for x in result_without_analysis] + result_without_analysis = [x[QUERY_PLAN] for x in result_without_analysis] assert expected_explain == result_without_analysis memgraph.execute("analyze graph;") @@ -449,7 +447,7 @@ def test_given_supernode_when_subquery_and_union_then_carry_information(memgraph for x in expected_explain ] result_with_analysis = list(memgraph.execute_and_fetch(query)) - result_with_analysis = [x[OptimizeIndexesConstants.QUERY_PLAN] for x in result_with_analysis] + result_with_analysis = [x[QUERY_PLAN] for x in result_with_analysis] assert expected_explain == result_with_analysis