searchkick 0.6.1 → 0.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +4 -0
- data/lib/searchkick.rb +1 -2
- data/lib/searchkick/index.rb +78 -8
- data/lib/searchkick/logging.rb +89 -0
- data/lib/searchkick/model.rb +7 -78
- data/lib/searchkick/query.rb +7 -8
- data/lib/searchkick/similar.rb +1 -1
- data/lib/searchkick/version.rb +1 -1
- data/test/inheritance_test.rb +1 -1
- data/test/test_helper.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b2be48320f7dd756e116946199f07a52642b3e7
|
4
|
+
data.tar.gz: dc9c8e1fc6c82afa143f55556157786f95fb1aeb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d88370f0e37d4da8c5c9bb57cdfda98b242b830cf156b099e7d69b5be338b0924b52a37b5a1c38a57cdd7e75b8984c00f83504bbda6870df4fe8e68cf75b295
|
7
|
+
data.tar.gz: 134b2bd7d3fd80cd5f2ff18288304edd543f0250e344303baf14bff18b1674e97468de3c5d7e93d99e5e531d2d2440658e51d75983295c43ed8a2fbd2a718aed
|
data/CHANGELOG.md
CHANGED
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
|
data/lib/searchkick.rb
CHANGED
@@ -11,8 +11,7 @@ require "searchkick/search"
|
|
11
11
|
require "searchkick/similar"
|
12
12
|
require "searchkick/model"
|
13
13
|
require "searchkick/tasks"
|
14
|
-
|
15
|
-
# require "searchkick/logger" if defined?(Rails)
|
14
|
+
require "searchkick/logging" if defined?(Rails)
|
16
15
|
|
17
16
|
module Searchkick
|
18
17
|
|
data/lib/searchkick/index.rb
CHANGED
@@ -25,16 +25,16 @@ module Searchkick
|
|
25
25
|
def store(record)
|
26
26
|
client.index(
|
27
27
|
index: name,
|
28
|
-
type: record
|
28
|
+
type: document_type(record),
|
29
29
|
id: record.id,
|
30
|
-
body: record
|
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
|
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
|
47
|
-
body: records.map{|r| data = r
|
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(
|
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
|
data/lib/searchkick/model.rb
CHANGED
@@ -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
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
|
data/lib/searchkick/query.rb
CHANGED
@@ -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(
|
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
|
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
|
data/lib/searchkick/similar.rb
CHANGED
@@ -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(
|
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
|
|
data/lib/searchkick/version.rb
CHANGED
data/test/inheritance_test.rb
CHANGED
data/test/test_helper.rb
CHANGED
@@ -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.
|
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-
|
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
|