【发布时间】:2016-07-05 17:32:52
【问题描述】:
我有一个子图,我知道如何到达根顶点。但接下来我需要走一遍。
在我的情况下,具体“遍历子图”意味着我必须走到子图的所有叶子(因为我知道子图就像一棵树),然后返回路径并在每个顶点之间进行一些计算.
我的问题是,如何以最高效的方式实现这一目标?
我可以考虑两种解决方案。
首先,我使用大量 session.executeGraph("g.V().has('id','1')").one() 语句遍历图表,以获取所有单个顶点和边并使用它们进行计算。但是我觉得这种方式效率很低。
或者我使用我可以获得的路径对象
GraphNode node = session.executeGraph("g.V().has('id','1').repeat(outE().subgraph('sg').otherV()).cap('sg').path()").one();
Path path = node.asPath();
我很确定,第二种解决方案是首选,但我不知道如何使用路径对象来遍历图形,因为我唯一能看到的是对象的平面图。
更新 #1
这是示例树的图片。目标,我需要节点 A 的“组合值”。规则非常简单。节点(根除外)具有值。边缘具有权重。我必须总结所有关于权重的值。只要孩子只有一个父母,我就可以接受完整的价值。如果一个孩子有多个父母,我必须考虑权重。在示例树中,B 的组合值为
100 + (500 * 50/60) + 1000 和 A 的组合值为 combined value of B plus value of C (A == 2156.67)。所以,我需要顶点和边的属性来进行计算。
更新 #2
所以,这是我的解决方案。
我已经实现了一个抽象的 Tree 类来进行实际的计算(因为我也有一个模拟实现)。
public abstract class Tree {
// String == item id
protected final Map<String, Item> items = new HashMap<>();
private final String rootItemId;
protected Tree(String rootItemId) {
this.rootItemId = rootItemId;
}
public void accumulateExpenses() {
accumulateExpenses(null, null);
}
private double accumulateExpenses(String itemId, String parentItemId) {
final Item item = itemId == null ? items.get(rootItemId) : items.get(itemId);
final double expense = item.getExpense();
double childExpenses = 0;
for (String childId : item.getChildIds()) {
childExpenses += accumulateExpenses(childId, item.getId());
}
// calculate the percentage in case the item has multiple parents
final double percentage = item.getPercentage(parentItemId);
final double accumulatedExpenses = percentage * (expense + childExpenses);
item.setAccumulatedExpense(accumulatedExpenses);
return accumulatedExpenses;
}
}
并且我已经实现了一个 GraphTree 类,它负责填充超类(抽象树)的项目图。
public class GraphTree extends Tree {
public GraphTree(GraphNode graphNode, String rootNodeId) {
super(rootNodeId);
final GraphNode vertices = graphNode.get("vertices");
final GraphNode edges = graphNode.get("edges");
for (int i = 0; i < vertices.size(); i++) {
final Vertex vertex = vertices.get(i).asVertex();
final Item item = Item.fromVertex(vertex);
super.items.put(item.getId(), item);
}
for (int i = 0; i < edges.size(); i++) {
final Edge edge = edges.get(i).asEdge();
final Relation relation = Relation.fromEdge(edge);
super.items.get(relation.getParentId()).getRelations().add(relation);
}
}
}
为了完整起见,这里也是Item类。
public class Item {
private String id;
private double accumulatedExpense;
private final List<Relation> relations = new ArrayList<>();
private final Map<String, Expense> expenses = new HashMap<>();
public void setAccumulatedExpense(double accumulatedExpense) {
this.accumulatedExpense = accumulatedExpense;
}
public double getPercentage(String parentId) {
if (parentId == null) {
return 1;
}
double totalWeight = 1;
double weight = 1;
for (Relation relation : relations) {
if (Objects.equals(id, relation.getChildId())) {
totalWeight += relation.getWeight();
if (Objects.equals(parentId, relation.getParentId())) {
weight = relation.getWeight();
}
}
}
return weight / totalWeight;
}
public static Item fromVertex(Vertex vertex) {
final Item item = new Item();
item.setId(IdGenerator.generate(vertex));
return item;
}
public List<String> getChildIds() {
return relations.parallelStream()
.filter(relation -> Objects.equals(relation.getParentId(),id))
.map(Relation::getChildId)
.collect(Collectors.toList());
}
}
为了获得初始子图,我使用了以下代码。
final String statement = String.format("g.V('%s').repeat(outE().subgraph('sg').otherV()).cap('sg')", rootNodeId);
final GraphNode node = session.executeGraph(statement).one();
【问题讨论】:
-
您是否考虑过进行广度优先搜索? This 展示了一种非常漂亮的方法。将 gremlin 查询传递到 DSE 图中很简单。
-
谢谢@Fido。但我遇到的问题不是如何获取图形(第二个查询可以正常工作),而是如何与 Java 驱动程序一起使用。因为我得到的是一个
GraphNode,它有一个包含所有顶点和边的平面Map。所以我失去了顶点之间的所有重要关系。我所期望的是node.getOutEdges().forEach(edge -> edge.getInVertices())之类的东西。所以我的主要问题是如何正确使用 Java 驱动程序。我对 gremlin 很陌生,但我想我到目前为止理解它,但我无法按预期将它转移到 Java。 -
您要寻找的最终结果是什么?听起来您甚至不需要路径,而只需要您将要积累的某些属性。
-
@DanielKuppitz:我已经更新了我的问题。我希望现在更清楚我必须完成的工作。但也许你是对的,我可以用一个复杂的 gremlin 语句来实现。在那种情况下,我必须了解更多关于我担心的 gremlin :)
-
谢谢,更新更清楚了。不过还有一个问题:在结果中,您只期望 B 及其值 1516.67。不包括 C,因为它没有子节点,不包括其他节点,因为它们不是 A 的直接子节点。我的假设是否正确?
标签: java datastax-enterprise gremlin datastax-java-driver