searchkick 2.1.1 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +10 -0
- data/README.md +97 -15
- data/lib/searchkick/index.rb +1 -0
- data/lib/searchkick/index_options.rb +4 -4
- data/lib/searchkick/model.rb +7 -1
- data/lib/searchkick/process_queue_job.rb +1 -1
- data/lib/searchkick/query.rb +11 -1
- data/lib/searchkick/reindex_v2_job.rb +2 -1
- data/lib/searchkick/version.rb +1 -1
- data/lib/searchkick.rb +13 -1
- data/test/aggs_test.rb +2 -2
- data/test/boost_test.rb +10 -0
- data/test/errors_test.rb +2 -2
- data/test/gemfiles/activerecord51.gemfile +7 -0
- data/test/gemfiles/cequel.gemfile +8 -0
- data/test/highlight_test.rb +5 -0
- data/test/index_test.rb +19 -2
- data/test/inheritance_test.rb +5 -0
- data/test/match_test.rb +14 -3
- data/test/model_test.rb +1 -1
- data/test/order_test.rb +2 -0
- data/test/records_test.rb +2 -0
- data/test/reindex_test.rb +2 -2
- data/test/test_helper.rb +86 -0
- data/test/where_test.rb +19 -6
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 85108ff6dc90bd7075f66c5627fc06eba581657f
|
4
|
+
data.tar.gz: 062420bd6cd4c9601026425d40923cc82e649364
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 680ef536ba5e15456b0df70412eec5e47d13f43424c02e7d039921abf3c83b06fbaefa95d824fa2ae0efeecde8c6488ad56b4aabed442eb6c191a309f2204c6c
|
7
|
+
data.tar.gz: d118d331ffd37c1fbec228bba2cc043f03730510a0ca45d7bd9afe9c04aa31a8ebeeaba82b57113c070fd7af3b1c8c347f0b22bd8cff43565f9246ed408a0c77
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
## 2.2.0
|
2
|
+
|
3
|
+
- Fixed bug with text values longer than 256 characters and `_all` field - see [#850](https://github.com/ankane/searchkick/issues/850)
|
4
|
+
- Fixed issue with `_all` field in `searchable`
|
5
|
+
- Fixed `exclude` option with `word_start`
|
6
|
+
|
1
7
|
## 2.1.1
|
2
8
|
|
3
9
|
- Fixed duplicate notifications
|
@@ -41,6 +47,10 @@ Breaking changes
|
|
41
47
|
- Removed support for Elasticsearch 1 as it reaches [end of life](https://www.elastic.co/support/eol)
|
42
48
|
- Removed facets, legacy options, and legacy methods
|
43
49
|
- Invalid options now throw an `ArgumentError`
|
50
|
+
- The `query` and `json` options have been removed in favor of `body`
|
51
|
+
- The `include` option has been removed in favor of `includes`
|
52
|
+
- The `personalize` option has been removed in favor of `boost_where`
|
53
|
+
- The `partial` option has been removed in favor of `operator`
|
44
54
|
- Renamed `select_v2` to `select` (legacy `select` no longer available)
|
45
55
|
- The `_all` field is disabled if `searchable` option is used (for performance)
|
46
56
|
- The `partial_reindex(:method_name)` method has been replaced with `reindex(:method_name)`
|
data/README.md
CHANGED
@@ -47,9 +47,7 @@ Plus:
|
|
47
47
|
|
48
48
|
```sh
|
49
49
|
brew install elasticsearch
|
50
|
-
|
51
|
-
# start the server
|
52
|
-
elasticsearch
|
50
|
+
brew services start elasticsearch
|
53
51
|
```
|
54
52
|
|
55
53
|
Add this line to your application’s Gemfile:
|
@@ -385,6 +383,17 @@ If a user searches `butter`, they may also get results for `peanut butter`. To p
|
|
385
383
|
Product.search "butter", exclude: ["peanut butter"]
|
386
384
|
```
|
387
385
|
|
386
|
+
You can map queries and terms to exclude with:
|
387
|
+
|
388
|
+
```ruby
|
389
|
+
exclude_queries = {
|
390
|
+
"butter" => ["peanut butter"],
|
391
|
+
"cream" => ["ice cream"]
|
392
|
+
}
|
393
|
+
|
394
|
+
Product.search query, exclude: exclude_queries[query]
|
395
|
+
```
|
396
|
+
|
388
397
|
### Emoji
|
389
398
|
|
390
399
|
Search :ice_cream::cake: and get `ice cream cake`!
|
@@ -1018,7 +1027,7 @@ Product.search_index.tokens("dieg", analyzer: "searchkick_word_search")
|
|
1018
1027
|
# ["dieg"] - match!!
|
1019
1028
|
```
|
1020
1029
|
|
1021
|
-
See the [complete list of analyzers](lib/searchkick/
|
1030
|
+
See the [complete list of analyzers](https://github.com/ankane/searchkick/blob/31780ddac7a89eab1e0552a32b403f2040a37931/lib/searchkick/index_options.rb#L32).
|
1022
1031
|
|
1023
1032
|
## Deployment
|
1024
1033
|
|
@@ -1136,9 +1145,11 @@ Significantly increase performance with faster JSON generation. Add [Oj](https:/
|
|
1136
1145
|
gem 'oj'
|
1137
1146
|
```
|
1138
1147
|
|
1148
|
+
This speeds up all JSON generation and parsing in your application (automatically!)
|
1149
|
+
|
1139
1150
|
### Persistent HTTP Connections
|
1140
1151
|
|
1141
|
-
Significantly increase performance with persistent HTTP connections. Add [Typhoeus](https://github.com/typhoeus/typhoeus) to your Gemfile.
|
1152
|
+
Significantly increase performance with persistent HTTP connections. Add [Typhoeus](https://github.com/typhoeus/typhoeus) to your Gemfile and it’ll automatically be used.
|
1142
1153
|
|
1143
1154
|
```ruby
|
1144
1155
|
gem 'typhoeus'
|
@@ -1199,18 +1210,19 @@ And use:
|
|
1199
1210
|
Searchkick.reindex_status(index_name)
|
1200
1211
|
```
|
1201
1212
|
|
1202
|
-
You can use [ActiveJob::TrafficControl](https://github.com/nickelser/activejob-traffic_control) to control concurrency. Install the gem
|
1213
|
+
You can use [ActiveJob::TrafficControl](https://github.com/nickelser/activejob-traffic_control) to control concurrency. Install the gem:
|
1203
1214
|
|
1204
1215
|
```ruby
|
1205
|
-
|
1216
|
+
gem 'activejob-traffic_control', '>= 0.1.3'
|
1217
|
+
```
|
1206
1218
|
|
1207
|
-
|
1219
|
+
And create an initializer with:
|
1220
|
+
|
1221
|
+
```ruby
|
1208
1222
|
ActiveJob::TrafficControl.client = Searchkick.redis
|
1209
1223
|
|
1210
1224
|
class Searchkick::BulkReindexJob
|
1211
|
-
|
1212
|
-
|
1213
|
-
concurrency 3, drop: false
|
1225
|
+
concurrency 3
|
1214
1226
|
end
|
1215
1227
|
```
|
1216
1228
|
|
@@ -1677,21 +1689,78 @@ Product.search "ah", misspellings: {prefix_length: 2} # ah, no aha
|
|
1677
1689
|
|
1678
1690
|
## Testing
|
1679
1691
|
|
1680
|
-
|
1692
|
+
For performance, only enable Searchkick callbacks for the tests that need it.
|
1693
|
+
|
1694
|
+
### Minitest
|
1695
|
+
|
1696
|
+
Add to your `test/test_helper.rb`:
|
1697
|
+
|
1698
|
+
```ruby
|
1699
|
+
# reindex models
|
1700
|
+
Product.reindex
|
1701
|
+
|
1702
|
+
# and disable callbacks
|
1703
|
+
Searchkick.disable_callbacks
|
1704
|
+
```
|
1705
|
+
|
1706
|
+
And use:
|
1707
|
+
|
1708
|
+
```ruby
|
1709
|
+
class ProductTest < Minitest::Test
|
1710
|
+
def setup
|
1711
|
+
Searchkick.enable_callbacks
|
1712
|
+
end
|
1713
|
+
|
1714
|
+
def teardown
|
1715
|
+
Searchkick.disable_callbacks
|
1716
|
+
end
|
1717
|
+
|
1718
|
+
def test_search
|
1719
|
+
Product.create!(name: "Apple")
|
1720
|
+
Product.search_index.refresh
|
1721
|
+
assert_equal ["Apple"], Product.search("apple").map(&:name)
|
1722
|
+
end
|
1723
|
+
end
|
1724
|
+
```
|
1681
1725
|
|
1682
1726
|
### RSpec
|
1683
1727
|
|
1728
|
+
Add to your `spec/spec_helper.rb`:
|
1729
|
+
|
1684
1730
|
```ruby
|
1685
|
-
|
1686
|
-
|
1731
|
+
RSpec.configure do |config|
|
1732
|
+
config.before(:suite) do
|
1733
|
+
# reindex models
|
1687
1734
|
Product.reindex
|
1688
|
-
|
1735
|
+
|
1736
|
+
# and disable callbacks
|
1737
|
+
Searchkick.disable_callbacks
|
1738
|
+
end
|
1739
|
+
|
1740
|
+
config.around(:each, search: true) do |example|
|
1741
|
+
Searchkick.enable_callbacks
|
1742
|
+
example.run
|
1743
|
+
Searchkick.disable_callbacks
|
1744
|
+
end
|
1745
|
+
end
|
1746
|
+
```
|
1747
|
+
|
1748
|
+
And use:
|
1749
|
+
|
1750
|
+
```ruby
|
1751
|
+
describe Product, search: true do
|
1752
|
+
it "searches" do
|
1753
|
+
Product.create!(name: "Apple")
|
1754
|
+
Product.search_index.refresh
|
1755
|
+
assert_equal ["Apple"], Product.search("apple").map(&:name)
|
1689
1756
|
end
|
1690
1757
|
end
|
1691
1758
|
```
|
1692
1759
|
|
1693
1760
|
### Factory Girl
|
1694
1761
|
|
1762
|
+
Manually reindex after an instance is created.
|
1763
|
+
|
1695
1764
|
```ruby
|
1696
1765
|
product = FactoryGirl.create(:product)
|
1697
1766
|
product.reindex(refresh: true)
|
@@ -1716,6 +1785,10 @@ Important notes are listed below.
|
|
1716
1785
|
- Removed support for Elasticsearch 1 as it reaches [end of life](https://www.elastic.co/support/eol)
|
1717
1786
|
- Removed facets, legacy options, and legacy methods
|
1718
1787
|
- Invalid options now throw an `ArgumentError`
|
1788
|
+
- The `query` and `json` options have been removed in favor of `body`
|
1789
|
+
- The `include` option has been removed in favor of `includes`
|
1790
|
+
- The `personalize` option has been removed in favor of `boost_where`
|
1791
|
+
- The `partial` option has been removed in favor of `operator`
|
1719
1792
|
- Renamed `select_v2` to `select` (legacy `select` no longer available)
|
1720
1793
|
- The `_all` field is disabled if `searchable` option is used (for performance)
|
1721
1794
|
- The `partial_reindex(:method_name)` method has been replaced with `reindex(:method_name)`
|
@@ -1754,6 +1827,15 @@ Before `0.3.0`, locations were indexed incorrectly. When upgrading, be sure to r
|
|
1754
1827
|
|
1755
1828
|
## Elasticsearch Gotchas
|
1756
1829
|
|
1830
|
+
### Consistency
|
1831
|
+
|
1832
|
+
Elasticsearch is eventually consistent, meaning it can take up to a second for a change to reflect in search. You can use the `refresh` method to have it show up immediately.
|
1833
|
+
|
1834
|
+
```ruby
|
1835
|
+
product.save!
|
1836
|
+
Product.search_index.refresh
|
1837
|
+
```
|
1838
|
+
|
1757
1839
|
### Inconsistent Scores
|
1758
1840
|
|
1759
1841
|
Due to the distributed nature of Elasticsearch, you can get incorrect results when the number of documents in the index is low. You can [read more about it here](https://www.elastic.co/blog/understanding-query-then-fetch-vs-dfs-query-then-fetch). To fix this, do:
|
data/lib/searchkick/index.rb
CHANGED
@@ -25,7 +25,7 @@ module Searchkick
|
|
25
25
|
}
|
26
26
|
end
|
27
27
|
|
28
|
-
keyword_mapping[:ignore_above] = (options[:ignore_above] ||
|
28
|
+
keyword_mapping[:ignore_above] = (options[:ignore_above] || 30000) unless below22
|
29
29
|
|
30
30
|
settings = {
|
31
31
|
analysis: {
|
@@ -227,6 +227,8 @@ module Searchkick
|
|
227
227
|
|
228
228
|
word = options[:word] != false && (!options[:match] || options[:match] == :word)
|
229
229
|
|
230
|
+
mapping_options[:searchable].delete("_all")
|
231
|
+
|
230
232
|
mapping_options.values.flatten.uniq.each do |field|
|
231
233
|
fields = {}
|
232
234
|
|
@@ -286,8 +288,6 @@ module Searchkick
|
|
286
288
|
dynamic_fields["{name}"] = {type: default_type, index: "no"}
|
287
289
|
end
|
288
290
|
|
289
|
-
dynamic_fields["{name}"][:ignore_above] = (options[:ignore_above] || 256) unless below22
|
290
|
-
|
291
291
|
unless options[:searchable]
|
292
292
|
if options[:match] && options[:match] != :word
|
293
293
|
dynamic_fields[options[:match]] = {type: default_type, index: "analyzed", analyzer: "searchkick_#{options[:match]}_index"}
|
@@ -301,7 +301,7 @@ module Searchkick
|
|
301
301
|
# http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/
|
302
302
|
multi_field = dynamic_fields["{name}"].merge(fields: dynamic_fields.except("{name}"))
|
303
303
|
|
304
|
-
all_enabled = !options[:searchable] || options[:searchable].to_a.include?("_all")
|
304
|
+
all_enabled = !options[:searchable] || options[:searchable].to_a.map(&:to_s).include?("_all")
|
305
305
|
|
306
306
|
mappings = {
|
307
307
|
_default_: {
|
data/lib/searchkick/model.rb
CHANGED
@@ -26,7 +26,7 @@ module Searchkick
|
|
26
26
|
|
27
27
|
class << self
|
28
28
|
def searchkick_search(term = "*", **options, &block)
|
29
|
-
|
29
|
+
Searchkick.search(term, {model: self}.merge(options), &block)
|
30
30
|
end
|
31
31
|
alias_method Searchkick.search_method_name, :searchkick_search if Searchkick.search_method_name
|
32
32
|
|
@@ -144,6 +144,12 @@ module Searchkick
|
|
144
144
|
def should_index?
|
145
145
|
true
|
146
146
|
end unless method_defined?(:should_index?)
|
147
|
+
|
148
|
+
if defined?(Cequel) && self < Cequel::Record && !method_defined?(:destroyed?)
|
149
|
+
def destroyed?
|
150
|
+
transient?
|
151
|
+
end
|
152
|
+
end
|
147
153
|
end
|
148
154
|
end
|
149
155
|
end
|
@@ -6,7 +6,7 @@ module Searchkick
|
|
6
6
|
model = class_name.constantize
|
7
7
|
|
8
8
|
limit = model.searchkick_index.options[:batch_size] || 1000
|
9
|
-
record_ids =
|
9
|
+
record_ids = model.searchkick_index.reindex_queue.reserve(limit: limit)
|
10
10
|
if record_ids.any?
|
11
11
|
Searchkick::ProcessBatchJob.perform_later(
|
12
12
|
class_name: model.name,
|
data/lib/searchkick/query.rb
CHANGED
@@ -283,18 +283,25 @@ module Searchkick
|
|
283
283
|
|
284
284
|
shared_options[:operator] = operator if match_type == :match
|
285
285
|
|
286
|
+
exclude_analyzer = nil
|
287
|
+
exclude_field = field
|
288
|
+
|
286
289
|
if field == "_all" || field.end_with?(".analyzed")
|
287
290
|
shared_options[:cutoff_frequency] = 0.001 unless operator == "and" || misspellings == false
|
288
291
|
qs.concat [
|
289
292
|
shared_options.merge(analyzer: "searchkick_search"),
|
290
293
|
shared_options.merge(analyzer: "searchkick_search2")
|
291
294
|
]
|
295
|
+
exclude_analyzer = "searchkick_search2"
|
292
296
|
elsif field.end_with?(".exact")
|
293
297
|
f = field.split(".")[0..-2].join(".")
|
294
298
|
queries_to_add << {match: {f => shared_options.merge(analyzer: "keyword")}}
|
299
|
+
exclude_field = f
|
300
|
+
exclude_analyzer = "keyword"
|
295
301
|
else
|
296
302
|
analyzer = field =~ /\.word_(start|middle|end)\z/ ? "searchkick_word_search" : "searchkick_autocomplete_search"
|
297
303
|
qs << shared_options.merge(analyzer: analyzer)
|
304
|
+
exclude_analyzer = analyzer
|
298
305
|
end
|
299
306
|
|
300
307
|
if misspellings != false && match_type == :match
|
@@ -324,7 +331,10 @@ module Searchkick
|
|
324
331
|
options[:exclude].map do |phrase|
|
325
332
|
{
|
326
333
|
match_phrase: {
|
327
|
-
|
334
|
+
exclude_field => {
|
335
|
+
query: phrase,
|
336
|
+
analyzer: exclude_analyzer
|
337
|
+
}
|
328
338
|
}
|
329
339
|
}
|
330
340
|
end
|
data/lib/searchkick/version.rb
CHANGED
data/lib/searchkick.rb
CHANGED
@@ -81,7 +81,17 @@ module Searchkick
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def self.search(term = "*", **options, &block)
|
84
|
-
|
84
|
+
klass = options[:model]
|
85
|
+
|
86
|
+
# TODO add in next major version
|
87
|
+
# if !klass
|
88
|
+
# index_name = Array(options[:index_name])
|
89
|
+
# if index_name.size == 1 && index_name.first.respond_to?(:searchkick_index)
|
90
|
+
# klass = index_name.first
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
|
94
|
+
query = Searchkick::Query.new(klass, term, options.except(:model))
|
85
95
|
block.call(query.body) if block
|
86
96
|
if options[:execute] == false
|
87
97
|
query
|
@@ -169,6 +179,8 @@ module Searchkick
|
|
169
179
|
elsif records.respond_to?(:unscoped) && :id.respond_to?(:in)
|
170
180
|
# Nobrainer
|
171
181
|
records.unscoped.where(:id.in => ids)
|
182
|
+
elsif records.respond_to?(:key_column_names)
|
183
|
+
records.where(records.key_column_names.first => ids)
|
172
184
|
end
|
173
185
|
|
174
186
|
raise Searchkick::Error, "Not sure how to load records" if !records
|
data/test/aggs_test.rb
CHANGED
@@ -6,8 +6,8 @@ class AggsTest < Minitest::Test
|
|
6
6
|
store [
|
7
7
|
{name: "Product Show", latitude: 37.7833, longitude: 12.4167, store_id: 1, in_stock: true, color: "blue", price: 21, created_at: 2.days.ago},
|
8
8
|
{name: "Product Hide", latitude: 29.4167, longitude: -98.5000, store_id: 2, in_stock: false, color: "green", price: 25, created_at: 2.days.from_now},
|
9
|
-
{name: "Product B", latitude: 43.9333, longitude: -122.4667, store_id: 2, in_stock: false, color: "red", price: 5},
|
10
|
-
{name: "Foo", latitude: 43.9333, longitude: 12.4667, store_id: 3, in_stock: false, color: "yellow", price: 15}
|
9
|
+
{name: "Product B", latitude: 43.9333, longitude: -122.4667, store_id: 2, in_stock: false, color: "red", price: 5, created_at: Time.now},
|
10
|
+
{name: "Foo", latitude: 43.9333, longitude: 12.4667, store_id: 3, in_stock: false, color: "yellow", price: 15, created_at: Time.now}
|
11
11
|
]
|
12
12
|
end
|
13
13
|
|
data/test/boost_test.rb
CHANGED
@@ -86,6 +86,14 @@ class BoostTest < Minitest::Test
|
|
86
86
|
assert_order "red", ["Red", "White"], fields: [{"name^10" => :word_start}, "color"]
|
87
87
|
end
|
88
88
|
|
89
|
+
# for issue #855
|
90
|
+
def test_apostrophes
|
91
|
+
store_names ["Valentine's Day Special"]
|
92
|
+
assert_search "Valentines", ["Valentine's Day Special"], fields: ["name^5"]
|
93
|
+
assert_search "Valentine's", ["Valentine's Day Special"], fields: ["name^5"]
|
94
|
+
assert_search "Valentine", ["Valentine's Day Special"], fields: ["name^5"]
|
95
|
+
end
|
96
|
+
|
89
97
|
def test_boost_by
|
90
98
|
store [
|
91
99
|
{name: "Tomato A"},
|
@@ -157,6 +165,8 @@ class BoostTest < Minitest::Test
|
|
157
165
|
end
|
158
166
|
|
159
167
|
def test_boost_by_indices
|
168
|
+
skip if cequel?
|
169
|
+
|
160
170
|
store_names ["Rex"], Animal
|
161
171
|
store_names ["Rexx"], Product
|
162
172
|
|
data/test/errors_test.rb
CHANGED
@@ -2,8 +2,8 @@ require_relative "test_helper"
|
|
2
2
|
|
3
3
|
class ErrorsTest < Minitest::Test
|
4
4
|
def test_bulk_import_raises_error
|
5
|
-
valid_dog =
|
6
|
-
invalid_dog =
|
5
|
+
valid_dog = Product.new(name: "2016-01-02")
|
6
|
+
invalid_dog = Product.new(name: "Ol' One-Leg")
|
7
7
|
index = Searchkick::Index.new "dogs", mappings: {
|
8
8
|
dog: {
|
9
9
|
properties: {
|
data/test/highlight_test.rb
CHANGED
@@ -46,6 +46,11 @@ class HighlightTest < Minitest::Test
|
|
46
46
|
assert_equal "<b><em>Hello</em></b>", Product.search("hello", fields: [:name], highlight: {encoder: "html"}, misspellings: false).first.search_highlights[:name]
|
47
47
|
end
|
48
48
|
|
49
|
+
def test_word_middle
|
50
|
+
store_names ["Two Door Cinema Club"]
|
51
|
+
assert_equal "Two Door <em>Cinema</em> Club", Product.search("ine", fields: [:name], match: :word_middle, highlight: true).first.search_highlights[:name]
|
52
|
+
end
|
53
|
+
|
49
54
|
def test_body
|
50
55
|
skip if ENV["MATCH"] == "word_start"
|
51
56
|
store_names ["Two Door Cinema Club"]
|
data/test/index_test.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
require_relative "test_helper"
|
2
2
|
|
3
3
|
class IndexTest < Minitest::Test
|
4
|
+
def setup
|
5
|
+
super
|
6
|
+
Region.destroy_all
|
7
|
+
end
|
8
|
+
|
4
9
|
def test_clean_indices
|
5
10
|
old_index = Searchkick::Index.new("products_test_20130801000000000")
|
6
11
|
different_index = Searchkick::Index.new("items_test_20130801000000000")
|
@@ -127,8 +132,20 @@ class IndexTest < Minitest::Test
|
|
127
132
|
|
128
133
|
def test_large_value
|
129
134
|
skip if nobrainer?
|
135
|
+
large_value = 1000.times.map { "hello" }.join(" ")
|
136
|
+
store [{name: "Product A", text: large_value}], Region
|
137
|
+
assert_search "product", ["Product A"], {}, Region
|
138
|
+
assert_search "hello", ["Product A"], {fields: [:name, :text]}, Region
|
139
|
+
assert_search "hello", ["Product A"], {}, Region
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_very_large_value
|
143
|
+
skip if nobrainer? || elasticsearch_below22?
|
130
144
|
large_value = 10000.times.map { "hello" }.join(" ")
|
131
|
-
store [{name: "Product A",
|
132
|
-
assert_search "product", ["Product A"]
|
145
|
+
store [{name: "Product A", text: large_value}], Region
|
146
|
+
assert_search "product", ["Product A"], {}, Region
|
147
|
+
assert_search "hello", ["Product A"], {fields: [:name, :text]}, Region
|
148
|
+
# values that exceed ignore_above are not included in _all field :(
|
149
|
+
# assert_search "hello", ["Product A"], {}, Region
|
133
150
|
end
|
134
151
|
end
|
data/test/inheritance_test.rb
CHANGED
data/test/match_test.rb
CHANGED
@@ -161,21 +161,31 @@ class MatchTest < Minitest::Test
|
|
161
161
|
|
162
162
|
# butter
|
163
163
|
|
164
|
-
def
|
164
|
+
def test_exclude_butter
|
165
165
|
store_names ["Butter Tub", "Peanut Butter Tub"]
|
166
166
|
assert_search "butter", ["Butter Tub"], exclude: ["peanut butter"]
|
167
167
|
end
|
168
168
|
|
169
|
-
def
|
169
|
+
def test_exclude_butter_word_start
|
170
170
|
store_names ["Butter Tub", "Peanut Butter Tub"]
|
171
171
|
assert_search "butter", ["Butter Tub"], exclude: ["peanut butter"], match: :word_start
|
172
172
|
end
|
173
173
|
|
174
|
-
def
|
174
|
+
def test_exclude_butter_exact
|
175
175
|
store_names ["Butter Tub", "Peanut Butter Tub"]
|
176
176
|
assert_search "butter", [], exclude: ["peanut butter"], match: :exact
|
177
177
|
end
|
178
178
|
|
179
|
+
def test_exclude_same_exact
|
180
|
+
store_names ["Butter Tub", "Peanut Butter Tub"]
|
181
|
+
assert_search "Butter Tub", [], exclude: ["Butter Tub"], match: :exact
|
182
|
+
end
|
183
|
+
|
184
|
+
def test_exclude_egg_word_start
|
185
|
+
store_names ["eggs", "eggplant"]
|
186
|
+
assert_search "egg", ["eggs"], exclude: ["eggplant"], match: :word_start
|
187
|
+
end
|
188
|
+
|
179
189
|
# other
|
180
190
|
|
181
191
|
def test_all
|
@@ -184,6 +194,7 @@ class MatchTest < Minitest::Test
|
|
184
194
|
end
|
185
195
|
|
186
196
|
def test_no_arguments
|
197
|
+
store_names []
|
187
198
|
assert_equal [], Product.search.to_a
|
188
199
|
end
|
189
200
|
|
data/test/model_test.rb
CHANGED
@@ -37,6 +37,6 @@ class ModelTest < Minitest::Test
|
|
37
37
|
def test_multiple_models
|
38
38
|
store_names ["Product A"]
|
39
39
|
store_names ["Product B"], Speaker
|
40
|
-
assert_equal Product.all + Speaker.all, Searchkick.search("product", index_name: [Product, Speaker], fields: [:name], order: "name").to_a
|
40
|
+
assert_equal Product.all.to_a + Speaker.all.to_a, Searchkick.search("product", index_name: [Product, Speaker], fields: [:name], order: "name").to_a
|
41
41
|
end
|
42
42
|
end
|
data/test/order_test.rb
CHANGED
data/test/records_test.rb
CHANGED
data/test/reindex_test.rb
CHANGED
@@ -2,7 +2,7 @@ require_relative "test_helper"
|
|
2
2
|
|
3
3
|
class ReindexTest < Minitest::Test
|
4
4
|
def test_scoped
|
5
|
-
skip if nobrainer?
|
5
|
+
skip if nobrainer? || cequel?
|
6
6
|
|
7
7
|
store_names ["Product A"]
|
8
8
|
Searchkick.callbacks(false) do
|
@@ -13,7 +13,7 @@ class ReindexTest < Minitest::Test
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_associations
|
16
|
-
skip if nobrainer?
|
16
|
+
skip if nobrainer? || cequel?
|
17
17
|
|
18
18
|
store_names ["Product A"]
|
19
19
|
store = Store.create!(name: "Test")
|
data/test/test_helper.rb
CHANGED
@@ -45,6 +45,10 @@ def nobrainer?
|
|
45
45
|
defined?(NoBrainer)
|
46
46
|
end
|
47
47
|
|
48
|
+
def cequel?
|
49
|
+
defined?(Cequel)
|
50
|
+
end
|
51
|
+
|
48
52
|
if defined?(Mongoid)
|
49
53
|
Mongoid.logger.level = Logger::INFO
|
50
54
|
Mongo::Logger.logger.level = Logger::INFO if defined?(Mongo::Logger)
|
@@ -162,6 +166,88 @@ elsif defined?(NoBrainer)
|
|
162
166
|
|
163
167
|
class Cat < Animal
|
164
168
|
end
|
169
|
+
elsif defined?(Cequel)
|
170
|
+
cequel =
|
171
|
+
Cequel.connect(
|
172
|
+
host: "127.0.0.1",
|
173
|
+
port: 9042,
|
174
|
+
keyspace: "searchkick_test",
|
175
|
+
default_consistency: :all
|
176
|
+
)
|
177
|
+
# cequel.logger = ActiveSupport::Logger.new(STDOUT)
|
178
|
+
cequel.schema.drop! if cequel.schema.exists?
|
179
|
+
cequel.schema.create!
|
180
|
+
Cequel::Record.connection = cequel
|
181
|
+
|
182
|
+
class Product
|
183
|
+
include Cequel::Record
|
184
|
+
|
185
|
+
key :id, :uuid, auto: true
|
186
|
+
column :name, :text, index: true
|
187
|
+
column :store_id, :int
|
188
|
+
column :in_stock, :boolean
|
189
|
+
column :backordered, :boolean
|
190
|
+
column :orders_count, :int
|
191
|
+
column :found_rate, :decimal
|
192
|
+
column :price, :int
|
193
|
+
column :color, :text
|
194
|
+
column :latitude, :decimal
|
195
|
+
column :longitude, :decimal
|
196
|
+
column :description, :text
|
197
|
+
column :alt_description, :text
|
198
|
+
column :created_at, :timestamp
|
199
|
+
end
|
200
|
+
|
201
|
+
class Store
|
202
|
+
include Cequel::Record
|
203
|
+
|
204
|
+
key :id, :timeuuid, auto: true
|
205
|
+
column :name, :text
|
206
|
+
|
207
|
+
# has issue with id serialization
|
208
|
+
def search_data
|
209
|
+
{
|
210
|
+
name: name
|
211
|
+
}
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
class Region
|
216
|
+
include Cequel::Record
|
217
|
+
|
218
|
+
key :id, :timeuuid, auto: true
|
219
|
+
column :name, :text
|
220
|
+
column :text, :text
|
221
|
+
end
|
222
|
+
|
223
|
+
class Speaker
|
224
|
+
include Cequel::Record
|
225
|
+
|
226
|
+
key :id, :timeuuid, auto: true
|
227
|
+
column :name, :text
|
228
|
+
end
|
229
|
+
|
230
|
+
class Animal
|
231
|
+
include Cequel::Record
|
232
|
+
|
233
|
+
key :id, :timeuuid, auto: true
|
234
|
+
column :name, :text
|
235
|
+
|
236
|
+
# has issue with id serialization
|
237
|
+
def search_data
|
238
|
+
{
|
239
|
+
name: name
|
240
|
+
}
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
class Dog < Animal
|
245
|
+
end
|
246
|
+
|
247
|
+
class Cat < Animal
|
248
|
+
end
|
249
|
+
|
250
|
+
[Product, Store, Region, Speaker, Animal].each(&:synchronize_schema)
|
165
251
|
else
|
166
252
|
require "active_record"
|
167
253
|
|
data/test/where_test.rb
CHANGED
@@ -10,16 +10,22 @@ class WhereTest < Minitest::Test
|
|
10
10
|
{name: "Product D", store_id: 4, in_stock: false, backordered: false, created_at: now - 3, orders_count: 1}
|
11
11
|
]
|
12
12
|
assert_search "product", ["Product A", "Product B"], where: {in_stock: true}
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
|
14
|
+
# due to precision
|
15
|
+
unless cequel?
|
16
|
+
# date
|
17
|
+
assert_search "product", ["Product A"], where: {created_at: {gt: now - 1}}
|
18
|
+
assert_search "product", ["Product A", "Product B"], where: {created_at: {gte: now - 1}}
|
19
|
+
assert_search "product", ["Product D"], where: {created_at: {lt: now - 2}}
|
20
|
+
assert_search "product", ["Product C", "Product D"], where: {created_at: {lte: now - 2}}
|
21
|
+
end
|
22
|
+
|
18
23
|
# integer
|
19
24
|
assert_search "product", ["Product A"], where: {store_id: {lt: 2}}
|
20
25
|
assert_search "product", ["Product A", "Product B"], where: {store_id: {lte: 2}}
|
21
26
|
assert_search "product", ["Product D"], where: {store_id: {gt: 3}}
|
22
27
|
assert_search "product", ["Product C", "Product D"], where: {store_id: {gte: 3}}
|
28
|
+
|
23
29
|
# range
|
24
30
|
assert_search "product", ["Product A", "Product B"], where: {store_id: 1..2}
|
25
31
|
assert_search "product", ["Product A"], where: {store_id: 1...2}
|
@@ -27,23 +33,30 @@ class WhereTest < Minitest::Test
|
|
27
33
|
assert_search "product", ["Product B", "Product C", "Product D"], where: {store_id: {not: 1}}
|
28
34
|
assert_search "product", ["Product C", "Product D"], where: {store_id: {not: [1, 2]}}
|
29
35
|
assert_search "product", ["Product A"], where: {user_ids: {lte: 2, gte: 2}}
|
36
|
+
|
30
37
|
# or
|
31
38
|
assert_search "product", ["Product A", "Product B", "Product C"], where: {or: [[{in_stock: true}, {store_id: 3}]]}
|
32
39
|
assert_search "product", ["Product A", "Product B", "Product C"], where: {or: [[{orders_count: [2, 4]}, {store_id: [1, 2]}]]}
|
33
40
|
assert_search "product", ["Product A", "Product D"], where: {or: [[{orders_count: 1}, {created_at: {gte: now - 1}, backordered: true}]]}
|
41
|
+
|
34
42
|
# _or
|
35
43
|
assert_search "product", ["Product A", "Product B", "Product C"], where: {_or: [{in_stock: true}, {store_id: 3}]}
|
36
44
|
assert_search "product", ["Product A", "Product B", "Product C"], where: {_or: [{orders_count: [2, 4]}, {store_id: [1, 2]}]}
|
37
45
|
assert_search "product", ["Product A", "Product D"], where: {_or: [{orders_count: 1}, {created_at: {gte: now - 1}, backordered: true}]}
|
46
|
+
|
38
47
|
# _and
|
39
48
|
assert_search "product", ["Product A"], where: {_and: [{in_stock: true}, {backordered: true}]}
|
49
|
+
|
40
50
|
# _not
|
41
51
|
assert_search "product", ["Product B", "Product C"], where: {_not: {_or: [{orders_count: 1}, {created_at: {gte: now - 1}, backordered: true}]}}
|
52
|
+
|
42
53
|
# all
|
43
54
|
assert_search "product", ["Product A", "Product C"], where: {user_ids: {all: [1, 3]}}
|
44
55
|
assert_search "product", [], where: {user_ids: {all: [1, 2, 3, 4]}}
|
56
|
+
|
45
57
|
# any / nested terms
|
46
58
|
assert_search "product", ["Product B", "Product C"], where: {user_ids: {not: [2], in: [1, 3]}}
|
59
|
+
|
47
60
|
# not / exists
|
48
61
|
assert_search "product", ["Product D"], where: {user_ids: nil}
|
49
62
|
assert_search "product", ["Product A", "Product B", "Product C"], where: {user_ids: {not: nil}}
|
@@ -78,7 +91,7 @@ class WhereTest < Minitest::Test
|
|
78
91
|
|
79
92
|
def test_where_id
|
80
93
|
store_names ["Product A"]
|
81
|
-
product = Product.
|
94
|
+
product = Product.first
|
82
95
|
assert_search "product", ["Product A"], where: {id: product.id.to_s}
|
83
96
|
end
|
84
97
|
|
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: 2.
|
4
|
+
version: 2.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: 2017-
|
11
|
+
date: 2017-03-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -138,7 +138,9 @@ files:
|
|
138
138
|
- test/gemfiles/activerecord40.gemfile
|
139
139
|
- test/gemfiles/activerecord41.gemfile
|
140
140
|
- test/gemfiles/activerecord42.gemfile
|
141
|
+
- test/gemfiles/activerecord51.gemfile
|
141
142
|
- test/gemfiles/apartment.gemfile
|
143
|
+
- test/gemfiles/cequel.gemfile
|
142
144
|
- test/gemfiles/mongoid2.gemfile
|
143
145
|
- test/gemfiles/mongoid3.gemfile
|
144
146
|
- test/gemfiles/mongoid4.gemfile
|
@@ -209,7 +211,9 @@ test_files:
|
|
209
211
|
- test/gemfiles/activerecord40.gemfile
|
210
212
|
- test/gemfiles/activerecord41.gemfile
|
211
213
|
- test/gemfiles/activerecord42.gemfile
|
214
|
+
- test/gemfiles/activerecord51.gemfile
|
212
215
|
- test/gemfiles/apartment.gemfile
|
216
|
+
- test/gemfiles/cequel.gemfile
|
213
217
|
- test/gemfiles/mongoid2.gemfile
|
214
218
|
- test/gemfiles/mongoid3.gemfile
|
215
219
|
- test/gemfiles/mongoid4.gemfile
|