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 +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
|