elastic_record 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +3 -6
  3. data/Gemfile +0 -2
  4. data/README.md +25 -9
  5. data/elastic_record.gemspec +1 -1
  6. data/lib/elastic_record/as_document.rb +41 -0
  7. data/lib/elastic_record/callbacks.rb +11 -56
  8. data/lib/elastic_record/connection.rb +1 -1
  9. data/lib/elastic_record/doctype.rb +43 -0
  10. data/lib/elastic_record/index/deferred.rb +13 -15
  11. data/lib/elastic_record/index/documents.rb +23 -13
  12. data/lib/elastic_record/index/manage.rb +4 -6
  13. data/lib/elastic_record/index/mapping.rb +7 -26
  14. data/lib/elastic_record/index/settings.rb +17 -2
  15. data/lib/elastic_record/index.rb +12 -24
  16. data/lib/elastic_record/model.rb +14 -4
  17. data/lib/elastic_record/percolator_model.rb +44 -0
  18. data/lib/elastic_record/relation.rb +1 -2
  19. data/lib/elastic_record/searching.rb +5 -1
  20. data/lib/elastic_record/tasks/index.rake +0 -10
  21. data/lib/elastic_record.rb +3 -0
  22. data/test/dummy/app/models/mock_model.rb +108 -0
  23. data/test/dummy/app/models/project.rb +1 -1
  24. data/test/dummy/app/models/test_model.rb +1 -102
  25. data/test/dummy/app/models/test_percolator_model.rb +8 -0
  26. data/test/dummy/app/models/widget.rb +2 -5
  27. data/test/dummy/app/models/widget_query.rb +14 -0
  28. data/test/dummy/config/environments/test.rb +3 -3
  29. data/test/dummy/config/initializers/elastic_record.rb +1 -1
  30. data/test/elastic_record/as_document_test.rb +65 -0
  31. data/test/elastic_record/callbacks_test.rb +6 -81
  32. data/test/elastic_record/config_test.rb +1 -1
  33. data/test/elastic_record/doctype_test.rb +45 -0
  34. data/test/elastic_record/index/documents_test.rb +1 -1
  35. data/test/elastic_record/index/mapping_test.rb +16 -13
  36. data/test/elastic_record/index/settings_test.rb +34 -1
  37. data/test/elastic_record/index_test.rb +7 -15
  38. data/test/elastic_record/model_test.rb +1 -7
  39. data/test/elastic_record/percolator_model_test.rb +54 -0
  40. data/test/elastic_record/relation/batches_test.rb +0 -1
  41. data/test/elastic_record/relation/delegation_test.rb +0 -1
  42. data/test/elastic_record/relation/finder_methods_test.rb +0 -1
  43. data/test/elastic_record/relation_test.rb +0 -2
  44. data/test/elastic_record/searching_test.rb +7 -0
  45. metadata +11 -10
  46. data/lib/elastic_record/index/configurator.rb +0 -18
  47. data/lib/elastic_record/index/percolator.rb +0 -50
  48. data/lib/elastic_record/index/warmer.rb +0 -24
  49. data/lib/elastic_record/relation/admin.rb +0 -13
  50. data/test/elastic_record/index/configurator_test.rb +0 -18
  51. data/test/elastic_record/index/percolator_test.rb +0 -45
  52. data/test/elastic_record/index/warmer_test.rb +0 -20
  53. data/test/elastic_record/relation/admin_test.rb +0 -28
@@ -1,41 +1,22 @@
1
1
  module ElasticRecord
2
2
  class Index
3
3
  module Mapping
4
- def mapping=(custom_mapping)
5
- mapping.deep_merge!(custom_mapping)
6
- end
7
-
8
4
  def update_mapping(index_name = alias_name)
9
- connection.json_put "/#{index_name}/#{type}/_mapping", type => mapping
5
+ connection.json_put "/#{index_name}/_mapping", mapping_body
10
6
  end
11
7
 
12
8
  def get_mapping(index_name = alias_name)
13
- json = connection.json_get "/#{index_name}/#{type}/_mapping"
9
+ json = connection.json_get "/#{index_name}/_mapping"
10
+
14
11
  unless json.empty?
15
12
  json.values.first['mappings']
16
13
  end
17
14
  end
18
15
 
