searchkick 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c81923ad42ba7a15c923bf2b2320ed03894b6a14
4
- data.tar.gz: 5655aa933464e320c0473b41b9b6a7d644c46dbb
3
+ metadata.gz: 9b2be48320f7dd756e116946199f07a52642b3e7
4
+ data.tar.gz: dc9c8e1fc6c82afa143f55556157786f95fb1aeb
5
5
  SHA512:
6
- metadata.gz: fb8db1d17809462eb65aacb6662b9157637b68cc99ac417e2b570a3ff589a547b0bd72d66d50cb1b1b1e3a7d469d5787e653976916b9438ec887c44a3a975373
7
- data.tar.gz: ce0f005d8c74c490007d39a9c65d07455a81ab8d2a5ca0377b9f93d3cf6b7d799f45ce6324ebc5bee3060dea1f6d75a8762105dd9e308289e2c130eb5f1400e8
6
+ metadata.gz: 8d88370f0e37d4da8c5c9bb57cdfda98b242b830cf156b099e7d69b5be338b0924b52a37b5a1c38a57cdd7e75b8984c00f83504bbda6870df4fe8e68cf75b295
7
+ data.tar.gz: 134b2bd7d3fd80cd5f2ff18288304edd543f0250e344303baf14bff18b1674e97468de3c5d7e93d99e5e531d2d2440658e51d75983295c43ed8a2fbd2a718aed
@@ -1,3 +1,9 @@
1
+ ## 0.6.2
2
+
3
+ - Added logging
4
+ - Fixed index_name option
5
+ - Added ability to use proc as the index name
6
+
1
7
  ## 0.6.1
2
8
 
3
9
  - Fixed huge issue w/ zero-downtime reindexing on 0.90 and elasticsearch-ruby 1.0
data/README.md CHANGED
@@ -744,6 +744,10 @@ rake searchkick:reindex:all
744
744
 
745
745
  4. Once it finishes, replace search calls w/ searchkick calls
746
746
 
747
+ ## Note about 0.6.0
748
+
749
+ If running Searchkick `0.6.0` and Elasticsearch `0.90`, we recommend upgrading to Searchkick `0.6.1` to fix an issue that causes downtime when reindexing.
750
+
747
751
  ## Elasticsearch Gotchas
748
752
 
749
753
  ### Inconsistent Scores
@@ -11,8 +11,7 @@ require "searchkick/search"
11
11
  require "searchkick/similar"
12
12
  require "searchkick/model"
13
13
  require "searchkick/tasks"
14
- # TODO add logger
15
- # require "searchkick/logger" if defined?(Rails)
14
+ require "searchkick/logging" if defined?(Rails)
16
15
 
17
16
  module Searchkick
18
17
 
@@ -25,16 +25,16 @@ module Searchkick
25
25
  def store(record)
26
26
  client.index(
27
27
  index: name,
28
- type: record.document_type,
28
+ type: document_type(record),
29
29
  id: record.id,
30
- body: record.as_indexed_json
30
+ body: search_data(record)
31
31
  )
32
32
  end
33
33
 
34
34
  def remove(record)
35
35
  client.delete(
36
36
  index: name,
37
- type: record.document_type,
37
+ type: document_type(record),
38
38
  id: record.id
39
39
  )
40
40
  end
@@ -43,25 +43,95 @@ module Searchkick
43
43
  if records.any?
44
44
  client.bulk(
45
45
  index: name,
46
- type: records.first.document_type,
47
- body: records.map{|r| data = r.as_indexed_json; {index: {_id: data["_id"] || data["id"] || r.id, data: data}} }
46
+ type: document_type(records.first),
47
+ body: records.map{|r| data = search_data(r); {index: {_id: data["_id"] || data["id"] || r.id, data: data}} }
48
48
  )
49
49
  end
50
50
  end
51
51
 
52
- def retrieve(document_type, id)
52
+ def retrieve(record)
53
53
  client.get(
54
54
  index: name,
55
- type: document_type,
56
- id: id
55
+ type: document_type(record),
56
+ id: record.id
57
57
  )["_source"]
58
58
  end
59
59
 
60
+ def klass_document_type(klass)
61
+ klass.model_name.to_s.underscore
62
+ end
63
+
60
64
  protected
