pacer-neo4j 2.0.1-java → 2.1.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/{pacer-neo4j-2.0.1-standalone.jar → pacer-neo4j-2.1.0-standalone.jar} +0 -0
- data/lib/pacer-neo4j.rb +74 -0
- data/lib/pacer-neo4j/algo.rb +406 -0
- data/lib/pacer-neo4j/algo/block_cost_evaluator.rb +38 -0
- data/lib/pacer-neo4j/algo/block_estimate_evaluator.rb +32 -0
- data/lib/pacer-neo4j/algo/block_path_expander.rb +61 -0
- data/lib/pacer-neo4j/algo/path_pipe.rb +79 -0
- data/lib/pacer-neo4j/algo/path_wrapper.rb +152 -0
- data/lib/pacer-neo4j/algo/traversal_branch_wrapper.rb +47 -0
- data/lib/pacer-neo4j/graph.rb +72 -40
- data/lib/pacer-neo4j/lucene_filter.rb +112 -0
- data/lib/pacer-neo4j/raw_vertex_wrapping_pipe.rb +18 -0
- data/lib/pacer-neo4j/version.rb +1 -1
- data/pom.xml +6 -1
- metadata +12 -3
Binary file
|
data/lib/pacer-neo4j.rb
CHANGED
@@ -8,3 +8,77 @@ require 'pacer-neo4j/version'
|
|
8
8
|
require Pacer::Neo4j::JAR
|
9
9
|
|
10
10
|
require 'pacer-neo4j/graph'
|
11
|
+
require 'pacer-neo4j/algo/path_pipe'
|
12
|
+
require 'pacer-neo4j/algo/block_cost_evaluator'
|
13
|
+
require 'pacer-neo4j/algo/block_estimate_evaluator'
|
14
|
+
require 'pacer-neo4j/algo/block_path_expander'
|
15
|
+
require 'pacer-neo4j/algo/path_wrapper'
|
16
|
+
require 'pacer-neo4j/algo/traversal_branch_wrapper'
|
17
|
+
require 'pacer-neo4j/algo'
|
18
|
+
require 'pacer-neo4j/raw_vertex_wrapping_pipe'
|
19
|
+
require 'pacer-neo4j/lucene_filter'
|
20
|
+
|
21
|
+
Pacer::FunctionResolver.clear_cache
|
22
|
+
|
23
|
+
module Pacer
|
24
|
+
# Add 'static methods' to the Pacer namespace.
|
25
|
+
class << self
|
26
|
+
# Return a graph for the given path. Will create a graph if none exists at
|
27
|
+
# that location. (The graph is only created if data is actually added to it).
|
28
|
+
#
|
29
|
+
# If the graph is opened from a path, it will be registered to be closed by
|
30
|
+
# Ruby's at_exit callback, but if an already open graph is given, it will
|
31
|
+
# not.
|
32
|
+
#
|
33
|
+
# Please note that Pacer turns on Neo4j's checkElementsInTransaction
|
34
|
+
# feature by default. For some sort of performance improvement at
|
35
|
+
# the expense of an odd consistency model within transactions that
|
36
|
+
# require considerable more complexity in client code, you can use
|
37
|
+
# `graph.setCheckElementsInTransaction(false)` to disable the
|
38
|
+
# feature.
|
39
|
+
def neo4j(path_or_graph, args = nil)
|
40
|
+
bp_neo_class = com.tinkerpop.blueprints.impls.neo4j.Neo4jGraph
|
41
|
+
if path_or_graph.is_a? String
|
42
|
+
path = File.expand_path(path_or_graph)
|
43
|
+
open = proc do
|
44
|
+
graph = Pacer.open_graphs[path]
|
45
|
+
unless graph
|
46
|
+
if args
|
47
|
+
graph = bp_neo_class.new(path, args.to_hash_map)
|
48
|
+
else
|
49
|
+
graph = bp_neo_class.new(path)
|
50
|
+
end
|
51
|
+
Pacer.open_graphs[path] = graph
|
52
|
+
graph.setCheckElementsInTransaction true
|
53
|
+
end
|
54
|
+
graph
|
55
|
+
end
|
56
|
+
shutdown = proc do |g|
|
57
|
+
g.blueprints_graph.shutdown
|
58
|
+
Pacer.open_graphs.delete path
|
59
|
+
end
|
60
|
+
Neo4j::Graph.new(Pacer::YamlEncoder, open, shutdown)
|
61
|
+
else
|
62
|
+
# Don't register the new graph so that it won't be automatically closed.
|
63
|
+
Neo4j::Graph.new Pacer::YamlEncoder, proc { bp_neo_class.new(path_or_graph) }
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def neo_batch(path)
|
68
|
+
bp_neo_class = com.tinkerpop.blueprints.impls.neo4jbatch.Neo4jBatchGraph
|
69
|
+
path = File.expand_path(path)
|
70
|
+
open = proc do
|
71
|
+
graph = bp_neo_class.new(path)
|
72
|
+
Pacer.open_graphs[path] = :open_batch_graph
|
73
|
+
graph
|
74
|
+
end
|
75
|
+
shutdown = proc do |g|
|
76
|
+
g.blueprints_graph.shutdown
|
77
|
+
Pacer.open_graphs.delete path
|
78
|
+
end
|
79
|
+
g = PacerGraph.new(Pacer::YamlEncoder, open, shutdown)
|
80
|
+
g.disable_transactions = true
|
81
|
+
g
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,406 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Core::Graph
|
3
|
+
module VerticesRoute
|
4
|
+
def path_to(to_v, opts = {})
|
5
|
+
route = self
|
6
|
+
route = make_pairs(to_v) if to_v.is_a? Enumerable
|
7
|
+
route.chain_route({transform: :path_finder, element_type: :path, max_hits: 1, target: to_v}.merge opts)
|
8
|
+
end
|
9
|
+
|
10
|
+
def paths_to(to_v, opts = {})
|
11
|
+
route = self
|
12
|
+
route = make_pairs(to_v) if to_v.is_a? Enumerable
|
13
|
+
route.chain_route({transform: :path_finder, element_type: :path, target: to_v}.merge opts)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module PathRoute
|
18
|
+
def expand(opts = {})
|
19
|
+
chain_route({transform: :path_finder, element_type: :path}.merge opts)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
module Transform
|
26
|
+
module PathFinder
|
27
|
+
import org.neo4j.graphalgo.CommonEvaluators
|
28
|
+
import org.neo4j.graphalgo.GraphAlgoFactory
|
29
|
+
import org.neo4j.graphdb.Direction
|
30
|
+
import org.neo4j.kernel.Traversal
|
31
|
+
import org.neo4j.graphdb.DynamicRelationshipType
|
32
|
+
include Pacer::Neo4j::Algo
|
33
|
+
|
34
|
+
def after_initialize
|
35
|
+
fail Pacer::ClientError, 'graph must be neo4j' unless graph.vendor == 'neo4j'
|
36
|
+
end
|
37
|
+
|
38
|
+
def help(opt = nil)
|
39
|
+
case opt
|
40
|
+
when nil
|
41
|
+
puts <<HELP
|
42
|
+
Finds paths between pairs of vertices. The algorithm used depends on the
|
43
|
+
options specified. All supported path finding algorithms including in Neo4j 1.8
|
44
|
+
are included, and all of their documented usages are possible.
|
45
|
+
|
46
|
+
USAGE:
|
47
|
+
|
48
|
+
vertices.path_to(targets, options = {})
|
49
|
+
Find the first path from each vertex to each target vertex
|
50
|
+
|
51
|
+
vertices.paths_to(targets, options = {})
|
52
|
+
Find multiple paths from each vertex to each target vertex
|
53
|
+
|
54
|
+
paths.expand(options = {})
|
55
|
+
Find multiple paths from the first vertex in each path to the last vertex
|
56
|
+
in each path.
|
57
|
+
|
58
|
+
All options are optional!
|
59
|
+
|
60
|
+
These methods only work on Neo4j graphs.
|
61
|
+
|
62
|
+
More details:
|
63
|
+
|
64
|
+
help :options for simple path algorithms and other options
|
65
|
+
find_all, cyclical, length, max_depth, max_hits
|
66
|
+
|
67
|
+
help :cost for Dijkstra and aStar
|
68
|
+
cost, cost_property, cost_default
|
69
|
+
|
70
|
+
help :estimate for aStar
|
71
|
+
estimate, estimate_default, lat_property, long_property
|
72
|
+
|
73
|
+
help :expansion customize how any path is expanded
|
74
|
+
in_labels, out_labels, both_labels, expander, forward, reverse
|
75
|
+
|
76
|
+
HELP
|
77
|
+
when :path
|
78
|
+
puts <<HELP
|
79
|
+
Details for path: expander: proc { |path, state| edges }
|
80
|
+
|
81
|
+
#end_v Returns the end vertex of this path.
|
82
|
+
#start_v Returns the start vertex of this path.
|
83
|
+
#length Returns the length of this path.
|
84
|
+
#path Iterates through both the vertices and edges of this path in
|
85
|
+
order.
|
86
|
+
#end_e Returns the last edge in this path.
|
87
|
+
#v Returns all the vertices in this path starting from the start
|
88
|
+
vertex going forward towards the end vertex.
|
89
|
+
#e Returns all the edges in between the vertices which this path
|
90
|
+
consists of.
|
91
|
+
#reverse_v Like #v but reversed.
|
92
|
+
#reverse_e Like #e but reversed.
|
93
|
+
|
94
|
+
The following methods all proxy to the vertex returned by #end_v: and behave
|
95
|
+
exactly like standard Pacer Vertex methods.
|
96
|
+
|
97
|
+
The iterators can be combined with the + operator.
|
98
|
+
|
99
|
+
Fast edge iterators:
|
100
|
+
#out_edges(*args)
|
101
|
+
#in_edges(*args)
|
102
|
+
#both_edges(*args)
|
103
|
+
|
104
|
+
Fast vertex iterators:
|
105
|
+
#out_vertices(*args)
|
106
|
+
#in_vertices(*args)
|
107
|
+
#both_vertices(*args)
|
108
|
+
|
109
|
+
Edge routes:
|
110
|
+
#out_e(*args)
|
111
|
+
#in_e(*args)
|
112
|
+
#both_e(*args)
|
113
|
+
|
114
|
+
Vertex routes:
|
115
|
+
#out(*args)
|
116
|
+
#in(*args)
|
117
|
+
#both(*args)
|
118
|
+
|
119
|
+
HELP
|
120
|
+
when :expansion
|
121
|
+
puts <<HELP
|
122
|
+
Path expansion options:
|
123
|
+
|
124
|
+
By default, all edges will be followed. By specifying expansion rules you can
|
125
|
+
limit which paths are attempted. All algorithms use the same expanders so
|
126
|
+
these options do not effect the algorithm selection.
|
127
|
+
|
128
|
+
in_labels: label | [labels] only follow : in edges : with the given label(s)
|
129
|
+
out_labels: : out edges :
|
130
|
+
both_labels: : edges :
|
131
|
+
These options can be combined.
|
132
|
+
|
133
|
+
Expanders search forward from the start vertex and backwards from the target
|
134
|
+
vertex. Either expander
|
135
|
+
|
136
|
+
expander: Proc | PathExpander Custom rule for forward search
|
137
|
+
If no reverse is specified, will be used for reverse too.
|
138
|
+
forward: synonym for the expander option
|
139
|
+
reverse: Proc | PathExpander Custom rule for the reverse search
|
140
|
+
|
141
|
+
proc { |path, state| edges }:
|
142
|
+
path is a Pacer::Neo4j::Algo::PathWrapper - help(:path) for details
|
143
|
+
The proc must simply return an Enumerable of edges that the
|
144
|
+
|
145
|
+
HELP
|
146
|
+
when :options
|
147
|
+
puts <<HELP
|
148
|
+
Simple options:
|
149
|
+
|
150
|
+
find_all: Boolean Find all non-cyclical paths.
|
151
|
+
Algorithm: allSimplePaths
|
152
|
+
|
153
|
+
cyclical: Boolean Find all paths including cyclical ones.
|
154
|
+
Algorithm: allPaths
|
155
|
+
|
156
|
+
length: Number Number of edges that the path contains.
|
157
|
+
Algorithm: pathsWithLength
|
158
|
+
Returns only paths of the specified length.
|
159
|
+
|
160
|
+
max_depth: Number Number of edges to search in a potential path.
|
161
|
+
Default: 5
|
162
|
+
Limits how many edges will be traversed searching for a path. Higher
|
163
|
+
numbers can take exponentially longer, I think. Does not apply to aStar,
|
164
|
+
Dijkstra, or pathsWithLength algorithms.
|
165
|
+
|
166
|
+
Required for find_all, cyclical, and shortest path algorithms.
|
167
|
+
|
168
|
+
max_hits: Number Maximum number of paths to find for each pair of vertices.
|
169
|
+
#path_to defaults this to 1. All algorithms use this but only
|
170
|
+
some support it natively in Neo4j's implementations.
|
171
|
+
|
172
|
+
|
173
|
+
HELP
|
174
|
+
when :cost
|
175
|
+
puts <<HELP
|
176
|
+
Cost options:
|
177
|
+
|
178
|
+
Specifying these chooses the Dijkstra algorithm unless an estimate is also
|
179
|
+
specified.
|
180
|
+
|
181
|
+
cost: Proc | CostEvaluator Calculate the cost for this edge.
|
182
|
+
Must return a Numeric unless cost_default is set.
|
183
|
+
proc { |edge, direction| Float }:
|
184
|
+
direction is either :in or :out.
|
185
|
+
|
186
|
+
cost_property: String get the cost from the given edge property
|
187
|
+
cost_default: Float default if the property isn't there
|
188
|
+
|
189
|
+
HELP
|
190
|
+
when :estimate
|
191
|
+
puts <<HELP
|
192
|
+
Estimate options
|
193
|
+
Specifying these together with cost chooses the a* / aStar algorithm.
|
194
|
+
|
195
|
+
estimate:
|
196
|
+
Must return a Numeric unless estimate_default is set.
|
197
|
+
proc { |vertex, goal_vertex| Float }
|
198
|
+
|
199
|
+
estimate_default: Float only works with the proc estimate
|
200
|
+
|
201
|
+
lat_property: String latitude property name
|
202
|
+
long_property: String longitude property name
|
203
|
+
Use latitude and longitude if all estimated vertices have the necessary
|
204
|
+
properties.
|
205
|
+
|
206
|
+
HELP
|
207
|
+
else
|
208
|
+
super
|
209
|
+
end
|
210
|
+
description
|
211
|
+
end
|
212
|
+
|
213
|
+
def method
|
214
|
+
if has_cost?
|
215
|
+
if has_estimate?
|
216
|
+
:aStar
|
217
|
+
else
|
218
|
+
:dijkstra
|
219
|
+
end
|
220
|
+
elsif cyclical and max_depth
|
221
|
+
:all
|
222
|
+
elsif find_all and max_depth
|
223
|
+
:all_simple
|
224
|
+
elsif length
|
225
|
+
:with_length
|
226
|
+
elsif max_depth
|
227
|
+
if max_hits
|
228
|
+
:shortest_with_max_hits
|
229
|
+
else
|
230
|
+
:shortest
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
attr_accessor :target
|
236
|
+
|
237
|
+
# specify one or many edge labels that the path may take in the given direction
|
238
|
+
attr_accessor :in_labels, :out_labels, :both_labels
|
239
|
+
|
240
|
+
# note that expander procs *must* return edge(s) that are connected to the end_v of the given path
|
241
|
+
#
|
242
|
+
# expander yields: { |path, state| path.is_a? Pacer::Neo4j::Algo::PathWrapper }
|
243
|
+
attr_accessor :expander, :forward, :reverse
|
244
|
+
|
245
|
+
# use dijkstra unless the below estimate properties are set
|
246
|
+
#
|
247
|
+
# note that cost proc must return a Numeric unless cost_default is set
|
248
|
+
#
|
249
|
+
# cost yields: { |edge, direction| [:in, :out, :both].include? direction }
|
250
|
+
attr_accessor :cost, :cost_property, :cost_default
|
251
|
+
|
252
|
+
def set_cost(property = nil, default = nil, &block)
|
253
|
+
self.cost_property = property
|
254
|
+
self.cost_default = default
|
255
|
+
self.cost = block
|
256
|
+
self
|
257
|
+
end
|
258
|
+
|
259
|
+
# use the aStar algorithm
|
260
|
+
#
|
261
|
+
# note that estimate proc must return a Numeric unless estimate_default is set
|
262
|
+
#
|
263
|
+
# estimate yields: { |vertex, goal_vertex| }
|
264
|
+
attr_accessor :estimate, :lat_property, :long_property, :estimate_default
|
265
|
+
|
266
|
+
def set_estimate(lat = nil, long = nil, &block)
|
267
|
+
self.lat_property = lat
|
268
|
+
self.long_property = long
|
269
|
+
self.estimate = block
|
270
|
+
self
|
271
|
+
end
|
272
|
+
|
273
|
+
# use pathsWithLength
|
274
|
+
#
|
275
|
+
# Return only paths of the given length
|
276
|
+
attr_accessor :length
|
277
|
+
|
278
|
+
# default to shortest_path unless find_all is set
|
279
|
+
attr_writer :max_depth
|
280
|
+
def max_depth
|
281
|
+
@max_depth || 5
|
282
|
+
end
|
283
|
+
|
284
|
+
# use shortestPath
|
285
|
+
attr_accessor :max_hits
|
286
|
+
|
287
|
+
# Possible values:
|
288
|
+
attr_accessor :find_all
|
289
|
+
attr_accessor :cyclical
|
290
|
+
|
291
|
+
protected
|
292
|
+
|
293
|
+
def attach_pipe(end_pipe)
|
294
|
+
if back.element_type == :path
|
295
|
+
p = PathFromPathPipe.new build_algo, graph, max_hits
|
296
|
+
else
|
297
|
+
p = PathPipe.new build_algo, graph, target, max_hits
|
298
|
+
end
|
299
|
+
p.setStarts end_pipe
|
300
|
+
attach_length_filter(p) if length and method != :with_length
|
301
|
+
p
|
302
|
+
end
|
303
|
+
|
304
|
+
def attach_length_filter(end_pipe)
|
305
|
+
pipe = Pacer::Pipes::BlockFilterPipe.new(self, proc { |p| p.length == length }, false)
|
306
|
+
pipe.set_starts end_pipe if end_pipe
|
307
|
+
pipe
|
308
|
+
end
|
309
|
+
|
310
|
+
def inspect_string
|
311
|
+
if back.element_type == :path
|
312
|
+
"expand[#{method}](max_depth: #{ max_depth })"
|
313
|
+
else
|
314
|
+
"paths_to[#{method}](#{ target.inspect }, max_depth: #{ max_depth })"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
private
|
319
|
+
|
320
|
+
def has_cost?
|
321
|
+
cost or cost_property or cost_default
|
322
|
+
end
|
323
|
+
|
324
|
+
def has_estimate?
|
325
|
+
estimate or (lat_property and long_property) or estimate_default
|
326
|
+
end
|
327
|
+
|
328
|
+
def build_algo
|
329
|
+
case method
|
330
|
+
when :aStar
|
331
|
+
GraphAlgoFactory.aStar build_expander, build_cost, build_estimate
|
332
|
+
when :dijkstra
|
333
|
+
GraphAlgoFactory.dijkstra build_expander, build_cost
|
334
|
+
when :with_length
|
335
|
+
GraphAlgoFactory.pathsWithLength build_expander, length
|
336
|
+
when :all
|
337
|
+
GraphAlgoFactory.allPaths build_expander, max_depth
|
338
|
+
when :all_simple
|
339
|
+
GraphAlgoFactory.allSimplePaths build_expander, max_depth
|
340
|
+
when :shortest_with_max_hits
|
341
|
+
GraphAlgoFactory.shortestPath build_expander, max_depth, max_hits
|
342
|
+
when :shortest
|
343
|
+
GraphAlgoFactory.shortestPath build_expander, max_depth
|
344
|
+
when nil
|
345
|
+
fail Pacer::ClientError, "Could not choose a path algorithm"
|
346
|
+
else
|
347
|
+
fail Pacer::LogicError, "Unable to build algo for #{ method }"
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def build_expander
|
352
|
+
if forward.is_a? Proc and reverse.is_a? Proc
|
353
|
+
BlockPathExpander.new forward, reverse, graph, max_depth
|
354
|
+
elsif expander.is_a? Proc
|
355
|
+
BlockPathExpander.new expander, expander, graph, max_depth
|
356
|
+
elsif expander
|
357
|
+
expander
|
358
|
+
else
|
359
|
+
e = Traversal.emptyExpander
|
360
|
+
[*out_labels].each do |label|
|
361
|
+
e.add DynamicRelationshipType.withName(label.to_s), Direction::OUTGOING
|
362
|
+
end
|
363
|
+
[*in_labels].each do |label|
|
364
|
+
e.add DynamicRelationshipType.withName(label.to_s), Direction::INCOMING
|
365
|
+
end
|
366
|
+
[*both_labels].each do |label|
|
367
|
+
e.add DynamicRelationshipType.withName(label.to_s), Direction::BOTH
|
368
|
+
end
|
369
|
+
e
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
def build_cost
|
374
|
+
if cost.is_a? Proc
|
375
|
+
BlockCostEvaluator.new cost, graph, cost_default
|
376
|
+
elsif cost
|
377
|
+
cost
|
378
|
+
elsif cost_property
|
379
|
+
if cost_default
|
380
|
+
CommonEvaluators.doubleCostEvaluator cost_property.to_s, cost_default.to_f
|
381
|
+
else
|
382
|
+
CommonEvaluators.doubleCostEvaluator cost_property.to_s
|
383
|
+
end
|
384
|
+
elsif cost_default
|
385
|
+
CommonEvaluators.doubleCostEvaluator ' not a property ', cost_default.to_f
|
386
|
+
else
|
387
|
+
fail Pacer::LogicError, "could not build cost"
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
def build_estimate
|
392
|
+
if estimate.is_a? Proc
|
393
|
+
BlockEstimateEvaluator.new estimate, graph, estimate_default
|
394
|
+
elsif estimate
|
395
|
+
estimate
|
396
|
+
elsif lat_property and long_property
|
397
|
+
CommonEvaluators.geoEstimateEvaluator lat_property.to_s, long_property.to_s
|
398
|
+
elsif estimate_default
|
399
|
+
BlockEstimateEvaluator.new proc { estimate_default }, graph, estimate_default
|
400
|
+
else
|
401
|
+
fail Pacer::LogicError, "could not build estimate"
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Neo4j
|
3
|
+
module Algo
|
4
|
+
class BlockCostEvaluator
|
5
|
+
import org.neo4j.graphalgo.CostEvaluator
|
6
|
+
import org.neo4j.graphdb.Direction
|
7
|
+
import com.tinkerpop.blueprints.impls.neo4j.Neo4jEdge
|
8
|
+
include CostEvaluator
|
9
|
+
|
10
|
+
DIRS = {
|
11
|
+
Direction::INCOMING => :in,
|
12
|
+
Direction::OUTGOING => :out,
|
13
|
+
Direction::BOTH => :both
|
14
|
+
}
|
15
|
+
|
16
|
+
attr_reader :block, :graph, :default
|
17
|
+
|
18
|
+
def initialize(block, graph, default)
|
19
|
+
@block = block
|
20
|
+
@graph = graph
|
21
|
+
@default = default.to_f
|
22
|
+
end
|
23
|
+
|
24
|
+
def getCost(rel, dir)
|
25
|
+
e = Pacer::Wrappers::EdgeWrapper.new graph, Neo4jEdge.new(rel, graph.blueprints_graph)
|
26
|
+
result = block.call e, DIRS[dir]
|
27
|
+
if result.is_a? Numeric
|
28
|
+
result.to_f
|
29
|
+
elsif default
|
30
|
+
default
|
31
|
+
else
|
32
|
+
fail Pacer::ClientError, "No cost returned and no default specified: #{ result.inspect }"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Neo4j
|
3
|
+
module Algo
|
4
|
+
class BlockEstimateEvaluator
|
5
|
+
import org.neo4j.graphalgo.EstimateEvaluator
|
6
|
+
import com.tinkerpop.blueprints.impls.neo4j.Neo4jVertex
|
7
|
+
include EstimateEvaluator
|
8
|
+
|
9
|
+
attr_reader :block, :graph, :default
|
10
|
+
|
11
|
+
def initialize(block, graph, default)
|
12
|
+
@block = block
|
13
|
+
@graph = graph
|
14
|
+
@default = default.to_f
|
15
|
+
end
|
16
|
+
|
17
|
+
def getCost(node, goal)
|
18
|
+
node = Pacer::Wrappers::VertexWrapper.new graph, Neo4jVertex.new(node, graph.blueprints_graph)
|
19
|
+
goal = Pacer::Wrappers::VertexWrapper.new graph, Neo4jVertex.new(goal, graph.blueprints_graph)
|
20
|
+
result = block.call node, goal
|
21
|
+
if result.is_a? Numeric
|
22
|
+
result.to_f
|
23
|
+
elsif default
|
24
|
+
default
|
25
|
+
else
|
26
|
+
fail Pacer::ClientError, "No estimate returned and no default specified: #{ result.inspect }"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Neo4j
|
3
|
+
module Algo
|
4
|
+
class BlockPathExpander
|
5
|
+
import org.neo4j.graphdb.PathExpander
|
6
|
+
import com.tinkerpop.pipes.Pipe
|
7
|
+
|
8
|
+
include PathExpander
|
9
|
+
attr_reader :block, :rev, :graph, :max_depth
|
10
|
+
|
11
|
+
def initialize(block, rev, graph, max_depth)
|
12
|
+
@block = block
|
13
|
+
@rev = rev
|
14
|
+
@graph = graph
|
15
|
+
@max_depth = max_depth
|
16
|
+
end
|
17
|
+
|
18
|
+
def expand(path, state)
|
19
|
+
path = PathWrapper.new(path, graph)
|
20
|
+
if max_depth and path.length >= max_depth
|
21
|
+
result = []
|
22
|
+
else
|
23
|
+
result = block.call path, state
|
24
|
+
end
|
25
|
+
pipe = Pacer::Pipes::NakedPipe.new
|
26
|
+
pipe.set_starts result_to_enumerable(result)
|
27
|
+
pipe
|
28
|
+
end
|
29
|
+
|
30
|
+
def reverse
|
31
|
+
BlockPathExpander.new rev, block, graph, max_depth
|
32
|
+
end
|
33
|
+
|
34
|
+
def result_to_enumerable(result)
|
35
|
+
case result
|
36
|
+
when PathWrapper
|
37
|
+
fail "Don't just return the arguments in your expander, return edges!"
|
38
|
+
when Pacer::Route
|
39
|
+
if result.element_type == :edge
|
40
|
+
result.pipe.starts
|
41
|
+
else
|
42
|
+
fail "Expander must return edges"
|
43
|
+
end
|
44
|
+
when Pacer::Wrappers::EdgeWrapper
|
45
|
+
Pacer::Pipes::EnumerablePipe.new [result]
|
46
|
+
when Pacer::Pipes::WrappingPipe
|
47
|
+
result.starts
|
48
|
+
when Pipe
|
49
|
+
result
|
50
|
+
when Enumerable
|
51
|
+
Pacer::Pipes::EnumerablePipe.new result
|
52
|
+
when nil
|
53
|
+
Pacer::Pipes::EnumerablePipe.new []
|
54
|
+
else
|
55
|
+
fail "Can't figure out what to do with #{ result.class }"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Neo4j
|
3
|
+
module Algo
|
4
|
+
class PathPipe < Pacer::Pipes::RubyPipe
|
5
|
+
import org.neo4j.graphdb::Node
|
6
|
+
import org.neo4j.graphdb::Relationship
|
7
|
+
import com.tinkerpop.blueprints.impls.neo4j.Neo4jVertex
|
8
|
+
import com.tinkerpop.blueprints.impls.neo4j.Neo4jEdge
|
9
|
+
|
10
|
+
attr_reader :algo, :target, :graph, :max_hits
|
11
|
+
attr_accessor :current_paths, :hits
|
12
|
+
|
13
|
+
def initialize(algo, graph, target, max_hits)
|
14
|
+
super()
|
15
|
+
@algo = algo
|
16
|
+
@max_hits = max_hits || -1
|
17
|
+
@graph = graph.blueprints_graph
|
18
|
+
@target = unwrap target if target
|
19
|
+
end
|
20
|
+
|
21
|
+
def processNextStart
|
22
|
+
next_raw_path.map do |e|
|
23
|
+
if e.is_a? Node
|
24
|
+
Neo4jVertex.new e, graph
|
25
|
+
elsif e.is_a? Relationship
|
26
|
+
Neo4jEdge.new e, graph
|
27
|
+
else
|
28
|
+
e
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def next_raw_path
|
34
|
+
loop do
|
35
|
+
if current_paths
|
36
|
+
if hits == 0
|
37
|
+
self.current_paths = nil
|
38
|
+
elsif current_paths.hasNext
|
39
|
+
self.hits -= 1
|
40
|
+
return current_paths.next
|
41
|
+
else
|
42
|
+
self.current_paths = nil
|
43
|
+
end
|
44
|
+
else
|
45
|
+
self.hits = max_hits
|
46
|
+
self.current_paths = @algo.findAllPaths(next_raw, target).iterator
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def next_raw
|
52
|
+
unwrap starts.next
|
53
|
+
end
|
54
|
+
|
55
|
+
def unwrap(vertex)
|
56
|
+
if vertex.respond_to? :element
|
57
|
+
vertex.element.raw_element
|
58
|
+
else
|
59
|
+
vertex.raw_element
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class PathFromPathPipe < PathPipe
|
65
|
+
attr_writer :target
|
66
|
+
|
67
|
+
def initialize(algo, graph, max_hits)
|
68
|
+
super(algo, graph, nil, max_hits)
|
69
|
+
end
|
70
|
+
|
71
|
+
def next_raw
|
72
|
+
path = starts.next
|
73
|
+
self.target = unwrap path.to_a.last
|
74
|
+
unwrap path[0]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Neo4j
|
3
|
+
module Algo
|
4
|
+
# Uses the interface defined here:
|
5
|
+
# http://api.neo4j.org/1.8/org/neo4j/graphdb/Path.html
|
6
|
+
#
|
7
|
+
# Note that I have removed methods that I didn't understand, assuming they are internal.
|
8
|
+
class PathWrapper
|
9
|
+
import org.neo4j.graphdb.Node
|
10
|
+
import com.tinkerpop.blueprints.impls.neo4j.Neo4jVertex
|
11
|
+
import com.tinkerpop.blueprints.impls.neo4j.Neo4jEdge
|
12
|
+
|
13
|
+
attr_reader :graph, :raw_path
|
14
|
+
|
15
|
+
def initialize(path, graph)
|
16
|
+
@raw_path = path
|
17
|
+
@graph = graph
|
18
|
+
@gv = graph.v
|
19
|
+
@ge = graph.e
|
20
|
+
end
|
21
|
+
|
22
|
+
#Returns the end vertex of this path.
|
23
|
+
def end_v
|
24
|
+
wrap_vertex raw_path.endNode
|
25
|
+
end
|
26
|
+
|
27
|
+
# Iterates through both the vertices and edges of this path in order.
|
28
|
+
def path
|
29
|
+
raw_path.iterator.to_route.map(graph: graph, element_type: :mixed) do |e|
|
30
|
+
if e.is_a? Node
|
31
|
+
wrap_vertex e
|
32
|
+
else
|
33
|
+
wrap_edge e
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_a
|
39
|
+
path.to_a
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the last edge in this path.
|
43
|
+
def end_e
|
44
|
+
wrap_edge raw_path.lastRelationship
|
45
|
+
end
|
46
|
+
|
47
|
+
# Returns the length of this path.
|
48
|
+
def length
|
49
|
+
raw_path.length
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns all the vertices in this path starting from the start vertex going forward towards the end vertex.
|
53
|
+
def v
|
54
|
+
raw_path.nodes.map { |n| wrap_vertex n }.to_route based_on: @gv
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns all the edges in between the vertices which this path consists of.
|
58
|
+
def e
|
59
|
+
raw_path.relationships.map { |r| wrap_edge r }.to_route based_on @ge
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns all the vertices in this path in reversed order, i.e.
|
63
|
+
def reverse_v
|
64
|
+
raw_path.reverseNodes.map { |n| wrap_vertex n }.to_route based_on @gv
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns all the edges in between the vertices which this path consists of in reverse order, i.e.
|
68
|
+
def reverse_e
|
69
|
+
raw_path.reverseRelationships.map { |r| wrap_edge r }.to_route based_on @ge
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the start vertex of this path.
|
73
|
+
def start_v
|
74
|
+
wrap_vertex raw_path.startNode
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_s
|
78
|
+
"#{ start_v.inspect }-(#{length})->#{end_v.inspect}"
|
79
|
+
end
|
80
|
+
|
81
|
+
def inspect
|
82
|
+
"#<Path #{ to_s }>"
|
83
|
+
end
|
84
|
+
|
85
|
+
# skips route creation = faster but less features
|
86
|
+
def out_edges(*args)
|
87
|
+
end_v.out_edges(*args)
|
88
|
+
end
|
89
|
+
|
90
|
+
# skips route creation = faster but less features
|
91
|
+
def in_edges(*args)
|
92
|
+
end_v.in_edges(*args)
|
93
|
+
end
|
94
|
+
|
95
|
+
# skips route creation = faster but less features
|
96
|
+
def both_edges(*args)
|
97
|
+
end_v.both_edges(*args)
|
98
|
+
end
|
99
|
+
|
100
|
+
# skips route creation = faster but less features
|
101
|
+
def out_vertices(*args)
|
102
|
+
end_v.out_vertices(*args)
|
103
|
+
end
|
104
|
+
|
105
|
+
# skips route creation = faster but less features
|
106
|
+
def in_vertices(*args)
|
107
|
+
end_v.in_vertices(*args)
|
108
|
+
end
|
109
|
+
|
110
|
+
# skips route creation = faster but less features
|
111
|
+
def both_vertices(*args)
|
112
|
+
end_v.both_vertices(*args)
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def out_e(*args)
|
117
|
+
end_v.out_e(*args)
|
118
|
+
end
|
119
|
+
|
120
|
+
def in_e(*args)
|
121
|
+
end_v.in_e(*args)
|
122
|
+
end
|
123
|
+
|
124
|
+
def both_e(*args)
|
125
|
+
end_v.both_e(*args)
|
126
|
+
end
|
127
|
+
|
128
|
+
def out(*args)
|
129
|
+
end_v.out(*args)
|
130
|
+
end
|
131
|
+
|
132
|
+
def in(*args)
|
133
|
+
end_v.in(*args)
|
134
|
+
end
|
135
|
+
|
136
|
+
def both(*args)
|
137
|
+
end_v.both(*args)
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def wrap_vertex(v)
|
143
|
+
Pacer::Wrappers::VertexWrapper.new graph, Neo4jVertex.new(v, graph.blueprints_graph)
|
144
|
+
end
|
145
|
+
|
146
|
+
def wrap_edge(e)
|
147
|
+
Pacer::Wrappers::EdgeWrapper.new graph, Neo4jEdge.new(e, graph.blueprints_graph)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Neo4j
|
3
|
+
module Algo
|
4
|
+
# Uses the interface defined here:
|
5
|
+
# http://api.neo4j.org/1.8/org/neo4j/graphdb/traversal/TraversalBranch.html
|
6
|
+
#
|
7
|
+
# Note that I have removed methods that I didn't understand, assuming they are internal.
|
8
|
+
class TraversalBranchWrapper < PathWrapper
|
9
|
+
# Returns whether or not the traversal should continue further along this branch.
|
10
|
+
def continues?
|
11
|
+
raw_path.continues
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns the number of edges this expansion source has expanded.
|
15
|
+
def num_expanded
|
16
|
+
raw_path.expanded
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns whether or not this branch (the Path representation of this
|
20
|
+
# branch at least) should be included in the result of this traversal,
|
21
|
+
# i.e. returned as one of the Paths from f.ex.
|
22
|
+
# TraversalDescription.traverse(org.neo4j.graphdb.Node...)
|
23
|
+
def included?
|
24
|
+
raw_path.includes
|
25
|
+
end
|
26
|
+
|
27
|
+
# The parent expansion source which created this TraversalBranch.
|
28
|
+
def parent
|
29
|
+
TraversalBranchWrapper.new raw_path.parent, graph
|
30
|
+
end
|
31
|
+
|
32
|
+
# Explicitly tell this branch to be pruned so that consecutive calls to #next() is guaranteed to return null.
|
33
|
+
def prune!
|
34
|
+
raw_path.prune
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_s
|
38
|
+
"#{super} num_expanded: #{ num_expanded }#{ continues? ? ' continues' : '' }#{ included? ? ' included' : '' }"
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
"#<TBR #{to_s}>"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/pacer-neo4j/graph.rb
CHANGED
@@ -1,50 +1,82 @@
|
|
1
|
-
require 'yaml'
|
2
|
-
|
3
1
|
module Pacer
|
2
|
+
module Neo4j
|
3
|
+
class Graph < PacerGraph
|
4
|
+
# I'm not sure exactly what this impacts but if it is false, many Pacer tests fail.
|
5
|
+
#
|
6
|
+
# Presumably Neo4j is faster with it set to false.
|
7
|
+
def safe_transactions=(b)
|
8
|
+
blueprints_graph.setCheckElementsInTransaction b
|
9
|
+
end
|
10
|
+
|
11
|
+
def safe_transactions
|
12
|
+
blueprints_graph.getCheckElementsInTransaction
|
13
|
+
end
|
14
|
+
|
15
|
+
def key_index_cache(type, name, size = :undefined)
|
16
|
+
if size == :undefined
|
17
|
+
lucene_auto_index(type).getCacheCapacity name
|
18
|
+
else
|
19
|
+
lucene_auto_index(type).setCacheCapacity name, size
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def index_properties(type, filters)
|
26
|
+
filters.properties.select { |k, v| key_indices(type).include?(k) and not v.nil? }
|
27
|
+
end
|
4
28
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
# Ruby's at_exit callback, but if an already open graph is given, it will
|
12
|
-
# not.
|
13
|
-
#
|
14
|
-
# Please note that Pacer turns on Neo4j's checkElementsInTransaction
|
15
|
-
# feature by default. For some sort of performance improvement at
|
16
|
-
# the expense of an odd consistency model within transactions that
|
17
|
-
# require considerable more complexity in client code, you can use
|
18
|
-
# `graph.setCheckElementsInTransaction(false)` to disable the
|
19
|
-
# feature.
|
20
|
-
def neo4j(path_or_graph, args = nil)
|
21
|
-
neo = com.tinkerpop.blueprints.impls.neo4j.Neo4jGraph
|
22
|
-
if path_or_graph.is_a? String
|
23
|
-
path = File.expand_path(path_or_graph)
|
24
|
-
open = proc do
|
25
|
-
graph = Pacer.open_graphs[path]
|
26
|
-
unless graph
|
27
|
-
if args
|
28
|
-
graph = neo.new(path, args.to_hash_map)
|
29
|
+
def build_query(type, filters)
|
30
|
+
indexed = index_properties type, filters
|
31
|
+
if indexed.any?
|
32
|
+
indexed.map do |k, v|
|
33
|
+
if v.is_a? Numeric
|
34
|
+
"#{k}:#{v}"
|
29
35
|
else
|
30
|
-
|
36
|
+
s = encode_property(v)
|
37
|
+
if s.is_a? String and s =~ /\s/
|
38
|
+
%{#{k}:"#{s}"}
|
39
|
+
else
|
40
|
+
"#{k}:#{s}"
|
41
|
+
end
|
31
42
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
graph
|
43
|
+
end.join " AND "
|
44
|
+
else
|
45
|
+
nil
|
36
46
|
end
|
37
|
-
|
38
|
-
|
39
|
-
|
47
|
+
end
|
48
|
+
|
49
|
+
def neo_graph
|
50
|
+
blueprints_graph.raw_graph
|
51
|
+
end
|
52
|
+
|
53
|
+
def lucene_auto_index(type)
|
54
|
+
if type == :vertex
|
55
|
+
neo_graph.index.getNodeAutoIndexer.getIndexInternal
|
56
|
+
elsif type == :edge
|
57
|
+
neo_graph.index.getRelationshipAutoIndexer.getIndexInternal
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def indexed_route(element_type, filters, block)
|
62
|
+
if search_manual_indices
|
63
|
+
super
|
64
|
+
else
|
65
|
+
query = build_query(element_type, filters)
|
66
|
+
if query
|
67
|
+
route = lucene query, element_type: element_type
|
68
|
+
filters.remove_property_keys key_indices(element_type)
|
69
|
+
if filters.any?
|
70
|
+
Pacer::Route.property_filter(route, filters, block)
|
71
|
+
else
|
72
|
+
route
|
73
|
+
end
|
74
|
+
elsif filters.route_modules.any?
|
75
|
+
mod = filters.route_modules.shift
|
76
|
+
Pacer::Route.property_filter(mod.route(self), filters, block)
|
77
|
+
end
|
40
78
|
end
|
41
|
-
PacerGraph.new(Pacer::YamlEncoder, open, shutdown)
|
42
|
-
else
|
43
|
-
# Don't register the new graph so that it won't be automatically closed.
|
44
|
-
PacerGraph.new Pacer::YamlEncoder, proc { neo.new(path_or_graph) }
|
45
79
|
end
|
46
80
|
end
|
47
81
|
end
|
48
|
-
|
49
|
-
|
50
82
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Neo4j
|
3
|
+
class Graph
|
4
|
+
def lucene(query, opts = {})
|
5
|
+
opts = { back: self, element_type: :vertex }.merge opts
|
6
|
+
chain_route(opts.merge(query: query,
|
7
|
+
filter: :lucene,
|
8
|
+
index: choose_index(opts)))
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def choose_index(opts)
|
14
|
+
et = opts[:element_type]
|
15
|
+
idx = opts[:index]
|
16
|
+
case idx
|
17
|
+
when String, Symbol
|
18
|
+
index(idx, et).index.raw_index
|
19
|
+
when Pacer::Wrappers::IndexWrapper
|
20
|
+
idx.index.raw_index
|
21
|
+
when com.tinkerpop.blueprints.Index
|
22
|
+
idx.raw_index
|
23
|
+
else
|
24
|
+
lucene_auto_index(et)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
module Filter
|
32
|
+
module LuceneFilter
|
33
|
+
import org.neo4j.index.lucene.QueryContext
|
34
|
+
|
35
|
+
attr_accessor :index, :query, :sort_by, :reverse_numeric, :sort_numeric, :sort_by_score, :top, :fast
|
36
|
+
|
37
|
+
def count(max = nil)
|
38
|
+
iter = query_result
|
39
|
+
c = iter.count
|
40
|
+
if c >= 0
|
41
|
+
c
|
42
|
+
elsif max
|
43
|
+
iter.inject(0) do |n, _|
|
44
|
+
if n == max
|
45
|
+
return :max
|
46
|
+
else
|
47
|
+
n + 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
else
|
51
|
+
iter.inject(0) { |n, _| n + 1 }
|
52
|
+
end
|
53
|
+
ensure
|
54
|
+
iter.close
|
55
|
+
end
|
56
|
+
|
57
|
+
def sort_by_score!
|
58
|
+
self.sort_by_score = true
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def sort(*keys)
|
63
|
+
self.sort_by = keys
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
def top_hits(n)
|
68
|
+
self.top = n
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
def fast!
|
73
|
+
self.fast = true
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
def build_query
|
80
|
+
qc = QueryContext.new(query)
|
81
|
+
qc = qc.tradeCorrectnessForSpeed if fast
|
82
|
+
qc = qc.top(top) if top
|
83
|
+
if sort_by_score
|
84
|
+
qc.sortByScore
|
85
|
+
elsif sort_by
|
86
|
+
qc.sort(*[*sort_by].map(&:to_s))
|
87
|
+
elsif sort_numeric
|
88
|
+
qc.sortNumeric(sort_numeric, false)
|
89
|
+
elsif reverse_numeric
|
90
|
+
qc.sortNumeric(reverse_numeric, true)
|
91
|
+
else
|
92
|
+
qc
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def query_result
|
97
|
+
index.query build_query
|
98
|
+
end
|
99
|
+
|
100
|
+
def source_iterator
|
101
|
+
pipe = Pacer::Neo4j::RawVertexWrappingPipe.new graph
|
102
|
+
pipe.setStarts query_result
|
103
|
+
pipe.enablePath(true)
|
104
|
+
pipe
|
105
|
+
end
|
106
|
+
|
107
|
+
def inspect_string
|
108
|
+
"#{ inspect_class_name }(#{ query }) ~ #{ query_result.count }"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Pacer
|
2
|
+
module Neo4j
|
3
|
+
class RawVertexWrappingPipe < Pacer::Pipes::RubyPipe
|
4
|
+
import com.tinkerpop.blueprints.impls.neo4j.Neo4jVertex
|
5
|
+
|
6
|
+
attr_reader :graph
|
7
|
+
|
8
|
+
def initialize(graph)
|
9
|
+
super()
|
10
|
+
@graph = graph.blueprints_graph
|
11
|
+
end
|
12
|
+
|
13
|
+
def processNextStart
|
14
|
+
Neo4jVertex.new starts.next, graph
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/pacer-neo4j/version.rb
CHANGED
data/pom.xml
CHANGED
@@ -7,7 +7,7 @@
|
|
7
7
|
<artifactId>pacer-neo4j</artifactId>
|
8
8
|
<!-- NOTE: the following properties are automatically updated based on the values in lib/pacer-neo4j/version.rb -->
|
9
9
|
<properties>
|
10
|
-
<gem.version>2.0
|
10
|
+
<gem.version>2.1.0</gem.version>
|
11
11
|
<blueprints.version>2.1.0</blueprints.version>
|
12
12
|
<pipes.version>2.1.0</pipes.version>
|
13
13
|
</properties>
|
@@ -32,6 +32,11 @@
|
|
32
32
|
<artifactId>blueprints-neo4j-graph</artifactId>
|
33
33
|
<version>${blueprints.version}</version>
|
34
34
|
</dependency>
|
35
|
+
<dependency>
|
36
|
+
<groupId>com.tinkerpop.blueprints</groupId>
|
37
|
+
<artifactId>blueprints-neo4jbatch-graph</artifactId>
|
38
|
+
<version>${blueprints.version}</version>
|
39
|
+
</dependency>
|
35
40
|
</dependencies>
|
36
41
|
|
37
42
|
<repositories>
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: pacer-neo4j
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 2.0
|
5
|
+
version: 2.1.0
|
6
6
|
platform: java
|
7
7
|
authors:
|
8
8
|
- Darrick Wiebe
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: pacer
|
@@ -39,13 +39,22 @@ files:
|
|
39
39
|
- README.md
|
40
40
|
- Rakefile
|
41
41
|
- lib/pacer-neo4j.rb
|
42
|
+
- lib/pacer-neo4j/algo.rb
|
43
|
+
- lib/pacer-neo4j/algo/block_cost_evaluator.rb
|
44
|
+
- lib/pacer-neo4j/algo/block_estimate_evaluator.rb
|
45
|
+
- lib/pacer-neo4j/algo/block_path_expander.rb
|
46
|
+
- lib/pacer-neo4j/algo/path_pipe.rb
|
47
|
+
- lib/pacer-neo4j/algo/path_wrapper.rb
|
48
|
+
- lib/pacer-neo4j/algo/traversal_branch_wrapper.rb
|
42
49
|
- lib/pacer-neo4j/graph.rb
|
50
|
+
- lib/pacer-neo4j/lucene_filter.rb
|
51
|
+
- lib/pacer-neo4j/raw_vertex_wrapping_pipe.rb
|
43
52
|
- lib/pacer-neo4j/rspec.rb
|
44
53
|
- lib/pacer-neo4j/version.rb
|
45
54
|
- pacer-neo4j.gemspec
|
46
55
|
- pom.xml
|
47
56
|
- pom/standalone.xml
|
48
|
-
- lib/pacer-neo4j-2.0
|
57
|
+
- lib/pacer-neo4j-2.1.0-standalone.jar
|
49
58
|
homepage: http://neo4j.org
|
50
59
|
licenses: []
|
51
60
|
post_install_message:
|