19
- def mapping
20
- @mapping ||= {
21
- properties: {
22
- },
23
- _all: {
24
- enabled: false
25
- },
26
- dynamic_templates: [
27
- {
28
- no_string_analyzing: {
29
- match: "*",
30
- match_mapping_type: "string",
31
- mapping: {
32
- type: "string",
33
- index: "not_analyzed"
34
- }
35
- }
36
- }
37
- ]
38
- }
16
+ def mapping_body
17
+ doctypes.each_with_object({}) do |doctype, result|
18
+ result[doctype.name] = doctype.mapping
19
+ end
39
20
  end
40
21
  end
41
22
  end
@@ -6,12 +6,27 @@ module ElasticRecord
6
6
  end
7
7
 
8
8
  def settings
9
- @settings ||= {}
9
+ @settings ||=
10
+ begin
11
+ result = {}
12
+
13
+ if (analysis = analysis_body).any?
14
+ result['analysis'] = analysis
15
+ end
16
+
17
+ result
18
+ end
10
19
  end
11
20
 
12
21
  def update_settings(index_name = alias_name)
13
22
  connection.json_put "/#{index_name}/_settings", settings
14
23
  end
24
+
25
+ def analysis_body
26
+ doctypes.each_with_object({}) do |doctype, result|
27
+ result.deep_merge!(doctype.analysis)
28
+ end
29
+ end
15
30
  end
16
31
  end
17
- end
32
+ end
@@ -1,12 +1,9 @@
1
1
  require 'elastic_record/index/analyze'
2
- require 'elastic_record/index/configurator'
3
2
  require 'elastic_record/index/deferred'
4
3
  require 'elastic_record/index/documents'
5
4
  require 'elastic_record/index/manage'
6
5
  require 'elastic_record/index/mapping'
7
- require 'elastic_record/index/percolator'
8
6
  require 'elastic_record/index/settings'
9
- require 'elastic_record/index/warmer'
10
7
 
11
8
  require 'active_support/core_ext/object/deep_dup'
12
9
 
@@ -26,30 +23,30 @@ module ElasticRecord
26
23
  # Returns if the index exists
27
24
  # [get_mapping]
28
25
  # Returns the mapping currently stored by elastic search.
29
- # [put_mapping]
26
+ # [update_mapping]
30
27
  # Update elastic search's mapping
31
28
  class Index
32
29
  include Documents
33
30
  include Manage
34
31
  include Mapping, Settings
35
- include Percolator, Warmer
36
32
  include Analyze
37
33
  include Deferred
38
34
 
39
- attr_accessor :model
35
+ attr_accessor :doctypes
40
36
 
41
37
  attr_accessor :disabled
42
- attr_accessor :has_percolator
38
+ attr_accessor :model
43
39
  attr_accessor :partial_updates
44
40
 
45
- def initialize(model)
46
- @model = model
41
+ def initialize(models)
42
+ models = Array.wrap(models)
43
+ @model = models.first
44
+ @doctypes = models.map(&:doctype)
47
45
  @disabled = false
48
46
  end
49
47
 
50
48
  def initialize_copy(other)
51
49
  @settings = settings.deep_dup
52
- @mapping = mapping.deep_dup
53
50
  end
54
51
 
55
52
  def alias_name=(name)
@@ -60,14 +57,6 @@ module ElasticRecord
60
57
  @alias_name ||= model.base_class.name.demodulize.underscore.pluralize
61
58
  end
62
59
 
63
- def type=(name)
64
- @type = name
65
- end
66
-
67
- def type
68
- @type ||= model.base_class.name.demodulize.underscore
69
- end
70
-
71
60
  def disable!
72
61
  @disabled = true
73
62
  end
@@ -80,12 +69,12 @@ module ElasticRecord
80
69
  model.elastic_connection
81
70
  end
82
71
 
83
- def configure(&block)
84
- Configurator.new(self).instance_eval(&block)
85
- end
72
+ def get(end_path, doctype = nil, json = nil)
73
+ path = "/#{alias_name}"
74
+ path += "/#{doctype.name}" if doctype
75
+ path += "/#{end_path}"
86
76
 
87
- def get(end_path, json = nil)
88
- connection.json_get "/#{alias_name}/#{type}/#{end_path}", json
77
+ connection.json_get path, json
89
78
  end
90
79
 
91
80
  private
@@ -93,6 +82,5 @@ module ElasticRecord
93
82
  def new_index_name