61
65
 
62
66
  def client
63
67
  Searchkick.client
64
68
  end
65
69
 
70
+ def document_type(record)
71
+ klass_document_type(record.class)
72
+ end
73
+
74
+ def search_data(record)
75
+ source = record.search_data
76
+
77
+ # stringify fields
78
+ source = source.inject({}){|memo,(k,v)| memo[k.to_s] = v; memo}
79
+
80
+ # Mongoid 4 hack
81
+ if defined?(BSON::ObjectId) and source["_id"].is_a?(BSON::ObjectId)
82
+ source["_id"] = source["_id"].to_s
83
+ end
84
+
85
+ options = record.class.searchkick_options
86
+
87
+ # conversions
88
+ conversions_field = options[:conversions]
89
+ if conversions_field and source[conversions_field]
90
+ source[conversions_field] = source[conversions_field].map{|k, v| {query: k, count: v} }
91
+ end
92
+
93
+ # hack to prevent generator field doesn't exist error
94
+ (options[:suggest] || []).map(&:to_s).each do |field|
95
+ source[field] = nil if !source[field]
96
+ end
97
+
98
+ # locations
99
+ (options[:locations] || []).map(&:to_s).each do |field|
100
+ if source[field]
101
+ if source[field].first.is_a?(Array) # array of arrays
102
+ source[field] = source[field].map{|a| a.map(&:to_f).reverse }
103
+ else
104
+ source[field] = source[field].map(&:to_f).reverse
105
+ end
106
+ end
107
+ end
108
+
109
+ cast_big_decimal(source)
110
+
111
+ # p search_data
112
+
113
+ source.as_json
114
+ end
115
+
116
+ # change all BigDecimal values to floats due to
117
+ # https://github.com/rails/rails/issues/6033
118
+ # possible loss of precision :/
119
+ def cast_big_decimal(obj)
120
+ case obj
121
+ when BigDecimal
122
+ obj.to_f
123
+ when Hash
124
+ obj.each do |k, v|
125
+ obj[k] = cast_big_decimal(v)
126
+ end
127
+ when Enumerable
128
+ obj.map do |v|
129
+ cast_big_decimal(v)
130
+ end
131
+ else
132
+ obj
133
+ end
134
+ end
135
+
66
136
  end
67
137
  end
@@ -0,0 +1,89 @@
1
+ # based on https://gist.github.com/mnutt/566725
2
+
3
+ module Searchkick
4
+ class Query
5
+ def execute_with_instrumentation
6
+ event = {
7
+ name: "#{searchkick_klass.name} Search",
8
+ query: params
9
+ }
10
+ ActiveSupport::Notifications.instrument("search.searchkick", event) do
11
+ execute_without_instrumentation
12
+ end
13
+ end
14
+
15
+ alias_method_chain :execute, :instrumentation
16
+ end
17
+
18
+ # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/log_subscriber.rb
19
+ class LogSubscriber < ActiveSupport::LogSubscriber
20
+ def self.runtime=(value)
21
+ Thread.current[:searchkick_runtime] = value
22
+ end
23
+
24
+ def self.runtime
25
+ Thread.current[:searchkick_runtime] ||= 0
26
+ end
27
+
28
+ def self.reset_runtime
29
+ rt, self.runtime = runtime, 0
30
+ rt
31
+ end
32
+
33
+ def search(event)
34
+ self.class.runtime += event.duration
35
+ return unless logger.debug?
36
+
37
+ payload = event.payload
38
+ name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
39
+ type = payload[:query][:type]
40
+
41
+ # no easy way to tell which host the client will use
42
+ host = Searchkick.client.transport.hosts.first
43
+ debug " #{color(name, YELLOW, true)} curl #{host[:protocol]}://#{host[:host]}:#{host[:port]}/#{CGI.escape(payload[:query][:index])}#{type ? "/#{type.map{|t| CGI.escape(t) }.join(",")}" : ""}/_search?pretty -d '#{payload[:query][:body].to_json}'"
44
+ end
45
+ end
46
+
47
+ # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/railties/controller_runtime.rb
48
+ module ControllerRuntime
49
+ extend ActiveSupport::Concern
50
+
51
+ protected
52
+
53
+ attr_internal :searchkick_runtime
54
+
55
+ def process_action(action, *args)
56
+ # We also need to reset the runtime before each action
57
+ # because of queries in middleware or in cases we are streaming
58
+ # and it won't be cleaned up by the method below.
59
+ Searchkick::LogSubscriber.reset_runtime
60
+ super
61
+ end
62
+
63
+ def cleanup_view_runtime
64
+ searchkick_rt_before_render = Searchkick::LogSubscriber.reset_runtime
65
+ runtime = super
66
+ searchkick_rt_after_render = Searchkick::LogSubscriber.reset_runtime
67
+ self.searchkick_runtime = searchkick_rt_before_render + searchkick_rt_after_render
68
+ runtime - searchkick_rt_after_render
69
+ end
70
+
71
+ def append_info_to_payload(payload)
72
+ super
73
+ payload[:searchkick_runtime] = (searchkick_runtime || 0) + Searchkick::LogSubscriber.reset_runtime
74
+ end
75
+
76
+ module ClassMethods
77
+ def log_process_action(payload)
78
+ messages, runtime = super, payload[:searchkick_runtime]
79
+ messages << ("Searchkick: %.1fms" % runtime.to_f) if runtime.to_f > 0
80
+ messages
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ Searchkick::LogSubscriber.attach_to :searchkick
87
+ ActiveSupport.on_load(:action_controller) do
88
+ include Searchkick::ControllerRuntime
89
+ end
@@ -3,17 +3,19 @@ module Searchkick
3
3
 
