searchkick 4.2.0 → 4.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -3
- data/LICENSE.txt +1 -1
- data/README.md +253 -202
- data/lib/searchkick.rb +31 -12
- data/lib/searchkick/bulk_indexer.rb +1 -1
- data/lib/searchkick/index.rb +22 -2
- data/lib/searchkick/index_options.rb +468 -382
- data/lib/searchkick/model.rb +11 -6
- data/lib/searchkick/query.rb +40 -6
- data/lib/searchkick/results.rb +10 -0
- data/lib/searchkick/version.rb +1 -1
- data/lib/tasks/searchkick.rake +12 -11
- metadata +3 -46
- data/CONTRIBUTING.md +0 -53
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff49d45a4473f44b07e8f1654d47e9b0590fd71eb3c6567f62b2fbcdc1e837b9
|
4
|
+
data.tar.gz: fd6ac4c931c7250787bc6f905c6c72b8412355e6b505bb2ef9d8cf5731d2939d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 05630a20b302fd406e5545935861b6616db79e2dd12e2eb11fe82bb3733c8b21af1087b7ad8d0fd4bd93eb3a07d2bd67461815a293746a2d2c2d3f2148d7147b
|
7
|
+
data.tar.gz: 571528f3967fd921e92dda6413313d29bd9048ee832e44bdb1a31a297178c3ee2f0b31dead3c573b297da96b676fdd74467bd7aa514c6a97f2a38b2500901057
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
## 4.4.1 (2020-06-24)
|
2
|
+
|
3
|
+
- Added `stem_exclusion` and `stemmer_override` options
|
4
|
+
- Added `with_score` method to search results
|
5
|
+
- Improved error message for `reload_synonyms` with non-OSS version of Elasticsearch
|
6
|
+
- Improved output for reindex rake task
|
7
|
+
|
8
|
+
## 4.4.0 (2020-06-17)
|
9
|
+
|
10
|
+
- Added support for reloadable, multi-word, search time synonyms
|
11
|
+
- Fixed another deprecation warning in Ruby 2.7
|
12
|
+
|
13
|
+
## 4.3.1 (2020-05-13)
|
14
|
+
|
15
|
+
- Fixed error with `exclude` in certain cases for Elasticsearch 7.7
|
16
|
+
|
17
|
+
## 4.3.0 (2020-02-19)
|
18
|
+
|
19
|
+
- Fixed `like` queries with `"` character
|
20
|
+
- Better error when invalid parameters passed to `where`
|
21
|
+
|
22
|
+
## 4.2.1 (2020-01-27)
|
23
|
+
|
24
|
+
- Fixed deprecation warnings with Elasticsearch
|
25
|
+
- Fixed deprecation warnings in Ruby 2.7
|
26
|
+
|
1
27
|
## 4.2.0 (2019-12-18)
|
2
28
|
|
3
29
|
- Added safety check for multiple `Model.reindex`
|
@@ -40,6 +66,7 @@ Breaking changes
|
|
40
66
|
|
41
67
|
- Removed support for Elasticsearch 5
|
42
68
|
- Removed support for multi-word synonyms (they no longer work with shingles)
|
69
|
+
- Removed support for Active Record < 5
|
43
70
|
|
44
71
|
## 3.1.3 (2019-04-11)
|
45
72
|
|
@@ -106,7 +133,7 @@ Breaking changes
|
|
106
133
|
Breaking changes
|
107
134
|
|
108
135
|
- Removed support for Elasticsearch 2
|
109
|
-
- Removed support for
|
136
|
+
- Removed support for Active Record < 4.2 and Mongoid < 5
|
110
137
|
- Types are no longer used
|
111
138
|
- The `_all` field is disabled by default in Elasticsearch 5
|
112
139
|
- Conversions are not stemmed by default
|
@@ -411,7 +438,7 @@ Breaking changes
|
|
411
438
|
|
412
439
|
## 0.8.3 (2014-09-20)
|
413
440
|
|
414
|
-
- Added support for
|
441
|
+
- Added support for Active Job
|
415
442
|
- Added `timeout` setting
|
416
443
|
- Fixed import with no records
|
417
444
|
|
@@ -518,7 +545,7 @@ Breaking changes
|
|
518
545
|
|
519
546
|
## 0.5.2 (2014-02-12)
|
520
547
|
|
521
|
-
- Use after_commit hook for
|
548
|
+
- Use after_commit hook for Active Record to prevent data inconsistencies
|
522
549
|
|
523
550
|
## 0.5.1 (2014-02-12)
|
524
551
|
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -4,12 +4,6 @@
|
|
4
4
|
|
5
5
|
**Searchkick learns what your users are looking for.** As more people search, it gets smarter and the results get better. It’s friendly for developers - and magical for your users.
|
6
6
|
|
7
|
-
---
|
8
|
-
|
9
|
-
[Searchkick Pro](https://searchkick.org/pro?utm_source=readme) is now available!
|
10
|
-
|
11
|
-
---
|
12
|
-
|
13
7
|
Searchkick handles:
|
14
8
|
|
15
9
|
- stemming - `tomatoes` matches `tomato`
|
@@ -39,17 +33,19 @@ Plus:
|
|
39
33
|
- [Getting Started](#getting-started)
|
40
34
|
- [Querying](#querying)
|
41
35
|
- [Indexing](#indexing)
|
36
|
+
- [Intelligent Search](#intelligent-search)
|
42
37
|
- [Instant Search / Autocomplete](#instant-search--autocomplete)
|
43
38
|
- [Aggregations](#aggregations)
|
39
|
+
- [Testing](#testing)
|
44
40
|
- [Deployment](#deployment)
|
45
41
|
- [Performance](#performance)
|
46
42
|
- [Elasticsearch DSL](#advanced)
|
47
43
|
- [Reference](#reference)
|
48
|
-
- [
|
44
|
+
- [Contributing](#contributing)
|
49
45
|
|
50
46
|
## Getting Started
|
51
47
|
|
52
|
-
[Install Elasticsearch](https://www.elastic.co/
|
48
|
+
[Install Elasticsearch](https://www.elastic.co/downloads/elasticsearch). For Homebrew, use:
|
53
49
|
|
54
50
|
```sh
|
55
51
|
brew install elasticsearch
|
@@ -143,7 +139,7 @@ Select
|
|
143
139
|
select: [:name]
|
144
140
|
```
|
145
141
|
|
146
|
-
[These source filtering options are supported](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-source-filtering
|
142
|
+
[These source filtering options are supported](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-body.html#request-body-search-source-filtering)
|
147
143
|
|
148
144
|
### Results
|
149
145
|
|
@@ -303,7 +299,9 @@ To only match the exact order, use:
|
|
303
299
|
User.search "fresh honey", match: :phrase
|
304
300
|
```
|
305
301
|
|
306
|
-
### Language
|
302
|
+
### Stemming and Language
|
303
|
+
|
304
|
+
Searchkick stems words by default for better matching. `apple` and `apples` both stem to `appl`, so searches for either term will have the same matches.
|
307
305
|
|
308
306
|
Searchkick defaults to English for stemming. To change this, use:
|
309
307
|
|
@@ -313,9 +311,7 @@ class Product < ApplicationRecord
|
|
313
311
|
end
|
314
312
|
```
|
315
313
|
|
316
|
-
|
317
|
-
|
318
|
-
A few languages require plugins:
|
314
|
+
See the [list of stemmers](https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-stemmer-tokenfilter.html). A few languages require plugins:
|
319
315
|
|
320
316
|
- `chinese` - [analysis-ik plugin](https://github.com/medcl/elasticsearch-analysis-ik)
|
321
317
|
- `chinese2` - [analysis-smartcn plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/7.4/analysis-smartcn.html)
|
@@ -326,33 +322,80 @@ A few languages require plugins:
|
|
326
322
|
- `ukrainian` - [analysis-ukrainian plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/7.4/analysis-ukrainian.html)
|
327
323
|
- `vietnamese` - [analysis-vietnamese plugin](https://github.com/duydo/elasticsearch-analysis-vietnamese)
|
328
324
|
|
325
|
+
Disable stemming with:
|
326
|
+
|
327
|
+
```ruby
|
328
|
+
class Image < ApplicationRecord
|
329
|
+
searchkick stem: false
|
330
|
+
end
|
331
|
+
```
|
332
|
+
|
333
|
+
Exclude certain words from stemming with:
|
334
|
+
|
335
|
+
```ruby
|
336
|
+
class Image < ApplicationRecord
|
337
|
+
searchkick stem_exclusion: ["apples"]
|
338
|
+
end
|
339
|
+
```
|
340
|
+
|
341
|
+
Or change how words are stemmed:
|
342
|
+
|
343
|
+
```ruby
|
344
|
+
class Image < ApplicationRecord
|
345
|
+
searchkick stemmer_override: ["apples => other"]
|
346
|
+
end
|
347
|
+
```
|
348
|
+
|
329
349
|
### Synonyms
|
330
350
|
|
331
351
|
```ruby
|
332
352
|
class Product < ApplicationRecord
|
333
|
-
searchkick
|
353
|
+
searchkick search_synonyms: [["pop", "soda"], ["burger", "hamburger"]]
|
334
354
|
end
|
335
355
|
```
|
336
356
|
|
337
|
-
Call `Product.reindex` after changing synonyms.
|
357
|
+
Call `Product.reindex` after changing synonyms. Synonyms are applied at search time before stemming, and can be a single word or multiple words.
|
358
|
+
|
359
|
+
For directional synonyms, use:
|
360
|
+
|
361
|
+
```ruby
|
362
|
+
search_synonyms: ["lightbulb => halogenlamp"]
|
363
|
+
```
|
364
|
+
|
365
|
+
### Dynamic Synonyms
|
338
366
|
|
339
|
-
|
367
|
+
The above approach works well when your synonym list is static, but in practice, this is often not the case. When you analyze search conversions, you often want to add new synonyms without a full reindex.
|
340
368
|
|
341
|
-
|
369
|
+
#### Elasticsearch 7.3+
|
370
|
+
|
371
|
+
For Elasticsearch 7.3+, we recommend placing synonyms in a file on the Elasticsearch server (in the `config` directory). This allows you to reload synonyms without reindexing.
|
372
|
+
|
373
|
+
```txt
|
374
|
+
pop, soda
|
375
|
+
burger, hamburger
|
376
|
+
```
|
377
|
+
|
378
|
+
Then use:
|
342
379
|
|
343
380
|
```ruby
|
344
|
-
|
381
|
+
search_synonyms: "synonyms.txt"
|
345
382
|
```
|
346
383
|
|
347
|
-
|
384
|
+
Add [elasticsearch-xpack](https://github.com/elastic/elasticsearch-ruby/tree/master/elasticsearch-xpack) to your Gemfile:
|
385
|
+
|
386
|
+
```ruby
|
387
|
+
gem 'elasticsearch-xpack', '>= 7.8.0'
|
388
|
+
```
|
389
|
+
|
390
|
+
And use:
|
348
391
|
|
349
392
|
```ruby
|
350
|
-
|
393
|
+
Product.search_index.reload_synonyms
|
351
394
|
```
|
352
395
|
|
353
|
-
|
396
|
+
#### Elasticsearch < 7.3
|
354
397
|
|
355
|
-
|
398
|
+
You can use a library like [ActsAsTaggableOn](https://github.com/mbleigh/acts-as-taggable-on) and do:
|
356
399
|
|
357
400
|
```ruby
|
358
401
|
class Product < ApplicationRecord
|
@@ -504,7 +547,7 @@ For large data sets, try [parallel reindexing](#parallel-reindexing).
|
|
504
547
|
|
505
548
|
- app starts
|
506
549
|
|
507
|
-
###
|
550
|
+
### Strategies
|
508
551
|
|
509
552
|
There are four strategies for keeping the index synced with your database.
|
510
553
|
|
@@ -570,11 +613,9 @@ class Image < ApplicationRecord
|
|
570
613
|
end
|
571
614
|
```
|
572
615
|
|
573
|
-
|
616
|
+
## Intelligent Search
|
574
617
|
|
575
|
-
The best starting point to improve your search **by far** is to track searches and conversions.
|
576
|
-
|
577
|
-
[Searchjoy](https://github.com/ankane/searchjoy) makes it easy.
|
618
|
+
The best starting point to improve your search **by far** is to track searches and conversions. [Searchjoy](https://github.com/ankane/searchjoy) makes it easy.
|
578
619
|
|
579
620
|
```ruby
|
580
621
|
Product.search "apple", track: {user_id: current_user.id}
|
@@ -587,15 +628,9 @@ Focus on:
|
|
587
628
|
- top searches with low conversions
|
588
629
|
- top searches with no results
|
589
630
|
|
590
|
-
|
591
|
-
|
592
|
-
Searchkick can use conversion data to learn what users are looking for. If a user searches for “ice cream” and adds Ben & Jerry’s Chunky Monkey to the cart (our conversion metric at Instacart), that item gets a little more weight for similar searches.
|
593
|
-
|
594
|
-
The first step is to define your conversion metric and start tracking conversions. The database works well for low volume, but feel free to use Redis or another datastore.
|
631
|
+
Searchkick can then use the conversion data to learn what users are looking for. If a user searches for “ice cream” and adds Ben & Jerry’s Chunky Monkey to the cart (our conversion metric at Instacart), that item gets a little more weight for similar searches.
|
595
632
|
|
596
|
-
|
597
|
-
|
598
|
-
Next, add conversions to the index.
|
633
|
+
Add conversion data with:
|
599
634
|
|
600
635
|
```ruby
|
601
636
|
class Product < ApplicationRecord
|
@@ -619,9 +654,11 @@ Reindex and set up a cron job to add new conversions daily.
|
|
619
654
|
rake searchkick:reindex CLASS=Product
|
620
655
|
```
|
621
656
|
|
622
|
-
|
657
|
+
This can make a huge difference on the quality of your search.
|
658
|
+
|
659
|
+
For a more performant way to reindex conversion data, check out [performant conversions](#performant-conversions).
|
623
660
|
|
624
|
-
|
661
|
+
## Personalized Results
|
625
662
|
|
626
663
|
Order results differently for each user. For example, show a user’s previously purchased products before other results.
|
627
664
|
|
@@ -642,7 +679,7 @@ Reindex and search with:
|
|
642
679
|
Product.search "milk", boost_where: {orderer_ids: current_user.id}
|
643
680
|
```
|
644
681
|
|
645
|
-
|
682
|
+
## Instant Search / Autocomplete
|
646
683
|
|
647
684
|
Autocomplete predicts what a user will type, making the search experience faster and easier.
|
648
685
|
|
@@ -710,7 +747,7 @@ Then add the search box and JavaScript code to a view.
|
|
710
747
|
</script>
|
711
748
|
```
|
712
749
|
|
713
|
-
|
750
|
+
## Suggestions
|
714
751
|
|
715
752
|
![Suggest](https://gist.github.com/ankane/b6988db2802aca68a589b31e41b44195/raw/40febe948427e5bc53ec4e5dc248822855fef76f/recursion.png)
|
716
753
|
|
@@ -727,7 +764,7 @@ products = Product.search "peantu butta", suggest: true
|
|
727
764
|
products.suggestions # ["peanut butter"]
|
728
765
|
```
|
729
766
|
|
730
|
-
|
767
|
+
## Aggregations
|
731
768
|
|
732
769
|
[Aggregations](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations.html) provide aggregated search data.
|
733
770
|
|
@@ -770,8 +807,6 @@ Order
|
|
770
807
|
Product.search "wingtips", aggs: {color: {order: {"_key" => "asc"}}} # alphabetically
|
771
808
|
```
|
772
809
|
|
773
|
-
**Note:** Use `_term` instead of `_key` in Elasticsearch 5
|
774
|
-
|
775
810
|
[All of these options are supported](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-terms-aggregation.html#search-aggregations-bucket-terms-aggregation-order)
|
776
811
|
|
777
812
|
Ranges
|
@@ -802,10 +837,10 @@ Product.search "pear", aggs: {products_per_year: {date_histogram: {field: :creat
|
|
802
837
|
For other aggregation types, including sub-aggregations, use `body_options`:
|
803
838
|
|
804
839
|
```ruby
|
805
|
-
Product.search "orange", body_options: {aggs: {price: {histogram: {field: :price, interval: 10}}}
|
840
|
+
Product.search "orange", body_options: {aggs: {price: {histogram: {field: :price, interval: 10}}}}
|
806
841
|
```
|
807
842
|
|
808
|
-
|
843
|
+
## Highlight
|
809
844
|
|
810
845
|
Specify which fields to index with highlighting.
|
811
846
|
|
@@ -858,7 +893,7 @@ Band.search "cinema", fields: [:name], highlight: {fields: {name: {fragment_size
|
|
858
893
|
|
859
894
|
You can find available highlight options in the [Elasticsearch reference](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-highlighting.html#_highlighted_fragments).
|
860
895
|
|
861
|
-
|
896
|
+
## Similar Items
|
862
897
|
|
863
898
|
Find similar items.
|
864
899
|
|
@@ -867,7 +902,7 @@ product = Product.first
|
|
867
902
|
product.similar(fields: [:name], where: {size: "12 oz"})
|
868
903
|
```
|
869
904
|
|
870
|
-
|
905
|
+
## Geospatial Searches
|
871
906
|
|
872
907
|
```ruby
|
873
908
|
class Restaurant < ApplicationRecord
|
@@ -1034,13 +1069,165 @@ Product.search_index.tokens("dieg", analyzer: "searchkick_word_search")
|
|
1034
1069
|
|
1035
1070
|
See the [complete list of analyzers](https://github.com/ankane/searchkick/blob/31780ddac7a89eab1e0552a32b403f2040a37931/lib/searchkick/index_options.rb#L32).
|
1036
1071
|
|
1072
|
+
## Testing
|
1073
|
+
|
1074
|
+
As you iterate on your search, it’s a good idea to add tests.
|
1075
|
+
|
1076
|
+
For performance, only enable Searchkick callbacks for the tests that need it.
|
1077
|
+
|
1078
|
+
### Parallel Tests
|
1079
|
+
|
1080
|
+
Rails 6 enables parallel tests by default. Add to your `test/test_helper.rb`:
|
1081
|
+
|
1082
|
+
```ruby
|
1083
|
+
class ActiveSupport::TestCase
|
1084
|
+
parallelize_setup do |worker|
|
1085
|
+
Searchkick.index_suffix = worker
|
1086
|
+
|
1087
|
+
# reindex models
|
1088
|
+
Product.reindex
|
1089
|
+
|
1090
|
+
# and disable callbacks
|
1091
|
+
Searchkick.disable_callbacks
|
1092
|
+
end
|
1093
|
+
end
|
1094
|
+
```
|
1095
|
+
|
1096
|
+
And use:
|
1097
|
+
|
1098
|
+
```ruby
|
1099
|
+
class ProductTest < ActiveSupport::TestCase
|
1100
|
+
def setup
|
1101
|
+
Searchkick.enable_callbacks
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
def teardown
|
1105
|
+
Searchkick.disable_callbacks
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
def test_search
|
1109
|
+
Product.create!(name: "Apple")
|
1110
|
+
Product.search_index.refresh
|
1111
|
+
assert_equal ["Apple"], Product.search("apple").map(&:name)
|
1112
|
+
end
|
1113
|
+
end
|
1114
|
+
```
|
1115
|
+
|
1116
|
+
### Minitest
|
1117
|
+
|
1118
|
+
Add to your `test/test_helper.rb`:
|
1119
|
+
|
1120
|
+
```ruby
|
1121
|
+
# reindex models
|
1122
|
+
Product.reindex
|
1123
|
+
|
1124
|
+
# and disable callbacks
|
1125
|
+
Searchkick.disable_callbacks
|
1126
|
+
```
|
1127
|
+
|
1128
|
+
And use:
|
1129
|
+
|
1130
|
+
```ruby
|
1131
|
+
class ProductTest < Minitest::Test
|
1132
|
+
def setup
|
1133
|
+
Searchkick.enable_callbacks
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
def teardown
|
1137
|
+
Searchkick.disable_callbacks
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
def test_search
|
1141
|
+
Product.create!(name: "Apple")
|
1142
|
+
Product.search_index.refresh
|
1143
|
+
assert_equal ["Apple"], Product.search("apple").map(&:name)
|
1144
|
+
end
|
1145
|
+
end
|
1146
|
+
```
|
1147
|
+
|
1148
|
+
### RSpec
|
1149
|
+
|
1150
|
+
Add to your `spec/spec_helper.rb`:
|
1151
|
+
|
1152
|
+
```ruby
|
1153
|
+
RSpec.configure do |config|
|
1154
|
+
config.before(:suite) do
|
1155
|
+
# reindex models
|
1156
|
+
Product.reindex
|
1157
|
+
|
1158
|
+
# and disable callbacks
|
1159
|
+
Searchkick.disable_callbacks
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
config.around(:each, search: true) do |example|
|
1163
|
+
Searchkick.callbacks(nil) do
|
1164
|
+
example.run
|
1165
|
+
end
|
1166
|
+
end
|
1167
|
+
end
|
1168
|
+
```
|
1169
|
+
|
1170
|
+
And use:
|
1171
|
+
|
1172
|
+
```ruby
|
1173
|
+
describe Product, search: true do
|
1174
|
+
it "searches" do
|
1175
|
+
Product.create!(name: "Apple")
|
1176
|
+
Product.search_index.refresh
|
1177
|
+
assert_equal ["Apple"], Product.search("apple").map(&:name)
|
1178
|
+
end
|
1179
|
+
end
|
1180
|
+
```
|
1181
|
+
|
1182
|
+
### Factory Bot
|
1183
|
+
|
1184
|
+
Use a trait and an after `create` hook for each indexed model:
|
1185
|
+
|
1186
|
+
```ruby
|
1187
|
+
FactoryBot.define do
|
1188
|
+
factory :product do
|
1189
|
+
# ...
|
1190
|
+
|
1191
|
+
# Note: This should be the last trait in the list so `reindex` is called
|
1192
|
+
# after all the other callbacks complete.
|
1193
|
+
trait :reindex do
|
1194
|
+
after(:create) do |product, _evaluator|
|
1195
|
+
product.reindex(refresh: true)
|
1196
|
+
end
|
1197
|
+
end
|
1198
|
+
end
|
1199
|
+
end
|
1200
|
+
|
1201
|
+
# use it
|
1202
|
+
FactoryBot.create(:product, :some_trait, :reindex, some_attribute: "foo")
|
1203
|
+
```
|
1204
|
+
|
1037
1205
|
## Deployment
|
1038
1206
|
|
1039
1207
|
Searchkick uses `ENV["ELASTICSEARCH_URL"]` for the Elasticsearch server. This defaults to `http://localhost:9200`.
|
1040
1208
|
|
1209
|
+
- [Elastic Cloud](#elastic-cloud)
|
1210
|
+
- [Heroku](#heroku)
|
1211
|
+
- [Amazon Elasticsearch Service](#amazon-elasticsearch-service)
|
1212
|
+
- [Self-Hosted and Other](#other)
|
1213
|
+
|
1214
|
+
### Elastic Cloud
|
1215
|
+
|
1216
|
+
Create an initializer `config/initializers/elasticsearch.rb` with:
|
1217
|
+
|
1218
|
+
```ruby
|
1219
|
+
ENV["ELASTICSEARCH_URL"] = "https://user:password@host:port"
|
1220
|
+
```
|
1221
|
+
|
1222
|
+
Then deploy and reindex:
|
1223
|
+
|
1224
|
+
```sh
|
1225
|
+
rake searchkick:reindex:all
|
1226
|
+
```
|
1227
|
+
|
1041
1228
|
### Heroku
|
1042
1229
|
|
1043
|
-
Choose an add-on: [Bonsai](https://elements.heroku.com/addons/bonsai)
|
1230
|
+
Choose an add-on: [Bonsai](https://elements.heroku.com/addons/bonsai), [SearchBox](https://elements.heroku.com/addons/searchbox), or [Elastic Cloud](https://elements.heroku.com/addons/foundelasticsearch).
|
1044
1231
|
|
1045
1232
|
For Bonsai:
|
1046
1233
|
|
@@ -1049,6 +1236,13 @@ heroku addons:create bonsai
|
|
1049
1236
|
heroku config:set ELASTICSEARCH_URL=`heroku config:get BONSAI_URL`
|
1050
1237
|
```
|
1051
1238
|
|
1239
|
+
For SearchBox:
|
1240
|
+
|
1241
|
+
```sh
|
1242
|
+
heroku addons:create searchbox:starter
|
1243
|
+
heroku config:set ELASTICSEARCH_URL=`heroku config:get SEARCHBOX_URL`
|
1244
|
+
```
|
1245
|
+
|
1052
1246
|
For Elastic Cloud (previously Found):
|
1053
1247
|
|
1054
1248
|
```sh
|
@@ -1071,7 +1265,7 @@ heroku config:set ELASTICSEARCH_URL=https://elastic:password@12345.us-east-1.aws
|
|
1071
1265
|
Then deploy and reindex:
|
1072
1266
|
|
1073
1267
|
```sh
|
1074
|
-
heroku run rake searchkick:reindex
|
1268
|
+
heroku run rake searchkick:reindex:all
|
1075
1269
|
```
|
1076
1270
|
|
1077
1271
|
### Amazon Elasticsearch Service
|
@@ -1101,10 +1295,10 @@ Searchkick.aws_credentials = {
|
|
1101
1295
|
Then deploy and reindex:
|
1102
1296
|
|
1103
1297
|
```sh
|
1104
|
-
rake searchkick:reindex
|
1298
|
+
rake searchkick:reindex:all
|
1105
1299
|
```
|
1106
1300
|
|
1107
|
-
### Other
|
1301
|
+
### Self-Hosted and Other
|
1108
1302
|
|
1109
1303
|
Create an initializer `config/initializers/elasticsearch.rb` with:
|
1110
1304
|
|
@@ -1115,7 +1309,7 @@ ENV["ELASTICSEARCH_URL"] = "https://user:password@host:port"
|
|
1115
1309
|
Then deploy and reindex:
|
1116
1310
|
|
1117
1311
|
```sh
|
1118
|
-
rake searchkick:reindex
|
1312
|
+
rake searchkick:reindex:all
|
1119
1313
|
```
|
1120
1314
|
|
1121
1315
|
### Data Protection
|
@@ -1495,6 +1689,10 @@ Boost specific models with:
|
|
1495
1689
|
indices_boost: {Category => 2, Product => 1}
|
1496
1690
|
```
|
1497
1691
|
|
1692
|
+
## Multi-Tenancy
|
1693
|
+
|
1694
|
+
Check out [this great post](https://www.tiagoamaro.com.br/2014/12/11/multi-tenancy-with-searchkick/) on the [Apartment](https://github.com/influitive/apartment) gem. Follow a similar pattern if you use another gem.
|
1695
|
+
|
1498
1696
|
## Scroll API
|
1499
1697
|
|
1500
1698
|
Searchkick also supports the [scroll API](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-scroll.html). Scrolling is not intended for real time user requests, but rather for processing large amounts of data.
|
@@ -1701,14 +1899,6 @@ class Product < ApplicationRecord
|
|
1701
1899
|
end
|
1702
1900
|
```
|
1703
1901
|
|
1704
|
-
Turn off stemming
|
1705
|
-
|
1706
|
-
```ruby
|
1707
|
-
class Product < ApplicationRecord
|
1708
|
-
searchkick stem: false
|
1709
|
-
end
|
1710
|
-
```
|
1711
|
-
|
1712
1902
|
Turn on stemming for conversions
|
1713
1903
|
|
1714
1904
|
```ruby
|
@@ -1717,14 +1907,6 @@ class Product < ApplicationRecord
|
|
1717
1907
|
end
|
1718
1908
|
```
|
1719
1909
|
|
1720
|
-
Use a different [similarity algorithm](https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-similarity.html) for scoring
|
1721
|
-
|
1722
|
-
```ruby
|
1723
|
-
class Product < ApplicationRecord
|
1724
|
-
searchkick similarity: "classic"
|
1725
|
-
end
|
1726
|
-
```
|
1727
|
-
|
1728
1910
|
Make search case-sensitive
|
1729
1911
|
|
1730
1912
|
```ruby
|
@@ -1809,142 +1991,11 @@ Product.search "api", misspellings: {prefix_length: 2} # api, apt, no ahi
|
|
1809
1991
|
Product.search "ah", misspellings: {prefix_length: 2} # ah, no aha
|
1810
1992
|
```
|
1811
1993
|
|
1812
|
-
## Testing
|
1813
|
-
|
1814
|
-
For performance, only enable Searchkick callbacks for the tests that need it.
|
1815
|
-
|
1816
|
-
### Minitest
|
1817
|
-
|
1818
|
-
Add to your `test/test_helper.rb`:
|
1819
|
-
|
1820
|
-
```ruby
|
1821
|
-
# reindex models
|
1822
|
-
Product.reindex
|
1823
|
-
|
1824
|
-
# and disable callbacks
|
1825
|
-
Searchkick.disable_callbacks
|
1826
|
-
```
|
1827
|
-
|
1828
|
-
And use:
|
1829
|
-
|
1830
|
-
```ruby
|
1831
|
-
class ProductTest < Minitest::Test
|
1832
|
-
def setup
|
1833
|
-
Searchkick.enable_callbacks
|
1834
|
-
end
|
1835
|
-
|
1836
|
-
def teardown
|
1837
|
-
Searchkick.disable_callbacks
|
1838
|
-
end
|
1839
|
-
|
1840
|
-
def test_search
|
1841
|
-
Product.create!(name: "Apple")
|
1842
|
-
Product.search_index.refresh
|
1843
|
-
assert_equal ["Apple"], Product.search("apple").map(&:name)
|
1844
|
-
end
|
1845
|
-
end
|
1846
|
-
```
|
1847
|
-
|
1848
|
-
### RSpec
|
1849
|
-
|
1850
|
-
Add to your `spec/spec_helper.rb`:
|
1851
|
-
|
1852
|
-
```ruby
|
1853
|
-
RSpec.configure do |config|
|
1854
|
-
config.before(:suite) do
|
1855
|
-
# reindex models
|
1856
|
-
Product.reindex
|
1857
|
-
|
1858
|
-
# and disable callbacks
|
1859
|
-
Searchkick.disable_callbacks
|
1860
|
-
end
|
1861
|
-
|
1862
|
-
config.around(:each, search: true) do |example|
|
1863
|
-
Searchkick.callbacks(true) do
|
1864
|
-
example.run
|
1865
|
-
end
|
1866
|
-
end
|
1867
|
-
end
|
1868
|
-
```
|
1869
|
-
|
1870
|
-
And use:
|
1871
|
-
|
1872
|
-
```ruby
|
1873
|
-
describe Product, search: true do
|
1874
|
-
it "searches" do
|
1875
|
-
Product.create!(name: "Apple")
|
1876
|
-
Product.search_index.refresh
|
1877
|
-
assert_equal ["Apple"], Product.search("apple").map(&:name)
|
1878
|
-
end
|
1879
|
-
end
|
1880
|
-
```
|
1881
|
-
|
1882
|
-
### Factory Bot
|
1883
|
-
|
1884
|
-
Use a trait and an after `create` hook for each indexed model:
|
1885
|
-
|
1886
|
-
```ruby
|
1887
|
-
FactoryBot.define do
|
1888
|
-
factory :product do
|
1889
|
-
# ...
|
1890
|
-
|
1891
|
-
# Note: This should be the last trait in the list so `reindex` is called
|
1892
|
-
# after all the other callbacks complete.
|
1893
|
-
trait :reindex do
|
1894
|
-
after(:create) do |product, _evaluator|
|
1895
|
-
product.reindex(refresh: true)
|
1896
|
-
end
|
1897
|
-
end
|
1898
|
-
end
|
1899
|
-
end
|
1900
|
-
|
1901
|
-
# use it
|
1902
|
-
FactoryBot.create(:product, :some_trait, :reindex, some_attribute: "foo")
|
1903
|
-
```
|
1904
|
-
|
1905
|
-
### Parallel Tests
|
1906
|
-
|
1907
|
-
Set:
|
1908
|
-
|
1909
|
-
```ruby
|
1910
|
-
Searchkick.index_suffix = ENV["TEST_ENV_NUMBER"]
|
1911
|
-
```
|
1912
|
-
|
1913
|
-
## Multi-Tenancy
|
1914
|
-
|
1915
|
-
Check out [this great post](https://www.tiagoamaro.com.br/2014/12/11/multi-tenancy-with-searchkick/) on the [Apartment](https://github.com/influitive/apartment) gem. Follow a similar pattern if you use another gem.
|
1916
|
-
|
1917
|
-
## Upgrading
|
1918
|
-
|
1919
|
-
See [how to upgrade to Searchkick 3](docs/Searchkick-3-Upgrade.md)
|
1920
|
-
|
1921
1994
|
## Elasticsearch 6 to 7 Upgrade
|
1922
1995
|
|
1923
1996
|
1. Install Searchkick 4
|
1924
1997
|
2. Upgrade your Elasticsearch cluster
|
1925
1998
|
|
1926
|
-
## Elasticsearch 5 to 6 Upgrade
|
1927
|
-
|
1928
|
-
Elasticsearch 6 removes the ability to reindex with the `_all` field. Before you upgrade, we recommend disabling this field manually and specifying default fields on your models.
|
1929
|
-
|
1930
|
-
```ruby
|
1931
|
-
class Product < ApplicationRecord
|
1932
|
-
searchkick _all: false, default_fields: [:name]
|
1933
|
-
end
|
1934
|
-
```
|
1935
|
-
|
1936
|
-
If you need search across multiple fields, we recommend creating a similar field in your search data.
|
1937
|
-
|
1938
|
-
```ruby
|
1939
|
-
class Product < ApplicationRecord
|
1940
|
-
def search_data
|
1941
|
-
{
|
1942
|
-
all: [name, size, quantity].join(" ")
|
1943
|
-
}
|
1944
|
-
end
|
1945
|
-
end
|
1946
|
-
```
|
1947
|
-
|
1948
1999
|
## Elasticsearch Gotchas
|
1949
2000
|
|
1950
2001
|
### Consistency
|
@@ -1985,13 +2036,13 @@ Everyone is encouraged to help improve this project. Here are a few ways you can
|
|
1985
2036
|
- Write, clarify, or fix documentation
|
1986
2037
|
- Suggest or add new features
|
1987
2038
|
|
1988
|
-
|
1989
|
-
|
1990
|
-
To get started with development and testing:
|
2039
|
+
To get started with development:
|
1991
2040
|
|
1992
2041
|
```sh
|
1993
2042
|
git clone https://github.com/ankane/searchkick.git
|
1994
2043
|
cd searchkick
|
1995
2044
|
bundle install
|
1996
|
-
rake test
|
2045
|
+
bundle exec rake test
|
1997
2046
|
```
|
2047
|
+
|
2048
|
+
Feel free to open an issue to get feedback on your idea before spending too much time on it.
|