Uh oh!
There was an error while loading. Please reload this page.
feat: support betweenness centrality algorithm (#801) - #818
Conversation
97fc5fc to
aa9802aCompare| arr[SIGMA] = 1; | ||
| arr[FORWARDED] = 1; | ||
| Map<String, Object> state = newState(); | ||
| Map<Object, double[]> st = (Map<Object, double[]>) state.get("st"); |
There was a problem hiding this comment.
Thank you for your valuable contribution. I have some suggestions regarding this code and would like to discuss them with you.
Problem: The per-source states st (Map<Object, double[]>) and preds are kept in the vertex state. The current implementation does not release the corresponding entries after a source completes, causing them to accumulate and resulting in uncontrollable O(V^2) memory usage.
Suggestion: When a source's BACKWARD_DONE is set, immediately clear the entry for that source in st and preds (freeing up memory). It's possible to maintain a touched collection to only iterate over the sources actually involved (more efficient), but the minimum fix is to remove it after completion.
Here is a code example for reference; you might find it helpful.
// --- Insert/Replace Front: Safely Read or Initialize State ---
Map<String, Object> state;
if (updatedValues != null && updatedValues.isPresent()) {
state = (Map<String, Object>) updatedValues.get().getField(0, null);
if (state == null) {
state = newState();
}
} else {
/ // The vertex doesn't have a state yet, safely initialize it (so subsequent logic can rely on a non-null state)
state = newState();
}
double bc = 0.0;
if (state.get("bc") != null) {
bc = (Double) state.get("bc");
} final Map<Object, double[]> st = (Map<Object, double[]>) state.get("st");
| boolean childCountFinal = forwarded && arr[RESP_COUNT] >= outDegree; | ||
| if (childCountFinal && arr[RECV_CHILD] >= arr[CHILD_COUNT]) { | ||
| double sigma = arr[SIGMA]; | ||
| double delta = sigma * arr[PENDING_SUM]; |
There was a problem hiding this comment.
Problem: Calculating value = (1.0 + delta) / sigma and delta = sigma * pendingSum lacks protection against sigma == 0 (theoretically, sigma == 0 represents unaccessed data or an abnormal count), leading to division by zero or NaN.
Recommendation: Perform a sigma == 0 check (or sigma < eps) before using sigma for division; in this case, mark the source as complete and skip sending backwardMsg.
| } else if (tag == ACK) { | ||
| double[] arr = st.get(source); | ||
| if (arr != null) { | ||
| arr[CHILD_COUNT]++; |
There was a problem hiding this comment.
Robustness of ACK/NACK and Response Count
Issue: The logic for RESP_COUNT and CHILD_COUNT currently relies on outDegree(outEdges.size()) as the expected number of responses. However, in scenarios with directed graphs, parallel edges, or different edge loading methods, this may not be a strict match, leading to premature or delayed entry into the backward phase.
Recommendation: Record "how many forward messages have been sent to neighbors (actual childCandidates)" instead of directly using outDegree, or determine whether all responses have been received based on the touchedNeighbors set.
kitalkuyo-gita
commented
Jul 24, 2026
Hello @ArmxG, thank you for your valuable contribution! I've been a bit busy lately and just saw your code. I'm leaving some comments for you to review. Please feel free to point out any issues you find unreasonable. |
What this PR does
Adds a built-in Betweenness Centrality graph algorithm (UDGA), as requested in #801. The algorithm computes the betweenness centrality score for every vertex and outputs
(id, betweenness).Approach
This implementation uses a vertex-centric version of Brandes' algorithm with every vertex treated as a source.
sigma) and record predecessor information. ACK/NACK messages allow each vertex to determine when all child responses have been received.delta) from the leaves back to the source, accumulating each vertex's betweenness centrality score.Per-source state is stored in the vertex value, following the same design pattern as
AllSourceShortestPath. The algorithm has O(V·E) time complexity and O(V²) space complexity.Tests
gql_algorithm_betweenness.sqland its expected output, verified against the standard Brandes algorithm.testAlgorithmBetweennessCentralitytoGQLAlgorithmTest.