neo4j-core 0.0.5-java → 0.0.6-java

Sign up to get free protection for your applications and to get access to all the features.
data/lib/neo4j/algo.rb ADDED
@@ -0,0 +1,300 @@
1
+ module Neo4j
2
+
3
+
4
+ # A wrapper for the Neo4j Algo <tt>org.neo4j.graphalgo.GraphAlgoFactory</tt> class.
5
+ #
6
+ # @example the length of the first path found between two nodes
7
+ # Neo4j::Algo.all_paths(a,b).outgoing(:friends).depth(1).first.length
8
+ #
9
+ # @example the nodes in the shortest path between two nodes
10
+ # Neo4j::Algo.shortest_path(a,b).outgoing(:friends).outgoing(:knows).to_a #=> [node1, node2, node3 ...]
11
+ #
12
+ # @example the relationships in the shortest path between two nodes
13
+ # Neo4j::Algo.shortest_path(a,b).outgoing(:friends).outgoing(:knows).rels.to_a #=> [rel1, rel2, rel3 ...]
14
+ #
15
+ # @example The Dijkstra algorithm using a cost evaluator
16
+ # Neo4j::Algo.dijkstra_path(a,b).cost_evaluator{|rel,direction| rel[:weight]}
17
+ class Algo
18
+ include Enumerable
19
+ include Neo4j::Core::ToJava
20
+
21
+ class EstimateEvaluator #:nodoc
22
+ include org.neo4j.graphalgo.EstimateEvaluator
23
+ include Neo4j::Core::ToJava
24
+
25
+ def initialize(&evaluator)
26
+ @evaluator = evaluator
27
+ end
28
+
29
+ # Implements T getCost(Node node, Node goal)
30
+ # Estimate the weight of the remaining path from one node to another.
31
+ def get_cost(node, goal)
32
+ @evaluator.call(node, goal)
33
+ end
34
+ end
35
+
36
+ class CostEvaluator #:nodoc
37
+ include org.neo4j.graphalgo.CostEvaluator
38
+ include Neo4j::Core::ToJava
39
+
40
+ def initialize(&evaluator)
41
+ @evaluator = evaluator
42
+ end
43
+
44
+ # Implements the Java Method: T getCost(Relationship relationship, Direction direction)
45
+ # From the JavaDoc: <pre>
46
+ # This is the general method for looking up costs for relationships.
47
+ # This can do anything, like looking up a property or running some small calculation.
48
+ # Parameters:
49
+ # relationship -
50
+ # direction - The direction in which the relationship is being evaluated, either Direction.INCOMING or Direction.OUTGOING.
51
+ # Returns:
52
+ # The cost for this edge/relationship
53
+ # </pre>
54
+ def get_cost(relationship, direction)
55
+ @evaluator.call(relationship, dir_from_java(direction))
56
+ end
57
+ end
58
+
59
+ def initialize(from, to, &factory_proc) #:nodoc:
60
+ @from = from
61
+ @to = to
62
+ @factory_proc = factory_proc
63
+ @type_and_dirs = []
64
+
65
+ end
66
+
67
+ def _depth #:nodoc:
68
+ @depth || java.lang.Integer::MAX_VALUE
69
+ end
70
+
71
+ def _expander #:nodoc:
72
+ expander = @expander
73
+ expander ||= @type_and_dirs.empty? ? org.neo4j.kernel.Traversal.expanderForAllTypes() : org.neo4j.kernel.Traversal.expanderForTypes(*@type_and_dirs)
74
+ expander
75
+ end
76
+
77
+ def _cost_evaluator #:nodoc:
78
+ raise "Algorithm requeries a cost evalulator, use the cost_evaluator to provide one" unless @cost_evaluator
79
+ @cost_evaluator
80
+ end
81
+
82
+ def _estimate_evaluator #:nodoc:
83
+ raise "Algorithm requeries a estimate evaluator, use the estimate_evaluator to provide one" unless @estimate_evaluator
84
+ @estimate_evaluator
85
+ end
86
+
87
+ # Specifies which outgoing relationship should be traversed for the graph algorithm
88
+ #
89
+ # @param [String, Symbol] rel the relationship type
90
+ # @return self
91
+ def outgoing(rel)
92
+ @type_and_dirs << type_to_java(rel)
93
+ @type_and_dirs << dir_to_java(:outgoing)
94
+ self
95
+ end
96
+
97
+ # Specifies which incoming relationship should be traversed for the graph algorithm
98
+ #
99
+ # @param [String, Symbol] rel the relationship type
100
+ # @return self
101
+ def incoming(rel)
102
+ @type_and_dirs << type_to_java(rel)
103
+ @type_and_dirs << dir_to_java(:incoming)
104
+ self
105
+ end
106
+
107
+ # Specifies which relationship should be traversed for the graph algorithm
108
+ #
109
+ # @example
110
+ # Neo4j::Algo.shortest_path(@x,@y).expand{|node| node._rels(:outgoing, :friends)}
111
+ #
112
+ # @example the above is same as:
113
+ # Neo4j::Algo.shortest_path(@x,@y).outgoing(:friends)
114
+ #
115
+ # @param [Proc] expander_proc a proc relationship type (symbol)
116
+ # @return self
117
+ def expand(&expander_proc)
118
+ @expander = (Neo4j::Core::Traversal::RelExpander.create_pair(&expander_proc))
119
+ self
120
+ end
121
+
122
+ # If only a single path should be returned,
123
+ # default for some algorithms, like shortest_path
124
+ def single
125
+ @single = true
126
+ self
127
+ end
128
+
129
+ # See #single
130
+ # Not sure if this method is useful
131
+ def many
132
+ @single = false
133
+ end
134
+
135
+ # The depth of the traversal
136
+ # Notice not all algorithm uses this argument (aStar and dijkstra)
137
+ def depth(depth)
138
+ @depth = depth
139
+ self
140
+ end
141
+
142
+ # Specifies a cost evaluator for the algorithm.
143
+ # Only available for the aStar and dijkstra algorithms.
144
+ #
145
+ # @example
146
+ # Neo4j::Algo.dijkstra(@x,@y).cost_evaluator{|rel,*| rel[:weight]}
147
+ #
148
+ def cost_evaluator(&cost_evaluator_proc)
149
+ @cost_evaluator = CostEvaluator.new(&cost_evaluator_proc)
150
+ self
151
+ end
152
+
153
+ # Specifies an evaluator that returns an (optimistic) estimation of the cost to get from the current node (in the traversal) to the end node.
154
+ # Only available for the aStar algorithm.
155
+ #
156
+ # The provided proc estimate the weight of the remaining path from one node to another.
157
+ # The proc takes two parameters:
158
+ # * node :: the node to estimate the weight from.
159
+ # * goal :: the node to estimate the weight to.
160
+ #
161
+ # The proc should return an estimation of the weight of the path from the first node to the second.
162
+ #
163
+ # @example
164
+ # Neo4j::Algo.a_star(@x,@y).cost_evaluator{...}.estimate_evaluator{|node,goal| some calculation returning a Float}
165
+ #
166
+ def estimate_evaluator(&estimate_evaluator_proc)
167
+ @estimate_evaluator = EstimateEvaluator.new(&estimate_evaluator_proc)
168
+ self
169
+ end
170
+
171
+ # Specifies that nodes should be returned from as result
172
+ # @see #rels
173
+ def nodes
174
+ @path_finder_method = :nodes
175
+ self
176
+ end
177
+
178
+ # Specifies that relationships should be returned from as result
179
+ # @see #nodes
180
+ def rels
181
+ @path_finder_method = :relationships
182
+ self
183
+ end
184
+
185
+
186
+ # So that one can call directly method on the PathFinder result from an executed algorithm.
187
+ def method_missing(m, *args, &block)
188
+ execute_algo.send(m, *args)
189
+ end
190
+
191
+ def each(&block) #:nodoc:
192
+ if @single && @path_finder_method
193
+ execute_algo.send(@path_finder_method).each &block
194
+ else
195
+ traversal = execute_algo
196
+ traversal.each &block if traversal
197
+ end
198
+ end
199
+
200
+ def execute_algo #:nodoc:
201
+ instance = self.instance_eval(&@factory_proc)
202
+ if @single
203
+ instance.find_single_path(@from._java_node, @to._java_node)
204
+ else
205
+ instance.find_all_paths(@from._java_node, @to._java_node)
206
+ end
207
+ end
208
+
209
+ # Returns an instance of Neo4j::Algo which can find all available paths between two nodes.
210
+ # These returned paths can contain loops (i.e. a node can occur more than once in any returned path).
211
+ def self.all_paths(from, to)
212
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.all_paths(_expander, _depth) }
213
+ end
214
+
215
+ # See #all_paths, returns the first path found
216
+ def self.all_path(from, to)
217
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.all_paths(_expander, _depth) }.single
218
+ end
219
+
220
+ # Returns an instance of Neo4j::Algo which can find all simple paths between two nodes.
221
+ # These returned paths cannot contain loops (i.e. a node cannot occur more than once in any returned path).
222
+ def self.all_simple_paths(from, to)
223
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.all_simple_paths(_expander, _depth) }
224
+ end
225
+
226
+ # See #all_simple_paths, returns the first path found
227
+ def self.all_simple_path(from, to)
228
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.all_simple_paths(_expander, _depth) }.single
229
+ end
230
+
231
+ # Returns an instance of Neo4j::Algo which can find all shortest paths (that is paths with as short Path.length() as possible) between two nodes.
232
+ # These returned paths cannot contain loops (i.e. a node cannot occur more than once in any returned path).
233
+ def self.shortest_paths(from, to)
234
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.shortest_path(_expander, _depth) }
235
+ end
236
+
237
+ # See #shortest_paths, returns the first path found
238
+ def self.shortest_path(from, to)
239
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.shortest_path(_expander, _depth) }.single
240
+ end
241
+
242
+ # Returns an instance of Neo4j::Algo which uses the Dijkstra algorithm to find the cheapest path between two nodes.
243
+ # The definition of "cheap" is the lowest possible cost to get from the start node to the end node, where the cost is returned from costEvaluator.
244
+ # These returned paths cannot contain loops (i.e. a node cannot occur more than once in any returned path).
245
+ # See http://en.wikipedia.org/wiki/Dijkstra%27s_algorithm for more information.
246
+ #
247
+ # Example
248
+ #
249
+ # Neo4j::Algo.dijkstra_path(node_a,node_b).cost_evaluator{|rel,*| rel[:weight]}.rels
250
+ #
251
+ def self.dijkstra_paths(from, to)
252
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.dijkstra(_expander, _cost_evaluator) }
253
+ end
254
+
255
+ # See #dijkstra_paths, returns the first path found
256
+ #
257
+ def self.dijkstra_path(from, to)
258
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.dijkstra(_expander, _cost_evaluator) }.single
259
+ end
260
+
261
+ # Returns an instance of Neo4j::Algo which uses the A* algorithm to find the cheapest path between two nodes.
262
+ # The definition of "cheap" is the lowest possible cost to get from the start node to the end node, where the cost is returned from lengthEvaluator and estimateEvaluator. These returned paths cannot contain loops (i.e. a node cannot occur more than once in any returned path).
263
+ # See http://en.wikipedia.org/wiki/A*_search_algorithm for more information.
264
+ #
265
+ # Expacts an cost evaluator and estimate evaluator, see Algo#cost_evaluator and Algo#estimate_evaluator
266
+ #
267
+ # Example:
268
+ #
269
+ # Neo4j::Algo.a_star_path(@x,@y).cost_evaluator{|rel,*| rel[:weight]}.estimate_evaluator{|node,goal| returns a float value}
270
+ #
271
+ def self.a_star_paths(from, to)
272
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.a_star(_expander, _cost_evaluator, _estimate_evaluator) }
273
+ end
274
+
275
+ # See #a_star_paths, returns the first path found
276
+ #
277
+ def self.a_star_path(from, to)
278
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.a_star(_expander, _cost_evaluator, _estimate_evaluator) }.single
279
+ end
280
+
281
+ # Returns an instance of Neo4j::Algo can find all paths of a certain length(depth) between two nodes.
282
+ # These returned paths cannot contain loops (i.e. a node cannot occur more than once in any returned path).
283
+ # Expects setting the depth parameter (the lenghto of the path) by the Algo#depth method.
284
+ #
285
+ # Example:
286
+ #
287
+ # Neo4j::Algo.with_length_paths(node_a,node_b).depth(2).each {|x| puts "Node #{x}"}
288
+ #
289
+ def self.with_length_paths(from,to)
290
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.paths_with_length(_expander, _depth) }
291
+ end
292
+
293
+ # See #with_length_paths, returns the first path found
294
+ #
295
+ def self.with_length_path(from,to)
296
+ Algo.new(from, to) { org.neo4j.graphalgo.GraphAlgoFactory.paths_with_length(_expander, _depth) }.single
297
+ end
298
+
299
+ end
300
+ end
data/lib/neo4j/cypher.rb CHANGED
@@ -116,7 +116,7 @@ module Neo4j
116
116
 
