searchkick 1.1.2 → 1.2.0
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 +8 -0
- data/README.md +18 -1
- data/lib/searchkick.rb +10 -0
- data/lib/searchkick/index.rb +14 -7
- data/lib/searchkick/logging.rb +13 -15
- data/lib/searchkick/middleware.rb +2 -2
- data/lib/searchkick/query.rb +23 -7
- data/lib/searchkick/version.rb +1 -1
- data/test/highlight_test.rb +5 -0
- data/test/index_test.rb +7 -0
- data/test/model_test.rb +6 -0
- data/test/similar_test.rb +10 -0
- data/test/test_helper.rb +4 -0
- 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: 49a9ad19b612e5079b3c97ec4ff756e62b8e2333
|
4
|
+
data.tar.gz: 2e9133f49f0287cabf5bc88fe2fd28e6594ffa27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4e15ce0859a66945f0675226bb5492d67db7612f23e480d5cec930903db151c2622380d30192e1eace1feb146b455f56b5cb3f55c07129580ac8117da224f42e
|
7
|
+
data.tar.gz: 87c387df771fcf4dcec72b46f779169515acef02bd29ff12565c1c52374fc99a13d54a7d5a38ff0ef57cb7beb58412b0c354abf2beb0860342f2ff545605130a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 1.2.0
|
2
|
+
|
3
|
+
- Fixed deprecation warnings with `alias_method_chain`
|
4
|
+
- Added `analyzed_only` option for large text fields
|
5
|
+
- Added `encoder` option to highlight
|
6
|
+
- Fixed issue in `similar` method with `per_page` option
|
7
|
+
- Added basic support for multiple models
|
8
|
+
|
1
9
|
## 1.1.2
|
2
10
|
|
3
11
|
- Added bulk updates with `callbacks` method
|
data/README.md
CHANGED
@@ -35,6 +35,9 @@ Plus:
|
|
35
35
|
|
36
36
|
```sh
|
37
37
|
brew install elasticsearch
|
38
|
+
|
39
|
+
# start the server
|
40
|
+
elasticsearch
|
38
41
|
```
|
39
42
|
|
40
43
|
Add this line to your application’s Gemfile:
|
@@ -394,7 +397,7 @@ There are three strategies for keeping the index synced with your database.
|
|
394
397
|
end
|
395
398
|
```
|
396
399
|
|
397
|
-
And [install Active Job](https://github.com/ankane/activejob_backport) for Rails 4.1 and below
|
400
|
+
And [install Active Job](https://github.com/ankane/activejob_backport) for Rails 4.1 and below. Jobs are added to a queue named `searchkick`.
|
398
401
|
|
399
402
|
3. Manual
|
400
403
|
|
@@ -1121,6 +1124,14 @@ Remove old indices
|
|
1121
1124
|
Product.clean_indices
|
1122
1125
|
```
|
1123
1126
|
|
1127
|
+
Use custom settings
|
1128
|
+
|
1129
|
+
```ruby
|
1130
|
+
class Product < ActiveRecord::Base
|
1131
|
+
searchkick settings: {number_of_shards: 3}
|
1132
|
+
end
|
1133
|
+
```
|
1134
|
+
|
1124
1135
|
Use a different index name
|
1125
1136
|
|
1126
1137
|
```ruby
|
@@ -1235,6 +1246,12 @@ class Product < ActiveRecord::Base
|
|
1235
1246
|
end
|
1236
1247
|
```
|
1237
1248
|
|
1249
|
+
Search multiple models [master]
|
1250
|
+
|
1251
|
+
```ruby
|
1252
|
+
Searchkick.search "milk", index_name: [Product, Category]
|
1253
|
+
```
|
1254
|
+
|
1238
1255
|
Reindex all models - Rails only
|
1239
1256
|
|
1240
1257
|
```sh
|
data/lib/searchkick.rb
CHANGED
@@ -128,6 +128,16 @@ module Searchkick
|
|
128
128
|
def self.callbacks_value=(value)
|
129
129
|
Thread.current[:searchkick_callbacks_enabled] = value
|
130
130
|
end
|
131
|
+
|
132
|
+
def self.search(term = nil, options = {}, &block)
|
133
|
+
query = Searchkick::Query.new(nil, term, options)
|
134
|
+
block.call(query.body) if block
|
135
|
+
if options[:execute] == false
|
136
|
+
query
|
137
|
+
else
|
138
|
+
query.execute
|
139
|
+
end
|
140
|
+
end
|
131
141
|
end
|
132
142
|
|
133
143
|
# TODO find better ActiveModel hook
|
data/lib/searchkick/index.rb
CHANGED
@@ -102,7 +102,7 @@ module Searchkick
|
|
102
102
|
options[:where] ||= {}
|
103
103
|
options[:where][:_id] ||= {}
|
104
104
|
options[:where][:_id][:not] = record.id.to_s
|
105
|
-
options[:
|
105
|
+
options[:per_page] ||= 10
|
106
106
|
options[:similar] = true
|
107
107
|
|
108
108
|
# TODO use index class instead of record class
|
@@ -132,7 +132,12 @@ module Searchkick
|
|
132
132
|
|
133
133
|
# remove old indices that start w/ index_name
|
134
134
|
def clean_indices
|
135
|
-
all_indices =
|
135
|
+
all_indices =
|
136
|
+
begin
|
137
|
+
client.indices.get_aliases
|
138
|
+
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
139
|
+
[]
|
140
|
+
end
|
136
141
|
indices = all_indices.select { |k, v| (v.empty? || v["aliases"].empty?) && k =~ /\A#{Regexp.escape(name)}_\d{14,17}\z/ }.keys
|
137
142
|
indices.each do |index|
|
138
143
|
Searchkick::Index.new(index).delete
|
@@ -408,7 +413,7 @@ module Searchkick
|
|
408
413
|
end
|
409
414
|
|
410
415
|
mapping_options = Hash[
|
411
|
-
[:autocomplete, :suggest, :word, :text_start, :text_middle, :text_end, :word_start, :word_middle, :word_end, :highlight, :searchable]
|
416
|
+
[:autocomplete, :suggest, :word, :text_start, :text_middle, :text_end, :word_start, :word_middle, :word_end, :highlight, :searchable, :only_analyzed]
|
412
417
|
.map { |type| [type, (options[type] || []).map(&:to_s)] }
|
413
418
|
]
|
414
419
|
|
@@ -417,11 +422,13 @@ module Searchkick
|
|
417
422
|
mapping_options.values.flatten.uniq.each do |field|
|
418
423
|
field_mapping = {
|
419
424
|
type: "multi_field",
|
420
|
-
fields: {
|
421
|
-
field => {type: "string", index: "not_analyzed"}
|
422
|
-
}
|
425
|
+
fields: {}
|
423
426
|
}
|
424
427
|
|
428
|
+
unless mapping_options[:only_analyzed].include?(field)
|
429
|
+
field_mapping[:fields][field] = {type: "string", index: "not_analyzed"}
|
430
|
+
end
|
431
|
+
|
425
432
|
if !options[:searchable] || mapping_options[:searchable].include?(field)
|
426
433
|
if word
|
427
434
|
field_mapping[:fields]["analyzed"] = {type: "string", index: "analyzed"}
|
@@ -431,7 +438,7 @@ module Searchkick
|
|
431
438
|
end
|
432
439
|
end
|
433
440
|
|
434
|
-
mapping_options.except(:highlight, :searchable).each do |type, fields|
|
441
|
+
mapping_options.except(:highlight, :searchable, :only_analyzed).each do |type, fields|
|
435
442
|
if options[:match] == type || fields.include?(field)
|
436
443
|
field_mapping[:fields][type] = {type: "string", index: "analyzed", analyzer: "searchkick_#{type}_index"}
|
437
444
|
end
|
data/lib/searchkick/logging.rb
CHANGED
@@ -1,54 +1,51 @@
|
|
1
1
|
# based on https://gist.github.com/mnutt/566725
|
2
2
|
|
3
3
|
module Searchkick
|
4
|
-
|
5
|
-
def
|
4
|
+
module QueryWithInstrumentation
|
5
|
+
def execute_search
|
6
6
|
event = {
|
7
7
|
name: "#{searchkick_klass.name} Search",
|
8
8
|
query: params
|
9
9
|
}
|
10
10
|
ActiveSupport::Notifications.instrument("search.searchkick", event) do
|
11
|
-
|
11
|
+
super
|
12
12
|
end
|
13
13
|
end
|
14
|
-
alias_method_chain :execute_search, :instrumentation
|
15
14
|
end
|
16
15
|
|
17
|
-
|
18
|
-
def
|
16
|
+
module IndexWithInstrumentation
|
17
|
+
def store(record)
|
19
18
|
event = {
|
20
19
|
name: "#{record.searchkick_klass.name} Store",
|
21
20
|
id: search_id(record)
|
22
21
|
}
|
23
22
|
ActiveSupport::Notifications.instrument("request.searchkick", event) do
|
24
|
-
|
23
|
+
super(record)
|
25
24
|
end
|
26
25
|
end
|
27
|
-
alias_method_chain :store, :instrumentation
|
28
26
|
|
29
|
-
|
27
|
+
|
28
|
+
def remove(record)
|
30
29
|
event = {
|
31
30
|
name: "#{record.searchkick_klass.name} Remove",
|
32
31
|
id: search_id(record)
|
33
32
|
}
|
34
33
|
ActiveSupport::Notifications.instrument("request.searchkick", event) do
|
35
|
-
|
34
|
+
super(record)
|
36
35
|
end
|
37
36
|
end
|
38
|
-
alias_method_chain :remove, :instrumentation
|
39
37
|
|
40
|
-
def
|
38
|
+
def import(records)
|
41
39
|
if records.any?
|
42
40
|
event = {
|
43
41
|
name: "#{records.first.searchkick_klass.name} Import",
|
44
42
|
count: records.size
|
45
43
|
}
|
46
44
|
ActiveSupport::Notifications.instrument("request.searchkick", event) do
|
47
|
-
|
45
|
+
super(records)
|
48
46
|
end
|
49
47
|
end
|
50
48
|
end
|
51
|
-
alias_method_chain :import, :instrumentation
|
52
49
|
end
|
53
50
|
|
54
51
|
# https://github.com/rails/rails/blob/master/activerecord/lib/active_record/log_subscriber.rb
|
@@ -131,7 +128,8 @@ module Searchkick
|
|
131
128
|
end
|
132
129
|
end
|
133
130
|
end
|
134
|
-
|
131
|
+
Searchkick::Query.send(:prepend, Searchkick::QueryWithInstrumentation)
|
132
|
+
Searchkick::Index.send(:prepend, Searchkick::IndexWithInstrumentation)
|
135
133
|
Searchkick::LogSubscriber.attach_to :searchkick
|
136
134
|
ActiveSupport.on_load(:action_controller) do
|
137
135
|
include Searchkick::ControllerRuntime
|
@@ -3,8 +3,8 @@ require "faraday/middleware"
|
|
3
3
|
module Searchkick
|
4
4
|
class Middleware < Faraday::Middleware
|
5
5
|
def call(env)
|
6
|
-
if env
|
7
|
-
env
|
6
|
+
if env[:method] == :get && env[:url].path.to_s.end_with?("/_search")
|
7
|
+
env[:request][:timeout] = Searchkick.search_timeout
|
8
8
|
end
|
9
9
|
@app.call(env)
|
10
10
|
end
|
data/lib/searchkick/query.rb
CHANGED
@@ -28,20 +28,29 @@ module Searchkick
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def searchkick_index
|
31
|
-
klass.searchkick_index
|
31
|
+
klass ? klass.searchkick_index : nil
|
32
32
|
end
|
33
33
|
|
34
34
|
def searchkick_options
|
35
|
-
klass.searchkick_options
|
35
|
+
klass ? klass.searchkick_options : {}
|
36
36
|
end
|
37
37
|
|
38
38
|
def searchkick_klass
|
39
|
-
klass.searchkick_klass
|
39
|
+
klass ? klass.searchkick_klass : nil
|
40
40
|
end
|
41
41
|
|
42
42
|
def params
|
43
|
+
index =
|
44
|
+
if options[:index_name]
|
45
|
+
Array(options[:index_name]).map { |v| v.respond_to?(:searchkick_index) ? v.searchkick_index.name : v }.join(",")
|
46
|
+
elsif searchkick_index
|
47
|
+
searchkick_index.name
|
48
|
+
else
|
49
|
+
"_all"
|
50
|
+
end
|
51
|
+
|
43
52
|
params = {
|
44
|
-
index:
|
53
|
+
index: index,
|
45
54
|
body: body
|
46
55
|
}
|
47
56
|
params.merge!(type: @type) if @type
|
@@ -60,7 +69,7 @@ module Searchkick
|
|
60
69
|
rescue => e # TODO rescue type
|
61
70
|
status_code = e.message[1..3].to_i
|
62
71
|
if status_code == 404
|
63
|
-
raise MissingIndexError, "Index missing - run #{
|
72
|
+
raise MissingIndexError, "Index missing - run #{reindex_command}"
|
64
73
|
elsif status_code == 500 && (
|
65
74
|
e.message.include?("IllegalArgumentException[minimumSimilarity >= 1]") ||
|
66
75
|
e.message.include?("No query registered for [multi_match]") ||
|
@@ -71,7 +80,7 @@ module Searchkick
|
|
71
80
|
raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 1.0 or greater"
|
72
81
|
elsif status_code == 400
|
73
82
|
if e.message.include?("[multi_match] analyzer [searchkick_search] not found")
|
74
|
-
raise InvalidQueryError, "Bad mapping - run #{
|
83
|
+
raise InvalidQueryError, "Bad mapping - run #{reindex_command}"
|
75
84
|
else
|
76
85
|
raise InvalidQueryError, e.message
|
77
86
|
end
|
@@ -116,6 +125,10 @@ module Searchkick
|
|
116
125
|
|
117
126
|
private
|
118
127
|
|
128
|
+
def reindex_command
|
129
|
+
searchkick_klass ? "#{searchkick_klass.name}.reindex" : "reindex"
|
130
|
+
end
|
131
|
+
|
119
132
|
def execute_search
|
120
133
|
Searchkick.client.search(params)
|
121
134
|
end
|
@@ -536,6 +549,9 @@ module Searchkick
|
|
536
549
|
if (fragment_size = options[:highlight][:fragment_size])
|
537
550
|
payload[:highlight][:fragment_size] = fragment_size
|
538
551
|
end
|
552
|
+
if (encoder = options[:highlight][:encoder])
|
553
|
+
payload[:highlight][:encoder] = encoder
|
554
|
+
end
|
539
555
|
|
540
556
|
highlight_fields = options[:highlight][:fields]
|
541
557
|
if highlight_fields
|
@@ -558,7 +574,7 @@ module Searchkick
|
|
558
574
|
payload[:fields] = []
|
559
575
|
end
|
560
576
|
|
561
|
-
if options[:type] || klass != searchkick_klass
|
577
|
+
if options[:type] || (klass != searchkick_klass && searchkick_index)
|
562
578
|
@type = [options[:type] || klass].flatten.map { |v| searchkick_index.klass_document_type(v) }
|
563
579
|
end
|
564
580
|
|
data/lib/searchkick/version.rb
CHANGED
data/test/highlight_test.rb
CHANGED
@@ -36,6 +36,11 @@ class HighlightTest < Minitest::Test
|
|
36
36
|
assert_equal "<em>Hello</em> World <em>Hello</em>", Product.search("hello", fields: [:name], highlight: true).with_details.first[1][:highlight][:name]
|
37
37
|
end
|
38
38
|
|
39
|
+
def test_encoder
|
40
|
+
store_names ["<b>Hello</b>"]
|
41
|
+
assert_equal "<b><em>Hello</em></b>", Product.search("hello", fields: [:name], highlight: {encoder: "html"}, misspellings: false).with_details.first[1][:highlight][:name]
|
42
|
+
end
|
43
|
+
|
39
44
|
def test_json
|
40
45
|
skip if ENV["MATCH"] == "word_start"
|
41
46
|
store_names ["Two Door Cinema Club"]
|
data/test/index_test.rb
CHANGED
@@ -110,4 +110,11 @@ class IndexTest < Minitest::Test
|
|
110
110
|
end
|
111
111
|
assert_search "product", []
|
112
112
|
end
|
113
|
+
|
114
|
+
def test_analyzed_only
|
115
|
+
skip if nobrainer?
|
116
|
+
large_value = 10000.times.map { "hello" }.join(" ")
|
117
|
+
store [{name: "Product A", alt_description: large_value}]
|
118
|
+
assert_search "product", ["Product A"]
|
119
|
+
end
|
113
120
|
end
|
data/test/model_test.rb
CHANGED
@@ -33,4 +33,10 @@ class ModelTest < Minitest::Test
|
|
33
33
|
|
34
34
|
assert_search "product", ["product a", "product b"]
|
35
35
|
end
|
36
|
+
|
37
|
+
def test_multiple_models
|
38
|
+
store_names ["Product A"]
|
39
|
+
store_names ["Product B"], Store
|
40
|
+
assert_equal Product.all + Store.all, Searchkick.search("product", index_name: [Product, Store], order: "name").to_a
|
41
|
+
end
|
36
42
|
end
|
data/test/similar_test.rb
CHANGED
@@ -15,4 +15,14 @@ class SimilarTest < Minitest::Test
|
|
15
15
|
store_names ["Lucerne Milk Chocolate Fat Free", "Clover Fat Free Milk"]
|
16
16
|
assert_order "Lucerne Fat Free Chocolate Milk", ["Lucerne Milk Chocolate Fat Free", "Clover Fat Free Milk"], similar: true
|
17
17
|
end
|
18
|
+
|
19
|
+
def test_limit
|
20
|
+
store_names ["1% Organic Milk", "2% Organic Milk", "Fat Free Organic Milk", "Popcorn"]
|
21
|
+
assert_equal ["2% Organic Milk"], Product.where(name: "1% Organic Milk").first.similar(fields: ["name"], order: ["name"], limit: 1).map(&:name)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_per_page
|
25
|
+
store_names ["1% Organic Milk", "2% Organic Milk", "Fat Free Organic Milk", "Popcorn"]
|
26
|
+
assert_equal ["2% Organic Milk"], Product.where(name: "1% Organic Milk").first.similar(fields: ["name"], order: ["name"], per_page: 1).map(&:name)
|
27
|
+
end
|
18
28
|
end
|
data/test/test_helper.rb
CHANGED
@@ -73,6 +73,7 @@ if defined?(Mongoid)
|
|
73
73
|
field :latitude, type: BigDecimal
|
74
74
|
field :longitude, type: BigDecimal
|
75
75
|
field :description
|
76
|
+
field :alt_description
|
76
77
|
end
|
77
78
|
|
78
79
|
class Store
|
@@ -114,6 +115,7 @@ elsif defined?(NoBrainer)
|
|
114
115
|
field :latitude
|
115
116
|
field :longitude
|
116
117
|
field :description, type: String
|
118
|
+
field :alt_description, type: String
|
117
119
|
|
118
120
|
belongs_to :store, validates: false
|
119
121
|
end
|
@@ -164,6 +166,7 @@ else
|
|
164
166
|
t.decimal :latitude, precision: 10, scale: 7
|
165
167
|
t.decimal :longitude, precision: 10, scale: 7
|
166
168
|
t.text :description
|
169
|
+
t.text :alt_description
|
167
170
|
t.timestamps null: true
|
168
171
|
end
|
169
172
|
|
@@ -219,6 +222,7 @@ class Product
|
|
219
222
|
highlight: [:name],
|
220
223
|
# unsearchable: [:description],
|
221
224
|
searchable: [:name, :color],
|
225
|
+
only_analyzed: [:alt_description],
|
222
226
|
match: ENV["MATCH"] ? ENV["MATCH"].to_sym : nil
|
223
227
|
|
224
228
|
attr_accessor :conversions, :user_ids, :aisle
|
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: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -219,3 +219,4 @@ test_files:
|
|
219
219
|
- test/synonyms_test.rb
|
220
220
|
- test/test_helper.rb
|
221
221
|
- test/where_test.rb
|
222
|
+
has_rdoc:
|