neo4j 1.0.0.beta.9 → 1.0.0.beta.10

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.
Files changed (67) hide show
  1. data/README.rdoc +5 -1971
  2. data/lib/neo4j/mapping/class_methods/relationship.rb +2 -2
  3. data/lib/neo4j/mapping/decl_relationship_dsl.rb +6 -1
  4. data/lib/neo4j/mapping/has_n.rb +17 -1
  5. data/lib/neo4j/node_traverser.rb +14 -1
  6. data/lib/neo4j/rails/model.rb +127 -31
  7. data/lib/neo4j/rails/tx_methods.rb +11 -0
  8. data/lib/neo4j/rails/value.rb +44 -1
  9. data/lib/neo4j/version.rb +1 -1
  10. data/lib/neo4j.rb +1 -0
  11. metadata +4 -59
  12. data/lib/neo4j.old/batch_inserter.rb +0 -144
  13. data/lib/neo4j.old/config.rb +0 -138
  14. data/lib/neo4j.old/event_handler.rb +0 -73
  15. data/lib/neo4j.old/extensions/activemodel.rb +0 -158
  16. data/lib/neo4j.old/extensions/aggregate/aggregate_enum.rb +0 -40
  17. data/lib/neo4j.old/extensions/aggregate/ext/node_mixin.rb +0 -69
  18. data/lib/neo4j.old/extensions/aggregate/node_aggregate.rb +0 -8
  19. data/lib/neo4j.old/extensions/aggregate/node_aggregate_mixin.rb +0 -331
  20. data/lib/neo4j.old/extensions/aggregate/node_aggregator.rb +0 -216
  21. data/lib/neo4j.old/extensions/aggregate/node_group.rb +0 -43
  22. data/lib/neo4j.old/extensions/aggregate/prop_group.rb +0 -30
  23. data/lib/neo4j.old/extensions/aggregate/property_enum.rb +0 -24
  24. data/lib/neo4j.old/extensions/aggregate/props_aggregate.rb +0 -8
  25. data/lib/neo4j.old/extensions/aggregate/props_aggregate_mixin.rb +0 -31
  26. data/lib/neo4j.old/extensions/aggregate/props_aggregator.rb +0 -80
  27. data/lib/neo4j.old/extensions/aggregate.rb +0 -12
  28. data/lib/neo4j.old/extensions/find_path.rb +0 -117
  29. data/lib/neo4j.old/extensions/graph_algo/all_simple_paths.rb +0 -133
  30. data/lib/neo4j.old/extensions/graph_algo/neo4j-graph-algo-0.3.jar +0 -0
  31. data/lib/neo4j.old/extensions/graph_algo.rb +0 -1
  32. data/lib/neo4j.old/extensions/reindexer.rb +0 -104
  33. data/lib/neo4j.old/extensions/rest/rest.rb +0 -336
  34. data/lib/neo4j.old/extensions/rest/rest_mixin.rb +0 -193
  35. data/lib/neo4j.old/extensions/rest/server.rb +0 -50
  36. data/lib/neo4j.old/extensions/rest/stubs.rb +0 -141
  37. data/lib/neo4j.old/extensions/rest.rb +0 -21
  38. data/lib/neo4j.old/extensions/rest_master.rb +0 -34
  39. data/lib/neo4j.old/extensions/rest_slave.rb +0 -31
  40. data/lib/neo4j.old/extensions/tx_tracker.rb +0 -392
  41. data/lib/neo4j.old/indexer.rb +0 -187
  42. data/lib/neo4j.old/jars/geronimo-jta_1.1_spec-1.1.1.jar +0 -0
  43. data/lib/neo4j.old/jars/neo4j-kernel-1.0.jar +0 -0
  44. data/lib/neo4j.old/jars.rb +0 -6
  45. data/lib/neo4j.old/mixins/java_list_mixin.rb +0 -139
  46. data/lib/neo4j.old/mixins/java_node_mixin.rb +0 -205
  47. data/lib/neo4j.old/mixins/java_property_mixin.rb +0 -169
  48. data/lib/neo4j.old/mixins/java_relationship_mixin.rb +0 -60
  49. data/lib/neo4j.old/mixins/migration_mixin.rb +0 -157
  50. data/lib/neo4j.old/mixins/node_mixin.rb +0 -249
  51. data/lib/neo4j.old/mixins/property_class_methods.rb +0 -265
  52. data/lib/neo4j.old/mixins/rel_class_methods.rb +0 -167
  53. data/lib/neo4j.old/mixins/relationship_mixin.rb +0 -103
  54. data/lib/neo4j.old/neo.rb +0 -247
  55. data/lib/neo4j.old/node.rb +0 -49
  56. data/lib/neo4j.old/reference_node.rb +0 -15
  57. data/lib/neo4j.old/relationship.rb +0 -85
  58. data/lib/neo4j.old/relationships/decl_relationship_dsl.rb +0 -164
  59. data/lib/neo4j.old/relationships/has_list.rb +0 -101
  60. data/lib/neo4j.old/relationships/has_n.rb +0 -129
  61. data/lib/neo4j.old/relationships/node_traverser.rb +0 -138
  62. data/lib/neo4j.old/relationships/relationship_dsl.rb +0 -149
  63. data/lib/neo4j.old/relationships/traversal_position.rb +0 -50
  64. data/lib/neo4j.old/relationships/wrappers.rb +0 -51
  65. data/lib/neo4j.old/search_result.rb +0 -72
  66. data/lib/neo4j.old/transaction.rb +0 -254
  67. data/lib/neo4j.old/version.rb +0 -3
data/README.rdoc CHANGED
@@ -1,6 +1,8 @@
1
1
  = Neo4j.rb
2
2
 
3
3
  Neo4j.rb is a graph database for JRuby.
4
+
5
+
4
6
 
5
7
  It provides:
6
8
  * Mapping of ruby objects to nodes in networks rather than in tables.