94
83
  "#{alias_name}_#{Time.now.utc.strftime('%Y%m%d_%H%M%S')}"
95
84
  end
96
-
97
85
  end
98
86
  end
@@ -5,6 +5,7 @@ module ElasticRecord
5
5
  extend Searching
6
6
  extend ClassMethods
7
7
  include Callbacks
8
+ include AsDocument
8
9
 
9
10
  class_attribute :elastic_connection
10
11
  self.elastic_connection = ElasticRecord::Connection.new(ElasticRecord::Config.servers, ElasticRecord::Config.connection_options)
@@ -17,17 +18,22 @@ module ElasticRecord
17
18
 
18
19
  if child < child.base_class
19
20
  child.elastic_index = elastic_index.dup
21
+ child.doctype = doctype.dup
20
22
  end
21
23
  end
22
24
 
23
- def elastic_relation
24
- ElasticRecord::Relation.new(self)
25
- end
26
-
27
25
  def arelastic
28
26
  Arelastic::Builders::Search
29
27
  end
30
28
 
29
+ def doctype
30
+ @doctype ||= Doctype.new(base_class.name.demodulize.underscore)
31
+ end
32
+
33
+ def doctype=(new_doctype)
34
+ @doctype = new_doctype
35
+ end
36
+
31
37
  def elastic_index
32
38
  @elastic_index ||= ElasticRecord::Index.new(self)
33
39
  end
@@ -44,5 +50,9 @@ module ElasticRecord
44
50
  def elastic_index
45
51
  self.class.elastic_index
46
52
  end
53
+
54
+ def doctype
55
+ self.class.doctype
56
+ end
47
57
  end
48
58
  end
@@ -0,0 +1,44 @@
1
+ module ElasticRecord
2
+ module PercolatorModel
3
+ def self.included(base)
4
+ base.class_eval do
5
+ class_attribute :percolates_model
6
+
7
+ include Model
8
+ extend ClassMethods
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+ def elastic_index
14
+ @elastic_index ||=
15
+ begin
16
+ index = ElasticRecord::Index.new([self, percolates_model])
17
+ index.partial_updates = false
18
+ index
19
+ end
20
+ end
21
+
22
+ def doctype
23
+ @doctype ||= Doctype.percolator_doctype
24
+ end
25
+
26
+ def percolate(document)
27
+ query = {
28
+ "query" => {
29
+ "percolate" => {
30
+ "field" => "query",
31
+ "document_type" => percolates_model.doctype.name,
32
+ "document" => document
33
+ }
34
+ }
35
+ }
36
+
37
+ hits = elastic_index.search(query)['hits']['hits']
38
+ ids = hits.map { |hits| hits['_id'] }
39
+
40
+ where(id: ids)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,5 +1,4 @@
1
1
  require 'elastic_record/relation/value_methods'
2
- require 'elastic_record/relation/admin'
3
2
  require 'elastic_record/relation/batches'
4
3
  require 'elastic_record/relation/delegation'
5
4
  require 'elastic_record/relation/finder_methods'
@@ -9,7 +8,7 @@ require 'elastic_record/relation/search_methods'
9
8
 
10
9
  module ElasticRecord
11
10
  class Relation
12
- include Admin, Batches, Delegation, FinderMethods, Merging, SearchMethods
11
+ include Batches, Delegation, FinderMethods, Merging, SearchMethods
13
12
 
14
13
  attr_reader :klass, :values
15
14
 
@@ -1,5 +1,9 @@
1
1
  module ElasticRecord
2
2
  module Searching
3
+ def elastic_relation
4
+ ElasticRecord::Relation.new(self)
5
+ end
6
+
3
7
  def elastic_search
4
8
  if current_elastic_search
5
9
  current_elastic_search.clone
@@ -27,4 +31,4 @@ module ElasticRecord
27
31
  Thread.current["#{self}_current_elastic_search"] = relation
28
32
  end
29
33
  end
30
- end
34
+ end
@@ -17,11 +17,6 @@ namespace :index do
17
17
  index = model.elastic_index
18
18
  index_name = index.create_and_deploy
19
19
  puts "Created #{model.name} index (#{index_name})"
20
-
21
- if index.has_percolator
22
- index_name = index.create_percolator_index
23
- puts "Created #{model.name} percolator index (#{index_name})"
24
- end
25
20
  end