117
117
  def shortest_paths(&block)
118
118
  match = instance_eval(&block)
119
- match.algorithm = 'shortestPaths'
119
+ match.algorithm = 'allShortestPaths'
120
120
  match.find_match_start
121
121
  end
122
122
 
@@ -79,7 +79,6 @@ module Neo4j
79
79
  @_index_names = hash
80
80
  end
81
81
 
82
-
83
82
  def rm_index_config
84
83
  @_index_type = {}
85
84
  @_field_types = {}
@@ -94,7 +94,7 @@ module Neo4j
94
94
  # (by Rack).
95
95
  #
96
96
  # @example with a block
97
- # Person.find('name: kalle') {|query| puts "#{[*query].join(', )"}
97
+ # Person.find('name: kalle') {|query| puts "First item #{query.first}"}
98
98
  #
99
99
  # @example using an exact lucene index
100
100
  # query = Person.find('name: kalle')
@@ -109,6 +109,14 @@ module Neo4j
109
109
  # @example Sorting, descending by one property
110
110
  # Person.find({:name => 'kalle'}, :sort => {:name => :desc})
111
111
  #
112
+ # @example Sorting using the builder pattern
113
+ # Person.find(:name => 'kalle').asc(:name)
114
+ #
115
+ # @example Compound queries and Range queries
116
+ # Person.find('name: pelle').and(:age).between(2, 5)
117
+ # Person.find(:name => 'kalle', :age => (2..5))
118
+ # Person.find("name: 'asd'").and(:wheels => 8)
119
+ #
112
120
  # @example Using the lucene java object
