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

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