4
4
  def searchkick(options = {})
5
5
  class_eval do
6
- cattr_reader :searchkick_options, :searchkick_env, :searchkick_klass, :searchkick_index
6
+ cattr_reader :searchkick_options, :searchkick_env, :searchkick_klass
7
7
 
8
8
  class_variable_set :@@searchkick_options, options.dup
9
9
  class_variable_set :@@searchkick_env, ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
10
10
  class_variable_set :@@searchkick_klass, self
11
11
  class_variable_set :@@searchkick_callbacks, options[:callbacks] != false
12
+ class_variable_set :@@searchkick_index, options[:index_name] || [options[:index_prefix], model_name.plural, searchkick_env].compact.join("_")
12
13
 
13
- # set index name
14
- # TODO support proc
15
- index_name = options[:index_name] || [options[:index_prefix], model_name.plural, searchkick_env].compact.join("_")
16
- class_variable_set :@@searchkick_index, Searchkick::Index.new(index_name)
14
+ def self.searchkick_index
15
+ index = class_variable_get :@@searchkick_index
16
+ index = index.call if index.respond_to? :call
17
+ Searchkick::Index.new(index)
18
+ end
17
19
 
18
20
  extend Searchkick::Search
19
21
  extend Searchkick::Reindex
@@ -59,79 +61,6 @@ module Searchkick
59
61
  respond_to?(:to_hash) ? to_hash : serializable_hash
60
62
  end
61
63
 
62
- def as_indexed_json
63
- source = search_data
64
-
65
- # stringify fields
66
- source = source.inject({}){|memo,(k,v)| memo[k.to_s] = v; memo}
67
-
68
- # Mongoid 4 hack
69
- if defined?(BSON::ObjectId) and source["_id"].is_a?(BSON::ObjectId)
70
- source["_id"] = source["_id"].to_s
71
- end
72
-
73
- options = self.class.searchkick_options
74
-
75
- # conversions
76
- conversions_field = options[:conversions]
77
- if conversions_field and source[conversions_field]
78
- source[conversions_field] = source[conversions_field].map{|k, v| {query: k, count: v} }
79
- end
80
-
81
- # hack to prevent generator field doesn't exist error
82
- (options[:suggest] || []).map(&:to_s).each do |field|
83
- source[field] = nil if !source[field]
84
- end
85
-
86
- # locations
87
- (options[:locations] || []).map(&:to_s).each do |field|
88
- if source[field]
89
- if source[field].first.is_a?(Array) # array of arrays
90
- source[field] = source[field].map{|a| a.map(&:to_f).reverse }
91
- else
92
- source[field] = source[field].map(&:to_f).reverse
93
- end
94
- end
95
- end
96
-
97
- # change all BigDecimal values to floats due to
98
- # https://github.com/rails/rails/issues/6033
99
- # possible loss of precision :/
100
- cast_big_decimal =
101
- proc do |obj|
102
- case obj
103
- when BigDecimal
104
- obj.to_f
105
- when Hash
106
- obj.each do |k, v|
107
- obj[k] = cast_big_decimal.call(v)
108
- end
109
- when Enumerable
110
- obj.map! do |v|
111
- cast_big_decimal.call(v)
112
- end
113
- else
114
- obj
115
- end
116
- end
117
-
118
- cast_big_decimal.call(source)
119
-
120
- # p search_data
121
-
122
- source.as_json
123
- end
124
-
125
- # TODO remove
126
-
127
- def self.document_type
128
- model_name.to_s.underscore
129
- end
130
-
131
- def document_type
132
- self.class.document_type
133
- end
134
-
135
64
  end
