searchkick 3.0.3 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +4 -4
- data/lib/searchkick.rb +0 -7
- data/lib/searchkick/index.rb +1 -2
- data/lib/searchkick/index_options.rb +5 -5
- data/lib/searchkick/model.rb +2 -2
- data/lib/searchkick/query.rb +4 -2
- data/lib/searchkick/record_indexer.rb +2 -2
- data/lib/searchkick/reindex_v2_job.rb +1 -1
- data/lib/searchkick/results.rb +41 -19
- data/lib/searchkick/version.rb +1 -1
- data/test/highlight_test.rb +15 -0
- data/test/index_test.rb +5 -2
- data/test/routing_test.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2353bcf562a8f814430f473f0356e65cc8275c5bb21267fc46b96004c8edd27c
|
4
|
+
data.tar.gz: 5c570d53bc6d728a183de8ffb22056909ac748adebc6b436d2b8de785c3965fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0aa2359ff46b280d0cc87fe57cf809760de414e3e40d7f5cb3c33cd43124ef3ad7aba824aa87f43390a188983ae2c1dfecba141ddaa19ab27a1cb50f6368447
|
7
|
+
data.tar.gz: bbf49af1a70667bdfa24ebee0227b0fa2b8d1738cfcbb860680d597a245d6860b1e5b56b978fc6b4aa9aa96e41bd20392e6e99116b7e69ff4a233a5480003709
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## 3.1.0
|
2
|
+
|
3
|
+
- Added `:inline` as alias for `true` for `callbacks` and `mode` options
|
4
|
+
- Friendlier error message for bad mapping with partial matches
|
5
|
+
- Warn when records in search index do not exist in database
|
6
|
+
- Easier merging for `merge_mapping`
|
7
|
+
- Fixed `with_hit` and `with_highlights` when records in search index do not exist in database
|
8
|
+
- Fixed error with highlights and match all
|
9
|
+
|
1
10
|
## 3.0.3
|
2
11
|
|
3
12
|
- Added support for pagination with `body` option
|
data/README.md
CHANGED
@@ -507,7 +507,7 @@ For large data sets, try [parallel reindexing](#parallel-reindexing).
|
|
507
507
|
|
508
508
|
There are four strategies for keeping the index synced with your database.
|
509
509
|
|
510
|
-
1.
|
510
|
+
1. Inline (default)
|
511
511
|
|
512
512
|
Anytime a record is inserted, updated, or deleted
|
513
513
|
|
@@ -1790,12 +1790,12 @@ describe Product, search: true do
|
|
1790
1790
|
end
|
1791
1791
|
```
|
1792
1792
|
|
1793
|
-
### Factory
|
1793
|
+
### Factory Bot
|
1794
1794
|
|
1795
1795
|
Use a trait and an after `create` hook for each indexed model:
|
1796
1796
|
|
1797
1797
|
```ruby
|
1798
|
-
|
1798
|
+
FactoryBot.define do
|
1799
1799
|
factory :product do
|
1800
1800
|
# ...
|
1801
1801
|
|
@@ -1810,7 +1810,7 @@ FactoryGirl.define do
|
|
1810
1810
|
end
|
1811
1811
|
|
1812
1812
|
# use it
|
1813
|
-
|
1813
|
+
FactoryBot.create(:product, :some_trait, :reindex, some_attribute: "foo")
|
1814
1814
|
```
|
1815
1815
|
|
1816
1816
|
### Parallel Tests
|
data/lib/searchkick.rb
CHANGED
@@ -26,13 +26,6 @@ rescue LoadError
|
|
26
26
|
end
|
27
27
|
require "searchkick/tasks" if defined?(Rake)
|
28
28
|
|
29
|
-
begin
|
30
|
-
require "rake"
|
31
|
-
rescue LoadError
|
32
|
-
# do nothing
|
33
|
-
end
|
34
|
-
require "searchkick/tasks" if defined?(Rake)
|
35
|
-
|
36
29
|
# background jobs
|
37
30
|
begin
|
38
31
|
require "active_job"
|
data/lib/searchkick/index.rb
CHANGED
@@ -159,10 +159,9 @@ module Searchkick
|
|
159
159
|
.keep_if { |k, _| !options[:fields] || options[:fields].map(&:to_s).include?(k) }
|
160
160
|
.values.compact.join(" ")
|
161
161
|
|
162
|
-
# TODO deep merge method
|
163
162
|
options[:where] ||= {}
|
164
163
|
options[:where][:_id] ||= {}
|
165
|
-
options[:where][:_id][:not] = record.id.to_s
|
164
|
+
options[:where][:_id][:not] = Array(options[:where][:_id][:not]) + [record.id.to_s]
|
166
165
|
options[:per_page] ||= 10
|
167
166
|
options[:similar] = true
|
168
167
|
|
@@ -225,7 +225,7 @@ module Searchkick
|
|
225
225
|
}
|
226
226
|
end
|
227
227
|
|
228
|
-
settings.deep_merge
|
228
|
+
settings = settings.symbolize_keys.deep_merge((options[:settings] || {}).symbolize_keys)
|
229
229
|
|
230
230
|
# synonyms
|
231
231
|
synonyms = options[:synonyms] || []
|
@@ -311,10 +311,10 @@ module Searchkick
|
|
311
311
|
|
312
312
|
if !options[:searchable] || mapping_options[:searchable].include?(field)
|
313
313
|
if word
|
314
|
-
fields[
|
314
|
+
fields[:analyzed] = analyzed_field_options
|
315
315
|
|
316
316
|
if mapping_options[:highlight].include?(field)
|
317
|
-
fields[
|
317
|
+
fields[:analyzed][:term_vector] = "with_positions_offsets"
|
318
318
|
end
|
319
319
|
end
|
320
320
|
|
@@ -373,7 +373,7 @@ module Searchkick
|
|
373
373
|
end
|
374
374
|
|
375
375
|
if word
|
376
|
-
dynamic_fields[
|
376
|
+
dynamic_fields[:analyzed] = analyzed_field_options
|
377
377
|
end
|
378
378
|
end
|
379
379
|
|
@@ -402,7 +402,7 @@ module Searchkick
|
|
402
402
|
mappings[index_type][:_all] = all_enabled ? analyzed_field_options : {enabled: false}
|
403
403
|
end
|
404
404
|
|
405
|
-
mappings = mappings.deep_merge(options[:mappings] || {})
|
405
|
+
mappings = mappings.symbolize_keys.deep_merge((options[:mappings] || {}).symbolize_keys)
|
406
406
|
end
|
407
407
|
|
408
408
|
{
|
data/lib/searchkick/model.rb
CHANGED
@@ -16,8 +16,8 @@ module Searchkick
|
|
16
16
|
|
17
17
|
options[:_type] ||= -> { searchkick_index.klass_document_type(self, true) }
|
18
18
|
|
19
|
-
callbacks = options.key?(:callbacks) ? options[:callbacks] :
|
20
|
-
unless [true, false, :async, :queue].include?(callbacks)
|
19
|
+
callbacks = options.key?(:callbacks) ? options[:callbacks] : :inline
|
20
|
+
unless [:inline, true, false, :async, :queue].include?(callbacks)
|
21
21
|
raise ArgumentError, "Invalid value for callbacks"
|
22
22
|
end
|
23
23
|
|
data/lib/searchkick/query.rb
CHANGED
@@ -111,6 +111,7 @@ module Searchkick
|
|
111
111
|
model_includes: options[:model_includes],
|
112
112
|
json: !@json.nil?,
|
113
113
|
match_suffix: @match_suffix,
|
114
|
+
highlight: options[:highlight],
|
114
115
|
highlighted_fields: @highlighted_fields || [],
|
115
116
|
misspellings: @misspellings,
|
116
117
|
term: term,
|
@@ -188,7 +189,7 @@ module Searchkick
|
|
188
189
|
)
|
189
190
|
|
190
191
|
raise UnsupportedVersionError, "This version of Searchkick requires Elasticsearch 5 or greater"
|
191
|
-
elsif e.message
|
192
|
+
elsif e.message =~ /analyzer \[searchkick_.+\] not found/
|
192
193
|
raise InvalidQueryError, "Bad mapping - run #{reindex_command}"
|
193
194
|
else
|
194
195
|
raise InvalidQueryError, e.message
|
@@ -583,7 +584,8 @@ module Searchkick
|
|
583
584
|
unless attributes[:origin]
|
584
585
|
raise ArgumentError, "boost_by_distance requires :origin"
|
585
586
|
end
|
586
|
-
|
587
|
+
|
588
|
+
function_params = attributes.except(:factor, :function)
|
587
589
|
function_params[:origin] = location_value(function_params[:origin])
|
588
590
|
custom_filters << {
|
589
591
|
weight: attributes[:factor] || 1,
|
@@ -8,7 +8,7 @@ module Searchkick
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def reindex(method_name = nil, refresh: false, mode: nil)
|
11
|
-
unless [true, nil, :async, :queue].include?(mode)
|
11
|
+
unless [:inline, true, nil, :async, :queue].include?(mode)
|
12
12
|
raise ArgumentError, "Invalid value for mode"
|
13
13
|
end
|
14
14
|
|
@@ -31,7 +31,7 @@ module Searchkick
|
|
31
31
|
record.id.to_s,
|
32
32
|
method_name ? method_name.to_s : nil
|
33
33
|
)
|
34
|
-
else # bulk, true
|
34
|
+
else # bulk, inline/true/nil
|
35
35
|
reindex_record(method_name)
|
36
36
|
|
37
37
|
index.refresh if refresh
|
data/lib/searchkick/results.rb
CHANGED
@@ -16,7 +16,11 @@ module Searchkick
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def results
|
19
|
-
@results ||=
|
19
|
+
@results ||= with_hit.map(&:first)
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_hit
|
23
|
+
@with_hit ||= begin
|
20
24
|
if options[:load]
|
21
25
|
# results can have different types
|
22
26
|
results = {}
|
@@ -26,19 +30,31 @@ module Searchkick
|
|
26
30
|
results[type] = results_query(klass, grouped_hits).to_a.index_by { |r| r.id.to_s }
|
27
31
|
end
|
28
32
|
|
33
|
+
missing_ids = []
|
34
|
+
|
29
35
|
# sort
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
if
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
results =
|
37
|
+
hits.map do |hit|
|
38
|
+
result = results[hit["_type"]][hit["_id"].to_s]
|
39
|
+
if result && !(options[:load].is_a?(Hash) && options[:load][:dumpable])
|
40
|
+
if (hit["highlight"] || options[:highlight]) && !result.respond_to?(:search_highlights)
|
41
|
+
highlights = hit_highlights(hit)
|
42
|
+
result.define_singleton_method(:search_highlights) do
|
43
|
+
highlights
|
44
|
+
end
|
37
45
|
end
|
38
46
|
end
|
47
|
+
[result, hit]
|
48
|
+
end.select do |result, hit|
|
49
|
+
missing_ids << hit["_id"] unless result
|
50
|
+
result
|
39
51
|
end
|
40
|
-
|
41
|
-
|
52
|
+
|
53
|
+
if missing_ids.any?
|
54
|
+
warn "[searchkick] WARNING: Records in search index do not exist in database: #{missing_ids.join(", ")}"
|
55
|
+
end
|
56
|
+
|
57
|
+
results
|
42
58
|
else
|
43
59
|
hits.map do |hit|
|
44
60
|
result =
|
@@ -50,15 +66,15 @@ module Searchkick
|
|
50
66
|
hit
|
51
67
|
end
|
52
68
|
|
53
|
-
if hit["highlight"]
|
54
|
-
highlight = Hash[hit["highlight"].map { |k, v| [base_field(k), v.first] }]
|
69
|
+
if hit["highlight"] || options[:highlight]
|
70
|
+
highlight = Hash[hit["highlight"].to_a.map { |k, v| [base_field(k), v.first] }]
|
55
71
|
options[:highlighted_fields].map { |k| base_field(k) }.each do |k|
|
56
72
|
result["highlighted_#{k}"] ||= (highlight[k] || result[k])
|
57
73
|
end
|
58
74
|
end
|
59
75
|
|
60
76
|
result["id"] ||= result["_id"] # needed for legacy reasons
|
61
|
-
HashWrapper.new(result)
|
77
|
+
[HashWrapper.new(result), hit]
|
62
78
|
end
|
63
79
|
end
|
64
80
|
end
|
@@ -172,18 +188,16 @@ module Searchkick
|
|
172
188
|
end
|
173
189
|
end
|
174
190
|
|
175
|
-
def with_hit
|
176
|
-
results.zip(hits)
|
177
|
-
end
|
178
|
-
|
179
191
|
def highlights(multiple: false)
|
180
192
|
hits.map do |hit|
|
181
|
-
|
193
|
+
hit_highlights(hit, multiple: multiple)
|
182
194
|
end
|
183
195
|
end
|
184
196
|
|
185
197
|
def with_highlights(multiple: false)
|
186
|
-
|
198
|
+
with_hit do |result, hit|
|
199
|
+
[result, hit_highlights(hit, multiple: multiple)]
|
200
|
+
end
|
187
201
|
end
|
188
202
|
|
189
203
|
def misspellings?
|
@@ -231,5 +245,13 @@ module Searchkick
|
|
231
245
|
def base_field(k)
|
232
246
|
k.sub(/\.(analyzed|word_start|word_middle|word_end|text_start|text_middle|text_end|exact)\z/, "")
|
233
247
|
end
|
248
|
+
|
249
|
+
def hit_highlights(hit, multiple: false)
|
250
|
+
if hit["highlight"]
|
251
|
+
Hash[hit["highlight"].map { |k, v| [(options[:json] ? k : k.sub(/\.#{@options[:match_suffix]}\z/, "")).to_sym, multiple ? v : v.first] }]
|
252
|
+
else
|
253
|
+
{}
|
254
|
+
end
|
255
|
+
end
|
234
256
|
end
|
235
257
|
end
|
data/lib/searchkick/version.rb
CHANGED
data/test/highlight_test.rb
CHANGED
@@ -91,4 +91,19 @@ class HighlightTest < Minitest::Test
|
|
91
91
|
store_names ["Two Door Cinema Club"]
|
92
92
|
assert_equal "Two Door <em>Cinema</em> Club", Product.search("cinema", highlight: true).first.search_highlights[:name]
|
93
93
|
end
|
94
|
+
|
95
|
+
def test_match_all
|
96
|
+
store_names ["Two Door Cinema Club"]
|
97
|
+
assert_nil Product.search("*", highlight: true).highlights.first[:name]
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_match_all_load_false
|
101
|
+
store_names ["Two Door Cinema Club"]
|
102
|
+
assert_nil Product.search("*", highlight: true, load: false).highlights.first[:name]
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_match_all_search_highlights
|
106
|
+
store_names ["Two Door Cinema Club"]
|
107
|
+
assert_nil Product.search("*", highlight: true).first.search_highlights[:name]
|
108
|
+
end
|
94
109
|
end
|
data/test/index_test.rb
CHANGED
@@ -85,7 +85,9 @@ class IndexTest < Minitest::Test
|
|
85
85
|
def test_record_not_found
|
86
86
|
store_names ["Product A", "Product B"]
|
87
87
|
Product.where(name: "Product A").delete_all
|
88
|
-
|
88
|
+
assert_output nil, /\[searchkick\] WARNING: Records in search index do not exist in database/ do
|
89
|
+
assert_search "product", ["Product B"]
|
90
|
+
end
|
89
91
|
ensure
|
90
92
|
Product.reindex
|
91
93
|
end
|
@@ -93,7 +95,8 @@ class IndexTest < Minitest::Test
|
|
93
95
|
def test_bad_mapping
|
94
96
|
Product.searchkick_index.delete
|
95
97
|
store_names ["Product A"]
|
96
|
-
assert_raises(Searchkick::InvalidQueryError) { Product.search "test" }
|
98
|
+
error = assert_raises(Searchkick::InvalidQueryError) { Product.search "test" }
|
99
|
+
assert_equal "Bad mapping - run Product.reindex", error.message
|
97
100
|
ensure
|
98
101
|
Product.reindex
|
99
102
|
end
|
data/test/routing_test.rb
CHANGED
@@ -8,7 +8,7 @@ class RoutingTest < Minitest::Test
|
|
8
8
|
|
9
9
|
def test_routing_mappings
|
10
10
|
index_options = Store.searchkick_index.index_options
|
11
|
-
assert_equal index_options[:mappings][
|
11
|
+
assert_equal index_options[:mappings][:store][:_routing], required: true
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_routing_correct_node
|
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: 3.0
|
4
|
+
version: 3.1.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: 2018-
|
11
|
+
date: 2018-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|