|
| 1 | +CREATE TEMPLATE QUERY GDBMS_ALGO.centrality.betweenness_cent(SET<STRING> v_type_set, SET<STRING> e_type_set, STRING reverse_e_type,INT max_hops = 10, |
| 2 | + INT top_k = 100, BOOL print_results = True, STRING result_attribute = "", |
| 3 | + STRING file_path = "", BOOL display_edges = FALSE) SYNTAX V1 { |
| 4 | + |
| 5 | + /* |
| 6 | + First Author: karimsaraipour |
| 7 | + First Commit Date: Sep 2, 2021 |
| 8 | + |
| 9 | + Recent Author: Boyu Jiang |
| 10 | + Recent Commit Date: Mar 14, 2022 |
| 11 | + |
| 12 | + |
| 13 | + Repository: |
| 14 | + https://github.com/tigergraph/gsql-graph-algorithms/tree/master/algorithms/Centrality |
| 15 | + |
| 16 | + Maturity: |
| 17 | + Production |
| 18 | + |
| 19 | + Description: |
| 20 | + Compute Betweenness Centrality for each VERTEX. |
| 21 | + Use multi-source BFS. |
| 22 | + |
| 23 | + Publications: |
| 24 | + http://www.vldb.org/pvldb/vol8/p449-then.pdf |
| 25 | + |
| 26 | + TigerGraph Documentation: |
| 27 | + https://docs.tigergraph.com/graph-ml/current/centrality-algorithms/betweenness-centrality |
| 28 | + |
| 29 | + Parameters: |
| 30 | + v_type_set: |
| 31 | + vertex types to traverse |
| 32 | + print_results: |
| 33 | + If True, print JSON output |
| 34 | + e_type_set: |
| 35 | + edge types to traverse |
| 36 | + result_attribute: |
| 37 | + INT attribute to store results to |
| 38 | + reverse_e_type: |
| 39 | + reverse edge type in directed graph, in undirected graph set reverse_e_type=e_type_set |
| 40 | + max_hops: |
| 41 | + look only this far from each vertex |
| 42 | + file_path: |
| 43 | + file to write CSV output to |
| 44 | + top_k: |
| 45 | + report only this many top scores |
| 46 | + display_edges: |
| 47 | + If True, output edges for visualization |
| 48 | + */ |
| 49 | + |
| 50 | + TYPEDEF TUPLE<VERTEX Vertex_ID, FLOAT score> Vertex_Score; #tuple to store betweenness centrality score |
| 51 | + HeapAccum<Vertex_Score>(top_k, score DESC) @@top_scores_heap; #heap to store top K score |
| 52 | + SumAccum<INT> @@sum_curr_dist; #current distance |
| 53 | + BitwiseOrAccum @bitwise_or_visit_next; #use bitwise instead of setAccum |
| 54 | + BitwiseOrAccum @bitwise_or_seen; |
| 55 | + BitwiseOrAccum @bitwise_or_visit; |
| 56 | + SumAccum<INT> @@sum_count = 1;#used to set unique ID |
| 57 | + SumAccum<INT> @sum_id; #store the unique ID |
| 58 | + SetAccum<INT> @@batch_set; #used to set unique ID |
| 59 | + MapAccum<INT,INT> @@map; #used to set unique ID |
| 60 | + SetAccum<EDGE> @@edge_set; |
| 61 | + SumAccum<FLOAT> @sum_delta = 0; |
| 62 | + MapAccum<INT,BitwiseOrAccum> @times_map; |
| 63 | + MapAccum<INT,SumAccum<INT>> @sigma_map; |
| 64 | + |
| 65 | + INT empty=0; |
| 66 | + FILE f (file_path); |
| 67 | + INT num_vert; |
| 68 | + INT batch_number; |
| 69 | + |
| 70 | + # Compute betweenness |
| 71 | + all = {v_type_set}; |
| 72 | + num_vert = all.size(); |
| 73 | + batch_number = num_vert/60; |
| 74 | + |
| 75 | + IF batch_number == 0 THEN |
| 76 | + batch_number = 1; |
| 77 | + END; |
| 78 | + |
| 79 | + #Calculate the sum of distance to other vertex for each vertex |
| 80 | + FOREACH i IN RANGE[0, batch_number-1] DO |
| 81 | + Current = SELECT s |
| 82 | + FROM all:s |
| 83 | + WHERE getvid(s)%batch_number == i |
| 84 | + POST-ACCUM |
| 85 | + @@map+=(getvid(s)->0), |
| 86 | + @@batch_set+=getvid(s); |
| 87 | + |
| 88 | + FOREACH ver in @@batch_set DO |
| 89 | + @@map += (ver->@@sum_count); @@sum_count += 1; |
| 90 | + END; #set a unique ID for each vertex, ID from 1-63 |
| 91 | + |
| 92 | + Start = SELECT s |
| 93 | + FROM Current:s |
| 94 | + POST-ACCUM |
| 95 | + s.@sum_id=@@map.get(getvid(s)); |
| 96 | + |
| 97 | + Start = SELECT s |
| 98 | + FROM Current:s |
| 99 | + POST-ACCUM |
| 100 | + s.@bitwise_or_seen = 1<<s.@sum_id, |
| 101 | + s.@bitwise_or_visit = s.@bitwise_or_seen, |
| 102 | + s.@sigma_map += (0->1), |
| 103 | + s.@times_map += (0->s.@bitwise_or_visit); # set initial seen and visit |
| 104 | + |
| 105 | + @@batch_set.clear(); |
| 106 | + @@map.clear(); |
| 107 | + @@sum_count=0; |
| 108 | + |
| 109 | + WHILE (Start.size() > 0) LIMIT max_hops DO |
| 110 | + @@sum_curr_dist+=1; |
| 111 | + |
| 112 | + Start = SELECT t |
| 113 | + FROM Start:s -(reverse_e_type:e)-v_type_set:t |
| 114 | + WHERE s.@bitwise_or_visit&-t.@bitwise_or_seen-1>0 AND s!=t #use -t.@seen-1 to get the trverse of t.@seen |
| 115 | + ACCUM #updatevisitNext |
| 116 | + INT c = s.@bitwise_or_visit&-t.@bitwise_or_seen-1, |
| 117 | + IF c>0 THEN |
| 118 | + t.@bitwise_or_visit_next+=c, |
| 119 | + t.@bitwise_or_seen+=c |
| 120 | + END, |
| 121 | + t.@sigma_map+=(@@sum_curr_dist->s.@sigma_map.get(@@sum_curr_dist-1)) #set sigma based on depth |
| 122 | + POST-ACCUM |
| 123 | + t.@bitwise_or_visit=t.@bitwise_or_visit_next, |
| 124 | + t.@times_map+=(@@sum_curr_dist->t.@bitwise_or_visit), |
| 125 | + t.@bitwise_or_visit_next=0; |
| 126 | + END; |
| 127 | + |
| 128 | + @@sum_curr_dist+=-1; |
| 129 | + |
| 130 | + Start = SELECT s |
| 131 | + FROM all:s |
| 132 | + WHERE s.@sigma_map.get(@@sum_curr_dist)!=0; |
| 133 | + |
| 134 | + WHILE (Start.size()>0) LIMIT max_hops DO |
| 135 | + @@sum_curr_dist+=-1; |
| 136 | + Start = SELECT t |
| 137 | + FROM Start:s -(reverse_e_type:e)- v_type_set:t |
| 138 | + WHERE t.@times_map.get(@@sum_curr_dist)&s.@times_map.get(@@sum_curr_dist+1)!=0 |
| 139 | + ACCUM |
| 140 | + FLOAT currValue=t.@sigma_map.get(@@sum_curr_dist)/(s.@sigma_map.get(@@sum_curr_dist+1)*(1+s.@sum_delta)), |
| 141 | + INT r=t.@times_map.get(@@sum_curr_dist)&s.@times_map.get(@@sum_curr_dist+1), |
| 142 | + INT plus=0, |
| 143 | + WHILE r>0 DO |
| 144 | + r=r&(r-1),plus=plus+1 #count how many 1 in the number, same as setAccum,size() |
| 145 | + END, |
| 146 | + FLOAT value = currValue*plus/2.0, |
| 147 | + t.@sum_delta+=value; |
| 148 | + |
| 149 | + Start = SELECT s |
| 150 | + FROM all:s |
| 151 | + WHERE s.@sigma_map.get(@@sum_curr_dist)!=0; |
| 152 | + END; |
| 153 | + |
| 154 | + @@sum_curr_dist=0; |
| 155 | + Start = SELECT s |
| 156 | + FROM all:s |
| 157 | + POST-ACCUM |
| 158 | + s.@bitwise_or_seen=0, |
| 159 | + s.@bitwise_or_visit=0, |
| 160 | + s.@sigma_map.clear(), |
| 161 | + s.@times_map.clear(); |
| 162 | + END; |
| 163 | + |
| 164 | + #Output |
| 165 | + IF file_path != "" THEN |
| 166 | + f.println("Vertex_ID", "Betweenness"); |
| 167 | + END; |
| 168 | + |
| 169 | + Start = SELECT s |
| 170 | + FROM all:s |
| 171 | + POST-ACCUM |
| 172 | + IF result_attribute != "" THEN |
| 173 | + s.setAttr(result_attribute, s.@sum_delta) |
| 174 | + END, |
| 175 | + |
| 176 | + IF print_results THEN |
| 177 | + @@top_scores_heap += Vertex_Score(s, s.@sum_delta) |
| 178 | + END, |
| 179 | + |
| 180 | + IF file_path != "" THEN |
| 181 | + f.println(s, s.@sum_delta) |
| 182 | + END; |
| 183 | + |
| 184 | + IF print_results THEN |
| 185 | + PRINT @@top_scores_heap AS top_scores; |
| 186 | + |
| 187 | + IF display_edges THEN |
| 188 | + PRINT Start[Start.@sum_delta]; |
| 189 | + |
| 190 | + Start = SELECT s |
| 191 | + FROM Start:s -(e_type_set:e)-:t |
| 192 | + ACCUM |
| 193 | + @@edge_set += e; |
| 194 | + |
| 195 | + PRINT @@edge_set; |
| 196 | + |
| 197 | + END; |
| 198 | + END; |
| 199 | + |
| 200 | +} |
0 commit comments