persistence.asciidoc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. [[persistence]]
  2. == Persistence
  3. The `elasticsearch-persistence` http://rubygems.org/gems/elasticsearch-persistence[Rubygem]
  4. provides persistence layer for Ruby domain objects.
  5. It supports two design patterns for integrating with your objects: _repository_ and _active record_.
  6. === Repository
  7. The `Elasticsearch::Persistence::Repository` module provides an implementation of the repository pattern and allows to save, delete, find and search objects stored in Elasticsearch, as well as configure mappings and settings for the index.
  8. ==== Features At a Glance
  9. * Access to the Elasticsearch client
  10. * Setting the index name, document type, and object class for deserialization
  11. * Composing mappings and settings for the index
  12. * Creating, deleting or refreshing the index
  13. * Finding or searching for documents
  14. * Providing access both to domain objects and hits for search results
  15. * Providing access to the Elasticsearch response for search results (aggregations, total, ...)
  16. * Defining the methods for serialization and deserialization
  17. ==== Usage
  18. Let's have a simple plain old Ruby object (PORO):
  19. [source,ruby]
  20. ------------------------------------
  21. class Note
  22. attr_reader :attributes
  23. def initialize(attributes={})
  24. @attributes = attributes
  25. end
  26. def to_hash
  27. @attributes
  28. end
  29. end
  30. ------------------------------------
  31. Let's create a default, "dumb" repository, as a first step:
  32. [source,ruby]
  33. ------------------------------------
  34. require 'elasticsearch/persistence'
  35. repository = Elasticsearch::Persistence::Repository.new
  36. ------------------------------------
  37. We can save a `Note` instance into the repository, find it, search it, delete it:
  38. [source,ruby]
  39. ------------------------------------
  40. note = Note.new id: 1, text: 'Test'
  41. repository.save(note)
  42. # PUT http://localhost:9200/repository/note/1
  43. # > {"id":1,"text":"Test"}
  44. # < {"_index":"repository","_type":"note","_id":"1","_version":1,"created":true}
  45. n = repository.find(1)
  46. # GET http://localhost:9200/repository/_all/1
  47. # < {"_index":"repository","_type":"note","_id":"1","_version":2,"found":true, "_source" : {"id":1,"text":"Test"}}
  48. => <Note:0x007fcbfc0c4980 @attributes={"id"=>1, "text"=>"Test"}>
  49. repository.search(query: { match: { text: 'test' } }).first
  50. # GET http://localhost:9200/repository/_search
  51. # > {"query":{"match":{"text":"test"}}}
  52. # < {"took":2, ... "hits":{"total":1, ... "hits":[{ ... "_source" : {"id":1,"text":"Test"}}]}}
  53. => <Note:0x007fcbfc1c7b70 @attributes={"id"=>1, "text"=>"Test"}>
  54. repository.delete(note)
  55. # DELETE http://localhost:9200/repository/note/1
  56. # < {"found":true,"_index":"repository","_type":"note","_id":"1","_version":3}
  57. => {"found"=>true, "_index"=>"repository", "_type"=>"note", "_id"=>"1", "_version"=>2}
  58. ------------------------------------
  59. The repository module provides a number of features and facilities to configure and customize the behaviour,
  60. as well as support for extending your own, custom repository class.
  61. Please refer to the
  62. https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-persistence#the-repository-pattern[documentation]
  63. for more information.
  64. Also, check out the
  65. https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-persistence#example-application[example application] which demonstrates the usage patterns of the _repository_ approach to persistence.
  66. === Active Record
  67. The `Elasticsearch::Persistence::Model` module provides an implementation of the active record pattern, with
  68. a familiar interface for using Elasticsearch as a persistence layer in Ruby on Rails applications. The model
  69. is fully compatible with Rails' conventions and helpers, such as `url_for`.
  70. All the methods are documented with comprehensive examples in the source code, available also
  71. http://rubydoc.info/gems/elasticsearch-persistence/Elasticsearch/Persistence/Model[online].
  72. ==== Features At a Glance
  73. * Familiar interface for persistence methods from ActiveRecord
  74. * Common model features such as validations and callbacks
  75. * Methods for defining model attributes, including Elasticsearch mappings
  76. * Support for fetching data in bulk (`find_in_batches`, `find_each`)
  77. * Decorated search results for easy access to model instances and meta data (such as highlights or aggregations)
  78. * Easy access to the underlying gateway and client
  79. ==== Usage
  80. To use the library in a Rails application, add it to your Gemfile with a require statement:
  81. [source,ruby]
  82. ------------------------------------
  83. gem "elasticsearch-persistence", require: 'elasticsearch/persistence/model'
  84. ------------------------------------
  85. Include the module in a plain Ruby class, and set up the properties, mappings, etc:
  86. [source,ruby]
  87. ------------------------------------
  88. class Article
  89. include Elasticsearch::Persistence::Model
  90. # Define a plain `title` attribute
  91. #
  92. attribute :title, String
  93. # Define an `author` attribute, with multiple analyzers for this field
  94. #
  95. attribute :author, String, mapping: { fields: {
  96. author: { type: 'string'},
  97. raw: { type: 'string', analyzer: 'keyword' }
  98. } }
  99. # Define a `views` attribute, with default value
  100. #
  101. attribute :views, Integer, default: 0, mapping: { type: 'integer' }
  102. # Validate the presence of the `title` attribute
  103. #
  104. validates :title, presence: true
  105. # Execute code after saving the model.
  106. #
  107. after_save { puts "Successfully saved: #{self}" }
  108. end
  109. ------------------------------------
  110. The model attribute definition support is implemented with the https://github.com/solnic/virtus[_Virtus_] Rubygem,
  111. and the naming, validation, etc. features with the https://github.com/rails/rails/tree/master/activemodel[_ActiveModel_] Rubygem.
  112. Attribute validations work like for any other ActiveModel-compatible implementation:
  113. [source,ruby]
  114. ------------------------------------
  115. article = Article.new # => #<Article { ... }>
  116. article.valid?
  117. # => false
  118. article.errors.to_a
  119. # => ["Title can't be blank"]
  120. ------------------------------------
  121. We can create a new article in the database and find it:
  122. [source,ruby]
  123. ------------------------------------
  124. Article.create id: 1, title: 'Test', author: 'John'
  125. # PUT http://localhost:9200/articles/article/1 [status:201, request:0.015s, query:n/a]
  126. article = Article.find(1)
  127. # => #<Article { ... }>
  128. article._index
  129. # => "articles"
  130. article.id
  131. # => "1"
  132. article.title
  133. # => "Test"
  134. ------------------------------------
  135. To update the model, either update the attribute and save the model or use the `update_attributes` method:
  136. [source,ruby]
  137. ------------------------------------
  138. article.title = 'Updated'
  139. article.save
  140. # => {"_index"=>"articles", "_type"=>"article", "_id"=>"1", "_version"=>2, "created"=>false}
  141. article.update_attributes title: 'Test', author: 'Mary'
  142. # => {"_index"=>"articles", "_type"=>"article", "_id"=>"1", "_version"=>3}
  143. ------------------------------------
  144. The implementation supports the familiar interface for updating model timestamps and numeric attributes:
  145. [source,ruby]
  146. ------------------------------------
  147. article.touch
  148. # => => { ... "_version"=>4}
  149. article.views
  150. # => 0
  151. article.increment :views
  152. article.views
  153. # => 1
  154. ------------------------------------
  155. Any callbacks defined in the model will be triggered during the persistence operations:
  156. [source,ruby]
  157. ------------------------------------
  158. article.save
  159. # Successfully saved: #<Article {...}>
  160. ------------------------------------
  161. Please see the extensive documentation in the library
  162. https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-persistence#the-activerecord-pattern[README]
  163. for detailed information.
  164. Also, check out the
  165. https://github.com/elastic/elasticsearch-rails/tree/master/elasticsearch-persistence#example-application-1[example application] which demonstrates the usage patterns of the _active record_ approach to persistence.