113
121
  # # using the Neo4j query method directly
114
122
  # # see, http://api.neo4j.org/1.6.1/org/neo4j/graphdb/index/ReadableIndex.html#query(java.lang.Object)
@@ -1,5 +1,5 @@
1
1
  module Neo4j
2
2
  module Core
3
- VERSION = "0.0.5"
3
+ VERSION = "0.0.6"
4
4
  end
5
5
  end
data/lib/neo4j-core.rb CHANGED
@@ -61,6 +61,7 @@ require 'neo4j-core/traversal/traverser'
61
61
  require 'neo4j-core/cypher/cypher'
62
62
  require 'neo4j-core/cypher/result_wrapper'
63
63
 
64
+ require 'neo4j/algo'
64
65
  require 'neo4j/cypher'
65
66
  require 'neo4j/node'
66
67
  require 'neo4j/relationship'
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: neo4j-core
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.5
5
+ version: 0.0.6
6
6
  platform: java
7
7
  authors:
8
8
  - Andreas Ronge
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-04-01 00:00:00 Z
13
+ date: 2012-04-03 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: neo4j-community
@@ -39,6 +39,7 @@ extra_rdoc_files:
39
39
  files:
40
40
  - lib/neo4j-core.rb
41
41
  - lib/neo4j/config.rb
42
+ - lib/neo4j/algo.rb
42
43
  - lib/neo4j/cypher.rb
43
44
  - lib/neo4j/transaction.rb
44
45
  - lib/neo4j/neo4j.rb