match by label and properties; TODO: fix bug with bolt buffers

This commit is contained in:
Marko Budiselic 2016-10-19 17:07:40 +02:00
parent c312c2e369
commit 7d85bc2bc0
11 changed files with 189 additions and 91 deletions
include
query_engine
code_generator
hardcode
traverser
util.hpp
storage
utils/iterator
tests/integration

View File

@ -6,8 +6,8 @@
#include <vector>
#include "query_engine/code_generator/namer.hpp"
#include "storage/model/properties/flags.hpp"
#include "query_engine/exceptions/exceptions.hpp"
#include "storage/model/properties/flags.hpp"
// main states that are used while ast is traversed
// in order to generate ActionSequence
@ -43,7 +43,7 @@ enum class EntitySource : uint8_t
InternalId,
LabelIndex,
TypeIndex,
MainStorage
MainStorage
};
// TODO: reduce copying
@ -89,7 +89,7 @@ public:
return entity_source.at(name);
}
const std::map<std::string, EntityType> &all_typed_enteties()
const std::map<std::string, EntityType> &all_typed_enteties()
{
return entity_type;
}
@ -118,66 +118,87 @@ public:
entity_status[name] = EntityStatus::Created;
}
void source(const std::string& name, EntitySource source)
void source(const std::string &name, EntitySource source)
{
entity_source[name] = source;
}
// entity tags
auto tags(const std::string& name) const
auto tags(const std::string &name) const
{
if (entity_tags.find(name) == entity_tags.end())
throw CppGeneratorException("No tags for specified entity");
return entity_tags.at(name);
}
void tags(const std::string& name, tags_type tags)
void tags(const std::string &name, tags_type tags)
{
entity_tags[name] = tags;
}
void tag(const std::string& name, const std::string& new_tag)
void tag(const std::string &name, const std::string &new_tag)
{
if (entity_tags.find(name) != entity_tags.end())
{
if (entity_tags.find(name) == entity_tags.end()) {
entity_tags[name] = std::vector<std::string>{};
}
entity_tags[name].emplace_back(new_tag);
}
// entity properties
auto properties(const std::string& name) const
auto properties(const std::string &name) const
{
if (entity_properties.find(name) == entity_properties.end())
throw CppGeneratorException("No properties for specified entity");
return entity_properties.at(name);
}
void properties(const std::string& name, properties_type properties)
void properties(const std::string &name, properties_type properties)
{
entity_properties[name] = properties;
}
void index(const std::string& entity, const std::string& property, int64_t index)
void index(const std::string &entity, const std::string &property,
int64_t index)
{
if (entity_properties.find(entity) != entity_properties.end())
{
if (entity_properties.find(entity) == entity_properties.end()) {
entity_properties[entity] = properties_type{};
}
entity_properties[entity][property] = index;
}
auto index(const std::string& entity, const std::string& property_name)
auto index(const std::string &entity, const std::string &property_name)
{
if (entity_properties.find(entity) != entity_properties.end())
if (entity_properties.find(entity) == entity_properties.end())
throw CppGeneratorException("No properties for specified entity");
auto properties = entity_properties.at(entity);
if (properties.find(property_name) != properties.end())
throw CppGeneratorException("No property for specified property name");
if (properties.find(property_name) == properties.end())
throw CppGeneratorException(
"No property for specified property name");
return properties[property_name];
}
using iter_t = properties_type::iterator;
auto print_indices(const std::string &name,
const std::string &variable_name = "indices")
{
// TODO: find out smarter way it's not hard
std::string print =
"std::map<std::string, int64_t> " + variable_name + " = ";
print += "{";
auto indices = entity_properties.at(name);
size_t i = 0;
iter_t it = indices.begin();
for (; it != indices.end(); ++it, ++i)
{
print +=
"{\"" + it->first + "\"," + std::to_string(it->second) + "}";
if (i < indices.size() - 1)
print += ",";
}
print += "};";
return print;
}
};

View File

@ -46,13 +46,18 @@ auto return_query_action =
// node and no other property
if (cypher_data.type(entity) == EntityType::Node) {
// TODO: solve the case with more labels
auto label = cypher_data.tags(entity).at(0);
code += code_line(code::find_and_write_vertices_by_label,
entity, label);
if (cypher_data.properties(entity).size() > 0)
{
code += code_line(code::find_and_write_vertices_by_label_and_properties,
cypher_data.print_indices(entity), label, entity);
}
else
{
code += code_line(code::find_and_write_vertices_by_label,
entity, label);
}
}
// TODO: 16/10/2016 create match code if properties exist
}
if (cypher_data.source(entity) == EntitySource::TypeIndex)

