pacer 1.3.2-java → 1.3.3-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ideas.rb +32 -0
- data/lib/pacer/blueprints/group_vertex.rb +59 -0
- data/lib/pacer/filter/limit_section_filter.rb +57 -0
- data/lib/pacer/filter/loop_filter.rb +60 -14
- data/lib/pacer/loader.rb +3 -2
- data/lib/pacer/route_builder.rb +3 -1
- data/lib/pacer/transform/intersect_sections.rb +83 -0
- data/lib/pacer/transform/join.rb +39 -166
- data/lib/pacer/transform/parallel.rb +17 -0
- data/lib/pacer/version.rb +1 -1
- data/lib/{pacer-1.3.2-standalone.jar → pacer-1.3.3-standalone.jar} +0 -0
- data/pom.xml +1 -1
- data/spec/support/graph_runner.rb +0 -45
- metadata +8 -7
- data/lib/pacer/blueprints/multi_graph.rb +0 -109
- data/lib/pacer/blueprints/ruby_graph.rb +0 -223
- data/spec/pacer/transform/join_spec.rb +0 -139
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7e0a5a234c35970d36d359c87ba463f288153b1
|
4
|
+
data.tar.gz: 8fc9db2381222ca87e44dea2c59b41b8c41cf552
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 188528a64f6d2cb85fa57176ac500e9f9dc68b9859dc9b9fe6853025d5ce2a73812401f696654f8b5f8e5748671594dfd950088a96587a0fa2b15d285e03263d
|
7
|
+
data.tar.gz: 84608cddad663f171a8ad886f2c1f68e65ec33b9bea94a1107ec39301a2816e6fd10f69f49994145c0671effd4379ffc9c7c59819e4fd416c89cc40e65ee189c
|
data/ideas.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
g.v.parallel(threads: 8, in_buffer: 4, out_buffer: 10) { |v| v.out.out.out.out.out }
|
2
|
+
|
3
|
+
# - eagerly consume (1) input and push into a channel
|
4
|
+
# - ChannelCapPipe
|
5
|
+
# - create a cap pipe that does this. The pipe's output is the channel
|
6
|
+
# - source data may be slow. Should probably not use a go block
|
7
|
+
# - 1 thread in a loop
|
8
|
+
# - Control the construction of parallel pipes. Default 2 threads, make
|
9
|
+
# it configurable.
|
10
|
+
# - standard copy split pipe can push the channel to subchannels
|
11
|
+
# - each parallel route pulls from the channel.
|
12
|
+
# - in a go block (waits will not block go thread pool)
|
13
|
+
# - ChannelReaderPipe
|
14
|
+
# - PathChannelReaderPipe
|
15
|
+
# - parallel routes are unmodified
|
16
|
+
# - cap each route - eagerly consume input and push into a channel
|
17
|
+
# - ChannelCapPipe again
|
18
|
+
# -
|
19
|
+
# - like ExhaustMergePipe + GatherPipe
|
20
|
+
# - use alts to read from any of the channels
|
21
|
+
# - ChannelAltsReaderPipe
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
# CCP
|
26
|
+
# CSP (parallelism is 1 thread per pipe being split into)
|
27
|
+
# CRP -> Work ... -> CCP
|
28
|
+
# CRP -> Work ... -> CCP
|
29
|
+
# ...
|
30
|
+
# EMP
|
31
|
+
# GP
|
32
|
+
# CARP
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Pacer
|
2
|
+
# Created without property support, though it could easily be added if it is ever needed.
|
3
|
+
class GroupVertex
|
4
|
+
import com.tinkerpop.blueprints.util.VerticesFromEdgesIterable
|
5
|
+
IN = com.tinkerpop.blueprints.Direction::IN
|
6
|
+
OUT = com.tinkerpop.blueprints.Direction::OUT
|
7
|
+
BOTH = com.tinkerpop.blueprints.Direction::BOTH
|
8
|
+
|
9
|
+
attr_reader :components, :key
|
10
|
+
attr_reader :paths, :wrapper, :graph
|
11
|
+
|
12
|
+
# Initialize it with an empty set to force uniqueness. Non-unique by default.
|
13
|
+
def initialize(key, graph, wrapper, components = nil)
|
14
|
+
@key = key
|
15
|
+
@wrapper = wrapper
|
16
|
+
if components
|
17
|
+
@components = components
|
18
|
+
else
|
19
|
+
@components = []
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_component(vertex)
|
24
|
+
components << vertex
|
25
|
+
end
|
26
|
+
|
27
|
+
include com.tinkerpop.blueprints.Element
|
28
|
+
|
29
|
+
def getId
|
30
|
+
"#{ key }:#{ components.count }"
|
31
|
+
end
|
32
|
+
|
33
|
+
def getPropertyKeys
|
34
|
+
Set[]
|
35
|
+
end
|
36
|
+
|
37
|
+
def getProperty(key)
|
38
|
+
case key
|
39
|
+
when 'components' then components.map { |c| wrapper.new graph, c }
|
40
|
+
when 'key' then key
|
41
|
+
when 'count' then components.count
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
include com.tinkerpop.blueprints.Vertex
|
46
|
+
|
47
|
+
def getRawVertex
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
def getVertices(direction, *labels)
|
52
|
+
VerticesFromEdgesIterable.new self, direction, *labels
|
53
|
+
end
|
54
|
+
|
55
|
+
def getEdges(direction, *labels)
|
56
|
+
Pacer::Pipes::MultiPipe.new components.map { |v| v.getEdges(direction, *labels) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Routes
|
3
|
+
module RouteOperations
|
4
|
+
def limit_section(section = nil, max)
|
5
|
+
chain_route filter: Pacer::Filter::LimitSectionFilter, section_max: max, section: section
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
module Filter
|
11
|
+
module LimitSectionFilter
|
12
|
+
# VisitsSection module provides:
|
13
|
+
# section=
|
14
|
+
# section_visitor
|
15
|
+
include Pacer::Visitors::VisitsSection
|
16
|
+
|
17
|
+
attr_accessor :section_max
|
18
|
+
|
19
|
+
def attach_pipe(end_pipe)
|
20
|
+
pipe = LimitSectionPipe.new(self, section_visitor, section_max)
|
21
|
+
pipe.setStarts end_pipe if end_pipe
|
22
|
+
pipe
|
23
|
+
end
|
24
|
+
|
25
|
+
class LimitSectionPipe < Pacer::Pipes::RubyPipe
|
26
|
+
attr_reader :max, :section, :route
|
27
|
+
attr_accessor :hits
|
28
|
+
|
29
|
+
|
30
|
+
def initialize(route, section, max)
|
31
|
+
super()
|
32
|
+
@hits = 0
|
33
|
+
@max = max
|
34
|
+
@section = section
|
35
|
+
@route = route
|
36
|
+
section.visitor = self if section
|
37
|
+
end
|
38
|
+
|
39
|
+
def processNextStart
|
40
|
+
while hits == max
|
41
|
+
starts.next
|
42
|
+
end
|
43
|
+
self.hits += 1
|
44
|
+
starts.next
|
45
|
+
end
|
46
|
+
|
47
|
+
def after_element
|
48
|
+
self.hits = 0
|
49
|
+
end
|
50
|
+
|
51
|
+
def reset
|
52
|
+
self.hits = 0
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Pacer
|
2
2
|
module Routes
|
3
3
|
module RouteOperations
|
4
|
-
def loop(&block)
|
5
|
-
chain_route :filter => :loop, :looping_route => block
|
4
|
+
def loop(opts = {}, &block)
|
5
|
+
chain_route(opts.merge :filter => :loop, :looping_route => block)
|
6
6
|
end
|
7
7
|
|
8
|
-
def all(&block)
|
9
|
-
loop(&block).while do |e, depth|
|
8
|
+
def all(opts = {}, &block)
|
9
|
+
loop(opts, &block).while do |e, depth|
|
10
10
|
if depth == 0
|
11
11
|
:loop
|
12
12
|
else
|
@@ -60,6 +60,7 @@ module Pacer
|
|
60
60
|
module LoopFilter
|
61
61
|
attr_reader :looping_route
|
62
62
|
attr_accessor :while_description
|
63
|
+
attr_reader :reverse_loop_route, :reverse_emit_route
|
63
64
|
|
64
65
|
def help(section = nil)
|
65
66
|
case section
|
@@ -162,15 +163,42 @@ HELP
|
|
162
163
|
# this could have concurrency problems if multiple instances of the same
|
163
164
|
# route
|
164
165
|
def deepest!
|
165
|
-
@
|
166
|
+
@loop_when_route = @looping_route
|
167
|
+
@reverse_loop_route = false
|
168
|
+
@emit_when_route = @looping_route
|
169
|
+
@reverse_emit_route = true
|
170
|
+
self
|
171
|
+
end
|
172
|
+
|
173
|
+
def loop_when(&block)
|
174
|
+
@loop_when_route = Pacer::Route.block_branch(self, block)
|
175
|
+
@reverse_loop_route = false
|
176
|
+
self
|
177
|
+
end
|
178
|
+
|
179
|
+
def loop_when_not(&block)
|
180
|
+
@loop_when_route = Pacer::Route.block_branch(self, block)
|
181
|
+
@reverse_loop_route = true
|
182
|
+
self
|
183
|
+
end
|
184
|
+
|
185
|
+
def emit_when(&block)
|
186
|
+
@emit_when_route = Pacer::Route.block_branch(self, block)
|
187
|
+
@reverse_emit_route = false
|
188
|
+
self
|
189
|
+
end
|
190
|
+
|
191
|
+
def emit_when_not(&block)
|
192
|
+
@emit_when_route = Pacer::Route.block_branch(self, block)
|
193
|
+
@reverse_emit_route = true
|
166
194
|
self
|
167
195
|
end
|
168
196
|
|
169
197
|
protected
|
170
198
|
|
171
199
|
def attach_pipe(end_pipe)
|
172
|
-
if @
|
173
|
-
control_block =
|
200
|
+
if @loop_when_route or @emit_when_route
|
201
|
+
control_block = route_control_block
|
174
202
|
elsif @control_block
|
175
203
|
control_block = @control_block
|
176
204
|
else
|
@@ -181,19 +209,37 @@ HELP
|
|
181
209
|
pipe
|
182
210
|
end
|
183
211
|
|
184
|
-
def
|
212
|
+
def expandable(route = nil)
|
185
213
|
expando = Pacer::Pipes::ExpandablePipe.new
|
186
214
|
empty = java.util.ArrayList.new
|
187
215
|
expando.setStarts empty.iterator
|
188
|
-
|
216
|
+
if route
|
217
|
+
control_pipe = Pacer::Route.pipeline route
|
218
|
+
else
|
219
|
+
control_pipe = Pacer::Pipes::IdentityPipe.new
|
220
|
+
end
|
189
221
|
control_pipe.setStarts expando
|
222
|
+
[expando, control_pipe]
|
223
|
+
end
|
224
|
+
|
225
|
+
def route_control_block
|
226
|
+
loop_expando, loop_pipe = expandable @loop_when_route
|
227
|
+
emit_expando, emit_pipe = expandable @emit_when_route
|
190
228
|
proc do |el, depth|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
229
|
+
loop_pipe.reset
|
230
|
+
loop_expando.add el.element
|
231
|
+
emit_pipe.reset
|
232
|
+
emit_expando.add el.element
|
233
|
+
if loop_pipe.hasNext ^ reverse_loop_route
|
234
|
+
if emit_pipe.hasNext ^ reverse_emit_route
|
235
|
+
:loop_and_emit
|
236
|
+
else
|
237
|
+
:loop
|
238
|
+
end
|
195
239
|
elsif depth > 0
|
196
|
-
|
240
|
+
if emit_pipe.hasNext ^ reverse_emit_route
|
241
|
+
:emit
|
242
|
+
end
|
197
243
|
end
|
198
244
|
end
|
199
245
|
end
|
data/lib/pacer/loader.rb
CHANGED
@@ -49,8 +49,7 @@ require 'pacer/function_resolver'
|
|
49
49
|
require 'pacer/route'
|
50
50
|
|
51
51
|
require 'pacer/blueprints/tg'
|
52
|
-
require 'pacer/blueprints/
|
53
|
-
require 'pacer/blueprints/multi_graph'
|
52
|
+
require 'pacer/blueprints/group_vertex'
|
54
53
|
|
55
54
|
require 'pacer/blueprints/payload_elements'
|
56
55
|
|
@@ -79,6 +78,7 @@ require 'pacer/filter/loop_filter'
|
|
79
78
|
require 'pacer/filter/block_filter'
|
80
79
|
require 'pacer/filter/object_filter'
|
81
80
|
require 'pacer/filter/random_filter'
|
81
|
+
require 'pacer/filter/limit_section_filter'
|
82
82
|
|
83
83
|
require 'pacer/transform/branch'
|
84
84
|
require 'pacer/transform/cap'
|
@@ -97,6 +97,7 @@ require 'pacer/transform/wrapped_path'
|
|
97
97
|
require 'pacer/transform/scatter'
|
98
98
|
require 'pacer/transform/has_count_cap'
|
99
99
|
require 'pacer/transform/sort_section'
|
100
|
+
require 'pacer/transform/intersect_sections'
|
100
101
|
require 'pacer/transform/payload'
|
101
102
|
require 'pacer/transform/lookup_ids'
|
102
103
|
|
data/lib/pacer/route_builder.rb
CHANGED
@@ -42,6 +42,7 @@ module Pacer
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def type_def(source, args)
|
45
|
+
source = args.fetch(:based_on, source)
|
45
46
|
[
|
46
47
|
type_modules(source, args),
|
47
48
|
function_modules(source, args),
|
@@ -51,6 +52,7 @@ module Pacer
|
|
51
52
|
end
|
52
53
|
|
53
54
|
def configuration(source, args)
|
55
|
+
source = args.fetch(:based_on, source)
|
54
56
|
{
|
55
57
|
element_type: element_type(source, args),
|
56
58
|
graph: graph(source, args),
|
@@ -62,7 +64,7 @@ module Pacer
|
|
62
64
|
|
63
65
|
def arguments(source, args)
|
64
66
|
args.reject do |key, val|
|
65
|
-
Set[:element_type, :wrapper, :extensions, :modules, :graph, :back, :filter, :side_effect, :transform, :visitor].include? key
|
67
|
+
Set[:element_type, :wrapper, :extensions, :modules, :graph, :back, :filter, :side_effect, :transform, :visitor, :based_on].include? key
|
66
68
|
end
|
67
69
|
end
|
68
70
|
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Routes
|
3
|
+
module RouteOperations
|
4
|
+
def intersect_sections(section)
|
5
|
+
chain_route transform: Pacer::Transform::IntersectSections, section: section, operation: :intersection
|
6
|
+
end
|
7
|
+
|
8
|
+
def difference_sections(section)
|
9
|
+
chain_route transform: Pacer::Transform::IntersectSections, section: section, operation: :difference
|
10
|
+
end
|
11
|
+
|
12
|
+
def left_difference_sections(section)
|
13
|
+
chain_route transform: Pacer::Transform::IntersectSections, section: section, operation: :left_difference
|
14
|
+
end
|
15
|
+
|
16
|
+
def right_difference_sections(section)
|
17
|
+
chain_route transform: Pacer::Transform::IntersectSections, section: section, operation: :right_difference
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
module Transform
|
24
|
+
module IntersectSections
|
25
|
+
# VisitsSection module provides:
|
26
|
+
# section=
|
27
|
+
# section_visitor
|
28
|
+
include Pacer::Visitors::VisitsSection
|
29
|
+
|
30
|
+
attr_accessor :operation
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def attach_pipe(end_pipe)
|
35
|
+
pipe = IntersectSectionPipe.new(section_visitor, operation)
|
36
|
+
pipe.setStarts end_pipe if end_pipe
|
37
|
+
pipe
|
38
|
+
end
|
39
|
+
|
40
|
+
class IntersectSectionPipe < Pacer::Pipes::RubyPipe
|
41
|
+
attr_reader :section, :reduce_block
|
42
|
+
attr_accessor :to_emit, :current_set, :all_sets
|
43
|
+
|
44
|
+
def initialize(section, operation)
|
45
|
+
super()
|
46
|
+
@section = section
|
47
|
+
case operation
|
48
|
+
when :difference
|
49
|
+
@reduce_block = proc { |a, b| (a - b) + (b - a) }
|
50
|
+
when :left_difference
|
51
|
+
@reduce_block = proc { |a, b| a - b }
|
52
|
+
when :right_difference
|
53
|
+
@reduce_block = proc { |a, b| b - a }
|
54
|
+
when :intersection
|
55
|
+
@reduce_block = proc { |a, b| a.intersection b }
|
56
|
+
end
|
57
|
+
self.all_sets = []
|
58
|
+
if section
|
59
|
+
section.visitor = self
|
60
|
+
else
|
61
|
+
on_element nil
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def processNextStart
|
66
|
+
unless to_emit
|
67
|
+
while starts.hasNext
|
68
|
+
current_set << starts.next
|
69
|
+
end
|
70
|
+
self.to_emit = all_sets.reduce(&reduce_block).to_a
|
71
|
+
end
|
72
|
+
raise EmptyPipe.instance if to_emit.empty?
|
73
|
+
to_emit.shift
|
74
|
+
end
|
75
|
+
|
76
|
+
def on_element(x)
|
77
|
+
self.current_set = Set[]
|
78
|
+
all_sets << current_set
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/pacer/transform/join.rb
CHANGED
@@ -1,197 +1,70 @@
|
|
1
1
|
module Pacer
|
2
2
|
module Routes
|
3
3
|
module RouteOperations
|
4
|
-
def
|
5
|
-
|
4
|
+
def join(&block)
|
5
|
+
chain_route transform: Pacer::Transform::Join, block: block
|
6
6
|
end
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
:transform => :join,
|
11
|
-
element_type: :vertex,
|
12
|
-
graph: options.fetch(:multi_graph, Pacer::MultiGraph.blank),
|
13
|
-
from_graph: graph
|
14
|
-
}
|
15
|
-
args[:multi_graph] = options[:multi_graph] if options[:multi_graph]
|
16
|
-
route = chain_route(args)
|
17
|
-
route = route.key { |v| v } unless name == :key
|
18
|
-
if block and name == :key
|
19
|
-
route.key &block
|
20
|
-
elsif block
|
21
|
-
route.join(name || :values, &block)
|
22
|
-
else
|
23
|
-
route
|
24
|
-
end
|
8
|
+
def unjoin
|
9
|
+
map { |g| g[:components] }.scatter extensions: extensions, graph: graph, element_type: element_type
|
25
10
|
end
|
26
11
|
end
|
27
12
|
end
|
28
13
|
|
29
|
-
|
30
14
|
module Transform
|
31
15
|
module Join
|
32
|
-
|
33
|
-
import com.tinkerpop.pipes.sideeffect.SideEffectPipe
|
34
|
-
import java.util.ArrayList
|
35
|
-
import java.util.LinkedList
|
16
|
+
attr_reader :key_block, :unique
|
36
17
|
|
37
|
-
|
18
|
+
def block=(block)
|
19
|
+
@key_block = block
|
20
|
+
end
|
38
21
|
|
39
|
-
|
40
|
-
|
22
|
+
def uniq
|
23
|
+
@unique = true
|
24
|
+
self
|
25
|
+
end
|
41
26
|
|
42
|
-
|
43
|
-
super()
|
44
|
-
@from_graph = from_graph
|
45
|
-
@wrapper = Pacer::Wrappers::WrapperSelector.build from_graph
|
46
|
-
@multi_graph = multi_graph || Pacer::MultiGraph.blank
|
47
|
-
@values_pipes = []
|
48
|
-
@current_keys = []
|
49
|
-
@current_values = []
|
50
|
-
end
|
27
|
+
protected
|
51
28
|
|
52
|
-
|
53
|
-
|
54
|
-
|
29
|
+
def attach_pipe(end_pipe)
|
30
|
+
pipe = JoinPipe.new(self, key_block, unique)
|
31
|
+
pipe.setStarts end_pipe if end_pipe
|
32
|
+
pipe
|
33
|
+
end
|
55
34
|
|
56
|
-
|
57
|
-
|
58
|
-
|
35
|
+
class JoinPipe < Pacer::Pipes::RubyPipe
|
36
|
+
attr_reader :block, :groups, :unique
|
37
|
+
attr_accessor:to_emit
|
59
38
|
|
60
|
-
def
|
61
|
-
|
39
|
+
def initialize(back, key_block, unique)
|
40
|
+
super()
|
41
|
+
@unique = unique
|
42
|
+
@block = Pacer::Wrappers::WrappingPipeFunction.new back, key_block
|
62
43
|
end
|
63
44
|
|
64
|
-
protected
|
65
|
-
|
66
45
|
def processNextStart
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
key = current_keys.removeFirst
|
74
|
-
if key
|
75
|
-
combined = multi_graph.vertex(key) || multi_graph.create_vertex(key)
|
76
|
-
else
|
77
|
-
combined = multi_graph.create_vertex
|
78
|
-
end
|
79
|
-
combined.join_on join_on if join_on
|
80
|
-
combined[:key] = key
|
81
|
-
current_values.each do |key, values|
|
82
|
-
combined.element.append_property_array key, values
|
83
|
-
end
|
84
|
-
return combined
|
46
|
+
unless to_emit
|
47
|
+
coll = unique ? Set : Array
|
48
|
+
groups = Hash.new { |h, k| h[k] = Pacer::GroupVertex.new k, block.graph, block.wrapper, coll.new }
|
49
|
+
while starts.hasNext
|
50
|
+
el = starts.next
|
51
|
+
groups[block.call(el)].add_component el
|
85
52
|
end
|
53
|
+
self.to_emit = groups.values
|
86
54
|
end
|
87
|
-
|
88
|
-
|
89
|
-
def get_keys(element)
|
90
|
-
array = LinkedList.new
|
91
|
-
if key_expando
|
92
|
-
array.addAll next_results(key_expando, key_end, element)
|
55
|
+
if to_emit.empty?
|
56
|
+
raise Pacer::Pipes::EmptyPipe.instance
|
93
57
|
else
|
94
|
-
|
95
|
-
end
|
96
|
-
array
|
97
|
-
end
|
98
|
-
|
99
|
-
def get_values(element)
|
100
|
-
values_pipes.map do |name, expando, to_pipe|
|
101
|
-
[name, next_results(expando, to_pipe, element)]
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# doesn't need to be spun out because it's a capped aggregator
|
106
|
-
def next_results(expando, pipe, element)
|
107
|
-
pipe.reset
|
108
|
-
expando.add element, ArrayList.new, nil
|
109
|
-
array = pipe.next
|
110
|
-
array.map do |element|
|
111
|
-
if element.is_a? Pacer::Element
|
112
|
-
wrapper.new from_graph, element
|
113
|
-
else
|
114
|
-
element
|
115
|
-
end
|
58
|
+
to_emit.shift
|
116
59
|
end
|
117
60
|
end
|
118
61
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
agg_pipe = com.tinkerpop.pipes.sideeffect.AggregatePipe.new LinkedList.new
|
124
|
-
cap_pipe = com.tinkerpop.pipes.transform.SideEffectCapPipe.new agg_pipe
|
125
|
-
agg_pipe.setStarts to_pipe
|
126
|
-
cap_pipe.setStarts to_pipe
|
127
|
-
[expando, cap_pipe]
|
62
|
+
def reset
|
63
|
+
super
|
64
|
+
self.loaded = false
|
65
|
+
self.to_emit = nil
|
128
66
|
end
|
129
67
|
end
|
130
|
-
|
131
|
-
include Pacer::Core::SideEffect
|
132
|
-
|
133
|
-
attr_accessor :existing_multi_graph, :key_route, :values_routes, :from_graph
|
134
|
-
attr_writer :join_on
|
135
|
-
|
136
|
-
# FIXME: the pipe changes the graph. This does not fit with the idea of immutable routes.
|
137
|
-
def graph
|
138
|
-
@graph or super
|
139
|
-
end
|
140
|
-
|
141
|
-
def run!
|
142
|
-
super
|
143
|
-
@graph
|
144
|
-
end
|
145
|
-
|
146
|
-
def graph=(g)
|
147
|
-
@graph = g
|
148
|
-
end
|
149
|
-
|
150
|
-
def key(&block)
|
151
|
-
self.key_route = Pacer::Route.block_branch(self, block)
|
152
|
-
self
|
153
|
-
end
|
154
|
-
|
155
|
-
def join(name = nil, &block)
|
156
|
-
self.key_route = nil if name == :key
|
157
|
-
if block
|
158
|
-
values_routes << [(name || :values), Pacer::Route.block_branch(self, block)]
|
159
|
-
else
|
160
|
-
values_routes << [(name || :values), Pacer::Route.block_branch(self, proc { |v| v })]
|
161
|
-
end
|
162
|
-
self
|
163
|
-
end
|
164
|
-
|
165
|
-
def join_on(*keys)
|
166
|
-
@join_on = keys
|
167
|
-
self
|
168
|
-
end
|
169
|
-
|
170
|
-
def multigraph
|
171
|
-
cap.first
|
172
|
-
end
|
173
|
-
|
174
|
-
protected
|
175
|
-
|
176
|
-
def after_initialize
|
177
|
-
@values_routes = []
|
178
|
-
end
|
179
|
-
|
180
|
-
def attach_pipe(end_pipe)
|
181
|
-
pipe = CombinePipe.new(from_graph, existing_multi_graph)
|
182
|
-
self.graph = pipe.multi_graph
|
183
|
-
pipe.setKeyPipe *key_route.send(:build_pipeline) if key_route
|
184
|
-
pipe.join_on = @join_on
|
185
|
-
values_routes.each do |name, route|
|
186
|
-
pipe.addValuesPipe name, *route.send(:build_pipeline)
|
187
|
-
end
|
188
|
-
pipe.setStarts end_pipe if end_pipe
|
189
|
-
pipe
|
190
|
-
end
|
191
|
-
|
192
|
-
def inspect_string
|
193
|
-
"#{ inspect_class_name }(#{ key_route.inspect }: #{ Hash[values_routes].inspect })"
|
194
|
-
end
|
195
68
|
end
|
196
69
|
end
|
197
70
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Routes
|
3
|
+
module RouteOperations
|
4
|
+
def parallel(opts = {}, &block)
|
5
|
+
threads = opts.fetch(:threads, 2)
|
6
|
+
branched = (0..threads).reduce(channel_cap buffer: opts.fetch(:in_buffer, threads)) do |r, n|
|
7
|
+
r.branch do |x|
|
8
|
+
b = block.call x.channel_reader
|
9
|
+
b.channel_cap
|
10
|
+
end
|
11
|
+
end
|
12
|
+
branched.merge_exhaustive.gather.channel_fan_in(buffer: opts.fetch(:out_buffer, threads),
|
13
|
+
based_on: block.call(self))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/pacer/version.rb
CHANGED
Binary file
|
data/pom.xml
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
<!-- NOTE: the following properties are automatically updated based on the values in lib/pacer-neo4j/version.rb -->
|
9
9
|
<properties>
|
10
10
|
<blueprints.version>2.3.0</blueprints.version>
|
11
|
-
<gem.version>1.3.
|
11
|
+
<gem.version>1.3.3</gem.version>
|
12
12
|
<pipes.version>2.3.0</pipes.version>
|
13
13
|
<gremlin.version>2.3.0</gremlin.version>
|
14
14
|
</properties>
|
@@ -45,53 +45,8 @@ class RSpec::GraphRunner
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
module RubyGraph
|
49
|
-
def all(usage_style = :read_write, indices = true, &block)
|
50
|
-
super
|
51
|
-
rg(usage_style, indices, &block)
|
52
|
-
end
|
53
|
-
|
54
|
-
def rg(usage_style = :read_write, indices = true, &block)
|
55
|
-
for_graph('rg', usage_style, indices, false, ruby_graph, ruby_graph2, nil, block)
|
56
|
-
end
|
57
|
-
|
58
|
-
protected
|
59
|
-
|
60
|
-
def ruby_graph
|
61
|
-
Pacer::PacerGraph.new Pacer::SimpleEncoder, proc { Pacer::RubyGraph.new }
|
62
|
-
end
|
63
|
-
|
64
|
-
def ruby_graph2
|
65
|
-
Pacer::PacerGraph.new Pacer::SimpleEncoder, proc { Pacer::RubyGraph.new }
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
module MultiGraph
|
70
|
-
def all(usage_style = :read_write, indices = true, &block)
|
71
|
-
super
|
72
|
-
multigraph(usage_style, indices, &block)
|
73
|
-
end
|
74
|
-
|
75
|
-
def multigraph(usage_style = :read_write, indices = true, &block)
|
76
|
-
for_graph('multigraph', usage_style, indices, false, multi_graph, multi_graph2, nil, block)
|
77
|
-
end
|
78
|
-
|
79
|
-
protected
|
80
|
-
|
81
|
-
def multi_graph
|
82
|
-
Pacer::MultiGraph.blank
|
83
|
-
end
|
84
|
-
|
85
|
-
def multi_graph2
|
86
|
-
Pacer::MultiGraph.blank
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
|
91
48
|
include Stubs
|
92
49
|
include Tg
|
93
|
-
#include RubyGraph
|
94
|
-
#include MultiGraph
|
95
50
|
include Neo4j if defined? Neo4j
|
96
51
|
include Dex if defined? Dex
|
97
52
|
include Orient if defined? Orient
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pacer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.3
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Darrick Wiebe
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-08-
|
11
|
+
date: 2013-08-27 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Pacer defines routes through a graph and then traverses them very quickly.
|
14
14
|
email: darrick@innatesoftware.com
|
@@ -34,10 +34,10 @@ files:
|
|
34
34
|
- bin/yard
|
35
35
|
- bin/yardoc
|
36
36
|
- blog/2012-09-18-pacer-1.0.md
|
37
|
+
- ideas.rb
|
37
38
|
- lib/pacer.rb
|
38
|
-
- lib/pacer/blueprints/
|
39
|
+
- lib/pacer/blueprints/group_vertex.rb
|
39
40
|
- lib/pacer/blueprints/payload_elements.rb
|
40
|
-
- lib/pacer/blueprints/ruby_graph.rb
|
41
41
|
- lib/pacer/blueprints/tg.rb
|
42
42
|
- lib/pacer/core/array_route.rb
|
43
43
|
- lib/pacer/core/graph.rb
|
@@ -58,6 +58,7 @@ files:
|
|
58
58
|
- lib/pacer/filter/empty_filter.rb
|
59
59
|
- lib/pacer/filter/future_filter.rb
|
60
60
|
- lib/pacer/filter/index_filter.rb
|
61
|
+
- lib/pacer/filter/limit_section_filter.rb
|
61
62
|
- lib/pacer/filter/loop_filter.rb
|
62
63
|
- lib/pacer/filter/object_filter.rb
|
63
64
|
- lib/pacer/filter/property_filter.rb
|
@@ -129,10 +130,12 @@ files:
|
|
129
130
|
- lib/pacer/transform/flat_map.rb
|
130
131
|
- lib/pacer/transform/gather.rb
|
131
132
|
- lib/pacer/transform/has_count_cap.rb
|
133
|
+
- lib/pacer/transform/intersect_sections.rb
|
132
134
|
- lib/pacer/transform/join.rb
|
133
135
|
- lib/pacer/transform/lookup_ids.rb
|
134
136
|
- lib/pacer/transform/make_pairs.rb
|
135
137
|
- lib/pacer/transform/map.rb
|
138
|
+
- lib/pacer/transform/parallel.rb
|
136
139
|
- lib/pacer/transform/path.rb
|
137
140
|
- lib/pacer/transform/path_tree.rb
|
138
141
|
- lib/pacer/transform/payload.rb
|
@@ -200,7 +203,6 @@ files:
|
|
200
203
|
- spec/pacer/side_effect/is_unique_spec.rb
|
201
204
|
- spec/pacer/support/array_list_spec.rb
|
202
205
|
- spec/pacer/support/enumerable_spec.rb
|
203
|
-
- spec/pacer/transform/join_spec.rb
|
204
206
|
- spec/pacer/transform/map_spec.rb
|
205
207
|
- spec/pacer/transform/path_spec.rb
|
206
208
|
- spec/pacer/transform/path_tree_spec.rb
|
@@ -218,7 +220,7 @@ files:
|
|
218
220
|
- spec/support/use_transactions.rb
|
219
221
|
- spec/tackle/simple_mixin.rb
|
220
222
|
- spec/tackle/tinkerpop_graph_mixins.rb
|
221
|
-
- lib/pacer-1.3.
|
223
|
+
- lib/pacer-1.3.3-standalone.jar
|
222
224
|
homepage: http://github.com/pangloss/pacer
|
223
225
|
licenses:
|
224
226
|
- MIT
|
@@ -280,7 +282,6 @@ test_files:
|
|
280
282
|
- spec/pacer/side_effect/is_unique_spec.rb
|
281
283
|
- spec/pacer/support/array_list_spec.rb
|
282
284
|
- spec/pacer/support/enumerable_spec.rb
|
283
|
-
- spec/pacer/transform/join_spec.rb
|
284
285
|
- spec/pacer/transform/map_spec.rb
|
285
286
|
- spec/pacer/transform/path_spec.rb
|
286
287
|
- spec/pacer/transform/path_tree_spec.rb
|
@@ -1,109 +0,0 @@
|
|
1
|
-
module Pacer
|
2
|
-
class MultiGraph < RubyGraph
|
3
|
-
def self.blank
|
4
|
-
PacerGraph.new SimpleEncoder, proc { MultiGraph.new }
|
5
|
-
end
|
6
|
-
|
7
|
-
protected
|
8
|
-
|
9
|
-
def vertex_class
|
10
|
-
MultiVertex
|
11
|
-
end
|
12
|
-
|
13
|
-
def edge_class
|
14
|
-
RubyEdge
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
class MultiVertex < RubyVertex
|
20
|
-
import com.tinkerpop.pipes.util.iterators.MultiIterator
|
21
|
-
|
22
|
-
def initialize(*args)
|
23
|
-
super
|
24
|
-
@vertex_keys = Set[]
|
25
|
-
@join_keys = @vertex_keys
|
26
|
-
end
|
27
|
-
|
28
|
-
attr_accessor :vertex_keys, :join_keys
|
29
|
-
|
30
|
-
def join_on(keys)
|
31
|
-
if keys.is_a? Enumerable
|
32
|
-
@join_keys = keys.map { |k| k.to_s }.to_set
|
33
|
-
elsif keys
|
34
|
-
@join_keys = Set[keys.to_s]
|
35
|
-
else
|
36
|
-
@join_keys = Set[]
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def vertices
|
41
|
-
join_keys.flat_map do |key|
|
42
|
-
@properties[key]
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def setProperty(key, value)
|
47
|
-
case value
|
48
|
-
when Pacer::Vertex
|
49
|
-
vertex_keys << key.to_s
|
50
|
-
super
|
51
|
-
when Hash
|
52
|
-
vertex_keys.delete key.to_s
|
53
|
-
super
|
54
|
-
when Enumerable
|
55
|
-
values = value.to_a
|
56
|
-
if values.any? and values.all? { |v| v.is_a? Pacer::Vertex }
|
57
|
-
vertex_keys << key.to_s
|
58
|
-
end
|
59
|
-
super(key, values)
|
60
|
-
else
|
61
|
-
vertex_keys.delete key.to_s
|
62
|
-
super
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def append_property_array(key, value)
|
67
|
-
values = value.to_a
|
68
|
-
existing_values = getProperty(key)
|
69
|
-
if existing_values
|
70
|
-
if vertex_keys.include? key and not values.all? { |v| v.is_a? Pacer::Vertex }
|
71
|
-
vertex_keys.delete key.to_s
|
72
|
-
end
|
73
|
-
raise "Can't append to key #{ key } because it is not an Array" unless existing_values.is_a? Array
|
74
|
-
else
|
75
|
-
existing_values = []
|
76
|
-
setProperty(key, existing_values)
|
77
|
-
vertex_keys << key.to_s if values.all? { |v| v.is_a? Pacer::Vertex }
|
78
|
-
end
|
79
|
-
existing_values.concat values
|
80
|
-
end
|
81
|
-
|
82
|
-
def removeProperty(key)
|
83
|
-
vertex_keys.delete key.to_s
|
84
|
-
super
|
85
|
-
end
|
86
|
-
|
87
|
-
def getEdges(direction, *labels)
|
88
|
-
vs = vertices
|
89
|
-
if vs.any?
|
90
|
-
labels = extract_varargs_strings(labels)
|
91
|
-
p = Pacer::Pipes::IdentityPipe.new
|
92
|
-
p.setStarts(MultiIterator.new super, *vs.map { |v| v.getEdges(direction, *labels).iterator })
|
93
|
-
p
|
94
|
-
else
|
95
|
-
super
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def inspect
|
100
|
-
s = super
|
101
|
-
s[2] = 'M'
|
102
|
-
s
|
103
|
-
end
|
104
|
-
|
105
|
-
def to_s
|
106
|
-
"m[#{ element_id }]"
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
@@ -1,223 +0,0 @@
|
|
1
|
-
module Pacer
|
2
|
-
class RubyGraph
|
3
|
-
import com.tinkerpop.blueprints.Element
|
4
|
-
import com.tinkerpop.blueprints.Graph
|
5
|
-
import com.tinkerpop.blueprints.Features
|
6
|
-
|
7
|
-
include Graph
|
8
|
-
|
9
|
-
FEATURES = Features.new.tap do |features|
|
10
|
-
features.supportsDuplicateEdges = true
|
11
|
-
features.supportsSelfLoops = true
|
12
|
-
features.supportsSerializableObjectProperty = true
|
13
|
-
features.supportsBooleanProperty = true
|
14
|
-
features.supportsDoubleProperty = true
|
15
|
-
features.supportsFloatProperty = true
|
16
|
-
features.supportsIntegerProperty = true
|
17
|
-
features.supportsPrimitiveArrayProperty = true
|
18
|
-
features.supportsUniformListProperty = true
|
19
|
-
features.supportsMixedListProperty = true
|
20
|
-
features.supportsLongProperty = true
|
21
|
-
features.supportsMapProperty = true
|
22
|
-
features.supportsStringProperty = true
|
23
|
-
|
24
|
-
features.ignoresSuppliedIds = false
|
25
|
-
features.isPersistent = false
|
26
|
-
features.isWrapper = false
|
27
|
-
|
28
|
-
features.supportsIndices = false
|
29
|
-
features.supportsKeyIndices = false
|
30
|
-
features.supportsVertexKeyIndex = false
|
31
|
-
features.supportsEdgeKeyIndex = false
|
32
|
-
features.supportsVertexIndex = false
|
33
|
-
features.supportsEdgeIndex = false
|
34
|
-
features.supportsTransactions = false
|
35
|
-
features.supportsVertexIteration = true
|
36
|
-
features.supportsEdgeIteration = true
|
37
|
-
features.supportsEdgeRetrieval = true
|
38
|
-
features.supportsVertexProperties = true
|
39
|
-
features.supportsEdgeProperties = true
|
40
|
-
features.supportsThreadedTransactions = false
|
41
|
-
end
|
42
|
-
|
43
|
-
def initialize
|
44
|
-
clear
|
45
|
-
end
|
46
|
-
|
47
|
-
def addVertex(id)
|
48
|
-
if id
|
49
|
-
v_id = id
|
50
|
-
else
|
51
|
-
v_id = next_id
|
52
|
-
end
|
53
|
-
raise Pacer::ElementExists if @vertices.key? v_id
|
54
|
-
@vertices[v_id] = vertex_class.new self, v_id
|
55
|
-
end
|
56
|
-
|
57
|
-
def getVertex(id)
|
58
|
-
@vertices[id]
|
59
|
-
end
|
60
|
-
|
61
|
-
def removeVertex(vertex)
|
62
|
-
vertex.getEdges(Pacer::Pipes::BOTH).each do |e|
|
63
|
-
removeEdge e
|
64
|
-
end
|
65
|
-
@vertices.delete vertex.element_id
|
66
|
-
end
|
67
|
-
|
68
|
-
def getVertices
|
69
|
-
@vertices.values.to_iterable
|
70
|
-
end
|
71
|
-
|
72
|
-
def addEdge(id, outVertex, inVertex, label)
|
73
|
-
id ||= next_id
|
74
|
-
raise Pacer::ElementExists if @edges.key? id
|
75
|
-
@edges[id] = edge_class.new self, id, outVertex, inVertex, label
|
76
|
-
end
|
77
|
-
|
78
|
-
def getEdge(id)
|
79
|
-
@edges[id]
|
80
|
-
end
|
81
|
-
|
82
|
-
def removeEdge(edge)
|
83
|
-
@edges.delete edge.element_id
|
84
|
-
end
|
85
|
-
|
86
|
-
def getEdges
|
87
|
-
@edges.values.to_iterable
|
88
|
-
end
|
89
|
-
|
90
|
-
def clear
|
91
|
-
@vertices = {}
|
92
|
-
@edges = {}
|
93
|
-
@next_id = 0
|
94
|
-
end
|
95
|
-
|
96
|
-
def shutdown
|
97
|
-
clear
|
98
|
-
end
|
99
|
-
|
100
|
-
def ==(other)
|
101
|
-
other.equal? self
|
102
|
-
end
|
103
|
-
|
104
|
-
def features
|
105
|
-
FEATURES
|
106
|
-
end
|
107
|
-
|
108
|
-
protected
|
109
|
-
|
110
|
-
def vertex_class
|
111
|
-
RubyVertex
|
112
|
-
end
|
113
|
-
|
114
|
-
def edge_class
|
115
|
-
RubyEdge
|
116
|
-
end
|
117
|
-
|
118
|
-
def next_id
|
119
|
-
@next_id += 1
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
class RubyElement
|
124
|
-
include com.tinkerpop.blueprints.Element
|
125
|
-
|
126
|
-
def initialize(raw_graph, element_id)
|
127
|
-
@raw_graph = raw_graph
|
128
|
-
@element_id = element_id
|
129
|
-
@properties = {}
|
130
|
-
end
|
131
|
-
|
132
|
-
def getPropertyKeys
|
133
|
-
@properties.keys.to_hashset
|
134
|
-
end
|
135
|
-
|
136
|
-
def getProperty(key)
|
137
|
-
v = @properties[key.to_s]
|
138
|
-
if v.is_a? String
|
139
|
-
v.dup
|
140
|
-
else
|
141
|
-
v
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
def setProperty(key, value)
|
146
|
-
@properties[key.to_s] = value
|
147
|
-
end
|
148
|
-
|
149
|
-
def removeProperty(key)
|
150
|
-
@properties.delete key.to_s
|
151
|
-
end
|
152
|
-
|
153
|
-
def getId
|
154
|
-
@element_id
|
155
|
-
end
|
156
|
-
|
157
|
-
protected
|
158
|
-
|
159
|
-
attr_reader :raw_graph
|
160
|
-
|
161
|
-
def extract_varargs_strings(labels)
|
162
|
-
if labels.first.is_a? ArrayJavaProxy
|
163
|
-
labels.first.map { |l| l.to_s }
|
164
|
-
else
|
165
|
-
labels
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
|
171
|
-
class RubyVertex < RubyElement
|
172
|
-
include com.tinkerpop.blueprints.Vertex
|
173
|
-
import com.tinkerpop.blueprints.util.VerticesFromEdgesIterable
|
174
|
-
|
175
|
-
def getRawVertex
|
176
|
-
self
|
177
|
-
end
|
178
|
-
|
179
|
-
def getVertices(direction, *labels)
|
180
|
-
VerticesFromEdgesIterable.new self, direction, *labels
|
181
|
-
end
|
182
|
-
|
183
|
-
def getEdges(direction, *labels)
|
184
|
-
labels = extract_varargs_strings(labels)
|
185
|
-
if direction == Pacer::Pipes::BOTH
|
186
|
-
edges = raw_graph.getEdges.select do |e|
|
187
|
-
( (e.getVertex(Pacer::Pipes::IN) == self or e.getVertex(Pacer::Pipes::OUT) == self) and
|
188
|
-
(labels.empty? or labels.include? e.getLabel) )
|
189
|
-
end
|
190
|
-
else
|
191
|
-
edges = raw_graph.getEdges.select { |e| e.getVertex(direction) == self and (labels.empty? or labels.include? e.getLabel) }
|
192
|
-
end
|
193
|
-
Pacer::Pipes::EnumerablePipe.new edges
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
class RubyEdge < RubyElement
|
198
|
-
include com.tinkerpop.blueprints.Edge
|
199
|
-
|
200
|
-
def initialize(raw_graph, id, out_vertex, in_vertex, label)
|
201
|
-
super(raw_graph, id)
|
202
|
-
@out_vertex = out_vertex
|
203
|
-
@in_vertex = in_vertex
|
204
|
-
@label = label.to_s
|
205
|
-
end
|
206
|
-
|
207
|
-
def getRawEdge
|
208
|
-
self
|
209
|
-
end
|
210
|
-
|
211
|
-
def getLabel()
|
212
|
-
@label
|
213
|
-
end
|
214
|
-
|
215
|
-
def getVertex(direction)
|
216
|
-
if direction == Pacer::Pipes::OUT
|
217
|
-
@out_vertex
|
218
|
-
else
|
219
|
-
@in_vertex
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
end
|
@@ -1,139 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
Run.tg :read_only do
|
4
|
-
use_pacer_graphml_data :read_only
|
5
|
-
|
6
|
-
describe Pacer::Transform::Join do
|
7
|
-
context 'with no key or value specified' do
|
8
|
-
subject { graph.v.join }
|
9
|
-
its(:count) { should == 7 }
|
10
|
-
specify 'each element should be a node' do
|
11
|
-
subject.each do |group|
|
12
|
-
group[:key].should be_a Pacer::Vertex
|
13
|
-
group.property_keys.to_a.should == ['key']
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'with key_route only' do
|
19
|
-
subject { graph.v.join(:key) { |r| r[:type] } }
|
20
|
-
|
21
|
-
its(:count) { should == 7 }
|
22
|
-
its(:to_a) { should_not be_empty }
|
23
|
-
specify 'each result should have one value' do
|
24
|
-
subject.each do |group|
|
25
|
-
group[:key].should be_a String
|
26
|
-
group.property_keys.to_a.should == ['key']
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
context 'with key_route and value route' do
|
32
|
-
let(:route) { graph.v.join(:key) { |r| r[:type] }.join }
|
33
|
-
subject { route }
|
34
|
-
|
35
|
-
specify 'each result should reflect an element' do
|
36
|
-
subject.each.zip(graph.v.to_a) do |group, e|
|
37
|
-
group[:key].should == e[:type]
|
38
|
-
group.property_keys.to_set.should == Set['key', 'values']
|
39
|
-
group[:values].last.element_id.should == e.element_id
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context '#multigraph' do
|
44
|
-
subject { route.multigraph }
|
45
|
-
it { should be_a Pacer::PacerGraph }
|
46
|
-
its(:blueprints_graph) { should be_a Pacer::MultiGraph }
|
47
|
-
|
48
|
-
its('v.count') { should == 3 }
|
49
|
-
|
50
|
-
|
51
|
-
context 'person' do
|
52
|
-
subject { route.multigraph.vertex 'person' }
|
53
|
-
it 'should hove 2 values' do
|
54
|
-
subject[:values].length.should == 2
|
55
|
-
end
|
56
|
-
it { subject[:values].should == graph.v(:type => 'person').to_a }
|
57
|
-
end
|
58
|
-
|
59
|
-
context 'project' do
|
60
|
-
subject { route.multigraph.vertex 'project' }
|
61
|
-
it 'should hove 2 values' do
|
62
|
-
subject[:values].length.should == 4
|
63
|
-
end
|
64
|
-
it { subject[:values].should == graph.v(:type => 'project').to_a }
|
65
|
-
end
|
66
|
-
|
67
|
-
context 'reduced to a count' do
|
68
|
-
subject do
|
69
|
-
route.multigraph.v.reduce({}) do |h, v|
|
70
|
-
h[v.element_id] = v[:values].count
|
71
|
-
h
|
72
|
-
end
|
73
|
-
end
|
74
|
-
specify 'it should have a count for values' do
|
75
|
-
subject['project'].should == 4
|
76
|
-
subject['person'].should == 2
|
77
|
-
subject['group'].should == 1
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
context 'reduced to a string' do
|
82
|
-
subject do
|
83
|
-
route.multigraph.v.reduce({}) do |h, v|
|
84
|
-
h[v.element_id] = v[:values].map { |v| v[:name] }.join ', '
|
85
|
-
h
|
86
|
-
end
|
87
|
-
end
|
88
|
-
specify do
|
89
|
-
subject['project'].should == 'blueprints, pipes, pacer, gremlin'
|
90
|
-
subject['person'].should == 'pangloss, okram'
|
91
|
-
subject['group'].should == 'tinkerpop'
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
context 'with a key block that returns a literal value' do
|
98
|
-
subject { graph.v.join { |r| r[:type] }.key { |r| r[:type].length } }
|
99
|
-
its(:count) { should == 7 }
|
100
|
-
specify 'each value should have a numeric key' do
|
101
|
-
subject.each do |v|
|
102
|
-
v[:key].should == v.element_id
|
103
|
-
v[:key].should == v[:values].first.length
|
104
|
-
end
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
context 'with values_maps' do
|
109
|
-
let(:counted_group) do
|
110
|
-
graph.v.join(:count) { |r| r.out_e.counted.cap }.
|
111
|
-
join(:out_e, &:out_e).
|
112
|
-
key { |r| r[:type] }
|
113
|
-
end
|
114
|
-
subject do
|
115
|
-
counted_group.multigraph
|
116
|
-
end
|
117
|
-
its('v.count') { should == 3 }
|
118
|
-
specify { counted_group.count.should == 7 }
|
119
|
-
specify 'combine(:count) should group the counts in a hash' do
|
120
|
-
hash = Hash[subject.v[[:key, :count]].to_a]
|
121
|
-
hash.should == {"project"=>[0, 1, 3, 2], "person"=>[1, 3], "group"=>[4]}
|
122
|
-
end
|
123
|
-
|
124
|
-
specify 'reduce summarizes edge labels for each type' do
|
125
|
-
result = Hash[subject.v.map { |v| [v.element_id, v[:out_e].group_count { |e| e.label }] }.to_a]
|
126
|
-
result.should == {"project" => {"uses" => 5, "modelled_on" => 1},
|
127
|
-
"person" => {"wrote" => 4},
|
128
|
-
"group" => {"projects" => 3, "member" => 1}}
|
129
|
-
end
|
130
|
-
|
131
|
-
its(:blueprints_graph) { should be_a Pacer::MultiGraph }
|
132
|
-
|
133
|
-
specify do
|
134
|
-
counted_group.inspect.should ==
|
135
|
-
"#<GraphV -> V-Join(#<V -> Obj(type) -> decode>: {:count=>#<V -> outE -> Obj-Cap(E-Counted)>, :out_e=>#<V -> outE>})>"
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|