[英]DSE Graph with Java Driver, how to walk through a graph (like a tree)
我有一個子圖,我知道如何到達根頂點。 但后來我需要走過它。
具體而言,“遍歷子圖”意味着我必須走到子圖的所有葉子(因為我知道子圖就像一棵樹),然后 go 返回路徑並在每個頂點之間進行一些計算。
我的問題是,如何以最高效的方式實現這一目標?
我可以考慮兩種解決方案。
首先,我使用大量的session.executeGraph("gV().has('id','1')").one()
語句遍歷圖表以獲取所有單個頂點和邊並使用它們進行計算. 但我認為這種方式非常低效。
或者我使用可以使用的路徑 object
GraphNode node = session.executeGraph("g.V().has('id','1').repeat(outE().subgraph('sg').otherV()).cap('sg').path()").one();
Path path = node.asPath();
我很確定,第二種解決方案是首選,但我不知道如何使用路徑 object 來遍歷圖表,因為我唯一能看到的是一個平坦的 map 對象。
這是示例樹的圖片。 目標,我需要節點 A 的“組合值”。規則非常簡單。 節點(根除外)具有值。 邊緣具有權重。 我必須總結所有關於權重的值。 只要孩子只有一個父母,我就可以接受完整的價值。 如果一個孩子有多個父母,我必須考慮權重。 在示例樹中, B的組合值將是100 + (500 * 50/60) + 1000
, A的組合值將是combined value of B plus value of C
( A == 2156.67)。 所以,我需要頂點和邊的屬性來進行計算。
所以,這是我的解決方案。
我已經實現了一個抽象 Tree class 來進行實際計算(因為我也有一個模擬實現)。
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 class 負責填充超級 class(抽象樹)的項目 map。
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);
}
}
}
為了完整起見,這里也是項目 class。
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();
即使一遍又一遍地閱讀評論,當我嘗試使用單個查詢找到解決方案時,我仍然對邏輯感到困惑。 因此,最好只告訴您如何獲得樹表示:
g.V().has('id','1').repeat(outE().as("e").inV()).emit(__.not(outE())).tree()
如果您只需要某些信息(例如頂點的value
屬性和邊的weight
屬性),您可以這樣做:
g.V().has('id','1').
repeat(outE().as("e").inV()).emit(__.not(outE())).
tree().by("value").by("weight")
由於頂點A
似乎沒有value
屬性,因此您需要添加一個coalesce
步驟:
g.V().has('id','1').
repeat(outE().as("e").inV()).emit(__.not(outE())).
tree().by(coalesce(values("value"), constant(0))).by("weight")
更新
如果我稍后需要再次使用示例圖,這里是創建它的代碼:
g = TinkerGraph.open().traversal()
g.addV().property(id, "A").as("a").
addV().property(id, "B").property("value", 100).as("b").
addV().property(id, "C").property("value", 200).as("c").
addV().property(id, "D").property("value", 500).as("d").
addV().property(id, "E").property("value", 1000).as("e").
addV().property(id, "Z").property("value", 900).as("z").
addE("link").from("a").to("b").property("weight", 80).
addE("link").from("a").to("c").property("weight", 20).
addE("link").from("b").to("d").property("weight", 50).
addE("link").from("b").to("e").property("weight", 40).
addE("link").from("z").to("d").property("weight", 10).iterate()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.