136
65
  end
137
66
 
@@ -39,7 +39,6 @@ module Searchkick
39
39
  page = [options[:page].to_i, 1].max
40
40
  per_page = (options[:limit] || options[:per_page] || 100000).to_i
41
41
  offset = options[:offset] || (page - 1) * per_page
42
- index_name = options[:index_name] || searchkick_index.name
43
42
 
44
43
  conversions_field = searchkick_options[:conversions]
45
44
  personalize_field = searchkick_options[:personalize]
@@ -282,7 +281,7 @@ module Searchkick
282
281
  payload[:fields] = [] if load
283
282
 
284
283
  if options[:type] or klass != searchkick_klass
285
- @type = [options[:type] || klass].flatten.map(&:document_type)
284
+ @type = [options[:type] || klass].flatten.map{|v| searchkick_index.klass_document_type(v) }
286
285
  end
287
286
 
288
287
  @body = payload
@@ -304,16 +303,16 @@ module Searchkick
304
303
  klass.searchkick_klass
305
304
  end
306
305
 
307
- def document_type
308
- klass.document_type
309
- end
310
-
311
- def execute
306
+ def params
312
307
  params = {
313
- index: searchkick_index.name,
308
+ index: options[:index_name] || searchkick_index.name,
314
309
  body: body
315
310
  }
316
311
  params.merge!(type: @type) if @type
312
+ params
313
+ end
314
+
315
+ def execute
317
316
  begin
318
317
  response = Searchkick.client.search(params)
319
318
  rescue => e # TODO rescue type
@@ -2,7 +2,7 @@ module Searchkick
2
2
  module Similar
3
3
 
4
4
  def similar(options = {})
5
- like_text = self.class.searchkick_index.retrieve(document_type, id).to_hash
5
+ like_text = self.class.searchkick_index.retrieve(self).to_hash
6
6
  .keep_if{|k,v| !options[:fields] || options[:fields].map(&:to_s).include?(k) }
7
7
  .values.compact.join(" ")
8
8
 
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "0.6.1"
2
+ VERSION = "0.6.2"
3
3
  end
@@ -10,7 +10,7 @@ class TestInheritance < Minitest::Unit::TestCase
10
10
  end
11
11
 
12
12
  def test_child_index_name
13
- assert_equal "animals_test", Dog.searchkick_index.name
13
+ assert_equal "animals-#{Date.today.year}", Dog.searchkick_index.name
14
14
  end
15
15
 
16
16
  def test_child_search
@@ -143,7 +143,7 @@ class Store
143
143
  end
144
144
 
145
145
  class Animal
146
- searchkick autocomplete: [:name], suggest: [:name]
146
+ searchkick autocomplete: [:name], suggest: [:name], index_name: -> { "#{self.name.tableize}-#{Date.today.year}" }
147
147
  end
148
148
 
149
149
  Product.searchkick_index.delete if Product.searchkick_index.exists?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: searchkick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-25 00:00:00.000000000 Z
11
+ date: 2014-04-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -126,6 +126,7 @@ files:
126
126
  - gemfiles/mongoid4.gemfile
127
127
  - lib/searchkick.rb
128
128
  - lib/searchkick/index.rb
129
+ - lib/searchkick/logging.rb
129
130
  - lib/searchkick/model.rb
130
131
  - lib/searchkick/query.rb
131
132
  - lib/searchkick/reindex.rb