diff --git a/arangod/V8Server/V8Traverser.cpp b/arangod/V8Server/V8Traverser.cpp index e49d50ab63..523a1b5230 100644 --- a/arangod/V8Server/V8Traverser.cpp +++ b/arangod/V8Server/V8Traverser.cpp @@ -220,6 +220,22 @@ class SimpleEdgeExpander { // --SECTION-- ShortestPathOptions FUNCTIONS // ----------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +/// @brief Insert a new edge matcher object +//////////////////////////////////////////////////////////////////////////////// + +void ShortestPathOptions::addEdgeFilter( + v8::Isolate* isolate, + v8::Handle const& example, + TRI_shaper_t* shaper, + TRI_voc_cid_t const& cid, + string& errorMessage) { + auto it = _edgeFilter.find(cid); + if (it == _edgeFilter.end()) { + _edgeFilter.emplace(cid, new ExampleMatcher(isolate, example, shaper, errorMessage)); + } +} + //////////////////////////////////////////////////////////////////////////////// /// @brief Checks if an edge matches to given examples //////////////////////////////////////////////////////////////////////////////// @@ -238,22 +254,6 @@ bool ShortestPathOptions::matchesEdge(EdgeId& e, TRI_doc_mptr_copy_t* edge) cons return it->second->matches(edge); } -//////////////////////////////////////////////////////////////////////////////// -/// @brief Insert a new edge matcher object -//////////////////////////////////////////////////////////////////////////////// - -void ShortestPathOptions::addEdgeFilter( - v8::Isolate* isolate, - v8::Handle const& example, - TRI_shaper_t* shaper, - TRI_voc_cid_t const& cid, - string& errorMessage) { - auto it = _edgeFilter.find(cid); - if (it == _edgeFilter.end()) { - _edgeFilter.emplace(cid, new ExampleMatcher(isolate, example, shaper, errorMessage)); - } -} - //////////////////////////////////////////////////////////////////////////////// /// @brief Insert a new vertex matcher object //////////////////////////////////////////////////////////////////////////////// @@ -304,6 +304,45 @@ bool ShortestPathOptions::matchesVertex(VertexId& v) const { return it->second.matcher->matches(&vertex); } +// ----------------------------------------------------------------------------- +// --SECTION-- NeighborsOptions FUNCTIONS +// ----------------------------------------------------------------------------- + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Insert a new edge matcher object +//////////////////////////////////////////////////////////////////////////////// + +void NeighborsOptions::addEdgeFilter( + v8::Isolate* isolate, + v8::Handle const& example, + TRI_shaper_t* shaper, + TRI_voc_cid_t const& cid, + string& errorMessage) { + auto it = _edgeFilter.find(cid); + if (it == _edgeFilter.end()) { + _edgeFilter.emplace(cid, new ExampleMatcher(isolate, example, shaper, errorMessage)); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief Checks if an edge matches to given examples +//////////////////////////////////////////////////////////////////////////////// + +bool NeighborsOptions::matchesEdge(EdgeId& e, TRI_doc_mptr_copy_t* edge) const { + if (!useEdgeFilter) { + // Nothing to do + return true; + } + auto it = _edgeFilter.find(e.cid); + if (it == _edgeFilter.end()) { + // This collection does not have any object of this shape. + // Short circuit. + return false; + } + return it->second->matches(edge); +} + // ----------------------------------------------------------------------------- // --SECTION-- private Helper Functions // ----------------------------------------------------------------------------- @@ -361,9 +400,12 @@ void TRI_RunNeighborsSearch ( for (auto col : collectionInfos) { auto edges = col->getEdges(dir, opts.start); for (size_t j = 0; j < edges.size(); ++j) { - auto p = distinct.insert(extractFromId(edges[j])); - if (p.second) { - result.push_back(*p.first); + EdgeId edgeId = col->extractEdgeId(edges[j]); + if (opts.matchesEdge(edgeId, &edges[j])) { + auto p = distinct.insert(extractFromId(edges[j])); + if (p.second) { + result.push_back(*p.first); + } } } } @@ -373,9 +415,12 @@ void TRI_RunNeighborsSearch ( for (auto col : collectionInfos) { auto edges = col->getEdges(dir, opts.start); for (size_t j = 0; j < edges.size(); ++j) { - auto p = distinct.insert(extractToId(edges[j])); - if (p.second) { - result.push_back(*p.first); + EdgeId edgeId = col->extractEdgeId(edges[j]); + if (opts.matchesEdge(edgeId, &edges[j])) { + auto p = distinct.insert(extractToId(edges[j])); + if (p.second) { + result.push_back(*p.first); + } } } } @@ -386,7 +431,10 @@ void TRI_RunNeighborsSearch ( for (auto col : collectionInfos) { auto edges = col->getEdges(dir, opts.start); for (size_t j = 0; j < edges.size(); ++j) { - result.push_back(extractFromId(edges[j])); + EdgeId edgeId = col->extractEdgeId(edges[j]); + if (opts.matchesEdge(edgeId, &edges[j])) { + result.push_back(extractFromId(edges[j])); + } } } } @@ -395,7 +443,10 @@ void TRI_RunNeighborsSearch ( for (auto col : collectionInfos) { auto edges = col->getEdges(dir, opts.start); for (size_t j = 0; j < edges.size(); ++j) { - result.push_back(extractToId(edges[j])); + EdgeId edgeId = col->extractEdgeId(edges[j]); + if (opts.matchesEdge(edgeId, &edges[j])) { + result.push_back(extractToId(edges[j])); + } } } } diff --git a/arangod/V8Server/V8Traverser.h b/arangod/V8Server/V8Traverser.h index 6cce0b4eda..4dda63f330 100644 --- a/arangod/V8Server/V8Traverser.h +++ b/arangod/V8Server/V8Traverser.h @@ -184,14 +184,30 @@ namespace triagens { }; struct NeighborsOptions { - TRI_edge_direction_e direction; - bool distinct; - VertexId start; + private: + std::unordered_map _edgeFilter; - NeighborsOptions () : - direction(TRI_EDGE_OUT), - distinct(true) { - } + public: + TRI_edge_direction_e direction; + bool distinct; + VertexId start; + bool useEdgeFilter; + + NeighborsOptions () : + direction(TRI_EDGE_OUT), + distinct(true), + useEdgeFilter(false) { + } + + void addEdgeFilter ( + v8::Isolate* isolate, + v8::Handle const& example, + TRI_shaper_t* shaper, + TRI_voc_cid_t const& cid, + std::string& errorMessage + ); + + bool matchesEdge (EdgeId& e, TRI_doc_mptr_copy_t* edge) const; }; diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index 8e17a6f8e5..d15b14f95d 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -2155,7 +2155,7 @@ static void JS_QueryNeighbors (const v8::FunctionCallbackInfo& args) traverser::NeighborsOptions opts; bool includeData = false; - v8::Handle vertexExample; + v8::Handle edgeExample; if (args.Length() == 4) { if (! args[3]->IsObject()) { @@ -2190,6 +2190,12 @@ static void JS_QueryNeighbors (const v8::FunctionCallbackInfo& args) includeData = TRI_ObjectToBoolean(options->Get(keyIncludeData)); } + // Parse examples + v8::Local keyExamples = TRI_V8_ASCII_STRING("examples"); + if (options->Has(keyExamples)) { + opts.useEdgeFilter = true; + edgeExample = v8::Handle::Cast(options->Get(keyExamples)); + } } vector readCollections; @@ -2249,6 +2255,21 @@ static void JS_QueryNeighbors (const v8::FunctionCallbackInfo& args) unordered_set distinctNeighbors; vector neighbors; + + if (opts.useEdgeFilter) { + string errorMessage; + for (auto it: edgeCollectionInfos) { + try { + opts.addEdgeFilter(isolate, edgeExample, it->getShaper(), it->getCid(), errorMessage); + } catch (int e) { + // ELEMENT not found is expected, if there is no shape of this type in this collection + if (e != TRI_RESULT_ELEMENT_NOT_FOUND) { + // TODO Max fragen was mit Fehlern passieren muss + } + } + } + } + for (auto& startVertex : startVertices) { try { opts.start = idStringToVertexId(resolver, startVertex); diff --git a/js/server/modules/org/arangodb/aql.js b/js/server/modules/org/arangodb/aql.js index 08eb998d68..abaaf1963f 100644 --- a/js/server/modules/org/arangodb/aql.js +++ b/js/server/modules/org/arangodb/aql.js @@ -6523,18 +6523,18 @@ function AQL_NEIGHBORS (vertexCollection, vertex = TO_ID(vertex, vertexCollection); options = options || {}; options.direction = direction; - options.examples = examples; if (examples === undefined || - (Array.isArray(examples) && examples.length === 0)) { + (Array.isArray(examples) && examples.length <= 1)) { + if (examples.length === 1) { + options.examples = examples[0]; + } if (typeof options.distance === "number" && options.distance > 1) { return useCXXforDeepNeighbors(vertexCollection, edgeCollection, vertex, options); } else { - var x = CPP_NEIGHBORS([vertexCollection], [edgeCollection], vertex, options); - return x; - // return CPP_NEIGHBORS([vertexCollection], [edgeCollection], vertex, - // options); + return CPP_NEIGHBORS([vertexCollection], [edgeCollection], vertex, + options); } }