11# Elasticsearch::Persistence
22
3- Persistence layer for Ruby domain objects in Elasticsearch, using the Repository and ActiveRecord patterns .
3+ Persistence layer for Ruby domain objects in Elasticsearch, using the Repository pattern .
44
55## Compatibility
66
@@ -14,6 +14,7 @@ is compatible with the Elasticsearch `master` branch, therefore, with the next m
1414| 0.1 | → | 1.x |
1515| 2.x | → | 2.x |
1616| 5.x | → | 5.x |
17+ | 6.x | → | 6.x |
1718| master | → | master |
1819
1920## Installation
@@ -24,7 +25,7 @@ Install the package from [Rubygems](https://rubygems.org):
2425
2526To use an unreleased version, either add it to your ` Gemfile ` for [ Bundler] ( http://bundler.io ) :
2627
27- gem 'elasticsearch-persistence', git: 'git://github.com/elastic/elasticsearch-rails.git', branch: '5 .x'
28+ gem 'elasticsearch-persistence', git: 'git://github.com/elastic/elasticsearch-rails.git', branch: '6 .x'
2829
2930or install it from a source code checkout:
3031
@@ -35,9 +36,7 @@ or install it from a source code checkout:
3536
3637## Usage
3738
38- The library provides two different patterns for adding persistence to your Ruby objects:
39-
40- * [ Repository Pattern] ( #the-repository-pattern )
39+ The library provides the Repository pattern for adding persistence to your Ruby objects.
4140
4241### The Repository Pattern
4342
@@ -67,7 +66,8 @@ Let's create a default, "dumb" repository, as a first step:
6766
6867``` ruby
6968require ' elasticsearch/persistence'
70- repository = Elasticsearch ::Persistence ::Repository .new
69+ class MyRepository ; include Elasticsearch ::Persistence ::Repository ; end
70+ repository = MyRepository .new
7171```
7272
7373We can save a ` Note ` instance into the repository...
@@ -120,32 +120,17 @@ The repository module provides a number of features and facilities to configure
120120* Providing access to the Elasticsearch response for search results (aggregations, total, ...)
121121* Defining the methods for serialization and deserialization
122122
123- You can use the default repository class, or include the module in your own. Let's review it in detail.
123+ There are two mixins you can include in your Repository class. The first ` Elasticsearch::Persistence::Repository ` ,
124+ provides the basic methods and settings you'll need. The second, ` Elasticsearch::Persistence::Repository::DSL ` adds
125+ some additional class methods that allow you to set options that instances of the class will share.
124126
125- #### The Default Class
127+ #### Basic Repository mixin
126128
127- For simple cases, you can use the default, bundled repository class, and configure/customize it :
129+ For simple cases, you can just include the Elasticsearch::Persistence::Repository mixin to your class :
128130
129131``` ruby
130- repository = Elasticsearch ::Persistence ::Repository .new do
131- # Configure the Elasticsearch client
132- client Elasticsearch ::Client .new url: ENV [' ELASTICSEARCH_URL' ], log: true
133-
134- # Set a custom index name
135- index :my_notes
136-
137- # Set a custom document type
138- type :my_note
139-
140- # Specify the class to initialize when deserializing documents
141- klass Note
142-
143- # Configure the settings and mappings for the Elasticsearch index
144- settings number_of_shards: 1 do
145- mapping do
146- indexes :text , analyzer: ' snowball'
147- end
148- end
132+ class MyRepository
133+ include Elasticsearch ::Persistence ::Repository
149134
150135 # Customize the serialization logic
151136 def serialize (document )
@@ -154,10 +139,18 @@ repository = Elasticsearch::Persistence::Repository.new do
154139
155140 # Customize the de-serialization logic
156141 def deserialize (document )
157- puts " # ***** CUSTOM DESERIALIZE LOGIC KICKING IN ... *****"
142+ puts " # ***** CUSTOM DESERIALIZE LOGIC... *****"
158143 super
159144 end
160145end
146+
147+ client = Elasticsearch ::Client .new (url: ENV [' ELASTICSEARCH_URL' ], log: true )
148+ repository = MyRepository .new (client: client, index_name: :my_notes , type: :my_note , klass: Note )
149+ repository.settings number_of_shards: 1 do
150+ mapping do
151+ indexes :text , analyzer: ' snowball'
152+ end
153+ end
161154```
162155
163156The custom Elasticsearch client will be used now, with a custom index and type names,
@@ -188,28 +181,27 @@ repository.find(1)
188181< Note: 0x007f9bd782b7a0 @attributes = {... " my_special_key" =>" my_special_stuff" }>
189182```
190183
191- #### A Custom Class
184+ #### The DSL mixin
192185
193- In most cases, though, you'll want to use a custom class for the repository, so let's do that:
186+ In some cases, you'll want to set some of the repository configurations at the class level. This makes
187+ most sense when the instances of the repository will use that same configuration:
194188
195189``` ruby
196190require ' base64'
197191
198192class NoteRepository
199193 include Elasticsearch ::Persistence ::Repository
194+ include Elasticsearch ::Persistence ::Repository ::DSL
200195
201- def initialize (options = {})
202- index options[:index ] || ' notes'
203- client Elasticsearch ::Client .new url: options[:url ], log: options[:log ]
204- end
205-
196+ index_name ' notes'
197+ document_type ' note'
206198 klass Note
207199
208200 settings number_of_shards: 1 do
209201 mapping do
210202 indexes :text , analyzer: ' snowball'
211203 # Do not index images
212- indexes :image , index: ' no '
204+ indexes :image , index: false
213205 end
214206 end
215207
@@ -231,23 +223,26 @@ class NoteRepository
231223end
232224```
233225
234- Include the ` Elasticsearch::Persistence::Repository ` module to add the repository methods into the class .
226+ You can create an instance of this custom class and get each of the configurations .
235227
236- You can customize the repository in the familiar way, by calling the DSL-like methods.
228+ ``` ruby
229+ client = Elasticsearch ::Client .new (url: ' http://localhost:9200' , log: true )
230+ repository = NoteRepository .new (client: client)
231+ repository.index_name
232+ # => 'notes'
237233
238- You can implement a custom initializer for your repository, add complex logic in its
239- class and instance methods -- in general, have all the freedom of a standard Ruby class.
234+ ```
235+
236+ You can also override the default configuration with options passed to the initialize method:
240237
241238``` ruby
242- repository = NoteRepository .new url: ' http://localhost:9200' , log: true
239+ client = Elasticsearch ::Client .new (url: ' http://localhost:9250' , log: true )
240+ client.transport.logger.formatter = proc { |s , d , p , m | " \e [2m# #{ m } \n\e [0m" }
241+ repository = NoteRepository .new (client: client, index_name: ' notes_development' )
243242
244- # Configure the repository instance
245- repository.index = ' notes_development'
246- repository.client.transport.logger.formatter = proc { |s , d , p , m | " \e [2m# #{ m } \n\e [0m" }
243+ repository.create_index!(force: true )
247244
248- repository.create_index! force: true
249-
250- note = Note .new ' id' => 1 , ' text' => ' Document with image' , ' image' => ' ... BINARY DATA ...'
245+ note = Note .new (' id' => 1 , ' text' => ' Document with image' , ' image' => ' ... BINARY DATA ...' )
251246
252247repository.save(note)
253248# PUT http://localhost:9200/notes_development/note/1
@@ -258,47 +253,110 @@ puts repository.find(1).attributes['image']
258253# => ... BINARY DATA ...
259254```
260255
261- #### Methods Provided by the Repository
256+ #### Functionality Provided by the Repository mixin
257+
258+ Each of the following configurations can be set for a repository instance.
259+ If you have included the ` Elasticsearch::Persistence::Repository::DSL ` mixin, then you can use the class-level DSL
260+ methods to set each configuration. You can override the configuration for any instance by passing options to the
261+ ` #initialize ` method.
262+ If you don't use the DSL mixin, you can set also the instance configuration with options passed the ` #initialize ` method.
262263
263264##### Client
264265
265- The repository uses the standard Elasticsearch [ client] ( https://github.com/elastic/elasticsearch-ruby#usage ) ,
266- which is accessible with the ` client ` getter and setter methods:
266+ The repository uses the standard Elasticsearch [ client] ( https://github.com/elastic/elasticsearch-ruby#usage ) .
267267
268268``` ruby
269- repository.client = Elasticsearch ::Client .new url: ' http://search.server.org'
269+ client = Elasticsearch ::Client .new (url: ' http://search.server.org' )
270+ repository = NoteRepository .new (client: client)
270271repository.client.transport.logger = Logger .new (STDERR )
271272```
272273
274+ or with the DSL mixin:
275+
276+ ``` ruby
277+ class NoteRepository
278+ include Elasticsearch ::Persistence ::Repository
279+ include Elasticsearch ::Persistence ::Repository ::DSL
280+
281+ client Elasticsearch ::Client .new url: ' http://search.server.org'
282+ end
283+
284+ repository = NoteRepository .new
285+
286+ ```
287+
273288##### Naming
274289
275- The ` index ` method specifies the Elasticsearch index to use for storage, lookup and search
276- (when not set, the value is inferred from the repository class name):
290+ The ` index_name ` method specifies the Elasticsearch index to use for storage, lookup and search. The default index name
291+ is 'repository'.
292+
293+ ``` ruby
294+ repository = NoteRepository .new (index_name: ' notes_development' )
295+ ```
296+
297+ or with the DSL mixin:
298+
299+ ``` ruby
300+ class NoteRepository
301+ include Elasticsearch ::Persistence ::Repository
302+ include Elasticsearch ::Persistence ::Repository ::DSL
303+
304+ index_name ' notes_development'
305+ end
306+
307+ repository = NoteRepository .new
308+
309+ ```
310+
311+ The ` type ` method specifies the Elasticsearch document type to use for storage, lookup and search. The default value is
312+ '_ doc'. Keep in mind that future versions of Elasticsearch will not allow you to set this yourself and will use the type,
313+ '_ doc'.
277314
278315``` ruby
279- repository.index = ' notes_development '
316+ repository = NoteRepository . new ( document_type: ' note ' )
280317```
281318
282- The ` type ` method specifies the Elasticsearch document type to use for storage, lookup and search
283- (when not set, the value is inferred from the document class name, or ` _all ` is used):
319+ or with the DSL mixin:
284320
285321``` ruby
286- repository.type = ' my_note'
322+ class NoteRepository
323+ include Elasticsearch ::Persistence ::Repository
324+ include Elasticsearch ::Persistence ::Repository ::DSL
325+
326+ document_type ' note'
327+ end
328+
329+ repository = NoteRepository .new
330+
287331```
288332
289333The ` klass ` method specifies the Ruby class name to use when initializing objects from
290- documents retrieved from the repository (when not set, the value is inferred from the
291- document ` _type ` as fetched from Elasticsearch):
334+ documents retrieved from the repository. If this value is not set, a Hash representation of the document will be
335+ returned instead.
336+
337+ ``` ruby
338+ repository = NoteRepository .new (klass: Note )
339+ ```
340+
341+ or with the DSL mixin:
292342
293343``` ruby
294- repository.klass = MyNote
344+ class NoteRepository
345+ include Elasticsearch ::Persistence ::Repository
346+ include Elasticsearch ::Persistence ::Repository ::DSL
347+
348+ klass Note
349+ end
350+
351+ repository = NoteRepository .new
352+
295353```
296354
297355##### Index Configuration
298356
299357The ` settings ` and ` mappings ` methods, provided by the
300358[ ` elasticsearch-model ` ] ( http://rubydoc.info/gems/elasticsearch-model/Elasticsearch/Model/Indexing/ClassMethods )
301- gem, allow to configure the index properties:
359+ gem, allow you to configure the index properties:
302360
303361``` ruby
304362repository.settings number_of_shards: 1
@@ -310,7 +368,39 @@ repository.mappings.to_hash
310368# => { :note => {:properties=> ... }}
311369```
312370
371+ or with the DSL mixin:
372+
373+ ``` ruby
374+ class NoteRepository
375+ include Elasticsearch ::Persistence ::Repository
376+ include Elasticsearch ::Persistence ::Repository ::DSL
377+
378+ mappings { indexes :title , analyzer: ' snowball' }
379+ settings number_of_shards: 1
380+ end
381+
382+ repository = NoteRepository .new
383+
384+ ```
385+
386+ You can also use the ` #create ` method defined on the repository class to create and set the mappings and settings
387+ on an instance with a block in one call:
388+
389+ ``` ruby
390+ repository = NoteRepository .create(index_name: ' notes_development' ) do
391+ settings number_of_shards: 1 , number_of_replicas: 0 do
392+ mapping dynamic: ' strict' do
393+ indexes :foo do
394+ indexes :bar
395+ end
396+ indexes :baz
397+ end
398+ end
399+ end
400+ ```
401+
313402The convenience methods ` create_index! ` , ` delete_index! ` and ` refresh_index! ` allow you to manage the index lifecycle.
403+ These methods can only be called on repository instances and are not implemented at the class level.
314404
315405##### Serialization
316406
@@ -319,9 +409,12 @@ to the storage, and the initialization procedure when loading it from the storag
319409
320410``` ruby
321411class NoteRepository
412+ include Elasticsearch ::Persistence ::Repository
413+
322414 def serialize (document )
323415 Hash [document.to_hash.map() { |k ,v | v.upcase! if k == :title ; [k,v] }]
324416 end
417+
325418 def deserialize (document )
326419 MyNote .new ActiveSupport ::HashWithIndifferentAccess .new (document[' _source' ]).deep_symbolize_keys
327420 end
426519results.total
427520# => 2
428521
429- # Access the raw response as a Hashie::Mash instance
522+ # Access the raw response as a Hashie::Mash instance.
523+ # Note that a Hashie::Mash will only be created if the 'response' method is called on the results.
430524results.response._shards .failed
431525# => 0
526+
527+ # Access the raw response
528+ results.raw_response
529+ # => 0
530+
432531```
433532
434533#### Example Application
0 commit comments