View File

@ -37,6 +37,7 @@ namespace barrier
#include "utils/iterator/iterator.hpp"
#include "utils/option_ptr.hpp"
#include "utils/reference_wrapper.hpp"
#include "query_engine/util.hpp"
#endif
@ -472,33 +473,14 @@ auto load_queries(Db &db)
// MATCH (n:LABEL {name: "TEST01"}) RETURN n;
auto match_label_property = [&db](properties_t &&args) {
std::map<std::string, int64_t> properties{{"name", 0}};
std::map<std::string, int64_t> indices{{"name", 0}};
auto properties = query_properties(indices, args);
DbAccessor t(db);
try {
auto &label = t.label_find_or_create("LABEL");
label.index().for_range(t).for_all(
label.index().for_range(t).properties_filter(t, properties).for_all(
[&](auto vertex_accessor) -> void {
// TODO: record_accessor.match_execute(properties, op);
bool match = true;
for (auto &property_index : properties) {
auto property_key = t.vertex_property_key(
property_index.first,
args[property_index.second].key.flags());
if (!vertex_accessor.contains(property_key)) {
match = false;
break;
}
auto vertex_property_value =
vertex_accessor.at(property_key);
auto query_property_value = args[property_index.second];
if (!(vertex_property_value == query_property_value)) {
match = false;
break;
}
}
if (match) {
std::cout << "MATCH" << std::endl;
}
std::cout << "MATCH" << std::endl;
}
);
return t.commit();
@ -523,7 +505,7 @@ auto load_queries(Db &db)
queries[10597108978382323595u] = create_account;
queries[5397556489557792025u] = create_labeled_and_named_node;
// Query hasher reports two hash values
// TODO: query hasher reports two hash values
queries[998725786176032607u] = create_labeled_and_named_node_v2;
queries[16090682663946456821u] = create_labeled_and_named_node_v2;

View File

@ -59,14 +59,17 @@ const std::string write_entity = "stream.write_field(\"{0}\");\n"
" stream.chunk();"
" stream.write_meta(\"rw\");\n";
const std::string write_vertex_accessor =
" stream.write_record();\n"
" stream.write_list_header(1);\n"
" stream.write(vertex_accessor);\n"
" stream.chunk();\n";
const std::string write_all_vertices =
"stream.write_field(\"{0}\");\n"
" iter::for_all(t.vertex_access(), [&](auto vertex) {{\n"
" if (vertex.fill()) {{\n"
" stream.write_record();\n"
" stream.write_list_header(1);\n"
" stream.write(vertex);\n"
" stream.chunk();\n"
" iter::for_all(t.vertex_access(), [&](auto vertex_accessor) {{\n"
" if (vertex_accessor.fill()) {{\n"
+ write_vertex_accessor +
" }}\n"
" }});\n"
" stream.write_meta(\"rw\");\n";
@ -74,11 +77,19 @@ const std::string write_all_vertices =
const std::string find_and_write_vertices_by_label =
"auto &label = t.label_find_or_create(\"{1}\");\n"
" stream.write_field(\"{0}\");\n"
" label.index().for_range(t).for_all([&](auto vertex) {{\n"
" stream.write_record();\n"
" stream.write_list_header(1);\n"
" stream.write(vertex);\n"
" stream.chunk();\n"
" label.index().for_range(t).for_all([&](auto vertex_accessor) {{\n"
+ write_vertex_accessor +
" }});\n"
" stream.write_meta(\"rw\");\n";
const std::string find_and_write_vertices_by_label_and_properties =
"{0}\n"
" auto properties = query_properties(indices, args);\n"
" auto &label = t.label_find_or_create(\"{1}\");\n"
" stream.write_field(\"{2}\");\n"
" label.index().for_range(t).properties_filter(t, properties).for_all(\n"
" [&](auto vertex_accessor) -> void {{\n"
" "+ write_vertex_accessor +
" }});\n"
" stream.write_meta(\"rw\");\n";

View File

@ -3,6 +3,7 @@
#include <iostream>
#include <sstream>
#include <string>
#include <map>
#include "fmt/format.h"
#include "logging/default.hpp"
@ -52,6 +53,19 @@ std::string code_line(const std::string &format_str, const Args &... args)
throw CodeGenerationError(std::string(e.what()) + " " + format_str);
}
}
using name_properties_t = std::vector<std::pair<std::string, Property>>;
auto query_properties(const std::map<std::string, int64_t> &indices,
properties_t &values)
{
name_properties_t properties;
for (auto &property_index : indices) {
properties.push_back(
std::make_pair(std::move(property_index.first),
std::move(values[property_index.second])));
}
return properties;
}
class CoutSocket
@ -86,3 +100,5 @@ public:
private:
Logger logger;
};
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "utils/iterator/composable.hpp"
// Class for creating easy composable iterators for querying.
//
// This class contains graph specific methods.
//
// Derived - type of derived class
// T - return type
template <class T, Derived>
class GraphComposable : public Composable<T, GraphComposable<T, Derived>>
{
// TODO: various filters
// from filter
// to filter
// match filter
};

