簡體   English   中英

帶有 Java 驅動程序的 DSE Graph,如何遍歷圖形(像樹一樣)

[英]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 對象。

更新#1

這是示例樹的圖片。 目標,我需要節點 A 的“組合值”。規則非常簡單。 節點(根除外)具有值。 邊緣具有權重。 我必須總結所有關於權重的值。 只要孩子只有一個父母,我就可以接受完整的價值。 如果一個孩子有多個父母,我必須考慮權重。 在示例樹中, B的組合值將是100 + (500 * 50/60) + 1000A的組合值將是combined value of B plus value of CA == 2156.67)。 所以,我需要頂點和邊的屬性來進行計算。

更新#2

所以,這是我的解決方案。

我已經實現了一個抽象 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM