From a8cacef57d0febee872cb6488df7c0184ed712d7 Mon Sep 17 00:00:00 2001 From: scottashton Date: Tue, 20 May 2014 16:45:22 +0200 Subject: [PATCH] added GRAPH_NEIGHBORS --- arangod/Ahuacatl/ahuacatl-functions.c | 2 + js/server/modules/org/arangodb/ahuacatl.js | 92 +++++++++++++++++++++- js/server/tests/ahuacatl-general-graph.js | 34 +++++++- 3 files changed, 124 insertions(+), 4 deletions(-) diff --git a/arangod/Ahuacatl/ahuacatl-functions.c b/arangod/Ahuacatl/ahuacatl-functions.c index dc1f1409c6..fd7cd12b86 100644 --- a/arangod/Ahuacatl/ahuacatl-functions.c +++ b/arangod/Ahuacatl/ahuacatl-functions.c @@ -705,6 +705,7 @@ TRI_associative_pointer_t* TRI_CreateFunctionsAql (void) { REGISTER_FUNCTION("PATHS", "GRAPH_PATHS", false, false, "c,h|s,b", &OptimisePaths); REGISTER_FUNCTION("GRAPH_PATHS", "GENERAL_GRAPH_PATHS", false, false, "s|s,b,n,n", &OptimisePaths); REGISTER_FUNCTION("SHORTEST_PATH", "GRAPH_SHORTEST_PATH", false, false, "h,h,s,s,s|a", NULL); + REGISTER_FUNCTION("GRAPH_SHORTEST_PATH", "GENERAL_GRAPH_SHORTEST_PATH", false, false, "s,s,s,s|a", NULL); REGISTER_FUNCTION("TRAVERSAL", "GRAPH_TRAVERSAL", false, false, "h,h,s,s|a", NULL); REGISTER_FUNCTION("GRAPH_TRAVERSAL", "GENERAL_GRAPH_TRAVERSAL", false, false, "s,s,s|a", NULL); REGISTER_FUNCTION("TRAVERSAL_TREE", "GRAPH_TRAVERSAL_TREE", false, false, "h,h,s,s,s|a", NULL); @@ -712,6 +713,7 @@ TRI_associative_pointer_t* TRI_CreateFunctionsAql (void) { REGISTER_FUNCTION("EDGES", "GRAPH_EDGES", false, false, "h,s,s|l", NULL); REGISTER_FUNCTION("GRAPH_EDGES", "GENERAL_GRAPH_EDGES", false, false, "s,s,s|lza,ls", NULL); REGISTER_FUNCTION("NEIGHBORS", "GRAPH_NEIGHBORS", false, false, "h,h,s,s|l", NULL); + REGISTER_FUNCTION("GRAPH_NEIGHBORS", "GENERAL_GRAPH_NEIGHBORS", false, false, "s,s,s|l", NULL); // date functions REGISTER_FUNCTION("DATE_NOW", "DATE_NOW", false, false, "", NULL); // NOW is non-deterministic diff --git a/js/server/modules/org/arangodb/ahuacatl.js b/js/server/modules/org/arangodb/ahuacatl.js index 869bfb06e7..b977499f72 100644 --- a/js/server/modules/org/arangodb/ahuacatl.js +++ b/js/server/modules/org/arangodb/ahuacatl.js @@ -4495,7 +4495,46 @@ function GRAPH_SHORTEST_PATH (vertexCollection, direction, params); } - + +//////////////////////////////////////////////////////////////////////////////// +/// @brief shortest path algorithm +//////////////////////////////////////////////////////////////////////////////// + +function GENERAL_GRAPH_SHORTEST_PATH (graphName, + startVertex, + endVertex, + direction, + params) { + "use strict"; + + if (params === undefined) { + params = { }; + } + + params.strategy = "dijkstra"; + params.itemorder = "forward"; + params.visitor = TRAVERSAL_VISITOR; + + if (typeof params.distance === "string") { + var name = params.distance.toUpperCase(); + + params.distance = function (config, vertex1, vertex2, edge) { + return FCALL_USER(name, [ config, vertex1, vertex2, edge ]); + }; + } + else { + params.distance = undefined; + } + + return TRAVERSAL_FUNC("SHORTEST_PATH", + TRAVERSAL.generalGraphDatasourceFactory(graphName), + TO_ID(startVertex), + TO_ID(endVertex), + direction, + params); +} + + //////////////////////////////////////////////////////////////////////////////// /// @brief traverse a graph //////////////////////////////////////////////////////////////////////////////// @@ -4785,7 +4824,54 @@ function GRAPH_NEIGHBORS (vertexCollection, }); return result; -} +} + + +//////////////////////////////////////////////////////////////////////////////// +/// @brief return connected neighbors +//////////////////////////////////////////////////////////////////////////////// + +function GENERAL_GRAPH_NEIGHBORS (graphName, + vertex, + direction, + examples) { + "use strict"; + + + var edges = GENERAL_GRAPH_EDGES(graphName, TO_ID(vertex), direction); + var result = [ ]; + + FILTER(edges, examples).forEach (function (e) { + var key; + + if (direction === "inbound") { + key = e._from; + } + else if (direction === "outbound") { + key = e._to; + } + else if (direction === "any") { + key = e._from; + if (key === vertex) { + key = e._to; + } + } + + if (key === vertex) { + // do not return the start vertex itself + return; + } + + try { + result.push({ edge: CLONE(e), vertex: DOCUMENT_HANDLE(key) }); + } + catch (err) { + } + }); + + return result; +} + // ----------------------------------------------------------------------------- // --SECTION-- MODULE EXPORTS @@ -4892,6 +4978,7 @@ exports.GEO_WITHIN = GEO_WITHIN; exports.FULLTEXT = FULLTEXT; exports.GRAPH_PATHS = GRAPH_PATHS; exports.GRAPH_SHORTEST_PATH = GRAPH_SHORTEST_PATH; +exports.GENERAL_GRAPH_SHORTEST_PATH = GENERAL_GRAPH_SHORTEST_PATH; exports.GRAPH_TRAVERSAL = GRAPH_TRAVERSAL; exports.GRAPH_TRAVERSAL_TREE = GRAPH_TRAVERSAL_TREE; exports.GENERAL_GRAPH_TRAVERSAL = GENERAL_GRAPH_TRAVERSAL; @@ -4900,6 +4987,7 @@ exports.GRAPH_EDGES = GRAPH_EDGES; exports.GENERAL_GRAPH_EDGES = GENERAL_GRAPH_EDGES; exports.GENERAL_GRAPH_PATHS = GENERAL_GRAPH_PATHS; exports.GRAPH_NEIGHBORS = GRAPH_NEIGHBORS; +exports.GENERAL_GRAPH_NEIGHBORS = GENERAL_GRAPH_NEIGHBORS; exports.NOT_NULL = NOT_NULL; exports.FIRST_LIST = FIRST_LIST; exports.FIRST_DOCUMENT = FIRST_DOCUMENT; diff --git a/js/server/tests/ahuacatl-general-graph.js b/js/server/tests/ahuacatl-general-graph.js index afcca8d36d..f43f6c8873 100644 --- a/js/server/tests/ahuacatl-general-graph.js +++ b/js/server/tests/ahuacatl-general-graph.js @@ -113,7 +113,7 @@ function ahuacatlQueryGeneralEdgesTestSuite() { }, //////////////////////////////////////////////////////////////////////////////// -/// @brief checks EDGES() +/// @brief checks GRAPH_EDGES() and GRAPH_NEIGHBOURS() //////////////////////////////////////////////////////////////////////////////// testEdgesAny: function () { @@ -128,6 +128,9 @@ function ahuacatlQueryGeneralEdgesTestSuite() { actual = getQueryResults("FOR e IN GRAPH_EDGES('bla3', 'UnitTestsAhuacatlVertex1/v1', 'any' , [{'what' : 'v2->v1'}]) SORT e.what RETURN e.what"); assertEqual(actual, [ "v2->v1" ]); + actual = getQueryResults("FOR e IN GRAPH_NEIGHBORS('bla3', 'UnitTestsAhuacatlVertex1/v1', 'any' , [{'what' : 'v2->v1'}]) SORT e.what RETURN e"); + assertEqual(actual[0].edge.what , "v2->v1"); + assertEqual(actual[0].vertex._key , "v2"); }, //////////////////////////////////////////////////////////////////////////////// @@ -145,6 +148,10 @@ function ahuacatlQueryGeneralEdgesTestSuite() { actual = getQueryResults("FOR e IN GRAPH_EDGES('bla3', 'UnitTestsAhuacatlVertex3/v5', 'inbound' , [{'what' : 'v2->v5'}]) SORT e.what RETURN e.what"); assertEqual(actual, [ "v2->v5" ]); + + actual = getQueryResults("FOR e IN GRAPH_NEIGHBORS('bla3', 'UnitTestsAhuacatlVertex3/v5', 'inbound' , [{'what' : 'v2->v5'}]) SORT e.what RETURN e"); + assertEqual(actual[0].edge.what , "v2->v5"); + assertEqual(actual[0].vertex._key , "v2"); }, @@ -163,6 +170,12 @@ function ahuacatlQueryGeneralEdgesTestSuite() { actual = getQueryResults("FOR e IN GRAPH_EDGES('bla3', 'UnitTestsAhuacatlVertex1/v1', 'outbound' , [{'what' : 'v2->v5'}]) SORT e.what RETURN e.what"); assertEqual(actual, []); + + actual = getQueryResults("FOR e IN GRAPH_NEIGHBORS('bla3', 'UnitTestsAhuacatlVertex1/v1', 'outbound') SORT e.what RETURN e"); + assertEqual(actual[0].edge.what , "v1->v2"); + assertEqual(actual[0].vertex._key , "v2"); + assertEqual(actual[1].edge.what , "v1->v5"); + assertEqual(actual[1].vertex._key , "v5"); }, //////////////////////////////////////////////////////////////////////////////// @@ -353,7 +366,7 @@ function ahuacatlQueryGeneralPathsTestSuite() { //////////////////////////////////////////////////////////////////////////////// -/// @brief test suite for GRAPH_TRAVERSAL() function +/// @brief test suite for GRAPH_TRAVERSAL() and GRAPH_SHORTEST_PATH function //////////////////////////////////////////////////////////////////////////////// function ahuacatlQueryGeneralTraversalTestSuite() { @@ -494,6 +507,23 @@ function ahuacatlQueryGeneralTraversalTestSuite() { assertTrue(middle.connected.length === 1); assertEqual(middle.connected[0]._key, "Fritz"); + }, + + testGRAPH_SHORTEST_PATH: function () { + var actual, result= []; + + actual = getQueryResults("FOR e IN GRAPH_SHORTEST_PATH('werKenntWen', 'UnitTests_Hamburger/Caesar', 'UnitTests_Frankfurter/Emil', 'outbound') RETURN e"); + actual.forEach(function (s) { + result.push(s.vertex._key); + }); + assertEqual(result, [ + "Caesar", + "Berta", + "Gerda", + "Dieter", + "Emil" + ]); + } } }