pacer-neo4j 2.0.1-java → 2.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|