View File

@ -0,0 +1,19 @@
#pragma once
#include "utils/iterator/filter.hpp"
#include "storage/iterator/graph_composable.hpp"
template <class T, class I, class OP>
class GraphFilter : public Filter<T, I, OP>,
public GraphComposable<T, GraphFilter<T, I, OP>
{
using Filter::Filter;
};
template <class I, class OP>
auto make_graph_filter(I &&iter, OP &&op)
{
// Compiler cant deduce type T. decltype is here to help with it.
return GraphFilter<decltype(iter.next().take()), I, OP>(std::move(iter),
std::move(op));
}

View File

@ -187,7 +187,8 @@ public:
switch (key.get_type().flags()) {
GENERATE_FOR_ALL_PROPERTIES(GENERATE_CASE_CLAUSE_FOR_PRINT);
default:
assert(false);
// TODO: custom error
throw std::runtime_error("PropertyHolder::print -> unknown flag");
}
}

View File

@ -4,10 +4,9 @@
#include "utils/iterator/count.hpp"
#include "utils/option.hpp"
// class EdgeType;
namespace iter
{
template <class I, class OP>
auto make_map(I &&iter, OP &&op);
@ -33,6 +32,7 @@ template <class IT1, class IT2>
auto make_combined(IT1 &&iter1, IT2 &&iter2);
// Class for creating easy composable iterators fo querying.
//
// Derived - type of derived class
// T - return type
template <class T, class Derived>
@ -40,6 +40,7 @@ class Composable : public Crtp<Derived>
{
// Moves self
Derived &&move() { return std::move(this->derived()); }
public:
auto virtualize() { return iter::make_virtual(move()); }
@ -69,6 +70,33 @@ public:
move(), [&](auto v) mutable { return std::move(n); });
}
// For all items calls OP.
template <class OP>
void for_all(OP &&op)
{
iter::for_all(move(), std::move(op));
}
// All items must satisfy given predicate for this function to return true.
// Otherwise stops calling predicate on firts false and returns fasle.
template <class OP>
bool all(OP &&op)
{
auto iter = move();
auto e = iter.next();
while (e.is_present()) {
if (!op(e.take())) {
return false;
}
e = iter.next();
}
return true;
}
// !! MEMGRAPH specific composable filters
// TODO: isolate, but it is not trivial because this class
// is a base for other generic classes
// Maps with call to method to() and filters with call to fill.
auto to()
{
@ -98,7 +126,7 @@ public:
});
}
// Calls update on values and returns resoult.
// Calls update on values and returns result.
auto update()
{
return map([](auto ar) { return ar.update(); });
@ -151,27 +179,26 @@ public:
return filter([&](auto &element) { return element.isolated(); });
}
// For all items calls OP.
template <class OP>
void for_all(OP &&op)
// filter elements based on properties (all properties have to match)
// TRANSACTION -> transaction
// PROPERTIES -> [(name, property)]
template <class TRANSACTION, class PROPERTIES>
auto properties_filter(TRANSACTION &t, PROPERTIES& properties)
{
iter::for_all(move(), std::move(op));
}
// All items must satisfy given predicate for this function to return true.
// Otherwise stops calling predicate on firts false and returns fasle.
template <class OP>
bool all(OP &&op)
{
auto iter = move();
auto e = iter.next();
while (e.is_present()) {
if (!op(e.take())) {
return false;
return filter([&](auto &element) {
for (auto &name_value : properties) {
auto property_key = t.vertex_property_key(
name_value.first,
name_value.second.key.flags());
if (!element.contains(property_key))
return false;
auto vertex_property_value = element.at(property_key);
if (!(vertex_property_value == name_value.second))
return false;
}
e = iter.next();
}
return true;
return true;
});
}
};
}