26
21
  end
27
22
 
@@ -31,11 +26,6 @@ namespace :index do
31
26
  index = model.elastic_index
32
27
  index.delete_all
33
28
  puts "Dropped #{model.name} index"
34
-
35
- if index.has_percolator
36
- index.delete_percolator_index
37
- puts "Dropped #{model.name} percolator index (#{index.percolator_name})"
38
- end
39
29
  end
40
30
  end
41
31
 
@@ -3,13 +3,16 @@ require 'active_support/concern'
3
3
  require 'active_model'
4
4
 
5
5
  module ElasticRecord
6
+ autoload :AsDocument, 'elastic_record/as_document'
6
7
  autoload :Callbacks, 'elastic_record/callbacks'
7
8
  autoload :Config, 'elastic_record/config'
8
9
  autoload :Connection, 'elastic_record/connection'
10
+ autoload :Doctype, 'elastic_record/doctype'
9
11
  autoload :Index, 'elastic_record/index'
10
12
  autoload :JSON, 'elastic_record/json'
11
13
  autoload :Lucene, 'elastic_record/lucene'
12
14
  autoload :Model, 'elastic_record/model'
15
+ autoload :PercolatorModel, 'elastic_record/percolator_model'
13
16
  autoload :Relation, 'elastic_record/relation'
14
17
  autoload :Searching, 'elastic_record/searching'
15
18
 
@@ -0,0 +1,108 @@
1
+ # Essentially a fake ActiveRecord::Base
2
+ module MockModel
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ extend ActiveModel::Naming
7
+ extend ActiveModel::Callbacks
8
+ define_model_callbacks :save, :update, :create, :destroy
9
+
10
+ include ActiveModel::Dirty
11
+ include ActiveModel::Validations
12
+ end
13
+
14
+ module ClassMethods
15
+ def find(ids)
16
+ ids.map { |id| new(id: id) }
17
+ end
18
+
19
+ def where(query)
20
+ find query[:id]
21
+ end
22
+
23
+ def primary_key
24
+ 'id'
25
+ end
26
+
27
+ def base_class
28
+ self
29
+ end
30
+
31
+ def create(attributes = {})
32
+ record = new(attributes)
33
+ record.save
34
+ record
35
+ end
36
+
37
+ def define_attributes(attributes)
38
+ define_attribute_methods attributes
39
+
40
+ attributes.each do |attribute|
41
+ define_method attribute do
42
+ instance_variable_get("@#{attribute}")
43
+ end
44
+
45
+ define_method "#{attribute}=" do |value|
46
+ send("#{attribute}_will_change!")
47
+ instance_variable_set("@#{attribute}", value)
48
+ end
49
+ end
50
+
51
+ define_method 'attributes' do
52
+ Hash[attributes.map { |attr| [attr.to_s, send(attr)] }]
53
+ end
54
+ end
55
+ end
56
+
57
+ def initialize(attrs = {})
58
+ self.attributes = attrs
59
+ end
60
+
61
+ def attributes=(attrs)
62
+ attrs.each do |key, val|
63
+ send("#{key}=", val)
64
+ end
65
+ end
66
+
67
+ def id=(value)
68
+ @id = value
69
+ end
70
+
71
+ def id
72
+ @id ||= rand(10000).to_s
73
+ end
74
+
75
+ def save
76
+ @persisted = true
77
+ callback_method = new_record? ? :create : :update
78
+ run_callbacks callback_method
79
+ end
80
+
81
+ def destroy
82
+ @destroyed = true
83
+ run_callbacks :destroy
84
+ end
85
+
86
+ def ==(other)
87
+ id == other.id
88
+ end
89
+
90
+ def changed?
91
+ true
92
+ end
93
+
94
+ def new_record?
95
+ !@persisted
96
+ end
97
+
98
+ def persisted?
99
+ @persisted
100
+ end
101
+
102
+ def destroyed?
103
+ @destroyed
104
+ end
105
+
106
+ def reload
107
+ end
108
+ end
@@ -1,7 +1,7 @@
1
1
  class Project < ActiveRecord::Base
2
2
  include ElasticRecord::Model
3
3
 
4
- self.elastic_index.mapping[:properties].update(
4
+ self.doctype.mapping[:properties].update(
5
5
  'name' => { type: 'string', index: 'not_analyzed' }
6
6
  )
7
7
  end