@@ -17,16 +19,15 @@ It uses two powerful and mature Java libraries:
17
19
  * Neo4J (http://www.neo4j.org/) - for persistence and traversal of the graph
18
20
  * Lucene (http://lucene.apache.org/java/docs/index.html) for querying and indexing.
19
21
 
20
- === Status
21
- * There are over 500 RSpecs.
22
- * Has been tested with rails applications, used Neo4j.rb instead of ActiveRecord
22
+ === Documentation
23
+ * Wiki: http://github.com/andreasronge/neo4j/wiki
24
+ * API Documentation - http://neo4j.rubyforge.org/ (of the released version)
23
25
 
24
26
  === Project information
25
27
  * GitHub - http://github.com/andreasronge/neo4j/tree/master
26
28
  * Issue Tracking - http://neo4j.lighthouseapp.com
27
29
  * Twitter - http://twitter.com/ronge
28
30
  * IRC - #neo4j @ irc.freenode.net
29
- * API Documentation - http://neo4j.rubyforge.org/ (of the released version)
30
31
  * Source repo - git://github.com/andreasronge/neo4j.git
31
32
  * Mailing list - http://groups.google.com/group/neo4jrb (neo4jrb@googlegroups.com)
32
33
 
@@ -46,1970 +47,3 @@ Please also check/add issues at lighthouse, http://neo4j.lighthouseapp.com
46
47
  * Neo4j.rb - MIT, see the LICENSE file http://github.com/andreasronge/neo4j/tree/master/LICENSE.
47
48
  * Lucene - Apache, see http://lucene.apache.org/java/docs/features.html
48
49
  * Neo4j - Dual free software/commercial license, see http://neo4j.org/
49
-
50
- === Content
51
- This page contains the following information:
52
- * Installation guide
53
- * Three Minute Tutorial
54
- * Ten Minute Tutorial
55
- * Neo4j API Documentation
56
- * Extensions: REST (see Neo4j::RestMixin) and find_path (Neo4j::GraphAlgo::AllSimplePaths)
57
- * Performance issues
58
- * Ruby on Rails with Neo4j.rb
59
- * Lucene API Documentation
60
-
61
- There are also some complete examples in the example folder
62
- * admin - an incomplete admin web gui for the Neo4j.rb/REST interface
63
- * railway - an example of a railway network application
64
- * imdb - an example of a Neo4j database consisting of movies, role and actors nodes/relationships (over 18000 nodes).
65
- * rest - an example how to expose Neo4j nodes as REST resources
66
- * Ruby on Rails - see http://github.com/andreasronge/neo4j-rails-example/tree/master or http://github.com/sashaagafonoff/peoplemap
67
- * Rails3/ActiveModel integration see: http://github.com/nicksieger/neo4j-rails
68
-
69
- For most of the examples below there are RSpecs available, check the test/neo4j/readme_spec.rb file.
70
-
71
- == Installation
72
-
73
- To install it:
74
-
75
- jruby -S gem install neo4j
76
-
77
- To install from the latest source:
78
- git clone git://github.com/andreasronge/neo4j.git
79
- cd neo4j
80
- gem install bundler # only needed for development
81
- bundle install # to install all test dependencies needed for development
82
- gem build rspec-apigen.gemspec
83
- gem install neo4j-x.y.z.gem
84
-
85
- This has been verified to work on JRuby 1.5.2
86
-
87
- ==== Running all RSpecs
88
-
89
- To check that neo4j.rb is working:
90
-
91
- cd neo4j # the folder containing the Rakefile
92
- rake # you may have to type jruby -S rake depending how you installed JRuby
93
-
94
-
95
- = Three Minute Tutorial
96
-
97
- Neo node space consists of three basic elements: nodes, relationships that connect nodes and properties attached
98
- to both nodes and relationships. All relationships have a type, for example if the node space represents
99
- a social network, a relationship type could be KNOWS. If a relationship of the type KNOWS connects two nodes,
100
- that probably represents two people that know each other. A lot of the semantics, the meaning, of a node space
101
- is encoded in the relationship types of the application.
102
-
103
- === Creating Nodes
104
-
105
- Example of creating a Neo4j::Node
106
-
107
- require "rubygems"
108
- require 'neo4j'
109
-
110
- Neo4j::Transaction.run do
111
- node = Neo4j::Node.new
112
- end
113
-
114
- === Transactions
115
-
116
- Almost all Neo4j operation must be wrapped in a transaction as shown above.
117
- In all the following examples we assume that the operations are inside an Neo4j transaction.
118
- There are two ways of creating transaction - in a block or the Transaction.new method
119
-
120
- Using a block:
121
-
122
- Neo4j::Transaction.run do
123
- # neo4j operations goes here
124
- end
125
-
126
- Using the Neo4j::Transaction#new and Neo4j::Transaction#finish methods:
127
-
128
- Neo4j::Transaction.new
129
- # neo4j operations goes here
130
- Neo4j::Transaction.finish
131
-
132
- === Properties
133
-
134
- Example of setting properties
135
-
136
- Neo4j::Node.new :name=>'foo', :age=>123, :hungry => false, 4 => 3.14
137
- # which is same as the following:
138
- node = Neo4j::Node.new
139
- node[:name] = 'foo'
140
- node[:age] = 123
141
- node[:hungry] = false
142
- node[4] = 3.14
143
- node[:age] # => 123
144
-
145
- === Creating Relationships
146
- Example of creating an outgoing Neo4j::Relationship from node1 to node2 of type friends
147
-
148
- node1 = Neo4j::Node.new
149
- node2 = Neo4j::Node.new
150
- Neo4j::Relationship.new(:friends, node1, node2)
151
-
152
- # which is same as
153
- node1.rels.outgoing(:friends) << node2
154
-
155
- === Accessing Relationships
156
- Example of getting relationships
157
-
158
- node1.rels.empty? # => false
159
-
160
- # The rels method returns an enumeration of relationship objects.
161
- # The nodes method on the relationships returns the nodes instead.
162
- node1.rels.nodes.include?(node2) # => true
163
-
164
- node1.rels.first # => the first relationship this node1 has which is between node1 and node2 of any type
165
- node1.rels.nodes.first # => node2 first node of any relationship type
166
- node2.rels.incoming(:friends).nodes.first # => node1 first node of relationship type 'friends'
167
- node2.rels.incoming(:friends).first # => a relationship object between node1 and node2
168
-
169
- === Properties on Relationships
170
- Example of setting properties on relationships
171
-
172
- rel = node1.rels.outgoing(:friends).first
173
- rel[:since] = 1982
174
- node1.rels.first[:since] # => 1982 (there is only one relationship defined on node1 in this example)
175
-
176
- = Ten Minute Tutorial
177
-
178
- === Creating a Model
179
-
180
- The following example specifies how to map a Neo4j node to a Ruby Person instance.
181
-
182
- require "rubygems"
183
- require "neo4j"
184
-
185
- class Person
186
- include Neo4j::NodeMixin
187
-
188
- # define Neo4j properties
189
- property :name, :salary, :age, :country
190
-
191
- # define an one way relationship to any other node
192
- has_n :friends
193
-
194
- # adds a Lucene index on the following properties
195
- index :name, :salary, :age, :country
196
- end
197
-
198
- Neo properties and relationships are declared using the 'property' and 'has_n'/'has_one' NodeMixin class method.
199
- Adding new types of properties and relationships can also be done without
200
- declaring those properties/relationships by using the operator '[]' on Neo4j::NodeMixin and the
201
- '<<' on the Neo4j::Relationships::RelationshipTraverser.
202
-
203
- By using the NodeMixin and by declaring properties and indices, all instances of the Person class can now be stored in
204
- the Neo4j node space and be retrieved/queried by traversing the node space or performing Lucene queries.
205
-
206
- A Lucene index will be updated when the name or salary property changes.
207
-
208
- === Creating a node
209
-
210
- Creating a Person node instance
211
-
212
- person = Person.new
213
-
214
- === Setting properties
215
-
216
- Setting a property:
217
-
218
- person.name = 'kalle'
219
- person.salary = 10000
220
-
221
- You can also set this (or any property) when you create the node:
222
-
223
- person = Person.new :name => 'kalle', :salary => 10000, :foo => 'bar'
224
-
225
-
226
- === Properties and the [] operator
227
- Notice that it is not required to specify which attributes should be available on a node. Any attributes can be
228
- set using the [] operator. Declared properties set an expectation, not an requirement. It can be used for documenting your model objects and
229
- catching typos.
230
-
231
- Example:
232
-
233
- person['an_undefined_property'] = 'hello'
234
-
235
- So, why declare properties in the class at all? By declaring a property in the class, you get the sexy dot notation.
236
- But also, if you declare a Lucene index on the declared property and update the value, then the Lucene index will
237
- automatically be updated. The property declaration is required before declaring an index on the property.
238
-
239
- === Relationships
240
- Like properties, relationships do not have to be defined using has_n or has_one for a class.
241
- A relationship can be added at any time on any node.
242
-
243
- Example:
244
-
245
- person.rels.outgoing(:best_friends) << other_node
246
- person.rels.outgoing(:best_friends).first.end_node # => other_node (if there is only one relationship of type 'best_friends' on person)
247
- # the line above can also be written as below - take the first outgoing relationship:
248
- person.rel(:best_friends).end_node
249
-
250
-
251
- === Finding Nodes and Queries
252
-
253
- There are three ways of finding/querying nodes in Neo4j:
254
- 1. by traversing the graph
255
- 2. by using Lucene queries
256
- 3. using the unique neo4j id (Neo4j::NodeMixin#neo_id).
257
-
258
- When doing a traversal one starts from a node and traverses one or more relationships (one or more levels deep).
259
- This start node can be either the reference node which is always found (Neo4j#ref_node) or by finding a start
260
- node from a Lucene query.
261
-
262
- === Lucene Queries
263
-
264
- There are different ways to write Lucene queries.
265
- Using a hash:
266
- Person.find (:name => 'kalle', :salary => 20000..30000) # find people with name kalle and age between 20 and 30
267
-
268
- or using the Lucene query language:
269
-
270
- Person.find("name:kalle AND salary:[10000 TO 30000]")
271
-
272
- The Lucene query language supports wildcard, grouping, boolean, fuzzy queries, etc...
273
- For more information see: http://lucene.apache.org/java/2_4_0/queryparsersyntax.html
274
-
275
- === Sorting, example
276
-
277
- Person.find(:age => 25).sort_by(:salary)
278
- Person.find(:age => 25).sort_by(Lucene::Desc[:salary], Lucene::Asc[:country])
279
- Person.find(:age => 25).sort_by(Lucene::Desc[:salary, :country])
280
-
281
- === Search Results
282
-
283
- The query is not performed until the search result is requested.
284
- Example of using the search result.
285
-
286
- res = Person.find(:name => 'kalle')
287
- res.size # => 10
288
- res.each {|x| puts x.name}
289
- res[0].name = 'sune'
290
-
291
- === Creating a Relationships
292
-
293
- Since we declared a relationship in the example above with <tt>has_n :friends</tt> (see Neo4j::RelClassMethods#has_n) we
294
- can use the generated methods <tt>Person#friends</tt> and <tt>Person#friends_rels</tt>
295
- The <tt>friends_rels</tt> method is used to access relationships and the <tt>Person#friends</tt>
296
- method for accessing nodes.
297
-
298
- Adding a relationship between two nodes:
299
-
300
- person2 = Person.new
301
- person.friends << person2
302
-
303
- The person.friends returns an object that has a number of useful methods (it also includes the Enumerable mixin).
304
- Example
305
-
306
- person.friends.empty? # => false
307
- person.friends.first # => person2
308
- person.friends.include?(person2) # => true
309
-
310
-
311
- === Deleting a Relationship
312
-
313
- To delete the relationship between person and person2:
314
-
315
- person.friends_rels.first.del
316
-
317
- If a node is deleted then all its relationship will also be deleted
318
- Deleting a node is performed by using the delete method:
319
-
320
- person.del
321
-
322
- === Node Traversals
323
-
324
- The has_one and has_many methods create a convenient method for traversals and
325
- managing relationships to other nodes.
326
- Example:
327
-
328
- Person.has_n :friends # generates the friends instance method
329
- # all instances of Person now has a friends method so that we can do the following
330
- person.friends.each {|n| ... }
331
-
332
- Traversing using a filter
333
-
334
- person.friends{ salary == 10000 }.each {|n| ...}
335
-
336
- Traversing with a specific depth (depth 1 is default)
337
-
338
- person.friends{ salary == 10000}.depth(3).each { ... }
339
-
340
- There is also a more powerful method for traversing several relationships at
341
- the same time - Neo4j::NodeMixin#traverse, Neo4j::JavaNodeMixin#outgoing and Neo4j::JavaNodeMixin:incoming see below.
342
-
343
- === Example on Relationships
344
-
345
- In the first example the friends relationship can have relationships to any
346
- other node of any class.
347
- In the next example we specify that the 'acted_in' relationship should use
348
- the Ruby classes Actor, Role and Movie.
349
- This is done by using the has_n class method:
350
-
351
- class Role
352
- include Neo4j::RelationshipMixin
353
- # notice that neo4j relationships can also have properties
354
- property :name
355
- end
356
-
357
- class Actor
358
- include Neo4j::NodeMixin
359
-
360
- # The following line defines the acted_in relationship
361
- # using the following classes:
362
- # Actor[Node] --(Role[Relationship])--> Movie[Node]
363
- #
364
- has_n(:acted_in).to(Movie).relationship(Role)
365
- end
366
-
367
- class Movie
368
- include Neo4j::NodeMixin
369
- property :title
370
- property :year
371
-
372
- # defines a method for traversing incoming acted_in relationships from Actor
373
- has_n(:actors).from(Actor, :acted_in)
374
- end
375
-
376
- Creating a new Actor-Role-Movie relationship can be done like this:
377
-
378
- keanu_reeves = Actor.new
379
- matrix = Movie.new
380
- keanu_reeves.acted_in << matrix
381
-
382
- or you can also specify this relationship on the incoming node
383
- (since we provided that information in the has_n methods).
384
-
385
- keanu_reeves = Actor.new
386
- matrix = Movie.new
387
- matrix.actors << keanu_reeves
388
-
389
- More information about neo4j can be found after the Lucene section below.
390
-
391
- = Neo4j API Documentation
392
-
393
- === Start and Stop of the Neo4j
394
-
395
- Unlike the Java Neo4j implementation it is not necessarily to start Neo4j.
396
- It will automatically be started when needed.
397
- It also uses a hook to automatically shutdown Neo4j.
398
- Shutdown of Neo4j can also be done using the stop method, example:
399
-
400
- Neo4j.stop
401
-
402
- ==== Neo4j Configuration
403
-
404
- Before using Neo4j the location where the database is stored on disk should be configured.
405
- The Neo4j configuration is kept in the Neo4j::Config class:
406
-
407
- Neo4j::Config[:storage_path] = '/home/neo/neodb'
408
-
409
- ==== Accessing the Java Neo4j API
410
-
411
- You can access the org.neo4j.kernel.EmbeddedGraphDatabase class by
412
-
413
- Neo4j.instance
414
-
415
- You can create an org.neo4j.graphdb.Node object by using the Neo4j::Node.new method (!)
416
-
417
- node = Neo4j::Node.new # => an instance of org.neo4j.graphdb.Node
418
-
419
- To load a specific node by its ID (see javadoc org.neo4j.graphdb.Node.getId()), do
420
-
421
- node_id = node.neo_id
422
- ref_node = Neo4j.load_node(node_id)
423
-
424
- The neo_id method works both for the Neo4j::NodeMixin and for org.neo4j.graphdb.Node java objects.
425
-
426
- You can create a relationship of type org.neo4j.graphdb.Relationship by
427
-
428
- a = Neo4j::Node.new
429
- b = Neo4j::Node.new
430
- r = a.add_rel(:friends, b)
431
- r.java_class # => class org.neo4j.kernel.impl.core.RelationshipProxy
432
-
433
- === Lucene Integration
434
-
435
- Neo4j.rb uses the Lucene module. That means that the Neo4j::NodeMixin has methods for
436
- both traversal and Lucene queries/indexing.
437
-
438
- ==== Lucene Configuration
439
-
440
- By default Lucene indexes are kept in memory.
441
- Keeping index in memory will increase the performance of Lucene operations (such as updating the index).
442
-
443
- Example to configure Lucene to store indexes on disk instead
444
-
445
- Lucene::Config[:store_on_file] = true
446
- Lucene::Config[:storage_path] = '/home/neo/lucene-db'
447
-
448
- ==== Lucene Index in Memory
449
-
450
- If index is stored in memory then one needs to reindex all nodes when the application starts up again.
451
-
452
- MyNode.update_index # will traverse all MyNode instances and (re)create the Lucene index in memory.
453
-
454
- === Neo4j::NodeMixin
455
-
456
- Neo4j::NodeMixin is a mixin that lets instances to be stored as a node in the Neo node space on disk.
457
- A node can have properties and relationships to other nodes.
458
-
459
- Example of how declare a class that has this behaviour:
460
-
461
- class MyNode
462
- include Neo4j::NodeMixin
463
- end
464
-
465
-
466
- === Neo4j::Node
467
-
468
- If you do not need to map a node to a ruby instance you can simply use the Neo4j::Node object.
469
-
470
- Example:
471
-
472
- node = Neo4j::Node.new
473
- node[:name] = 'foo'
474
-
475
- The Neo4j::Node.new method actually returns a Java object that implements the org.neo4j.graphdb.Node interface.
476
- That Java interface is extended with methods so it behaviors almost like using the your own Ruby Neo4j::NodeMixin class.
477
-
478
- === Create a Node
479
-
480
- node = MyNode.new
481
-
482
- === Delete a Node
483
-
484
- The Neo4j::NodeMixin mixin defines a delete method that will delete the node and all its relationships.
485
-
486
- Example:
487
-
488
- node = MyNode.new
489
- node.del
490
-
491
- The node in the example above will be removed from the Neo database on the filesystem and the Lucene index
492
-
493
- ==== Neo4j::Node#del method
494
-
495
- Since one can both use the org.neo4j.graphdb.Node directly or using the Neo4j::NodeMixin there might be a clash
496
- in method names.
497
- For example the method Neo4j::NodeMixin#del deletes the node and all its relationships.
498
- The org.neo4j.graphdb.Node#delete (which is created by Neo4j::Node.new) will raise an exception if not all relationships are already deleted.
499
-
500
-
501
- === Node and Relationship Identity
502
-
503
- Each node has an unique identity (neo_id) which can be used for loading the node:
504
-
505
- id = Neo4j::Node.new.neo_id
506
- Neo4j.load_node(id) # will return the node that was created above
507
-
508
- And for relationships:
509
-
510
- rel = Neo4j::Node.new.add_rel(:some_relationship_type, Neo4j::Node.new)
511
- id = rel.neo_id
512
- # Load the node
513
- Neo4j.load_rel(id) # will return the relationship (rel) that was created above
514
-
515
- === Node Properties
516
-
517
- In order to use properties they have to be declared first
518
-
519
- class MyNode
520
- include Neo4j::NodeMixin
521
- property :foo, :bar
522
- end
523
-
524
- These properties (foo and bar) will be stored in the Neo database.
525
- You can set those properties:
526
-
527
- # create a node with two properties in one transaction
528
- node = MyNode.new { |n|
529
- n.foo = 123
530
- n.bar = 3.14
531
- }
532
-
533
- # access those properties
534
- puts node.foo
535
-
536
-
537
- You can also set a property like this:
538
-
539
- f = SomeNode.new
540
- f.foo = 123
541
-
542
- Neo4j.rb supports properties to by of type String, Fixnum, Float and true/false
543
-
544
- === Property Types and Marshalling
545
-
546
- If you want to set a property of a different type then String, Fixnum, Float or true/false
547
- you have to specify its type.
548
-
549
- Example, to set a property to any type
550
-
551
- class MyNode
552
- include Neo4j::NodeMixin
553
- property :foo, :type => Object
554
- end
555
-
556
-
557
- node = MyNode.new
558
- node.foo = [1,"3", 3.14]
559
-
560
- Neo4j.load_node(node.neo_id).foo.class # => Array
561
-
562
-
563
- === Property of type Date and DateTime
564
-
565
- Example of using Date queries:
566
-
567
- class MyNode
568
- include Neo4j::NodeMixin
569
- property :born, :type => Date
570
- index :born, :type => Date
571
- end
572
-
573
- Neo4j::Transaction.run do
574
- node = MyNode.new
575
- node.born = Date.new 2008, 05, 06
576
- end
577
-
578
- Neo4j::Transaction.run do
579
- MyNode.find("born:[20080427 TO 20100203]")[0].born # => Date
580
- end
581
-
582
- Example of using DateTime queries:
583
-
584
- class MyNode
585
- include Neo4j::NodeMixin
586
- property :since, :type => DateTime
587
- index :since, :type => DateTime
588
- end
589
-
590
- Neo4j::Transaction.run do
591
- node = MyNode.new
592
- node.since = DateTime.civil 2008, 04, 27, 15, 25, 59
593
- end
594
-
595
- Neo4j::Transaction.run do
596
- MyNode.find("since:[200804271504 TO 201002031534]")[0].since # => DateTime
597
- end
598
-
599
- Only UTC timezone is allowed.
600
- Notice that the query must be performed in a new transaction.
601
-
602
- === Finding all nodes
603
-
604
- To find all nodes use the Neo4j#all_nodes method.
605
-
606
- Example
607
-
608
- Neo4j.all_nodes{|node| puts node}
609
-
610
- === Declared Relationships
611
-
612
- Neo relationships are asymmetrical. That means that if A has a relationship to B
613
- then it may not be true that B has a relationship to A.
614
-
615
- Relationships can be declared by using 'has_n', 'has_one' or 'has_list' Neo4j::RelClassMethods methods (included in the Neo4j::NodeMixin).
616
-
617
- This methods generates accessor methods for relationships.
618
- By using those accessor methods we do no longer need to know which direction to navigate in the relationship.
619
- There are accessor methods for both relationships and nodes.
620
-
621
- The 'has_n', 'has_one' or 'has_list' Neo4j::RelClassMethods methods returns a Neo4j::Relationships::DeclRelationshipDsl.
622
-
623
- === has_n
624
-
625
- The Neo4j::NodeMixin#has_n class method (see Neo4j::RelClassMethods#has_n) creates a new instance method that can
626
- be used for both traversing and adding new objects to a specific relationship type.
627
- The has_n method returns a DSL object Neo4j::Relationships::DeclRelationshipDsl
628
-
629
- For example, let say that Person can have a relationship to any other node class with the type 'friends':
630
-
631
- class Person
632
- include Neo4j::NodeMixin
633
- has_n :knows # will generate a knows method for outgoing relationships
634
- end
635
-
636
- The generated knows method will allow you to add new relationships, example:
637
-
638
- me = Person.new
639
- neo = Person.new
640
- me.knows << neo # me knows neo but neo does not know me
641
-
642
- You can add any object to the 'knows' relationship as long as it
643
- includes the Neo4j::NodeMixin or is an org.neo4j.core.api.Node object, example:
644
-
645
- person = Person.new
646
- another_node = Neo4j::Node.new
647
- person.knows << another_node
648
-
649
- person.knows.include?(another_node) # => true
650
-
651
- ==== has_n to an outgoing class
652
-
653
- If you want to express that the relationship should point to a specific class
654
- use the 'to' method on the has_n method.
655
- (It's still possible to add any nodes to the relationship - no validation is performed)
656
-
657
- class Person
658
- include Neo4j::NodeMixin
659
- has_n(:knows).to(Person)
660
- end
661
-
662
- The difference between specifying a 'to' class and not doing that is that Neo4j.rb will create relationships of type
663
- 'Person#knows'.
664
-
665
- Example:
666
- a = Person.new
667
- b = Neo4j::Node.new
668
- a.knows << b
669
-
670
- # is the same as
671
- a.add_rel('Person#knows', b)
672
-
673
- The given class 'Person' will act like a name space for the relationship 'knows'.
674
-
675
- ==== has_n from an incoming class
676
-
677
- It's also possible to generate methods for incoming relationships by using the
678
- 'from' method on the has_n method.
679
-
680
- Example:
681
- class Person
682
- include Neo4j::NodeMixin
683
- has_n :knows # will generate a knows method for outgoing relationships
684
- has_n(:known_by).from(Person, :knows) # will generate a known_by method for incoming knows relationship
685
- end
686
-
687
- In the example above we can find outgoing nodes using the 'knows' method and incoming relationships using the 'known_by' method.
688
-
689
- Example:
690
-
691
- person = Person.new
692
- other_person = Person.new
693
- person.knows << other_person
694
- other_person.known_by.include?(person) # => true
695
-
696
- You can also add a relationships on either the incoming or outgoing node.
697
- The from method can also take an additional class parameter if it has incoming nodes
698
- from a different node class (see the Actor-Role-Movie example at the top of this document).
699
-
700
- Example of adding a 'knows' relationship from the other node:
701
-
702
- me = Person.new
703
- neo = Person.new
704
- neo.known_by << me
705
-
706
- # me knows neo but neo does not know me
707
- me.knows.include?(neo) # => true
708
- neo.knows.include?(me) # => false
709
-
710
- The known_by method creates a 'knows' relationship between the me and neo nodes.
711
- This is the same as doing:
712
-
713
- me.knows << neo # me knows neo but neo does not know me
714
-
715
- ==== has_n from an incoming class with 'namespace'
716
-
717
- In the example above we only provided the parameter :knows for the from method. That means that incoming relationship of type 'knows' will
718
- be accessible with the known_by method.
719
- The following many-to-many example demonstrates how to specify a from class.
720
-
721
- class Product
722
- include Neo4j::NodeMixin
723
- has_n(:orders).to(Order)
724
- end
725
-
726
- class Order
727
- include Neo4j::NodeMixin
728
- has_n(:products).from(Product, :orders)
729
- end
730
-
731
- Then you can add an order on the Product object or add an Product on the Order object.
732
-
733
- p = Product.new
734
- o = Order.new
735
- o.products << p
736
-
737
- Which is the same as
738
-
739
- p = Product.new
740
- o = Order.new
741
- p.orders << o
742
-
743
- Notice that we must provide the class name of the from method since we use the 'namespace' Order for the outgoing orders relationship.
744
-
745
- ==== Accessing Declared Relationships
746
-
747
- Neo4j.rb generates methods for accessing declared relationship.
748
- Example, let say that class Product declares a relationship 'order' to class Order.
749
-
750
- class Product
751
- include Neo4j::NodeMixin
752
- has_n(:orders).to(Order)
753
- end
754
-
755
- To access the relationships between Product and Order without specifying the 'Order#' namespace
756
- one can use the '<rel type>_rels' method.
757
-
758
- Example:
759
-
760
- product = Product.new
761
- order = Order.new
762
- product.orders << order
763
- prod_order_relationship = product.orders_rels.first
764
- prod_order_relationship.start_node # => product
765
- prod_order_relationship.end_node # => order
766
-
767
- For a has_one relationship the '<rel type>_rel' method will be generated instead.
768
- This work for both incoming and outgoing nodes.
769
-
770
- === Relationship has_one
771
-
772
- Example: A person can have at most one Address
773
-
774
- class Address; end
775
-
776
- class Person
777
- include Neo4j::NodeMixin
778
- has_one(:address).to(Address)
779
- end
780
-
781
- class Address
782
- include Neo4j::NodeMixin
783
- property :city, :road
784
- has_n(:people).from(Person, :address)
785
- end
786
-
787
- In the example above we have Neo4j.rb will generate the following methods
788
- * in Person, the method ''address='' and ''address''
789
- * in Address, the traversal method ''people'' for traversing incoming relationships from the Person node.
790
-
791
- Example of usage:
792
-
793
- p = Person.new
794
- p.address = Address.new
795
- p.address.city = 'malmoe'
796
- p.address.people.include?(p) # => true
797
-
798
- Or from the incoming ''address'' relationship
799
-
800
- a = Address.new {|n| n.city = 'malmoe'}
801
- a.people << Person.new
802
- a.people.first.address # => a
803
-
804
- For more documentation see the Neo4j::RelClassMethods#has_one.
805
-
806
- === Relationship has_list
807
- The has_n relationship will not maintain the order of when items are inserted to the relationship.
808
- If order should be preserved then use the has_list class method instead.
809
-
810
- Example
811
-
812
- class Company
813
- include Neo4j::NodeMixin
814
- has_list :employees
815
- end
816
-
817
- company = Company.new
818
- company.employees << employee1 << employee2
819
-
820
- # prints first employee2 and then employee1
821
- company.employees.each {|employee| puts employee.name}
822
-
823
- If the optional parameter :size is given then the list will contain a size counter.
824
-
825
- Example
826
-
827
- class Company
828
- has_list :employees, :counter => true
829
- end
830
-
831
- company = Company.new
832
- company.employees << employee1 << employee2
833
- company.employees.size # => 2
834
-
835
- For more documentation see the Neo4j::RelClassMethods#has_list.
836
-
837
- ==== Deleted List Items
838
-
839
- The list will be updated if an item is deleted in a list.
840
- Example:
841
-
842
- company = Company.new
843
- company.employees << employee1 << employee2 << employee3
844
- company.employees.size # => 3
845
-
846
- employee2.del
847
-
848
- company.employees.to_a # => [employee1, employee3]
849
- company.employees.size # => 2
850
-
851
- ==== Memberships in lists
852
-
853
- Each node in a list knows which lists it belongs to, and the next and previous item in the list
854
- Example:
855
-
856
- employee1.list(:employees).prev # => employee2
857
- employee2.list(:employees).next # => employee1
858
- employee1.list(:employees).size # => 3 # the size counter is available if the :counter parameter is given as shown above
859
-
860
-
861
- (The list method takes an optional extra parameter - the list node. Needed if one node is member of more then one list with the same name).
862
-
863
- === Cascade delete
864
-
865
- The has_one, has_n and has_list all support cascade delete.
866
- There are two types of cascade delete - incoming and outgoing.
867
- For an outgoing cascade delete the members (of the has_one/has_n/has_list) will all be deleted when the
868
- 'root' node is deleted. For incoming cascade the 'root' node will be deleted when all its members are deleted.
869
-
870
- Example, outgoing
871
-
872
- class Person
873
- include Neo4j::NodeMixin
874
- has_list :phone_nbr, :cascade_delete => :outgoing
875
- end
876
-
877
- p = Person.new
878
- phone1 = Neo4j::Node.new
879
- phone1[:number] = '+46123456789'
880
- p.phone_nbr << phone1
881
- p.phone_nbr << phone2
882
-
883
- p.del
884
-
885
- # then phone1 and phone2 node will also be deleted.
886
-
887
- Example, incoming
888
-
889
- class Phone
890
- include Neo4j::NodeMixin
891
- has_list :people, :cascade_delete => :incoming # a list of people having this phone number
892
- end
893
-
894
- phone1 = Phone.new
895
- p1 = Person.new
896
- p2 = person.new
897
- phone1.people << p1
898
- phone1.people << p2
899
-
900
- p1.del
901
- p2.del
902
-
903
- # then phone1 will be deleted
904
-
905
-
906
- === Finding all nodes
907
-
908
- To find all nodes of a specific type use the all method.
909
-
910
- Example
911
-
912
- require 'neo4j/extensions/reindexer'
913
-
914
- class Car
915
- include Neo4j::NodeMixin
916
- property :wheels
917
- end
918
-
919
- class Volvo < Car
920
- end
921
-
922
- v = Volvo.new
923
- c = Car.new
924
-
925
- Car.all # will return all relationships from the reference node to car objects
926
- Volvo.all # will return the same as Car.all
927
-
928
- To return nodes (just like the relationships method)
929
-
930
- Car.all.nodes # => [c,v]
931
- Volvo.all.nodes # => [v]
932
-
933
-
934
- The reindexer extension that is used in the example above will for each created node create a relationship
935
- from the index node (Neo4j#ref_node.relationships.outgoing(:index_node)) to that new node.
936
- The all method use these relationships in order to return nodes of a certain class.
937
- The update_index method also uses this all method in order to update index for all nodes of a specific class.
938
-
939
- === Traversing Relationships
940
-
941
- Each type of relationship has a method that returns an Enumerable object that enables you
942
- to traverse that type of relationship.
943
-
944
- For example the Person example above declares one relationship of type friends.
945
- You can traverse all Person's friends (depth 1 is default)
946
-
947
- f.friends.each { |n| puts n }
948
-
949
- It is also possible to traverse a relationship of an arbitrary depth.
950
- Example finding all friends and friends friends.
951
-
952
- f.friends.depth(2).each { ...}
953
-
954
- Traversing to the end of the graph
955
-
956
- f.friends.depth(:all).each { ...}
957
-
958
- ==== Filtering Nodes
959
-
960
- If you want to find one node in a relationship you can use a filter.
961
- Example, let say we want to find a friend with name 'andreas'
962
-
963
- n1 = Person.new
964
- n2 = Person.new :name => 'andreas'
965
- n3 = Person.new
966
- n1.friends << n2 << n3
967
- n1.friends{ name == 'andreas' }.to_a # => [n2]
968
-
969
- The block { name == 'andreas' } will be evaluated on each node in the relationship.
970
- If the evaluation returns true the node will be included in the filter search result.
971
-
972
- === Traversing Nodes
973
-
974
- The Neo4j::NodeMixin#incoming and Neo4j::NodeMixin#outgoing method are a more powerful methods compared to the
975
- generated has_n and has_one methods. Unlike the generated methods it can
976
- traverse several relationship types at the same time. The types of relationships
977
- being traversed must therefore always be specified in the incoming, outgoing or both method.
978
- The three methods can take one or more relationship types parameters
979
- if more than one type of relationship should be traversed.
980
-
981
- ==== Traversing Nodes of Arbitrary Depth
982
-
983
- The depth method allows you to specify how deep the traversal should be.
984
- If not specified, only one level is traversed.
985
-
986
- Example:
987
-
988
- me.incoming(:friends).depth(4).each {} # => people with a friend relationship to me
989
-
990
- ==== Traversing Nodes With Several Relationship Types
991
-
992
- It is possible to traverse several relationship types at the same type.
993
- The incoming, both and outgoing methods takes a list of arguments.
994
-
995
- Example, given the following holiday trip domain:
996
-
997
- # A location contains a hierarchy of other locations
998
- # Example region (asia) contains countries which contains cities etc...
999
- class Location
1000
- include Neo4j::NodeMixin
1001
- has_n :contains
1002
- has_n :trips
1003
- property :name
1004
- index :name
1005
-
1006
- # A Trip can be specific for one global area, such as "see all of sweden" or
1007
- # local such as a 'city tour of malmoe'
1008
- class Trip
1009
- include Neo4j::NodeMixin
1010
- property :name
1011
- end
1012
-
1013
- # create all nodes
1014
- # ...
1015
-
1016
- # setup the relationship between all nodes
1017
- @europe.contains << @sweden << @denmark
1018
- @sweden.contains << @malmoe << @stockholm
1019
-
1020
- @sweden.trips << @sweden_trip
1021
- @malmoe.trips << @malmoe_trip
1022
- @malmoe.trips << @city_tour
1023
- @stockholm.trips << @city_tour # the same city tour is available both in malmoe and stockholm
1024
-
1025
- Then we can traverse both the contains and the trips relationship types.
1026
- Example:
1027
- @sweden.outgoing(:contains, :trips).to_a # => [@malmoe, @stockholm, @sweden_trip]
1028
-
1029
- It is also possible to traverse both incoming and outgoing relationships, example:
1030
-
1031
- @sweden.outgoing(:contains, :trips).incoming(:contains).to_a # => [@malmoe, @stockholm, @sweden_trip, @europe]
1032
-
1033
- ==== Traversing Nodes With a Filter
1034
-
1035
- It's possible to filter which nodes should be returned from the traverser by
1036
- using the filter function. This filter function will be evaluated differently
1037
- depending the number of arguments it takes, see below.
1038
-
1039
- ==== Filtering: Using Evaluation in the Context of the Current Node
1040
- If the provided filter function does not take any parameter it will be evaluated in the context
1041
- of the current node being traversed.
1042
- That means that one can writer filter functions like this:
1043
-
1044
- @sweden.outgoing(:contains, :trips).filter { name == 'sweden' }
1045
-
1046
- ==== Filtering: Using the TraversalPostion
1047
- If the filter method takes one parameter then it will be given an object of type
1048
- TraversalPosition which contains information about current node, how many nodes
1049
- has been returned, depth etc.
1050
-
1051
- The information contained in the TraversalPostion can be used in order to decide if the node should be included in the traversal search result.
1052
- If the provided block returns true then the node will be included in the search result.
1053
-
1054
- The filter function will not be evaluated in the context of the current node when this parameter is provided.
1055
-
1056
- The TraversalPosition is a thin wrapper around the java interface TraversalPosition, see
1057
- http://api.neo4j.org/current/org/neo4j/api/core/TraversalPosition.html
1058
-
1059
- For example if we only want to return the Trip objects in the example above:
1060
-
1061
- # notice how the tp (TraversalPosition) parameter is used in order to only
1062
- # return nodes included in a 'trips' relationship.
1063
- traverser = @sweden.outgoing(:contains, :trips).filter do |tp|
1064
- tp.last_relationship_traversed.relationship_type == :trips
1065
- end
1066
-
1067
- traverser.to_a # => [@sweden_trip]
1068
-
1069
- === Relationships
1070
-
1071
- A relationship between two nodes can have properties just like a node.
1072
-
1073
- Example:
1074
-
1075
- p1 = Person.new
1076
- p2 = Person.new
1077
-
1078
- relationship = p1.friends.new(p2)
1079
-
1080
- # set a property 'since' on this relationship between p1 and p2
1081
- relationship.since = 1992
1082
-
1083
- If a Relationship class has not been specified for a relationship then any properties
1084
- can be set on the relationship. It has a default relationship class: Neo4j::Relationships::Relationship
1085
-
1086
- If you instead want to use your own class for a relationship use the
1087
- Neo4j::NodeMixin#has_n.relationship method, example:
1088
-
1089
- class Role
1090
- # This class can be used as the relationship between two nodes
1091
- # since it includes the following mixin
1092
- include Neo4j::RelationMixin
1093
- property :name
1094
- end
1095
-
1096
- class Actor
1097
- include Neo4j::NodeMixin
1098
- # use the Role class above in the relationship between Actor and Movie
1099
- has_n(:acted_in).to(Movie).relationship(Role)
1100
- end
1101
-
1102
-
1103
- === Finding Relationships
1104
-
1105
- The Neo4j::NodeMixin#relationships method can be used to find incoming or outgoing relationship objects.
1106
- Example of listing all types of outgoing (default) relationship objects (of depth one) from the me node.
1107
-
1108
- me.relationships.each {|rel| ... }
1109
-
1110
- If we instead want to list the nodes that those relationships points to then the nodes method can be used.
1111
-
1112
- me.rels.nodes.each {|rel| ... }
1113
-
1114
- Listing all incoming relationship objects of any relationship type:
1115
-
1116
- me.rels.incoming.each { ... }
1117
-
1118
- Listing both incoming and outgoing relationship object of a specific type:
1119
-
1120
- me.rels.both(:friends) { }
1121
-
1122
- Finding one outgoing relationship of a specific type and node (you)
1123
-
1124
- me.rels.outgoing(:friends)[you] # => [#<Neo4j::RelationshipMixin:0x134ae32]
1125
-
1126
-
1127
- ==== Finding Relationships Example
1128
-
1129
- Example, given we have the two nodes with a relationship between them:
1130
-
1131
- n1 = Person.new
1132
- n2 = Person.new
1133
-
1134
- n1.friends << n2
1135
-
1136
- Then we can find all incoming and outgoing relationships like this:
1137
-
1138
- n1.rels.to_a # => [#<Neo4j::RelationshipMixin:0x134ae32]
1139
-
1140
- A Neo4j::RelationshipMixin object represents a relationship between two nodes.
1141
-
1142
- n1.rels[0].start_node # => n1
1143
- n1.rels[0].end_node # => n2
1144
-
1145
- A RelationshipMixin contains the relationship type which connects the two nodes
1146
-
1147
- n1.rels[0].relationship_type # => :friends
1148
-
1149
- Relationships can also have properties just like a node (NodeMixin).
1150
-
1151
- === Finding outgoing and incoming relationships
1152
-
1153
- If we are only interested in all incoming nodes, we can do
1154
-
1155
- n2.rels.incoming # => [#<Neo4j::RelationshipMixin:0x134aea2]
1156
-
1157
- Or outgoing:
1158
-
1159
- n1.rels.outgoing # => [#<Neo4j::RelationshipMixin:0x134aea2]
1160
-
1161
- To find a specific relationship use the [] operator:
1162
-
1163
- n1.rels.outgoing[n2] = #<Neo4j::RelationshipMixin:0x134aea2
1164
-
1165
- Or which is better performance wise (since only friends relationships are being traversed):
1166
-
1167
- n1.rels.outgoing(:friends)[n2] = #<Neo4j::RelationshipMixin:0x134aea2
1168
-
1169
- === Deleting a relationship
1170
-
1171
- Use the Neo4j::RelationshipMixin#delete method.
1172
- For example, to delete the relationship between n1 and n2 from the example above:
1173
-
1174
- n1.rels.outgoing(:friends)[n2].delete
1175
-
1176
- === Finding nodes in a relationship
1177
-
1178
- If you do not want the relationship object, but just the nodes you can use the 'nodes' method
1179
- in the Neo4j::RelationshipMixin object.
1180
-
1181
- For example:
1182
-
1183
- n2.rels.incoming.nodes # => [n1]
1184
-
1185
- === Finding outgoing/incoming nodes of a specific relationship type
1186
-
1187
- Let say we want to find who has my phone number and who consider me as a friend
1188
-
1189
- # who has my phone numbers
1190
- me.rels.incoming(:phone_numbers).nodes # => people with my phone numbers
1191
-
1192
- # who consider me as a friend
1193
- me.rels.incoming(:friends).nodes # => people with a friend relationship to me
1194
-
1195
- Remember that relationships are not symmetrical.
1196
- Notice that, there is also another way of finding nodes, see the Neo4j::NodeMixin#traverse method below.
1197
-
1198
- === Transactions
1199
-
1200
- All operations that work with the node space (even read operations) must be wrapped in a transaction.
1201
- For example all get, set and find operations will start a new transaction if none is already not running (for that thread).
1202
-
1203
- If you want to perform a set of operation in a single transaction, use the Neo4j::Transaction.run method:
1204
-
1205
- Example
1206
-
1207
- Neo4j::Transaction.run {
1208
- node1.foo = "value"
1209
- node2.bar = "hi"
1210
- }
1211
-
1212
- There is also a auto commit feature available which is enabled by requiring 'neo4j/auto_tx' instead of 'neo4j',
1213
- see the three minutes tutorial above.
1214
-
1215
- You can also run it without a block, like this:
1216
-
1217
- transaction = Neo4j::Transaction.new
1218
- transaction.start
1219
- # do something
1220
- transaction.finish
1221
-
1222
- ==== Rollback
1223
-
1224
- Neo4j support rollbacks on transaction. Example:
1225
- Example:
1226
-
1227
- include 'neo4j'
1228
-
1229
- node = MyNode.new
1230
-
1231
- Neo4j::Transaction.run { |t|
1232
- node.foo = "hej"
1233
- # something failed so we signal for a failure
1234
- t.failure # will cause a rollback, node.foo will not be updated
1235
- }
1236
-
1237
-
1238
- === Indexing
1239
-
1240
- Properties and relationships which should be indexed by Lucene can be specified by the index class method.
1241
- For example to index the properties foo and bar
1242
-
1243
- class SomeNode
1244
- include Neo4j::NodeMixin
1245
- property :foo, :bar
1246
- index :foo, :bar
1247
- end
1248
-
1249
- Every time a node of type SomeNode (or a subclass) is created, deleted or updated the Lucene index will be updated.
1250
-
1251
- === Reindexing
1252
-
1253
- Sometimes it's necessarily to change the index of a class after a lot of node instances already have been created.
1254
- To delete an index use the class method 'remove_index'
1255
- To update an index use the class method 'update_index' which will update all already created nodes in the Neo database.
1256
-
1257
- Example:
1258
-
1259
- require 'neo4j'
1260
- require 'neo4j/extensions/reindexer' # needed for the update_index method
1261
- class Person
1262
- include Neo4j
1263
- property :name, :age, :phone
1264
- index :name, :age
1265
- end
1266
-
1267
- p1 = Person.new :name => 'andreas', :phone => 123
1268
- Person.find (:name => 'andreas') # => [p1]
1269
- Person.find (:phone => 123) # => []
1270
-
1271
- # change index and reindex all person nodes already created in the Neo database.
1272
- Person.remove_index :name
1273
- Person.index :phone # add an index on phone
1274
- Person.update_index
1275
-
1276
- Person.find (:name => 'andreas') # => []
1277
- Person.find (:phone => 123) # => [p1]
1278
-
1279
- In order to use the update_index method you must include the reindexer neo4j.rb extension.
1280
- This extension will keep a relationship to each created node so that it later can recreate
1281
- the index by traversing those relationships.
1282
-
1283
- === Updating Lucene Index
1284
-
1285
- The Lucene index will be updated after the transaction commits. It is not possible to
1286
- query for something that has been created inside the same transaction as where the query is performed.
1287
-
1288
- === Querying (using Lucene)
1289
-
1290
- You can declare properties to be indexed by Lucene by the index method:
1291
-
1292
- Example
1293
-
1294
- class Person
1295
- include Neo4j::NodeMixin
1296
- property :name, :age
1297
- index :name, :age
1298
- end
1299
-
1300
- node = Person.new
1301
- node.name = 'foo'
1302
- node.age = 42
1303
-
1304
-
1305
- Person.find(:name => 'foo', :age => 42) # => [node]
1306
-
1307
- The query parameter (like property on a Neo4j::NodeMixin) can be of type String, Fixnum, Float, boolean or Range.
1308
- The query above can also be written in a Lucene query DSL:
1309
-
1310
- Person.find{(name =='foo') & (age => 42)} # => [node]
1311
-
1312
- Or Lucene query language:
1313
-
1314
- Person.find("name:foo AND age:42")
1315
-
1316
- For more information see: http://lucene.apache.org/java/2_4_0/queryparsersyntax.html or the Lucene module above.
1317
-
1318
-
1319
- === Indexing and Property Types
1320
-
1321
- In order to use range query on numbers the property types must be converted.
1322
- This is done by using the :type optional parameter:
1323
-
1324
- class Person
1325
- include Neo4j::NodeMixin
1326
- property :name, :age
1327
- index :age, :type => Fixnum
1328
- end
1329
-
1330
- By using :type => Fixnum the age will be padded with '0's (Lucene only support string comparison).
1331
-
1332
- Example, if the :type => Fixnum was not specified then
1333
-
1334
- p = Person.new {|n| n.age = 100 }
1335
- Person.find(:age => 0..8) # => [p]
1336
-
1337
- === Indexing and Querying Relationships
1338
-
1339
- The Neo4j::NodeMixin#index method can be used to index relationships to other classes.
1340
-
1341
- Example, let say we have to classes, Customer and Orders:
1342
-
1343
- class Customer
1344
- include Neo4j::NodeMixin
1345
-
1346
- property :name
1347
-
1348
- # specifies outgoing relationships to Order
1349
- has_n(:orders).to(Order)
1350
-
1351
- # create an index on customer-->order#total_cost
1352
- index "orders.total_cost"
1353
- end
1354
-
1355
-
1356
- class Order
1357
- include Neo4j::NodeMixin
1358
-
1359
- property :total_cost
1360
-
1361
- # specifies one incoming relationship from Customer
1362
- has_one(:customer).from(Customer, :orders)
1363
-
1364
- # create an index on the order<--customer#name relationship
1365
- index "customer.name"
1366
- end
1367
-
1368
- Notice that we can index both incoming and outgoing relationships.
1369
-
1370
- Let's create a customer and one order for that customer
1371
-
1372
- Neo4j::Transaction.run do
1373
- cust = Customer.new
1374
- order = Order.new
1375
- cust.name = "kalle"
1376
- order.total_cost = "1000"
1377
-
1378
- cust.orders << order
1379
- end
1380
-
1381
- Now we can find both Orders with a total cost between 500 and 2000 and Customers with name 'kalle' using Lucene
1382
-
1383
- Example:
1384
-
1385
- customers = Customer.find('orders.total_cost' => 500..2000, 'name' => 'kalle')
1386
-
1387
- Or also possible from the other way:
1388
-
1389
- orders = Order.find('total_cost' => 500..2000, 'customer.name' => 'kalle')
1390
-
1391
- === Full text search
1392
-
1393
- Neo4j supports full text search by setting the tokenized property to true on an index.
1394
- (see JavaDoc for org.apache.lucene.document.Field.Index.ANALYZED).
1395
-
1396
- class Comment
1397
- include Neo4j::NodeMixin
1398
-
1399
- property :comment
1400
- index comment, :tokenized => true
1401
- end
1402
-
1403
- === Keyword searches
1404
-
1405
- If we want to search for exact matches, for example language codes like 'se', 'it' we must make sure
1406
- that the Lucene does not filters away stop words like 'it'
1407
-
1408
- class LangCodes
1409
- include Neo4j::NodeMixin
1410
- property :code
1411
- index :code, :analyzer => :keyword
1412
- end
1413
-
1414
- By using the keyword analyzer (instead of the default StandardAnalyzer) we make sure that Lucene indexes everything.
1415
- For more info, see the Lucene chapter below.
1416
-
1417
- === Unmarshalling
1418
-
1419
- The Neo module will automatically unmarshal nodes to the correct ruby class.
1420
- It does this by reading the classname property and loading that ruby class with that node.
1421
- If this classname property does not exist it will use the default Neo4j::Node for nodes and
1422
- Neo4j::Relationships::Relationship for relationship.
1423
-
1424
- class Person
1425
- include Neo4j::Node
1426
-
1427
- def hello
1428
- end
1429
- end
1430
-
1431
- f1 = Person.new {}
1432
-
1433
- # load the class again
1434
- f2 = Neo4j.load_node(foo.neo_id)
1435
-
1436
- # f2 will now be new instance of Person, but will be == f1
1437
- f1 == f2 # => true
1438
-
1439
- === Reference node
1440
-
1441
- There is one node that can always be found - the reference node, Neo4j::ReferenceNode.
1442
- Example:
1443
-
1444
- Neo4j.ref_node
1445
-
1446
- This node can have a relationship to the index node (Neo4j::IndexNode), which has relationships to all created nodes.
1447
- You can add relationships from this node to your nodes.
1448
-
1449
- == Performance Issues
1450
-
1451
- It is recommended to wrap several Neo4j operations including read operations
1452
- in a singe transaction if possible for better performance.
1453
- Updating a Lucene index can be slow. A solution to this is to keep the index in memory instead of on disk.
1454
-
1455
- Using raw java nodes (Neo4j::Node) and relationship (Neo4j::Relationship) will also increase performance.
1456
- Here is an example how to traverse only using Java objects (instead of Ruby wrappers):
1457
-
1458
- iter = folder.outgoing(:child_folders).raw(true).depth(:all).iterator
1459
- iter.hasNext()
1460
-
1461
- The example above gives you access to the raw Java iterator class.
1462
- Another way to improve performance is to rewrite the performance critical part of your application in Java and access it from neo4j.rb in JRuby.
1463
- Traversing in pure Java is of orders of magnitude faster then doing it in JRuby.
1464
-
1465
- == Migrations
1466
-
1467
- By using migrations you can keep the code and the database in sync. There are two types of migrations : none lazy and lazy.
1468
- In a none lazy migration the database is upgraded/downgraded all at once, while in lazy migrations the node/relationship is only upgraded/downgraded
1469
- when the node or relationship is loaded.
1470
-
1471
- === None Lazy Migration
1472
-
1473
- Here is an example of a use case for this feature.
1474
- Let say that we already have a database with nodes that have one property 'name'.
1475
- Now we want to split that property into two properties: 'surname' and 'given_name'.
1476
- We want to upgrade the database when it starts so we don't use the lazy migration feature.
1477
- The neo database starts at version 0 by default.
1478
-
1479
- Neo4j.migrate 1, "split name" do
1480
- up do
1481
- # find all people and change
1482
- Person.all.each {|p|
1483
- surname = self[:name].split[0]
1484
- given_name = self[:name].split[1]
1485
- delete_property(:name)
1486
- end
1487
-
1488
- down do
1489
- Person.all.each {|p|
1490
- name = "#{self[:surname]} {self[:given_name]}"
1491
- delete_property(:surname)
1492
- delete_property(:given_name)
1493
- end
1494
- end
1495
- end
1496
-
1497
- If the code above has been loaded before the neo database starts it will automatically upgrade to version 1 (running all the migrations to the higest migration available).
1498
- You can force the neo to go to a specific version by using Neo4j#migrate! method.
1499
- For more information see the example/imdb application or the RSpecs.
1500
-
1501
- === Lazy Migration
1502
-
1503
- The example above can also be run as lazy migration. i.e. perform the upgrade/downgrade when the node is loaded instead of all at once.
1504
- The following example demonstrates this feature:
1505
-
1506
- class Person
1507
- include Neo4j::NodeMixin
1508
- include Neo4j::MigrationMixin # you need to include this in order to use lazy migrations
1509
- ...
1510
- end
1511
-
1512
- Person.migration 1, :split_name do
1513
- up do
1514
- surname = self[:name].split[0]
1515
- given_name = self[:name].split[1]
1516
- delete_property(:name)
1517
- end
1518
-
1519
- down do
1520
- name = "self[:given_name] #{self[:surname]}"
1521
- delete_property(:surname)
1522
- delete_property(:given_name)
1523
- end
1524
- end
1525
-
1526
- == Batch Insert
1527
-
1528
- Sometimes you need a fast way to insert a lot of data into the database without any transactional support.
1529
- Neo4j.rb wrapps the Java BatchInserter API.
1530
-
1531
- Neo4j::BatchInserter.new do |b|
1532
- a = Neo4j::Node.new :name => 'a'
1533
- b = Neo4j::Node.new :name => 'b'
1534
- c = Foo.new :key1 => 'val1', :key2 => 'val2'
1535
- Neo4j::Relationship.new(:friend, a, b, :since => '2001-01-01')
1536
- end
1537
-
1538
- Creating nodes and relationships inside the code block uses the batch inserter API. Only a limited set of the API for nodes and relationships are available
1539
- inside the code block (e.g. traversing is not possible).
1540
-
1541
- If you need lucene indexing you have to wrap your code inside a transaction, since only when the transaction is finished the lucene database will be updated
1542
- (the neo4j transaction is disabled). Example:
1543
-
1544
- Neo4j::BatchInserter.new do
1545
- Neo4j::Transaction.new
1546
- foo = Foo98.new
1547
- foo.name = 'hej'
1548
- Neo4j::Transaction.finish # update the lucene index, neo4j transaction is disabled here.
1549
- end
1550
-
1551
- To get even better insertion speed one can use the raw java Batch Inserter API: http://wiki.neo4j.org/content/Batch_Insert.
1552
-
1553
- Example:
1554
-
1555
- Neo4j::BatchInserter.new do |b|
1556
- b.createNode({'name' => 'me'})
1557
- end
1558
-
1559
- Notice that the BatchInserter can be used together with Migrations.
1560
-
1561
- == Extensions: Replication
1562
-
1563
- There is an experimental extension that makes it possible to replicate a Neo4j database to another machine.
1564
- For example how to use it see the test/replication/test_master.rb and test_slave.rb
1565
- It has only been tested to work with a very simple node space.
1566
-
1567
- == Extension: REST
1568
-
1569
- There is a REST extension to Neo4j.rb.
1570
- It requires the following gems
1571
- * Sinatra >= 0.9.4
1572
- * Rack >= 1.0
1573
- * json-jruby >= 1.1.6
1574
-
1575
- For RSpec testing it also needs:
1576
- * rack-test
1577
-
1578
- For more information see the examples/rest/example.rb or the examples/admin or Neo4j::RestMixin.
1579
-
1580
-
1581
- == Extension: find_path
1582
-
1583
- Extension which finds the shortest path (in terms of number of links) between
1584
- two nodes. Use something like this:
1585
-
1586
- require 'neo4j/extensions/find_path'
1587
- node1.traverse.both(:knows).depth(:all).path_to(node2)
1588
- # => [node1, node42, node1234, node256, node2]
1589
-
1590
- This extension is still rather experimental. The algorithm is based on the one
1591
- used in the Neo4j Java IMDB example. For more information see Neo4j::Relationships::NodeTraverser#path_to
1592
- or the RSpec find_path_spec.rb.
1593
-
1594
- == Extension: graph_algo
1595
-
1596
- This extension uses the Java Neo4j Graph Algo package - http://components.neo4j.org/graph-algo/
1597
- Currently only the AllSimplePaths algorithm supported. If you want the
1598
- other algorithms you either access the Java methods directly or write a new wrapper (like my AllSimplePath wrapper).
1599
-
1600
- == Ruby on Rails with Neo4j.rb
1601
-
1602
- Neo4j.rb does work nicely with R&R.
1603
- There are two ways to use neo4j.rb with rails - embedded or accessing it via REST.
1604
-
1605
- === Embedded Rails
1606
- A complete example of embedding Neo4j with rails can be found http://github.com/andreasronge/neo4j-rails-example/tree/master
1607
- (please fork and improve it).
1608
-
1609
- ==== Config rails
1610
- Config rails to use Neo4j.rb instead of ActiveRecord, edit movies/config/environment.rb
1611
- environment.rb:
1612
-
1613
- config.frameworks -= [ :active_record ] #, :active_resource, :action_mailer ]
1614
- config.gem "neo4j", :version => "0.3.1" # or the latest one
1615
-
1616
- If you need to reindex all nodes or use the Neo4j::NodeMixin#all method you must require the
1617
- reindexer neo4j.rb extension. Add a require in the environment.rb file:
1618
-
1619
- require 'neo4j/extensions/reindexer'
1620
-
1621
-
1622
- ==== Models
1623
- Create a new file for each Neo4j node or relationship class
1624
- Example for an Actor class create the file: app/models/actor.rb
1625
-
1626
- # filename app/models/actor.rb
1627
- class Actor
1628
- include Neo4j::NodeMixin
1629
- property :name, :phone, :salary
1630
- has_n(:acted_in).to(Movie).relationship(Role)
1631
- index :name
1632
- end
1633
-
1634
- ==== Create RESTful routes
1635
- Edit the config/routes.rb file
1636
- Example:
1637
-
1638
- ActionController::Routing::Routes.draw do |map|
1639
- map.resources :actors do |actor|
1640
- actor.resources :acted_in
1641
- actor.resource :movies, :controller => 'acted_in'
1642
- end
1643
-
1644
- ==== Create Controllers
1645
-
1646
- Since all Neo4j operations must be wrapped in a transaction, add an around filter for all operations
1647
- Example:
1648
-
1649
- acted_in_controller.rb:
1650
-
1651
- class ActedInController < ApplicationController
1652
- around_filter :neo_tx
1653
-
1654
- def index
1655
- @actor = Neo4j.load_node(params[:actor_id])
1656
- @movies = @actor.acted_in.nodes
1657
- end
1658
-
1659
- def create
1660
- @actor = Neo4j.load_node(params[:actor_id])
1661
- @movie = Movie.new
1662
- @movie.update(params[:movie])
1663
- @actor.acted_in << @movie
1664
- flash[:notice] = 'Movie was successfully created.'
1665
- redirect_to(@actor)
1666
- end
1667
-
1668
- def update
1669
- @actor = Neo4j.load_node(params[:actor_id])
1670
- @movie = Movie.new
1671
- @movie.update(params[:movie])
1672
- @actor.acted_in.new @movie
1673
- @movie.update(params[:movie])
1674
- flash[:notice] = 'Movie was successfully updated.'
1675
- redirect_to(@movie)
1676
- end
1677
-
1678
- def show
1679
- @movie = Neo4j.load_node(params[:id])
1680
- end
1681
-
1682
- def new
1683
- @actor = Neo4j.load_node(params[:actor_id])
1684
- @movie = Movie.value_object.new
1685
- end
1686
-
1687
- def edit
1688
- @movie = Neo4j.load_node(params[:id])
1689
- end
1690
-
1691
- private
1692
-
1693
- def neo_tx
1694
- Neo4j::Transaction.new
1695
- yield
1696
- Neo4j::Transaction.finish
1697
- end
1698
- end
1699
-
1700
- ==== Add views
1701
-
1702
- Add the following views in app/views/actors
1703
- index.html.erb:
1704
-
1705
- <h1>Listing actors</h1>
1706
-
1707
- <table>
1708
- <tr>
1709
- <th>Name</th>
1710
- </tr>
1711
-
1712
- <% for actor in @actors %>
1713
- <tr>
1714
- <td><%=h actor.name %></td>
1715
- <td><%= link_to 'Edit', edit_actor_path(actor) %></td>
1716
- <td><%= link_to 'Show', actor %></td>
1717
- <td><%= link_to 'Destroy', actor, :confirm => 'Are you sure?', :method => :delete %></td>
1718
- </tr>
1719
- <% end %>
1720
- </table>
1721
-
1722
- <br />
1723
-
1724
- <%= link_to 'New actor', new_actor_path %>
1725
-
1726
- new.html.erb:
1727
-
1728
- <h1>New Actor</h1>
1729
-
1730
- <% form_for(@actor) do |f| %>
1731
- <p>
1732
- <%= f.label :name %><br />
1733
- <%= f.text_field :name %>
1734
- </p>
1735
- <p>
1736
- <%= f.label :phone %><br />
1737
- <%= f.text_field :phone %>
1738
- </p>
1739
- <p>
1740
- <%= f.label :salary%><br />
1741
- <%= f.text_field :salary %>
1742
- </p>
1743
- <p>
1744
- <%= f.submit "Update" %>
1745
- </p>
1746
-
1747
- <% end %>
1748
-
1749
-
1750
-
1751
- <%= link_to 'Back', actors_path %>
1752
-
1753
-
1754
- == The Lucene Module
1755
-
1756
- You can use this module without using the Neo4j module.
1757
-
1758
- Lucene provides:
1759
- * Flexible Queries - Phrases, Wildcards, Compound boolean expressions etc...
1760
- * Field-specific Queries eg. title, artist, album
1761
- * Sorting
1762
- * Ranked Searching
1763
-
1764
- === Lucene Document
1765
-
1766
- In Lucene everything is a Document. A document can represent anything textual:
1767
- A Word Document, a DVD (the textual metadata only), or a Neo4j.rb node.
1768
- A document is like a record or row in a relationship database.
1769
-
1770
- The following example shows how a document can be created by using the ''<<'' operator
1771
- on the Lucene::Index class and found using the Lucene::Index#find method.
1772
-
1773
- Example of how to write a document and find it:
1774
-
1775
- require 'lucene'
1776
-
1777
- include Lucene
1778
-
1779
- # the var/myindex parameter is either a path where to store the index or
1780
- # just a key if index is kept in memory (see below)
1781
- index = Index.new('var/myindex')
1782
-
1783
- # add one document (a document is like a record or row in a relationship database)
1784
- index << {:id=>'1', :name=>'foo'}
1785
-
1786
- # write to the index file
1787
- index.commit
1788
-
1789
- # find a document with name foo
1790
- # hits is a ruby Enumeration of documents
1791
- hits = index.find{name == 'foo'}
1792
-
1793
- # show the id of the first document (document 0) found
1794
- # (the document contains all stored fields - see below)
1795
- hits[0][:id] # => '1'
1796
-
1797
- Notice that you have to call the commit method in order to update the index (both disk and in memory indexes).
1798
- Performing several update and delete operations before a commit will give much
1799
- better performance than committing after each operation.
1800
-
1801
- === Keep indexing on disk
1802
-
1803
- By default Neo4j::Lucene keeps indexes in memory. That means that when the application restarts
1804
- the index will be gone and you have to reindex everything again.
1805
-
1806
- To store indexes on file:
1807
-
1808
- Lucene::Config[:store_on_file] = true
1809
- Lucene::Config[:storage_path] => '/home/neo/lucene-db'
1810
-
1811
- When creating a new index the location of the index will be the Lucene::Config[:storage_path] + index path
1812
- Example:
1813
-
1814
- Lucene::Config[:store_on_file] = true
1815
- Lucene::Config[:storage_path] => '/home/neo/lucene-db'
1816
- index = Index.new('/foo/lucene')
1817
-
1818
- The example above will store the index at /home/neo/lucene-db/foo/lucene
1819
-
1820
- === Indexing several values with the same key
1821
-
1822
- Let say a person can have several phone numbers. How do we index that?
1823
-
1824
- index << {:id=>'1', :name=>'adam', :phone => ['987-654', '1234-5678']}
1825
-
1826
-
1827
- === Id field
1828
-
1829
- All Documents must have one id field. If an id is not specified, the default will be: :id of type String.
1830
- A different id can be specified using the field_infos id_field property on the index:
1831
-
1832
- index = Index.new('some/path/to/the/index')
1833
- index.field_infos.id_field = :my_id
1834
-
1835
- To change the type of the my_id from String to a different type see below.
1836
-
1837
- === Conversion of types
1838
-
1839
- Lucene.rb can handle type conversion for you. (The Java Lucene library stores all
1840
- the fields as Strings)
1841
- For example if you want the id field to be a Fixnum
1842
-
1843
- require 'lucene'
1844
- include Lucene
1845
-
1846
- index = Index.new('var/myindex') # store the index at dir: var/myindex
1847
- index.field_infos[:id][:type] = Fixnum
1848
-
1849
- index << {:id=>1, :name=>'foo'} # notice 1 is not a string now
1850
-
1851
- index.commit
1852
-
1853
- # find that document, hits is a ruby Enumeration of documents
1854
- hits = index.find(:name => 'foo')
1855
-
1856
- # show the id of the first document (document 0) found
1857
- # (the document contains all stored fields - see below)
1858
- doc[0][:id] # => 1
1859
-
1860
- If the field_info type parameter is not set then it has a default value of String.
1861
-
1862
- === Storage of fields
1863
-
1864
- By default only the id field will be stored.
1865
- That means that in the example above the :name field will not be included in the document.
1866
-
1867
- Example
1868
- doc = index.find('name' => 'foo')
1869
- doc[:id] # => 1
1870
- doc[:name] # => nil
1871
-
1872
- Use the field info :store=true if you want a field to be stored in the index
1873
- (otherwise it will only be searchable).
1874
-
1875
- Example
1876
-
1877
- require 'lucene'
1878
- include Lucene
1879
-
1880
- index = Index.new('var/myindex') # store the index at dir: var/myindex
1881
- index.field_infos[:id][:type] = Fixnum
1882
- index.field_infos[:name][:store] = true # store this field
1883
-
1884
- index << {:id=>1, :name=>'foo'} # notice 1 is not a string now
1885
-
1886
- index.commit
1887
-
1888
- # find that document, hits is a ruby Enumeration of documents
1889
- hits = index.find('name' => 'foo')
1890
-
1891
- # let say hits only contains one document so we can use doc[0] for that one
1892
- # that document contains all stored fields (see below)
1893
- doc[0][:id] # => 1
1894
- doc[0][:name] # => 'foo'
1895
-
1896
- === Setting field infos
1897
-
1898
- As shown above you can set field infos like this
1899
-
1900
- index.field_infos[:id][:type] = Fixnum
1901
-
1902
- Or you can set several properties like this:
1903
-
1904
- index.field_infos[:id] = {:type => Fixnum, :store => true}
1905
-
1906
- ==== Tokenized
1907
-
1908
- Field infos can be used to specify if the should be tokenized.
1909
- If this value is not set then the entire content of the field will be considered as a single term.
1910
-
1911
- Example
1912
-
1913
- index.field_infos[:text][:tokenized] = true
1914
-
1915
- If not specified, the default is 'false'
1916
-
1917
- ==== Analyzer
1918
-
1919
- Field infos can also be used to set which analyzer should be used.
1920
- If none is specified, the default analyzer - org.apache.lucene.analysis.standard.StandardAnalyzer (:standard) will be used.
1921
-
1922
-
1923
- index.field_infos[:code][:tokenized] = false
1924
- index.field_infos[:code][:analyzer] = :standard
1925
-
1926
- The following analyzer is supported
1927
- * :standard (default) - org.apache.lucene.analysis.standard.StandardAnalyzer
1928
- * :keyword - org.apache.lucene.analysis.KeywordAnalyzer
1929
- * :simple - org.apache.lucene.analysis.SimpleAnalyzer
1930
- * :whitespace - org.apache.lucene.analysis.WhitespaceAnalyzer
1931
- * :stop - org.apache.lucene.analysis.StopAnalyzer
1932
-
1933
- For more info, check the Lucene documentation, http://lucene.apache.org/java/docs/
1934
-
1935
-
1936
- === Simple Queries
1937
-
1938
- Lucene.rb support search in several fields:
1939
- Example:
1940
-
1941
- # finds all document having both name 'foo' and age 42
1942
- hits = index.find('name' => 'foo', :age=>42)
1943
-
1944
- Range queries:
1945
-
1946
- # finds all document having both name 'foo' and age between 3 and 30
1947
- hits = index.find('name' => 'foo', :age=>3..30)
1948
-
1949
- === Lucene Queries
1950
-
1951
- If the query is string then the string is a Lucene query.
1952
-
1953
- hits = index.find('name:foo')
1954
-
1955
- For more information see:
1956
- http://lucene.apache.org/java/2_4_0/queryparsersyntax.html
1957
-
1958
- === Advanced Queries (DSL)
1959
-
1960
- The queries above can also be written in a lucene.rb DSL:
1961
-
1962
- hits = index.find { (name == 'andreas') & (foo == 'bar')}
1963
-
1964
- Expression with OR (|) is supported, example
1965
-
1966
- # find all documents with name 'andreas' or age between 30 and 40
1967
- hits = index.find { (name == 'andreas') | (age == 30..40)}
1968
-
1969
- === Sorting
1970
-
1971
- Sorting is specified by the 'sort_by' parameter
1972
- Example:
1973
-
1974
- hits = index.find(:name => 'foo', :sort_by=>:category)
1975
-
1976
- To sort by several fields:
1977
-
1978
- hits = index.find(:name => 'foo', :sort_by=>[:category, :country])
1979
-
1980
- Example sort order:
1981
-
1982
- hits = index.find(:name => 'foo', :sort_by=>[Desc[:category, :country], Asc[:city]])
1983
-
1984
- === Thread-safety
1985
-
1986
- The Lucene::Index is thread safe.
1987
- It guarantees that an index is not updated from two threads at the same time.
1988
-
1989
-
1990
- === Lucene Transactions
1991
-
1992
- Use the Lucene::Transaction in order to do atomic commits.
1993
- By using a transaction you do not need to call the Index.commit method.
1994
-
1995
- Example:
1996
-
1997
- Transaction.run do |t|
1998
- index = Index.new('var/index/foo')
1999
- index << { id=>42, :name=>'andreas'}
2000
- t.failure # rollback
2001
- end
2002
-
2003
- result = index.find('name' => 'andreas')
2004
- result.size.should == 0
2005
-
2006
- You can find uncommitted documents with the uncommitted index property.
2007
-
2008
- Example:
2009
-
2010
- index = Index.new('var/index/foo')
2011
- index.uncommited #=> [document1, document2]
2012
-
2013
- Notice that even if it looks like a new Index instance object was created the index.uncommitted
2014
- may return a non-empty array. This is because Index.new is a singleton - a new instance object is not created.
2015
-