View File

@ -12,6 +12,7 @@ bool fill(A &a)
{
return a.fill();
}
};
// Base iterator for next() kind iterator.

View File

@ -9,11 +9,6 @@
#include "logging/default.hpp"
#include "logging/streams/stdout.hpp"
#include "query_engine/query_stripper.hpp"
// #include "storage/edges.cpp"
// #include "storage/edges.hpp"
// #include "storage/vertices.cpp"
// #include "storage/vertices.hpp"
// #include "utils/assert.hpp"
int main(void)
{
@ -36,7 +31,7 @@ int main(void)
// CREATE and MATCH by label and property
"CREATE (n:LABEL {name: \"TEST01\"}) RETURN n",
"CREATE (n:LABEL {name: \"TEST02\"}) RETURN n",
"MATCH (n:LABEL {name: \"TEST01\"}) RETURN n",
// "MATCH (n:LABEL {name: \"TEST01\"}) RETURN n",
"CREATE (n:LABEL {name: \"TEST2\"}) RETURN n",
"CREATE (n:LABEL {name: \"TEST3\"}) RETURN n",
@ -62,11 +57,11 @@ int main(void)
"MATCH (n)-[:TYPE]->(m) WHERE ID(n) = 0 RETURN m",
"MATCH (n)-[:TYPE]->(m) WHERE n.name = \"kruno\" RETURN m",
"MATCH (n)-[:TYPE]->(m) WHERE n.name = \"kruno\" RETURN n,m",
"MATCH (n:LABEL)-[:TYPE]->(m) RETURN n",
"MATCH (n:LABEL)-[:TYPE]->(m) RETURN n"
// CREATE and MATCH multiple labels and properties
"CREATE (n:LABEL1:LABEL2 {name: \"TEST01\", age: 20}) RETURN n",
"MATCH (n:LABEL1:LABEL2 {name: \"TEST01\", age: 20}) RETURN n"
// "CREATE (n:LABEL1:LABEL2 {name: \"TEST01\", age: 20}) RETURN n",
// "MATCH (n:LABEL1:LABEL2 {name: \"TEST01\", age: 20}) RETURN n"
};
for (auto &query : queries) {