mirror of https://gitee.com/bigwinds/arangodb
added AQL function NEIGHBORS
This commit is contained in:
parent
1d98c4b0f0
commit
badf20e47e
|
@ -103,6 +103,12 @@ v1.3.alpha1 (2013-04-05)
|
|||
v1.2.3 (XXXX-XX-XX)
|
||||
-------------------
|
||||
|
||||
* added optional parameter `edgexamples` for AQL function EDGES() and NEIGHBORS()
|
||||
|
||||
* added AQL function NEIGHBORS()
|
||||
|
||||
* added freebsd support
|
||||
|
||||
* fixed firstExample() query with `_id` and `_key` attributes
|
||||
|
||||
* issue triAGENS/ArangoDB-PHP#55: AQL optimiser may have mis-optimised duplicate
|
||||
|
|
|
@ -1007,7 +1007,8 @@ AQL supports the following functions to operate on document values:
|
|||
continue the comparison with the next example until there are no more examples left.
|
||||
|
||||
The @FA{examples} must be a list of 1..n example documents, with any number of attributes
|
||||
each.
|
||||
each. Note: specifying an empty list of examples is not allowed.
|
||||
|
||||
Example usage:
|
||||
|
||||
RETURN MATCHES({ "test" : 1 }, [
|
||||
|
@ -1287,16 +1288,39 @@ If no bounds are set, a traversal might run into an endless loop in a cyclic gra
|
|||
and even in a non-cyclic graph, traversing far into the graph might consume a lot of processing
|
||||
time and memory for the result set.
|
||||
|
||||
- @FN{EDGES(@FA{edgecollection}\, @FA{startvertex}\, @FA{direction})}:
|
||||
- @FN{EDGES(@FA{edgecollection}\, @FA{startvertex}\, @FA{direction}, @FA{edgeexamples})}:
|
||||
return all edges connected to the vertex @FA{startvertex} as a list. The possible values for
|
||||
direction are:
|
||||
@FA{direction} are:
|
||||
- `outbound`: return all outbound edges
|
||||
- `inbound`: return all inbound edges
|
||||
- `any`: return outbound and inbound edges
|
||||
|
||||
The @FA{edgeexamples} parameter can optionally be used to restrict the results to specific
|
||||
edge connections only. The matching is then done via the @LIT{MATCHES} function.
|
||||
To not restrict the result to specific connections, @FA{edgeexamples} should be left
|
||||
unspecified.
|
||||
|
||||
Example calls:
|
||||
|
||||
EDGES(friendrelations, "friends/john", "outbound")
|
||||
EDGES(friendrelations, "friends/john", "any", [ { "$label": "knows" } ])
|
||||
|
||||
- @FN{NEIGHBORS(@FA{vertexcollection}\, @FA{edgecollection}\, @FA{startvertex}\, @FA{direction}, @FA{edgeexamples})}:
|
||||
return all neighbors that are directly connected to the vertex @FA{startvertex} as a list.
|
||||
The possible values for @FA{direction} are:
|
||||
- `outbound`: return all outbound edges
|
||||
- `inbound`: return all inbound edges
|
||||
- `any`: return outbound and inbound edges
|
||||
|
||||
The @FA{edgeexamples} parameter can optionally be used to restrict the results to specific
|
||||
edge connections only. The matching is then done via the @LIT{MATCHES} function.
|
||||
To not restrict the result to specific connections, @FA{edgeexamples} should be left
|
||||
unspecified.
|
||||
|
||||
Example calls:
|
||||
|
||||
EDGES(friendrelations, "friends/john", "outgoing")
|
||||
NEIGHBORS(friends, friendrelations, "friends/john", "outbound")
|
||||
NEIGHBORS(users, usersrelations, "users/john", "any", [ { "$label": "recommends" } ] )
|
||||
|
||||
@subsubsection AqlFunctionsControl Control flow functions
|
||||
|
||||
|
|
|
@ -653,7 +653,8 @@ TRI_associative_pointer_t* TRI_InitialiseFunctionsAql (void) {
|
|||
REGISTER_FUNCTION("PATHS", "GRAPH_PATHS", false, false, "c,h|s,b", &OptimisePaths);
|
||||
REGISTER_FUNCTION("TRAVERSAL", "GRAPH_TRAVERSAL", false, false, "h,h,s,s,a", NULL);
|
||||
REGISTER_FUNCTION("TRAVERSAL_TREE", "GRAPH_TRAVERSAL_TREE", false, false, "h,h,s,s,s,a", NULL);
|
||||
REGISTER_FUNCTION("EDGES", "GRAPH_EDGES", false, false, "h,s,s", NULL);
|
||||
REGISTER_FUNCTION("EDGES", "GRAPH_EDGES", false, false, "h,s,s|l", NULL);
|
||||
REGISTER_FUNCTION("NEIGHBORS", "GRAPH_NEIGHBORS", false, false, "h,h,s,s|l", NULL);
|
||||
|
||||
// misc functions
|
||||
REGISTER_FUNCTION("FAIL", "FAIL", false, false, "|s", NULL); // FAIL is non-deterministic, otherwise query optimisation will fail!
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, continue: true */
|
||||
/*global require, exports, COMPARE_STRING */
|
||||
/*global require, exports, COMPARE_STRING, MATCHES */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Ahuacatl, internal query functions
|
||||
|
@ -79,6 +79,29 @@ var TYPEWEIGHT_DOCUMENT = 16;
|
|||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief filter using a list of examples
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function FILTER (list,
|
||||
examples) {
|
||||
var result = [ ], i;
|
||||
|
||||
if (examples === undefined || examples === null) {
|
||||
return list;
|
||||
}
|
||||
|
||||
for (i = 0; i < list.length; ++i) {
|
||||
var element = list[i];
|
||||
|
||||
if (MATCHES(element, examples, false)) {
|
||||
result.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief throw a runtime exception
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2803,6 +2826,7 @@ function MATCHES (element, examples, returnIndex) {
|
|||
if (! Array.isArray(examples)) {
|
||||
examples = [ examples ];
|
||||
}
|
||||
|
||||
if (examples.length === 0) {
|
||||
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "MATCHES");
|
||||
}
|
||||
|
@ -3258,7 +3282,8 @@ function GRAPH_TRAVERSAL_TREE (vertexCollection,
|
|||
|
||||
function GRAPH_EDGES (edgeCollection,
|
||||
vertex,
|
||||
direction) {
|
||||
direction,
|
||||
examples) {
|
||||
var c = COLLECTION(edgeCollection), result;
|
||||
|
||||
// validate arguments
|
||||
|
@ -3275,6 +3300,55 @@ function GRAPH_EDGES (edgeCollection,
|
|||
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "EDGES");
|
||||
}
|
||||
|
||||
return FILTER(result, examples);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return connected neighbors
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function GRAPH_NEIGHBORS (vertexCollection,
|
||||
edgeCollection,
|
||||
vertex,
|
||||
direction,
|
||||
examples) {
|
||||
var c = COLLECTION(vertexCollection);
|
||||
|
||||
if (vertex.indexOf('/') === -1) {
|
||||
vertex = vertexCollection + '/' + vertex;
|
||||
}
|
||||
|
||||
var edges = GRAPH_EDGES(edgeCollection, 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: c.document(key) });
|
||||
}
|
||||
catch (err) {
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -3446,6 +3520,7 @@ exports.GRAPH_PATHS = GRAPH_PATHS;
|
|||
exports.GRAPH_TRAVERSAL = GRAPH_TRAVERSAL;
|
||||
exports.GRAPH_TRAVERSAL_TREE = GRAPH_TRAVERSAL_TREE;
|
||||
exports.GRAPH_EDGES = GRAPH_EDGES;
|
||||
exports.GRAPH_NEIGHBORS = GRAPH_NEIGHBORS;
|
||||
exports.NOT_NULL = NOT_NULL;
|
||||
exports.FIRST_LIST = FIRST_LIST;
|
||||
exports.FIRST_DOCUMENT = FIRST_DOCUMENT;
|
||||
|
|
|
@ -206,6 +206,72 @@ function ahuacatlQueryEdgesTestSuite () {
|
|||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks NEIGHBORS()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testNeighborsAny : function () {
|
||||
var actual;
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v1', 'any') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]", true);
|
||||
assertEqual(actual, [ [ "v2", "v1->v2" ], [ "v3", "v1->v3" ] ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v2', 'any') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]", true);
|
||||
assertEqual(actual, [ [ "v1", "v1->v2" ], [ "v3", "v2->v3" ], [ "v4", "v4->v2" ] ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v3', 'any') SORT n.vertex._key, n.edge.what RETURN [ n.vertex._key, n.edge.what ]", true);
|
||||
assertEqual(actual, [ [ "v1", "v1->v3"], [ "v2", "v2->v3" ], [ "v4", "v3->v4" ], [ "v6", "v3->v6" ], [ "v6", "v6->v3"], [ "v7", "v3->v7" ], [ "v7", "v7->v3" ] ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v8', 'any') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v5', 'any') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/thefox', 'any') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
try {
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'thefox/thefox', 'any') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
}
|
||||
catch (err) {
|
||||
assertEqual(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, err.errorNum);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks NEIGHBORS()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testNeighborsIn : function () {
|
||||
var actual;
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v1', 'inbound') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v2', 'inbound') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]", true);
|
||||
assertEqual(actual, [ [ "v1", "v1->v2" ], [ "v4", "v4->v2" ] ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v3', 'inbound') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]", true);
|
||||
assertEqual(actual, [ [ "v1", "v1->v3"], [ "v2", "v2->v3" ], [ "v6", "v6->v3"], [ "v7", "v7->v3" ] ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v8', 'inbound') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v5', 'inbound') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/thefox', 'inbound') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
try {
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'thefox/thefox', 'inbound') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
}
|
||||
catch (err) {
|
||||
assertEqual(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, err.errorNum);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks EDGES()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -222,9 +288,6 @@ function ahuacatlQueryEdgesTestSuite () {
|
|||
actual = getQueryResults("FOR e IN EDGES(UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v3', 'outbound') SORT e.what RETURN e.what", true);
|
||||
assertEqual(actual, [ "v3->v4", "v3->v6", "v3->v7" ]);
|
||||
|
||||
actual = getQueryResults("FOR e IN EDGES(UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v3', 'outbound') SORT e.what RETURN e.what", true);
|
||||
assertEqual(actual, [ "v3->v4", "v3->v6", "v3->v7" ]);
|
||||
|
||||
actual = getQueryResults("FOR e IN EDGES(UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v8', 'outbound') SORT e.what RETURN e.what", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
|
@ -240,6 +303,39 @@ function ahuacatlQueryEdgesTestSuite () {
|
|||
catch (err) {
|
||||
assertEqual(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, err.errorNum);
|
||||
}
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks NEIGHBORS()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testNeighborsOut : function () {
|
||||
var actual;
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v1', 'outbound') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]", true);
|
||||
assertEqual(actual, [ [ "v2", "v1->v2" ], [ "v3", "v1->v3" ] ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v2', 'outbound') SORT n.vertex._key RETURN [ n.vertex._key, n.edge.what ]", true);
|
||||
assertEqual(actual, [ [ "v3", "v2->v3" ] ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v3', 'outbound') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
assertEqual(actual, [ "v4", "v6", "v7" ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v8', 'outbound') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/v5', 'outbound') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'UnitTestsAhuacatlVertex/thefox', 'outbound') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
assertEqual(actual, [ ]);
|
||||
|
||||
try {
|
||||
actual = getQueryResults("FOR n IN NEIGHBORS(UnitTestsAhuacatlVertex, UnitTestsAhuacatlEdge, 'thefox/thefox', 'outbound') SORT n.vertex._key RETURN n.vertex._key", true);
|
||||
}
|
||||
catch (err) {
|
||||
assertEqual(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, err.errorNum);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue