1
0
Fork 0

(K_)SHORTEST PATHS: Display correct directions in explainer/profiler (#9080)

This commit is contained in:
Markus Pfeiffer 2019-05-29 13:31:10 +00:00 committed by Michael Hackstein
parent de9ef00896
commit 73ac4f194d
3 changed files with 66 additions and 41 deletions

View File

@ -41,10 +41,7 @@ using namespace arangodb::aql;
using namespace arangodb::graph;
using namespace arangodb::traverser;
static TRI_edge_direction_e parseDirection(AstNode const* node) {
TRI_ASSERT(node->isIntValue());
auto dirNum = node->getIntValue();
static TRI_edge_direction_e uint64ToDirection(uint64_t dirNum) {
switch (dirNum) {
case 0:
return TRI_EDGE_ANY;
@ -59,6 +56,13 @@ static TRI_edge_direction_e parseDirection(AstNode const* node) {
}
}
static TRI_edge_direction_e parseDirection(AstNode const* node) {
TRI_ASSERT(node->isIntValue());
auto dirNum = node->getIntValue();
return uint64ToDirection(dirNum);
}
GraphNode::GraphNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase,
AstNode const* direction, AstNode const* graph,
std::unique_ptr<BaseOptions> options)
@ -81,7 +85,7 @@ GraphNode::GraphNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase,
// Direction is already the correct Integer.
// Is not inserted by user but by enum.
TRI_edge_direction_e baseDirection = parseDirection(direction);
_defaultDirection = parseDirection(direction);
std::unordered_map<std::string, TRI_edge_direction_e> seenCollections;
@ -130,7 +134,7 @@ GraphNode::GraphNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase,
dir = parseDirection(col->getMember(0));
col = col->getMember(1);
} else {
dir = baseDirection;
dir = _defaultDirection;
}
std::string eColName = col->getString();
@ -219,7 +223,7 @@ GraphNode::GraphNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase,
if (ServerState::instance()->isRunningInCluster()) {
auto c = ci->getCollection(_vocbase->name(), n);
if (!c->isSmart()) {
addEdgeCollection(n, baseDirection);
addEdgeCollection(n, _defaultDirection);
} else {
std::vector<std::string> names;
if (_isSmart) {
@ -228,11 +232,11 @@ GraphNode::GraphNode(ExecutionPlan* plan, size_t id, TRI_vocbase_t* vocbase,
names = c->realNamesForRead();
}
for (auto const& name : names) {
addEdgeCollection(name, baseDirection);
addEdgeCollection(name, _defaultDirection);
}
}
} else {
addEdgeCollection(n, baseDirection);
addEdgeCollection(n, _defaultDirection);
}
}
@ -263,25 +267,17 @@ GraphNode::GraphNode(ExecutionPlan* plan, arangodb::velocypack::Slice const& bas
_options(nullptr),
_optionsBuilt(false),
_isSmart(false) {
uint64_t dir = arangodb::basics::VelocyPackHelper::stringUInt64(base.get("defaultDirection"));
_defaultDirection = uint64ToDirection(dir);
// Directions
VPackSlice dirList = base.get("directions");
for (auto const& it : VPackArrayIterator(dirList)) {
uint64_t dir = arangodb::basics::VelocyPackHelper::stringUInt64(it);
TRI_edge_direction_e d;
switch (dir) {
case 1:
d = TRI_EDGE_IN;
break;
case 2:
d = TRI_EDGE_OUT;
break;
case 0:
TRI_ASSERT(false);
default:
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_BAD_PARAMETER,
"Invalid direction value");
break;
}
TRI_edge_direction_e d = uint64ToDirection(dir);
// Only TRI_EDGE_IN and TRI_EDGE_OUT allowed here
TRI_ASSERT(d == TRI_EDGE_IN || d == TRI_EDGE_OUT);
_directions.emplace_back(d);
}
@ -418,6 +414,9 @@ void GraphNode::toVelocyPackHelper(VPackBuilder& nodes, unsigned flags) const {
_graphObj->toVelocyPack(nodes);
}
// Default Direction
nodes.add("defaultDirection", VPackValue(_defaultDirection));
// Directions
nodes.add(VPackValue("directions"));
{

View File

@ -163,6 +163,9 @@ class GraphNode : public ExecutionNode {
/// @brief the vertex collection names
std::vector<std::unique_ptr<aql::Collection>> _vertexColls;
/// @brief The default direction given in the query
TRI_edge_direction_e _defaultDirection;
/// @brief The directions edges are followed
std::vector<TRI_edge_direction_e> _directions;

View File

@ -1081,9 +1081,11 @@ function processQuery(query, explain, planIndex) {
};
var label = function (node) {
var rc, v, e, edgeCols;
var rc, v, e, edgeCols, i, d, directions, isLast;
var parts = [];
var types = [];
// index in this array gives the traversal direction
const translate = ['ANY', 'INBOUND', 'OUTBOUND'];
switch (node.type) {
case 'SingletonNode':
return keyword('ROOT');
@ -1144,10 +1146,9 @@ function processQuery(query, explain, planIndex) {
rc += parts.join(', ') + ' ' + keyword('IN') + ' ' +
value(node.minMaxDepth) + ' ' + annotation('/* min..maxPathDepth */') + ' ';
var translate = ['ANY', 'INBOUND', 'OUTBOUND'];
var directions = [], d;
for (var i = 0; i < node.edgeCollections.length; ++i) {
var isLast = (i + 1 === node.edgeCollections.length);
directions = [];
for (i = 0; i < node.edgeCollections.length; ++i) {
isLast = (i + 1 === node.edgeCollections.length);
d = node.directions[i];
if (!isLast && node.edgeCollections[i] === node.edgeCollections[i + 1]) {
// direction ANY is represented by two traversals: an INBOUND and an OUTBOUND traversal
@ -1259,8 +1260,7 @@ function processQuery(query, explain, planIndex) {
if (node.hasOwnProperty('edgeOutVariable')) {
parts.push(variableName(node.edgeOutVariable) + ' ' + annotation('/* edge */'));
}
translate = ['ANY', 'INBOUND', 'OUTBOUND'];
let defaultDirection = node.directions[0];
let defaultDirection = node.defaultDirection;
rc = `${keyword("FOR")} ${parts.join(", ")} ${keyword("IN")} ${keyword(translate[defaultDirection])} ${keyword("SHORTEST_PATH")} `;
if (node.hasOwnProperty('startVertexId')) {
rc += `'${value(node.startVertexId)}'`;
@ -1277,13 +1277,25 @@ function processQuery(query, explain, planIndex) {
rc += ` ${annotation("/* targetnode */")} `;
if (Array.isArray(node.graph)) {
rc += node.graph.map(function (g, index) {
directions = [];
for (i = 0; i < node.edgeCollections.length; ++i) {
isLast = (i + 1 === node.edgeCollections.length);
d = node.directions[i];
if (!isLast && node.edgeCollections[i] === node.edgeCollections[i + 1]) {
// direction ANY is represented by two traversals: an INBOUND and an OUTBOUND traversal
// on the same collection
d = 0; // ANY
++i;
}
directions.push({ collection: node.edgeCollections[i], direction: d });
}
rc += directions.map(function (g, index) {
var tmp = '';
if (node.directions[index] !== defaultDirection) {
tmp += keyword(translate[node.directions[index]]);
if (g.direction !== defaultDirection) {
tmp += keyword(translate[g.direction]);
tmp += ' ';
}
return tmp + collection(g);
return tmp + collection(g.collection);
}).join(', ');
} else {
rc += keyword('GRAPH') + " '" + value(node.graph) + "'";
@ -1319,8 +1331,7 @@ function processQuery(query, explain, planIndex) {
if (node.hasOwnProperty('pathOutVariable')) {
parts.push(variableName(node.pathOutVariable) + ' ' + annotation('/* path */'));
}
translate = ['ANY', 'INBOUND', 'OUTBOUND'];
let defaultDirection = node.directions[0];
let defaultDirection = node.defaultDirection;
rc = `${keyword("FOR")} ${parts.join(", ")} ${keyword("IN")} ${keyword(translate[defaultDirection])} ${keyword("K_SHORTEST_PATHS")} `;
if (node.hasOwnProperty('startVertexId')) {
rc += `'${value(node.startVertexId)}'`;
@ -1337,13 +1348,25 @@ function processQuery(query, explain, planIndex) {
rc += ` ${annotation("/* targetnode */")} `;
if (Array.isArray(node.graph)) {
rc += node.graph.map(function (g, index) {
directions = [];
for (i = 0; i < node.edgeCollections.length; ++i) {
isLast = (i + 1 === node.edgeCollections.length);
d = node.directions[i];
if (!isLast && node.edgeCollections[i] === node.edgeCollections[i + 1]) {
// direction ANY is represented by two traversals: an INBOUND and an OUTBOUND traversal
// on the same collection
d = 0; // ANY
++i;
}
directions.push({ collection: node.edgeCollections[i], direction: d });
}
rc += directions.map(function (g, index) {
var tmp = '';
if (node.directions[index] !== defaultDirection) {
tmp += keyword(translate[node.directions[index]]);
if (g.direction !== defaultDirection) {
tmp += keyword(translate[g.direction]);
tmp += ' ';
}
return tmp + collection(g);
return tmp + collection(g.collection);
}).join(', ');
} else {
rc += keyword('GRAPH') + " '" + value(node.graph) + "'";