-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPageRank.rb
More file actions
110 lines (93 loc) · 3.74 KB
/
Copy pathPageRank.rb
File metadata and controls
110 lines (93 loc) · 3.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
require 'java'
# Modify this to point to your graphchi jar file
require "../graphchi-java/target/graphchi-java-0.2-jar-with-dependencies.jar"
java_import "java.io.FileInputStream"
java_import "java.util.logging.Logger"
require 'gc'
include GC
# Iteratively computes a pagerank for each vertex by averaging the pageranks
# of in-neighbors pageranks.
# Based on work from: @akyrola
# Written for jRuby by: @ericmichael
class PageRank
include GC::GraphChiProgram
@@logger = GC::ChiLogger.getLogger "pagerank"
class VertexProcessor
def receiveVertexValue(vertexId, token)
return token == nil ? 0.0 : java.lang.Float.parseFloat(token)
end
end
class EdgeProcessor
def receiveEdge(from, to, token)
return token == nil ? 0.0 : java.lang.Float.parseFloat(token)
end
end
# the update function the value that a vertex should
# take at each iteration
def update(vertex, context)
if context.getIteration == 0
# Initialize on first iteration
vertex.setValue(1.0)
else
# On other iterations, set my value to be the weighted
# average of my in-coming neighbors pageranks.
sum = 0.0
vertex.numInEdges.times { |i| sum += vertex.inEdge(i).getValue }
vertex.setValue(0.15 + 0.85 * sum)
end
# Write my value (divided by my out-degree) to my out-edges so neighbors can read it. #/
outValue = vertex.getValue / vertex.numOutEdges
vertex.numOutEdges().times { |i| vertex.outEdge(i).setValue(outValue) }
end
# These are not needed for PageRank but we must define them
def beginIteration(context) end
def endIteration(context) end
def beginInterval(context, interval) end
def endInterval(context, interval) end
def beginSubInterval(context, interval) end
def endSubInterval(context, interval) end
# Initialize the sharder-program.
# @param graphName
# @param numShards
# @return
def self.createSharder(graphName, numShards)
vp = VertexProcessor.new
ep = EdgeProcessor.new
fc = GC::DoubleConverter.new
fc2 = GC::DoubleConverter.new
return GC::FastSharder.new(graphName, numShards.to_i, vp, ep, fc, fc2)
end
def self.run(args)
baseFilename = args[0]
nShards = args[1]
fileType = args.length >= 3 ? args[2] : nil
# Create shards
sharder = createSharder(baseFilename, nShards)
if baseFilename=="pipein" # Allow piping graph in
sharder.shard(System.in, fileType)
else
if !File.exists?(GC::ChiFilenames.getFilenameIntervals(baseFilename, nShards.to_i))
sharder.shard(FileInputStream.new(java.io.File.new(baseFilename)), fileType)
else
@@logger.info("Found shards -- no need to preprocess")
end
end
# Run GraphChi
engine = GC::GraphChiEngine.new(baseFilename, nShards.to_i)
engine.setEdataConverter(GC::DoubleConverter.new)
engine.setVertexDataConverter(GC::DoubleConverter.new)
engine.setModifiesInedges(false) # Important optimization
engine.run(PageRank.new, 4)
@@logger.info("Ready.")
# Output results
i = 1
trans = engine.getVertexIdTranslate()
top20 = GC::Toplist.topListFloat(baseFilename, engine.numVertices(), 20)
top20.each_with_index do |vertexRank, i|
puts "#{i+1}) #{trans.backward(vertexRank.getVertexId())} = #{vertexRank.getValue()}"
end
end
end
# Usage: jruby PageRank.rb graph-name num-shards filetype(edgelist|adjlist)
# For specifying the number of shards, 20-50 million edges/shard is often a good configuration.
PageRank.run(ARGV)