Switch to text indices that are named

This commit is contained in:
Ante Pušić 2024-01-09 20:46:30 +01:00
parent ce718c4646
commit 5fb9324239
12 changed files with 106 additions and 76 deletions

View File

@ -326,8 +326,13 @@ inline mgp_vertex *graph_get_vertex_by_id(mgp_graph *g, mgp_vertex_id id, mgp_me
return MgInvoke<mgp_vertex *>(mgp_graph_get_vertex_by_id, g, id, memory);
}
inline bool graph_has_text_index(mgp_graph *graph, const char *label) {
return MgInvoke<int>(mgp_graph_has_text_index, graph, label);
inline bool graph_has_text_index(mgp_graph *graph, const char *index_name) {
return MgInvoke<int>(mgp_graph_has_text_index, graph, index_name);
}
// TODO antepusic change result type
inline bool graph_search_text_index(mgp_graph *graph, const char *index_name) {
return MgInvoke<int>(mgp_graph_has_text_index, graph, index_name);
}
inline mgp_vertices_iterator *graph_iter_vertices(mgp_graph *g, mgp_memory *memory) {

View File

@ -891,7 +891,10 @@ enum mgp_error mgp_edge_iter_properties(struct mgp_edge *e, struct mgp_memory *m
enum mgp_error mgp_graph_get_vertex_by_id(struct mgp_graph *g, struct mgp_vertex_id id, struct mgp_memory *memory,
struct mgp_vertex **result);
enum mgp_error mgp_graph_has_text_index(mgp_graph *graph, const char *label);
enum mgp_error mgp_graph_has_text_index(mgp_graph *graph, const char *label, int *result);
// TODO antepusic change result type
enum mgp_error mgp_graph_search_text_index(mgp_graph *graph, const char *index_name, int *result);
/// Creates label index for given label.
/// mgp_error::MGP_ERROR_NO_ERROR is always returned.

View File

@ -24,22 +24,21 @@ void Search(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_m
} // namespace TextSearch
void Search(mgp_list *args, mgp_graph *memgraph_graph, mgp_result *result, mgp_memory *memory) {
// CALL text_search.search("Label", "nekiQuery", searchFields, returnFields) RETURN node, score
mgp::MemoryDispatcherGuard guard{memory};
const auto record_factory = mgp::RecordFactory(result);
auto arguments = mgp::List(args);
auto label = arguments[0].ValueString();
auto search_string = arguments[1].ValueString();
// TODO antepusic:
// 1. Match the label to the appropriate text index
// auto label_id = memgraph_graph->impl->NameToLabel(label); <- needs API method
// 1. See if the given label is text-indexed
if (!mgp::graph_has_text_index(memgraph_graph, label.data())) {
return;
}
// 2. Run text search of that index
// * Add metadata to the return fields before search
mgp::graph_search_text_index(memgraph_graph, label.data());
// text_index.search(label, search_string);

View File

@ -553,7 +553,7 @@ class DbAccessor final {
return accessor_->LabelPropertyIndexExists(label, prop);
}
bool TextIndexExists(storage::LabelId label) const { return accessor_->TextIndexExists(label); }
bool TextIndexExists(std::string index_name) const { return accessor_->TextIndexExists(index_name); }
std::optional<storage::LabelIndexStats> GetIndexStats(const storage::LabelId &label) const {
return accessor_->GetIndexStats(label);
@ -630,12 +630,13 @@ class DbAccessor final {
return accessor_->DropIndex(label, property);
}
utils::BasicResult<storage::StorageIndexDefinitionError, void> CreateTextIndex(storage::LabelId label) {
return accessor_->CreateTextIndex(label);
utils::BasicResult<storage::StorageIndexDefinitionError, void> CreateTextIndex(std::string index_name,
storage::LabelId label) {
return accessor_->CreateTextIndex(index_name, label);
}
utils::BasicResult<storage::StorageIndexDefinitionError, void> DropTextIndex(storage::LabelId label) {
return accessor_->DropTextIndex(label);
utils::BasicResult<storage::StorageIndexDefinitionError, void> DropTextIndex(std::string index_name) {
return accessor_->DropTextIndex(index_name);
}
utils::BasicResult<storage::StorageExistenceConstraintDefinitionError, void> CreateExistenceConstraint(

View File

@ -2205,6 +2205,7 @@ class IndexQuery : public memgraph::query::Query {
memgraph::query::IndexQuery::Type type_;
memgraph::query::LabelIx label_;
std::vector<memgraph::query::PropertyIx> properties_;
std::string index_name_;
IndexQuery *Clone(AstStorage *storage) const override {
IndexQuery *object = storage->Create<IndexQuery>();
@ -2215,6 +2216,7 @@ class IndexQuery : public memgraph::query::Query {
for (auto i = 0; i < object->properties_.size(); ++i) {
object->properties_[i] = storage->GetPropertyIx(properties_[i].name);
}
object->index_name_ = index_name_;
return object;
}
@ -2222,6 +2224,9 @@ class IndexQuery : public memgraph::query::Query {
IndexQuery(Action action, Type type, LabelIx label, std::vector<PropertyIx> properties)
: action_(action), type_(type), label_(label), properties_(properties) {}
IndexQuery(Action action, Type type, LabelIx label, std::vector<PropertyIx> properties, std::string index_name)
: action_(action), type_(type), label_(label), properties_(properties), index_name_(index_name) {}
private:
friend class AstStorage;
};

View File

@ -257,6 +257,7 @@ antlrcpp::Any CypherMainVisitor::visitCreateIndex(MemgraphCypher::CreateIndexCon
antlrcpp::Any CypherMainVisitor::visitCreateTextIndex(MemgraphCypher::CreateTextIndexContext *ctx) {
auto *index_query = storage_->Create<IndexQuery>();
index_query->index_name_ = std::any_cast<std::string>(ctx->indexName()->accept(this));
index_query->action_ = IndexQuery::Action::CREATE;
index_query->type_ = IndexQuery::Type::TEXT;
index_query->label_ = AddLabel(std::any_cast<std::string>(ctx->labelName()->accept(this)));
@ -277,9 +278,9 @@ antlrcpp::Any CypherMainVisitor::visitDropIndex(MemgraphCypher::DropIndexContext
antlrcpp::Any CypherMainVisitor::visitDropTextIndex(MemgraphCypher::DropTextIndexContext *ctx) {
auto *index_query = storage_->Create<IndexQuery>();
index_query->index_name_ = std::any_cast<std::string>(ctx->indexName()->accept(this));
index_query->action_ = IndexQuery::Action::DROP;
index_query->type_ = IndexQuery::Type::TEXT;
index_query->label_ = AddLabel(std::any_cast<std::string>(ctx->labelName()->accept(this)));
return index_query;
}

View File

@ -339,9 +339,11 @@ createIndex : CREATE INDEX ON ':' labelName ( '(' propertyKeyName ')' )? ;
dropIndex : DROP INDEX ON ':' labelName ( '(' propertyKeyName ')' )? ;
createTextIndex : CREATE TEXT INDEX ON ':' labelName ;
indexName : symbolicName ;
dropTextIndex : DROP TEXT INDEX ON ':' labelName ;
createTextIndex : CREATE TEXT INDEX indexName ON ':' labelName ;
dropTextIndex : DROP TEXT INDEX indexName ;
doubleLiteral : FloatingLiteral ;

View File

@ -2153,6 +2153,7 @@ PreparedQuery PrepareIndexQuery(ParsedQuery parsed_query, bool in_explicit_trans
auto *storage = db_acc->storage();
auto label = storage->NameToLabel(index_query->label_.name);
auto &index_name = index_query->index_name_;
std::vector<storage::PropertyId> properties;
std::vector<std::string> properties_string;
@ -2176,7 +2177,7 @@ PreparedQuery PrepareIndexQuery(ParsedQuery parsed_query, bool in_explicit_trans
fmt::format("Created index on label {} on properties {}.", index_query->label_.name, properties_stringified);
// TODO: not just storage + invalidate_plan_cache. Need a DB transaction (for replication)
handler = [dba, index_type = index_query->type_, label,
handler = [dba, index_type = index_query->type_, label, index_name,
properties_stringified = std::move(properties_stringified), label_name = index_query->label_.name,
properties = std::move(properties),
invalidate_plan_cache = std::move(invalidate_plan_cache)](Notification &index_notification) {
@ -2185,7 +2186,7 @@ PreparedQuery PrepareIndexQuery(ParsedQuery parsed_query, bool in_explicit_trans
if (index_type == IndexQuery::Type::LOOKUP) {
maybe_index_error = properties.empty() ? dba->CreateIndex(label) : dba->CreateIndex(label, properties[0]);
} else if (index_type == IndexQuery::Type::TEXT) {
maybe_index_error = dba->CreateTextIndex(label);
maybe_index_error = dba->CreateTextIndex(index_name, label);
}
utils::OnScopeExit invalidator(invalidate_plan_cache);
@ -2203,7 +2204,7 @@ PreparedQuery PrepareIndexQuery(ParsedQuery parsed_query, bool in_explicit_trans
index_notification.title = fmt::format("Dropped index on label {} on properties {}.", index_query->label_.name,
utils::Join(properties_string, ", "));
// TODO: not just storage + invalidate_plan_cache. Need a DB transaction (for replication)
handler = [dba, index_type = index_query->type_, label,
handler = [dba, index_type = index_query->type_, label, index_name,
properties_stringified = std::move(properties_stringified), label_name = index_query->label_.name,
properties = std::move(properties),
invalidate_plan_cache = std::move(invalidate_plan_cache)](Notification &index_notification) {
@ -2212,7 +2213,7 @@ PreparedQuery PrepareIndexQuery(ParsedQuery parsed_query, bool in_explicit_trans
if (index_type == IndexQuery::Type::LOOKUP) {
maybe_index_error = properties.empty() ? dba->DropIndex(label) : dba->DropIndex(label, properties[0]);
} else if (index_type == IndexQuery::Type::TEXT) {
maybe_index_error = dba->DropTextIndex(label);
maybe_index_error = dba->DropTextIndex(index_name);
}
utils::OnScopeExit invalidator(invalidate_plan_cache);

View File

@ -3322,18 +3322,21 @@ mgp_error mgp_graph_delete_edge(struct mgp_graph *graph, mgp_edge *edge) {
});
}
mgp_error mgp_graph_has_text_index(mgp_graph *graph, const char *label, int *result) {
return WrapExceptions([graph, label, result]() {
std::visit(
memgraph::utils::Overloaded{
[&](memgraph::query::DbAccessor *impl) { *result = impl->TextIndexExists(impl->NameToLabel(label)); },
[&](memgraph::query::SubgraphDbAccessor *impl) {
*result = impl->GetAccessor()->TextIndexExists(impl->GetAccessor()->NameToLabel(label));
}},
graph->impl);
mgp_error mgp_graph_has_text_index(mgp_graph *graph, const char *index_name, int *result) {
return WrapExceptions([graph, index_name, result]() {
std::visit(memgraph::utils::Overloaded{
[&](memgraph::query::DbAccessor *impl) { *result = impl->TextIndexExists(index_name); },
[&](memgraph::query::SubgraphDbAccessor *impl) {
*result = impl->GetAccessor()->TextIndexExists(index_name);
}},
graph->impl);
});
}
mgp_error mgp_graph_search_text_index(mgp_graph *graph, const char *index_name, int *result) {
return WrapExceptions([graph, index_name, result]() { *result = 1; });
}
#ifdef MG_ENTERPRISE
namespace {
void NextPermitted(mgp_vertices_iterator &it) {

View File

@ -29,29 +29,31 @@ class TextIndex {
void UpdateOnRemoveLabel(LabelId removed_label, Vertex *vertex_after_update, const Transaction &tx) {}
/// @throw std::bad_alloc
bool CreateIndex(LabelId label, const std::optional<durability::ParallelizedSchemaCreationInfo> &parallel_exec_info) {
bool CreateIndex(std::string index_name, LabelId label,
const std::optional<durability::ParallelizedSchemaCreationInfo> &parallel_exec_info) {
auto index_config = mgcxx_mock::text_search::IndexConfig{.mappings = "TODO antepusic"};
auto new_index = mgcxx_mock::text_search::Mock::create_index(label.ToString(), index_config);
index_[label] = new_index;
auto new_index = mgcxx_mock::text_search::Mock::create_index(index_name, index_config);
index_[index_name] = new_index;
return true;
// TODO add documents to index
}
bool DropIndex(LabelId label) {
mgcxx_mock::text_search::Mock::drop_index(label.ToString());
index_.erase(label);
bool DropIndex(std::string index_name) {
mgcxx_mock::text_search::Mock::drop_index(index_name);
index_.erase(index_name);
return true;
}
bool IndexExists(LabelId label) { return index_.contains(label); }
bool IndexExists(std::string index_name) { return index_.contains(index_name); }
mgcxx_mock::text_search::SearchOutput Search(LabelId label, mgcxx_mock::text_search::SearchInput input) {
return mgcxx_mock::text_search::Mock::search(index_.at(label), input);
mgcxx_mock::text_search::SearchOutput Search(std::string index_name, mgcxx_mock::text_search::SearchInput input) {
// TODO antepusic: Add metadata to the return fields before search
return mgcxx_mock::text_search::Mock::search(index_.at(index_name), input);
}
std::vector<LabelId> ListIndices() {
std::vector<LabelId> ret;
std::vector<std::string> ListIndices() {
std::vector<std::string> ret;
ret.reserve(index_.size());
for (const auto &item : index_) {
ret.push_back(item.first);
@ -59,9 +61,9 @@ class TextIndex {
return ret;
}
uint64_t ApproximateVertexCount(LabelId label) { return 10; }
uint64_t ApproximateVertexCount(std::string index_name) { return 10; }
std::map<LabelId, mgcxx_mock::text_search::IndexContext> index_;
std::map<std::string, mgcxx_mock::text_search::IndexContext> index_;
};
} // namespace memgraph::storage

View File

@ -212,7 +212,9 @@ class Storage {
virtual bool LabelPropertyIndexExists(LabelId label, PropertyId property) const = 0;
bool TextIndexExists(LabelId label) const { return storage_->indices_.text_index_->IndexExists(label); }
bool TextIndexExists(std::string index_name) const {
return storage_->indices_.text_index_->IndexExists(index_name);
}
virtual IndicesInfo ListAllIndices() const = 0;
@ -250,9 +252,9 @@ class Storage {
std::vector<EdgeTypeId> ListAllPossiblyPresentEdgeTypes() const;
mgcxx_mock::text_search::SearchOutput TextSearch(LabelId label,
mgcxx_mock::text_search::SearchOutput TextSearch(std::string index_name,
mgcxx_mock::text_search::SearchInput &search_input) const {
return storage_->indices_.text_index_->Search(label, search_input);
return storage_->indices_.text_index_->Search(index_name, search_input);
}
virtual utils::BasicResult<StorageIndexDefinitionError, void> CreateIndex(LabelId label) = 0;
@ -263,14 +265,15 @@ class Storage {
virtual utils::BasicResult<StorageIndexDefinitionError, void> DropIndex(LabelId label, PropertyId property) = 0;
virtual utils::BasicResult<StorageIndexDefinitionError, void> CreateTextIndex(LabelId label) {
virtual utils::BasicResult<StorageIndexDefinitionError, void> CreateTextIndex(std::string index_name,
LabelId label) {
// TODO: pass vertices to CreateIndex
storage_->indices_.text_index_->CreateIndex(label, std::nullopt);
storage_->indices_.text_index_->CreateIndex(index_name, label, std::nullopt);
return {};
}
virtual utils::BasicResult<StorageIndexDefinitionError, void> DropTextIndex(LabelId label) {
storage_->indices_.text_index_->DropIndex(label);
virtual utils::BasicResult<StorageIndexDefinitionError, void> DropTextIndex(std::string index_name) {
storage_->indices_.text_index_->DropIndex(index_name);
return {};
}

View File

@ -21,7 +21,7 @@
#include "storage/v2/edge_accessor.hpp"
#include "storage/v2/id_types.hpp"
#include "storage/v2/indices/indices.hpp"
#include "storage/v2/mgcxx.hpp"
#include "storage/v2/mgcxx_mock.hpp"
#include "storage/v2/mvcc.hpp"
#include "storage/v2/property_value.hpp"
#include "storage/v2/result.hpp"
@ -274,13 +274,14 @@ Result<PropertyValue> VertexAccessor::SetProperty(PropertyId property, const Pro
utils::AtomicMemoryBlock atomic_memory_block{
[transaction = transaction_, storage = storage_, vertex = vertex_, &value, &property, &current_value]() {
CreateAndLinkDelta(transaction, vertex, Delta::SetPropertyTag(), property, current_value);
// Option 1 (current)
if (std::ranges::any_of(vertex->labels,
[storage](auto &label) { return storage->indices_.text_index_->IndexExists(label); })) {
vertex->properties.SetProperty(property, value, true, vertex->gid);
} else {
vertex->properties.SetProperty(property, value);
}
// // Option 1 (current)
// if (std::ranges::any_of(vertex->labels,
// [storage](auto &label) { return storage->indices_.text_index_->IndexExists(label);
// })) {
// vertex->properties.SetProperty(property, value, true, vertex->gid);
// } else {
// vertex->properties.SetProperty(property, value);
// }
// // Option 2 (proposed)
// if (flags::run_time::GetTextSearchEnabled()) {
@ -326,13 +327,15 @@ Result<bool> VertexAccessor::InitProperties(const std::map<storage::PropertyId,
bool result{false};
utils::AtomicMemoryBlock atomic_memory_block{
[&result, &properties, storage = storage_, transaction = transaction_, vertex = vertex_]() {
if (std::ranges::any_of(vertex->labels,
[storage](auto &label) { return storage->indices_.text_index_->IndexExists(label); })) {
if (!vertex->properties.InitProperties(properties, true, vertex->gid)) {
result = false;
return;
}
} else if (!vertex->properties.InitProperties(properties)) {
// if (std::ranges::any_of(vertex->labels,
// [storage](auto &label) { return storage->indices_.text_index_->IndexExists(label);
// })) {
// if (!vertex->properties.InitProperties(properties, true, vertex->gid)) {
// result = false;
// return;
// }
// } else
if (!vertex->properties.InitProperties(properties)) {
result = false;
return;
}
@ -370,12 +373,13 @@ Result<std::vector<std::tuple<PropertyId, PropertyValue, PropertyValue>>> Vertex
std::optional<ReturnType> id_old_new_change;
utils::AtomicMemoryBlock atomic_memory_block{
[storage = storage_, transaction = transaction_, vertex = vertex_, &properties, &id_old_new_change]() {
if (std::ranges::any_of(vertex->labels,
[storage](auto &label) { return storage->indices_.text_index_->IndexExists(label); })) {
id_old_new_change.emplace(vertex->properties.UpdateProperties(properties, true, vertex->gid));
} else {
id_old_new_change.emplace(vertex->properties.UpdateProperties(properties));
}
// if (std::ranges::any_of(vertex->labels,
// [storage](auto &label) { return storage->indices_.text_index_->IndexExists(label);
// })) {
// id_old_new_change.emplace(vertex->properties.UpdateProperties(properties, true, vertex->gid));
// } else {
id_old_new_change.emplace(vertex->properties.UpdateProperties(properties));
// }
if (!id_old_new_change.has_value()) {
return;
@ -420,12 +424,13 @@ Result<std::map<PropertyId, PropertyValue>> VertexAccessor::ClearProperties() {
transaction->constraint_verification_info.RemovedProperty(vertex);
transaction->manyDeltasCache.Invalidate(vertex, property);
}
if (std::ranges::any_of(vertex->labels,
[storage](auto &label) { return storage->indices_.text_index_->IndexExists(label); })) {
vertex->properties.ClearProperties(true, vertex->gid);
} else {
vertex->properties.ClearProperties();
}
// if (std::ranges::any_of(vertex->labels,
// [storage](auto &label) { return storage->indices_.text_index_->IndexExists(label);
// })) {
// vertex->properties.ClearProperties(true, vertex->gid);
// } else {
vertex->properties.ClearProperties();
// }
}};
std::invoke(atomic_memory_block);