Ответ 1
Извините за поздний ответ, мы были заняты зданием v2.8;) Я предлагаю сделать как можно больше возможностей на стороне базы данных, так как копирование и сериализация/десериализация JSON по сети обычно дорога, поэтому хорошая передача данных как можно меньше.
Прежде всего, я использовал ваш запрос и выполнил его на образце набора данных, который я создал (~ 800 вершин и 800 ребер попали в мой набор данных) В качестве базовой линии я использовал время выполнения вашего запроса, которое в моем случае было ~ 5.0s
Итак, я попытался создать тот же результат, что и в AQL.
Я нашел некоторые улучшения в вашем запросе:
1. GRAPH_NEIGHBORS
немного быстрее, чем GRAPH_EDGES
.
2. Если возможно, избегайте {includeData: true}
, если вам не нужны данные Особенно, если вам нужно /from vertices._id только GRAPH_NEIGHBORS
с {includeData: false}
превосходит GRAPH_EDGES
на порядок.
3. GRAPH_NEIGHBORS дедуплицируется, GRAPH_EDGES нет. Что в вашем случае кажется желательным.
3. Вы можете избавиться от пары подзапросов там.
Итак, вот чистый запрос AQL, который я мог бы придумать:
LET docId = "ExampleDocClass/1234567"
LET edges = GRAPH_EDGES('EdgeClass',docId,{direction:'any',maxDepth:1,includeData:true})
LET verticesTmp = (FOR v IN GRAPH_NEIGHBORS('EdgeClass', docId, {direction: 'any', maxDepth: 1, includeData: true})
RETURN {
vertexData: v,
outEdges: GRAPH_NEIGHBORS('EdgeClass', v, {direction: 'outbound', maxDepth: 1, includeData: false}),
inEdges: GRAPH_NEIGHBORS('EdgeClass', v, {direction: 'inbound', maxDepth: 1, includeData: false})
})
LET vertices = PUSH(verticesTmp, {
vertexData: DOCUMENT(docId),
outEdges: GRAPH_NEIGHBORS('EdgeClass', docId, {direction: 'outbound', maxDepth: 1, includeData: false}),
inEdges: GRAPH_NEIGHBORS('EdgeClass', docId, {direction: 'inbound', maxDepth: 1, includeData: false})
})
RETURN { edges, vertices }
Это дает тот же формат результата, что и ваш запрос, и имеет то преимущество, что каждая вершина, связанная с docId, хранится ровно один раз в вершинах. Также сам docId хранится ровно один раз в вершинах. Не требуется дедупликация на стороне клиента. Но в outEdges/inEdges каждой вершины все связные вершины также ровно один раз, я не знаю, нужно ли вам знать, есть ли несколько ребер между вершинами в этом списке.
Этот запрос использует ~ 0,06 с в моем наборе данных.
Однако, если вы приложите еще больше усилий, вы также можете использовать ручной обход внутри приложения Foxx. Это немного сложнее, но может быть быстрее в вашем случае, поскольку вы выполняете меньше подзапросов. Код для этого может выглядеть следующим образом:
var traversal = require("org/arangodb/graph/traversal");
var result = {
edges: [],
vertices: {}
}
var myVisitor = function (config, result, vertex, path, connected) {
switch (path.edges.length) {
case 0:
if (! result.vertices.hasOwnProperty(vertex._id)) {
// If we visit a vertex, we store it data and prepare out/in
result.vertices[vertex._id] = {
vertexData: vertex,
outEdges: [],
inEdges: []
};
}
// No further action
break;
case 1:
if (! result.vertices.hasOwnProperty(vertex._id)) {
// If we visit a vertex, we store it data and prepare out/in
result.vertices[vertex._id] = {
vertexData: vertex,
outEdges: [],
inEdges: []
};
}
// First Depth, we need EdgeData
var e = path.edges[0];
result.edges.push(e);
// We fill from / to for both vertices
result.vertices[e._from].outEdges.push(e._to);
result.vertices[e._to].inEdges.push(e._from);
break;
case 2:
// Second Depth, we do not need EdgeData
var e = path.edges[1];
// We fill from / to for all vertices that exist
if (result.vertices.hasOwnProperty(e._from)) {
result.vertices[e._from].outEdges.push(e._to);
}
if (result.vertices.hasOwnProperty(e._to)) {
result.vertices[e._to].inEdges.push(e._from);
}
break;
}
};
var config = {
datasource: traversal.generalGraphDatasourceFactory("EdgeClass"),
strategy: "depthfirst",
order: "preorder",
visitor: myVisitor,
expander: traversal.anyExpander,
minDepth: 0,
maxDepth: 2
};
var traverser = new traversal.Traverser(config);
traverser.traverse(result, {_id: "ExampleDocClass/1234567"});
return {
edges: result.edges,
vertices: Object.keys(result.vertices).map(function (key) {
return result.vertices[key];
})
};
Идея этого обхода - это посетить все вершины от начальной вершины до двух краев. Все вершины с глубиной 0 - 1 будут добавлены с данными в объект вершин. Все ребра, исходящие из начальной вершины, будут добавлены с данными в список ребер. Все вершины глубиной 2 будут только устанавливать outEdges/inEdges в результате.
Это имеет то преимущество, что vertices
дедуплицируется. и outEdges/inEdges содержат все связанные вершины несколько раз, если между ними есть несколько ребер.
Этот обход выполняется в моем наборе данных в ~ 0.025 с, поэтому он в два раза быстрее, чем решение AQL.
надеюсь, что это все еще помогает;)