searchkick 3.0.3 → 3.1.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 +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
|