pacer-neo4j2 2.0.1-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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 65bbc2ebae5136c5b95bdf14891ecd538522e719
4
+ data.tar.gz: 84bef1fdf8c9bbb626ef089ef0cedd59dff19ead
5
+ SHA512:
6
+ metadata.gz: 8e0a7bd049e14f3f101972f5a0696b6b6d47c30f575658a5cc713edd43605be26f86bbbb53149cbda18be86e7deadc4437053d32d118cf22e2a92e10a4bb1eb6
7
+ data.tar.gz: fc5480e6b8c60c18d56904b2e13b003607551a8111c40c4b45542d5a69ef7f21091a8a1c4fce8aec394937641f435bc9b2b390cc15ea32a0d0cf212b3a9aef19
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ target/*
6
+ lib/*.jar
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in pacer-graph.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # Neo4J Graph Database Adapter for Pacer
2
+
3
+ [Pacer](https://github.com/pangloss/pacer) is a
4
+ [JRuby](http://jruby.org) graph traversal framework built on the
5
+ [Tinkerpop](http://www.tinkerpop.com) stack.
6
+
7
+ This plugin enables full [Neo4J](http://neo4j.org) graph support in Pacer.
8
+
9
+
10
+ ## Usage
11
+
12
+ Here is how you open a Neo4J graph in Pacer.
13
+
14
+ require 'pacer'
15
+ require 'pacer-neo4j2'
16
+
17
+ # Graph will be created if it doesn't exist
18
+ graph = Pacer.neo4j 'path/to/graph'
19
+
20
+ All other operations are identical across graph implementations (except
21
+ where certain features are not supported). See Pacer's documentation for
22
+ more information.
23
+
data/Rakefile ADDED
@@ -0,0 +1,35 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ file 'pom.xml' => 'lib/pacer-neo4j2/version.rb' do
5
+ pom = File.read 'pom.xml'
6
+ when_writing('Update pom.xml version number') do
7
+ open 'pom.xml', 'w' do |f|
8
+ pom.each_line do |line|
9
+ line.sub!(%r{<gem.version>.*</gem.version>}, "<gem.version>#{ Pacer::Neo4j2::VERSION }</gem.version>")
10
+ line.sub!(%r{<blueprints.version>.*</blueprints.version>}, "<blueprints.version>#{ Pacer::Neo4j2::BLUEPRINTS_VERSION }</blueprints.version>")
11
+ line.sub!(%r{<pipes.version>.*</pipes.version>}, "<pipes.version>#{ Pacer::Neo4j2::PIPES_VERSION }</pipes.version>")
12
+ f << line
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ file Pacer::Neo4j2::JAR_PATH => 'pom.xml' do
19
+ when_writing("Execute 'mvn package' task") do
20
+ system('mvn clean package')
21
+ end
22
+ end
23
+
24
+ task :note do
25
+ puts "NOTE: touch lib/pacer-neo4j2/version.rb (or rake touch) to force everything to rebuild"
26
+ end
27
+
28
+ task :build => [:note, Pacer::Neo4j2::JAR_PATH]
29
+ task :install => [:note, Pacer::Neo4j2::JAR_PATH]
30
+
31
+ desc 'Touch version.rb so that the jar rebuilds'
32
+ task :touch do
33
+ system 'touch', 'lib/pacer-neo4j2/version.rb'
34
+ end
35
+
@@ -0,0 +1,38 @@
1
+ module Pacer
2
+ module Neo4j2
3
+ module Algo
4
+ class BlockCostEvaluator
5
+ import org.neo4j.graphalgo.CostEvaluator
6
+ import org.neo4j.graphdb.Direction
7
+ import com.tinkerpop.blueprints.impls.neo4j2.Neo4j2Edge
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, Neo4j2Edge.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 Neo4j2
3
+ module Algo
4
+ class BlockEstimateEvaluator
5
+ import org.neo4j.graphalgo.EstimateEvaluator
6
+ import com.tinkerpop.blueprints.impls.neo4j2.Neo4j2Vertex
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, Neo4j2Vertex.new(node, graph.blueprints_graph)
19
+ goal = Pacer::Wrappers::VertexWrapper.new graph, Neo4j2Vertex.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 Neo4j2
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,129 @@
1
+ module Pacer
2
+ module Core
3
+ module StringRoute
4
+ def raw_cypher(opts = {})
5
+ chain_route({element_type: :cypher, transform: Pacer::Transform::Cypher}.merge opts)
6
+ end
7
+
8
+ def cypher(opts = {})
9
+ raw_cypher(opts).paths
10
+ end
11
+ end
12
+
13
+ module Graph
14
+ module VerticesRoute
15
+ def raw_cypher(query, elements_per_query = nil)
16
+ reducer(element_type: :array).
17
+ enter { Set[] }.
18
+ leave { |x, a| x.nil? or (elements_per_query and a.length % elements_per_query == 0) }.
19
+ reduce { |v, ids| ids << v.element_id }.
20
+ map(element_type: :string) { |a| "start v=node(#{a.to_a.join(',')}) #{ query }"}.
21
+ raw_cypher
22
+ end
23
+
24
+ def cypher(query, elements_per_query = nil)
25
+ raw_cypher(query, elements_per_query).paths
26
+ end
27
+ end
28
+ end
29
+
30
+ module CypherRoute
31
+ def paths(*columns)
32
+ chain_route element_type: :path, transform: Pacer::Transform::CypherResults, columns: columns
33
+ end
34
+
35
+ def v(column = nil)
36
+ chain_route element_type: :vertex, transform: Pacer::Transform::CypherResults, columns: [column].compact, single: true
37
+ end
38
+
39
+ def e(column = nil)
40
+ chain_route element_type: :edge, transform: Pacer::Transform::CypherResults, columns: [column].compact, single: true
41
+ end
42
+
43
+ def results(*columns)
44
+ chain_route element_type: :array, transform: Pacer::Transform::CypherResults, columns: columns
45
+ end
46
+ end
47
+ Pacer::RouteBuilder.current.element_types[:cypher] = [CypherRoute]
48
+ end
49
+
50
+ module Transform
51
+ module Cypher
52
+ protected
53
+
54
+ def attach_pipe(end_pipe)
55
+ pipe = CypherPipe.new(self)
56
+ pipe.setStarts end_pipe if end_pipe
57
+ pipe
58
+ end
59
+
60
+ class CypherPipe < Pacer::Pipes::RubyPipe
61
+ import org.neo4j.cypher.javacompat.ExecutionEngine
62
+
63
+ attr_reader :engine
64
+
65
+ def initialize(route)
66
+ super()
67
+ graph = route.graph.neo_graph
68
+ @engine = ExecutionEngine.new graph
69
+ end
70
+
71
+ protected
72
+
73
+ def processNextStart
74
+ engine.execute starts.next
75
+ end
76
+ end
77
+ end
78
+
79
+ module CypherResults
80
+ attr_accessor :columns, :single
81
+
82
+ protected
83
+
84
+ def attach_pipe(end_pipe)
85
+ pipe = ResultsPipe.new(self, columns, single)
86
+ pipe.setStarts end_pipe if end_pipe
87
+ pipe
88
+ end
89
+
90
+ class ResultsPipe < Pacer::Pipes::RubyPipe
91
+ import org.neo4j.cypher.javacompat.ExecutionEngine
92
+
93
+ include Pacer::Neo4j2::Algo::Wrapping
94
+
95
+ attr_reader :columns, :graph, :single
96
+ attr_accessor :current
97
+
98
+ def initialize(route, columns, single)
99
+ super()
100
+ @single = single
101
+ @graph = route.graph
102
+ @columns = columns if columns and columns.any?
103
+ end
104
+
105
+ protected
106
+
107
+ def processNextStart
108
+ while true
109
+ if current
110
+ if current.first.hasNext
111
+ if single
112
+ return wrap_path(current.map(&:next)).first
113
+ else
114
+ return wrap_path current.map(&:next)
115
+ end
116
+ else
117
+ self.current = nil
118
+ end
119
+ else
120
+ results = starts.next
121
+ cols = columns || results.columns.to_a
122
+ self.current = cols.map { |col| results.columnAs col }
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,79 @@
1
+ module Pacer
2
+ module Neo4j2
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.neo4j2.Neo4j2Vertex
8
+ import com.tinkerpop.blueprints.impls.neo4j2.Neo4j2Edge
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
+ Neo4j2Vertex.new e, graph
25
+ elsif e.is_a? Relationship
26
+ Neo4j2Edge.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,134 @@
1
+ module Pacer
2
+ module Neo4j2
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
+ include Wrapping
10
+
11
+ attr_reader :graph, :raw_path
12
+
13
+ def initialize(path, graph)
14
+ @raw_path = path
15
+ @graph = graph
16
+ @gv = graph.v
17
+ @ge = graph.e
18
+ end
19
+
20
+ #Returns the end vertex of this path.
21
+ def end_v
22
+ wrap_vertex raw_path.endNode
23
+ end
24
+
25
+ # Iterates through both the vertices and edges of this path in order.
26
+ def path
27
+ wrap_path raw_path.iterator
28
+ end
29
+
30
+ def to_a
31
+ path.to_a
32
+ end
33
+
34
+ # Returns the last edge in this path.
35
+ def end_e
36
+ wrap_edge raw_path.lastRelationship
37
+ end
38
+
39
+ # Returns the length of this path.
40
+ def length
41
+ raw_path.length
42
+ end
43
+
44
+ # Returns all the vertices in this path starting from the start vertex going forward towards the end vertex.
45
+ def v
46
+ raw_path.nodes.map { |n| wrap_vertex n }.to_route based_on: @gv
47
+ end
48
+
49
+ # Returns all the edges in between the vertices which this path consists of.
50
+ def e
51
+ raw_path.relationships.map { |r| wrap_edge r }.to_route based_on @ge
52
+ end
53
+
54
+ # Returns all the vertices in this path in reversed order, i.e.
55
+ def reverse_v
56
+ raw_path.reverseNodes.map { |n| wrap_vertex n }.to_route based_on @gv
57
+ end
58
+
59
+ # Returns all the edges in between the vertices which this path consists of in reverse order, i.e.
60
+ def reverse_e
61
+ raw_path.reverseRelationships.map { |r| wrap_edge r }.to_route based_on @ge
62
+ end
63
+
64
+ # Returns the start vertex of this path.
65
+ def start_v
66
+ wrap_vertex raw_path.startNode
67
+ end
68
+
69
+ def to_s
70
+ "#{ start_v.inspect }-(#{length})->#{end_v.inspect}"
71
+ end
72
+
73
+ def inspect
74
+ "#<Path #{ to_s }>"
75
+ end
76
+
77
+ # skips route creation = faster but less features
78
+ def out_edges(*args)
79
+ end_v.out_edges(*args)
80
+ end
81
+
82
+ # skips route creation = faster but less features
83
+ def in_edges(*args)
84
+ end_v.in_edges(*args)
85
+ end
86
+
87
+ # skips route creation = faster but less features
88
+ def both_edges(*args)
89
+ end_v.both_edges(*args)
90
+ end
91
+
92
+ # skips route creation = faster but less features
93
+ def out_vertices(*args)
94
+ end_v.out_vertices(*args)
95
+ end
96
+
97
+ # skips route creation = faster but less features
98
+ def in_vertices(*args)
99
+ end_v.in_vertices(*args)
100
+ end
101
+
102
+ # skips route creation = faster but less features
103
+ def both_vertices(*args)
104
+ end_v.both_vertices(*args)
105
+ end
106
+
107
+
108
+ def out_e(*args)
109
+ end_v.out_e(*args)
110
+ end
111
+
112
+ def in_e(*args)
113
+ end_v.in_e(*args)
114
+ end
115
+
116
+ def both_e(*args)
117
+ end_v.both_e(*args)
118
+ end
119
+
120
+ def out(*args)
121
+ end_v.out(*args)
122
+ end
123
+
124
+ def in(*args)
125
+ end_v.in(*args)
126
+ end
127
+
128
+ def both(*args)
129
+ end_v.both(*args)
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,47 @@
1
+ module Pacer
2
+ module Neo4j2
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
@@ -0,0 +1,34 @@
1
+ module Pacer
2
+ module Neo4j2
3
+ module Algo
4
+ module Wrapping
5
+ import org.neo4j.graphdb.Node
6
+ import org.neo4j.graphdb.Relationship
7
+ import com.tinkerpop.blueprints.impls.neo4j2.Neo4j2Vertex
8
+ import com.tinkerpop.blueprints.impls.neo4j2.Neo4j2Edge
9
+
10
+ private
11
+
12
+ def wrap_path(p)
13
+ p.collect do |e|
14
+ if e.is_a? Node
15
+ wrap_vertex e
16
+ elsif e.is_a? Relationship
17
+ wrap_edge e
18
+ else
19
+ e
20
+ end
21
+ end
22
+ end
23
+
24
+ def wrap_vertex(v)
25
+ Pacer::Wrappers::VertexWrapper.new graph, Neo4j2Vertex.new(v, graph.blueprints_graph)
26
+ end
27
+
28
+ def wrap_edge(e)
29
+ Pacer::Wrappers::EdgeWrapper.new graph, Neo4j2Edge.new(e, graph.blueprints_graph)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end