pacer-neo4j2 2.0.1-java

Sign up to get free protection for your applications and to get access to all the features.
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