searchkick-hooopo 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.travis.yml +35 -0
  4. data/CHANGELOG.md +491 -0
  5. data/Gemfile +12 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +1908 -0
  8. data/Rakefile +20 -0
  9. data/benchmark/Gemfile +23 -0
  10. data/benchmark/benchmark.rb +97 -0
  11. data/lib/searchkick/bulk_reindex_job.rb +17 -0
  12. data/lib/searchkick/index.rb +500 -0
  13. data/lib/searchkick/index_options.rb +333 -0
  14. data/lib/searchkick/indexer.rb +28 -0
  15. data/lib/searchkick/logging.rb +242 -0
  16. data/lib/searchkick/middleware.rb +12 -0
  17. data/lib/searchkick/model.rb +156 -0
  18. data/lib/searchkick/process_batch_job.rb +23 -0
  19. data/lib/searchkick/process_queue_job.rb +23 -0
  20. data/lib/searchkick/query.rb +901 -0
  21. data/lib/searchkick/reindex_queue.rb +38 -0
  22. data/lib/searchkick/reindex_v2_job.rb +39 -0
  23. data/lib/searchkick/results.rb +216 -0
  24. data/lib/searchkick/tasks.rb +33 -0
  25. data/lib/searchkick/version.rb +3 -0
  26. data/lib/searchkick.rb +215 -0
  27. data/searchkick.gemspec +28 -0
  28. data/test/aggs_test.rb +197 -0
  29. data/test/autocomplete_test.rb +75 -0
  30. data/test/boost_test.rb +175 -0
  31. data/test/callbacks_test.rb +59 -0
  32. data/test/ci/before_install.sh +17 -0
  33. data/test/errors_test.rb +19 -0
  34. data/test/gemfiles/activerecord31.gemfile +7 -0
  35. data/test/gemfiles/activerecord32.gemfile +7 -0
  36. data/test/gemfiles/activerecord40.gemfile +8 -0
  37. data/test/gemfiles/activerecord41.gemfile +8 -0
  38. data/test/gemfiles/activerecord42.gemfile +7 -0
  39. data/test/gemfiles/activerecord50.gemfile +7 -0
  40. data/test/gemfiles/apartment.gemfile +8 -0
  41. data/test/gemfiles/cequel.gemfile +8 -0
  42. data/test/gemfiles/mongoid2.gemfile +7 -0
  43. data/test/gemfiles/mongoid3.gemfile +6 -0
  44. data/test/gemfiles/mongoid4.gemfile +7 -0
  45. data/test/gemfiles/mongoid5.gemfile +7 -0
  46. data/test/gemfiles/mongoid6.gemfile +8 -0
  47. data/test/gemfiles/nobrainer.gemfile +8 -0
  48. data/test/gemfiles/parallel_tests.gemfile +8 -0
  49. data/test/geo_shape_test.rb +172 -0
  50. data/test/highlight_test.rb +78 -0
  51. data/test/index_test.rb +153 -0
  52. data/test/inheritance_test.rb +83 -0
  53. data/test/marshal_test.rb +8 -0
  54. data/test/match_test.rb +276 -0
  55. data/test/misspellings_test.rb +56 -0
  56. data/test/model_test.rb +42 -0
  57. data/test/multi_search_test.rb +22 -0
  58. data/test/multi_tenancy_test.rb +22 -0
  59. data/test/order_test.rb +46 -0
  60. data/test/pagination_test.rb +53 -0
  61. data/test/partial_reindex_test.rb +58 -0
  62. data/test/query_test.rb +35 -0
  63. data/test/records_test.rb +10 -0
  64. data/test/reindex_test.rb +52 -0
  65. data/test/reindex_v2_job_test.rb +32 -0
  66. data/test/routing_test.rb +23 -0
  67. data/test/should_index_test.rb +32 -0
  68. data/test/similar_test.rb +28 -0
  69. data/test/sql_test.rb +198 -0
  70. data/test/suggest_test.rb +85 -0
  71. data/test/synonyms_test.rb +67 -0
  72. data/test/test_helper.rb +527 -0
  73. data/test/where_test.rb +223 -0
  74. metadata +250 -0
@@ -0,0 +1,32 @@
1
+ require_relative "test_helper"
2
+
3
+ class ReindexV2JobTest < Minitest::Test
4
+ def setup
5
+ skip unless defined?(ActiveJob)
6
+ super
7
+ Searchkick.disable_callbacks
8
+ end
9
+
10
+ def teardown
11
+ Searchkick.enable_callbacks
12
+ end
13
+
14
+ def test_create
15
+ product = Product.create!(name: "Boom")
16
+ Product.searchkick_index.refresh
17
+ assert_search "*", []
18
+ Searchkick::ReindexV2Job.perform_later("Product", product.id.to_s)
19
+ Product.searchkick_index.refresh
20
+ assert_search "*", ["Boom"]
21
+ end
22
+
23
+ def test_destroy
24
+ product = Product.create!(name: "Boom")
25
+ Product.reindex
26
+ assert_search "*", ["Boom"]
27
+ product.destroy
28
+ Searchkick::ReindexV2Job.perform_later("Product", product.id.to_s)
29
+ Product.searchkick_index.refresh
30
+ assert_search "*", []
31
+ end
32
+ end
@@ -0,0 +1,23 @@
1
+ require_relative "test_helper"
2
+
3
+ class RoutingTest < Minitest::Test
4
+ def test_routing_query
5
+ query = Store.search("Dollar Tree", routing: "Dollar Tree", execute: false)
6
+ assert_equal query.params[:routing], "Dollar Tree"
7
+ end
8
+
9
+ def test_routing_mappings
10
+ index_options = Store.searchkick_index.index_options
11
+ assert_equal index_options[:mappings][:_default_][:_routing], required: true
12
+ end
13
+
14
+ def test_routing_correct_node
15
+ store_names ["Dollar Tree"], Store
16
+ assert_search "dollar", ["Dollar Tree"], {routing: "Dollar Tree"}, Store
17
+ end
18
+
19
+ def test_routing_incorrect_node
20
+ store_names ["Dollar Tree"], Store
21
+ assert_search "dollar", ["Dollar Tree"], {routing: "Boom"}, Store
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ require_relative "test_helper"
2
+
3
+ class ShouldIndexTest < Minitest::Test
4
+ def test_basic
5
+ store_names ["INDEX", "DO NOT INDEX"]
6
+ assert_search "index", ["INDEX"]
7
+ end
8
+
9
+ def test_default_true
10
+ assert Animal.new.should_index?
11
+ end
12
+
13
+ def test_change_to_true
14
+ store_names ["DO NOT INDEX"]
15
+ assert_search "index", []
16
+ product = Product.first
17
+ product.name = "INDEX"
18
+ product.save!
19
+ Product.searchkick_index.refresh
20
+ assert_search "index", ["INDEX"]
21
+ end
22
+
23
+ def test_change_to_false
24
+ store_names ["INDEX"]
25
+ assert_search "index", ["INDEX"]
26
+ product = Product.first
27
+ product.name = "DO NOT INDEX"
28
+ product.save!
29
+ Product.searchkick_index.refresh
30
+ assert_search "index", []
31
+ end
32
+ end
@@ -0,0 +1,28 @@
1
+ require_relative "test_helper"
2
+
3
+ class SimilarTest < Minitest::Test
4
+ def test_similar
5
+ store_names ["Annie's Naturals Organic Shiitake & Sesame Dressing"]
6
+ assert_search "Annie's Naturals Shiitake & Sesame Vinaigrette", ["Annie's Naturals Organic Shiitake & Sesame Dressing"], similar: true
7
+ end
8
+
9
+ def test_fields
10
+ store_names ["1% Organic Milk", "2% Organic Milk", "Popcorn"]
11
+ assert_equal ["2% Organic Milk"], Product.where(name: "1% Organic Milk").first.similar(fields: ["name"]).map(&:name)
12
+ end
13
+
14
+ def test_order
15
+ store_names ["Lucerne Milk Chocolate Fat Free", "Clover Fat Free Milk"]
16
+ assert_order "Lucerne Fat Free Chocolate Milk", ["Lucerne Milk Chocolate Fat Free", "Clover Fat Free Milk"], similar: true
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
28
+ end
data/test/sql_test.rb ADDED
@@ -0,0 +1,198 @@
1
+ require_relative "test_helper"
2
+
3
+ class SqlTest < Minitest::Test
4
+ def test_operator
5
+ store_names ["Honey"]
6
+ assert_search "fresh honey", []
7
+ assert_search "fresh honey", ["Honey"], operator: "or"
8
+ end
9
+
10
+ def test_operator_scoring
11
+ store_names ["Big Red Circle", "Big Green Circle", "Small Orange Circle"]
12
+ assert_order "big red circle", ["Big Red Circle", "Big Green Circle", "Small Orange Circle"], operator: "or"
13
+ end
14
+
15
+ def test_fields_operator
16
+ store [
17
+ {name: "red", color: "red"},
18
+ {name: "blue", color: "blue"},
19
+ {name: "cyan", color: "blue green"},
20
+ {name: "magenta", color: "red blue"},
21
+ {name: "green", color: "green"}
22
+ ]
23
+ assert_search "red blue", ["red", "blue", "cyan", "magenta"], operator: "or", fields: ["color"]
24
+ end
25
+
26
+ def test_fields
27
+ store [
28
+ {name: "red", color: "light blue"},
29
+ {name: "blue", color: "red fish"}
30
+ ]
31
+ assert_search "blue", ["red"], fields: ["color"]
32
+ end
33
+
34
+ def test_non_existent_field
35
+ store_names ["Milk"]
36
+ assert_search "milk", [], fields: ["not_here"]
37
+ end
38
+
39
+ def test_fields_both_match
40
+ store [
41
+ {name: "Blue A", color: "red"},
42
+ {name: "Blue B", color: "light blue"}
43
+ ]
44
+ assert_first "blue", "Blue B", fields: [:name, :color]
45
+ end
46
+
47
+ def test_big_decimal
48
+ store [
49
+ {name: "Product", latitude: 80.0}
50
+ ]
51
+ assert_search "product", ["Product"], where: {latitude: {gt: 79}}
52
+ end
53
+
54
+ # body_options
55
+
56
+ def test_body_options_should_merge_into_body
57
+ query = Product.search("*", body_options: {min_score: 1.0}, execute: false)
58
+ assert_equal 1.0, query.body[:min_score]
59
+ end
60
+
61
+ # load
62
+
63
+ def test_load_default
64
+ store_names ["Product A"]
65
+ assert_kind_of Product, Product.search("product").first
66
+ end
67
+
68
+ def test_load_false
69
+ store_names ["Product A"]
70
+ assert_kind_of Hash, Product.search("product", load: false).first
71
+ end
72
+
73
+ def test_load_false_methods
74
+ store_names ["Product A"]
75
+ assert_equal "Product A", Product.search("product", load: false).first.name
76
+ end
77
+
78
+ def test_load_false_with_includes
79
+ store_names ["Product A"]
80
+ assert_kind_of Hash, Product.search("product", load: false, includes: [:store]).first
81
+ end
82
+
83
+ def test_load_false_nested_object
84
+ aisle = {"id" => 1, "name" => "Frozen"}
85
+ store [{name: "Product A", aisle: aisle}]
86
+ assert_equal aisle, Product.search("product", load: false).first.aisle.to_hash
87
+ end
88
+
89
+ # select
90
+
91
+ def test_select
92
+ store [{name: "Product A", store_id: 1}]
93
+ result = Product.search("product", load: false, select: [:name, :store_id]).first
94
+ assert_equal %w(id name store_id), result.keys.reject { |k| k.start_with?("_") }.sort
95
+ assert_equal "Product A", result.name
96
+ assert_equal 1, result.store_id
97
+ end
98
+
99
+ def test_select_array
100
+ store [{name: "Product A", user_ids: [1, 2]}]
101
+ result = Product.search("product", load: false, select: [:user_ids]).first
102
+ assert_equal [1, 2], result.user_ids
103
+ end
104
+
105
+ def test_select_single_field
106
+ store [{name: "Product A", store_id: 1}]
107
+ result = Product.search("product", load: false, select: :name).first
108
+ assert_equal %w(id name), result.keys.reject { |k| k.start_with?("_") }.sort
109
+ assert_equal "Product A", result.name
110
+ assert_nil result.store_id
111
+ end
112
+
113
+ def test_select_all
114
+ store [{name: "Product A", user_ids: [1, 2]}]
115
+ hit = Product.search("product", select: true).hits.first
116
+ assert_equal hit["_source"]["name"], "Product A"
117
+ assert_equal hit["_source"]["user_ids"], [1, 2]
118
+ end
119
+
120
+ def test_select_none
121
+ store [{name: "Product A", user_ids: [1, 2]}]
122
+ hit = Product.search("product", select: []).hits.first
123
+ assert_nil hit["_source"]
124
+ hit = Product.search("product", select: false).hits.first
125
+ assert_nil hit["_source"]
126
+ end
127
+
128
+ def test_select_include
129
+ skip unless elasticsearch_below50?
130
+ store [{name: "Product A", user_ids: [1, 2]}]
131
+ result = Product.search("product", load: false, select: {include: [:name]}).first
132
+ assert_equal %w(id name), result.keys.reject { |k| k.start_with?("_") }.sort
133
+ assert_equal "Product A", result.name
134
+ assert_nil result.store_id
135
+ end
136
+
137
+ def test_select_exclude
138
+ skip unless elasticsearch_below50?
139
+ store [{name: "Product A", user_ids: [1, 2], store_id: 1}]
140
+ result = Product.search("product", load: false, select: {exclude: [:name]}).first
141
+ assert_nil result.name
142
+ assert_equal [1, 2], result.user_ids
143
+ assert_equal 1, result.store_id
144
+ end
145
+
146
+ def test_select_include_and_exclude
147
+ skip unless elasticsearch_below50?
148
+ # let's take this to the next level
149
+ store [{name: "Product A", user_ids: [1, 2], store_id: 1}]
150
+ result = Product.search("product", load: false, select: {include: [:store_id], exclude: [:name]}).first
151
+ assert_equal 1, result.store_id
152
+ assert_nil result.name
153
+ assert_nil result.user_ids
154
+ end
155
+
156
+ def test_select_includes
157
+ skip if elasticsearch_below50?
158
+ store [{name: "Product A", user_ids: [1, 2]}]
159
+ result = Product.search("product", load: false, select: {includes: [:name]}).first
160
+ assert_equal %w(id name), result.keys.reject { |k| k.start_with?("_") }.sort
161
+ assert_equal "Product A", result.name
162
+ assert_nil result.store_id
163
+ end
164
+
165
+ def test_select_excludes
166
+ skip if elasticsearch_below50?
167
+ store [{name: "Product A", user_ids: [1, 2], store_id: 1}]
168
+ result = Product.search("product", load: false, select: {excludes: [:name]}).first
169
+ assert_nil result.name
170
+ assert_equal [1, 2], result.user_ids
171
+ assert_equal 1, result.store_id
172
+ end
173
+
174
+ def test_select_include_and_excludes
175
+ skip if elasticsearch_below50?
176
+ # let's take this to the next level
177
+ store [{name: "Product A", user_ids: [1, 2], store_id: 1}]
178
+ result = Product.search("product", load: false, select: {includes: [:store_id], excludes: [:name]}).first
179
+ assert_equal 1, result.store_id
180
+ assert_nil result.name
181
+ assert_nil result.user_ids
182
+ end
183
+
184
+ # nested
185
+
186
+ def test_nested_search
187
+ store [{name: "Product A", aisle: {"id" => 1, "name" => "Frozen"}}], Speaker
188
+ assert_search "frozen", ["Product A"], {fields: ["aisle.name"]}, Speaker
189
+ end
190
+
191
+ # other tests
192
+
193
+ def test_includes
194
+ skip unless defined?(ActiveRecord)
195
+ store_names ["Product A"]
196
+ assert Product.search("product", includes: [:store]).first.association(:store).loaded?
197
+ end
198
+ end
@@ -0,0 +1,85 @@
1
+ require_relative "test_helper"
2
+
3
+ class SuggestTest < Minitest::Test
4
+ def test_basic
5
+ store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
6
+ assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark", fields: [:name]
7
+ end
8
+
9
+ def test_perfect
10
+ store_names ["Tiger Shark", "Great White Shark"]
11
+ assert_suggest "Tiger Shark", nil, fields: [:name] # no correction
12
+ end
13
+
14
+ def test_phrase
15
+ store_names ["Big Tiger Shark", "Tiger Sharp Teeth", "Tiger Sharp Mind"]
16
+ assert_suggest "How to catch a big tiger shar", "how to catch a big tiger shark", fields: [:name]
17
+ end
18
+
19
+ def test_without_option
20
+ store_names ["hi"] # needed to prevent ElasticsearchException - seed 668
21
+ assert_raises(RuntimeError) { Product.search("hi").suggestions }
22
+ end
23
+
24
+ def test_multiple_fields
25
+ store [
26
+ {name: "Shark", color: "Sharp"},
27
+ {name: "Shark", color: "Sharp"}
28
+ ]
29
+ assert_suggest_all "shar", ["shark", "sharp"]
30
+ end
31
+
32
+ def test_multiple_fields_highest_score_first
33
+ store [
34
+ {name: "Tiger Shark", color: "Sharp"}
35
+ ]
36
+ assert_suggest "tiger shar", "tiger shark"
37
+ end
38
+
39
+ def test_multiple_fields_same_value
40
+ store [
41
+ {name: "Shark", color: "Shark"}
42
+ ]
43
+ assert_suggest_all "shar", ["shark"]
44
+ end
45
+
46
+ def test_fields_option
47
+ store [
48
+ {name: "Shark", color: "Sharp"}
49
+ ]
50
+ assert_suggest_all "shar", ["shark"], fields: [:name]
51
+ end
52
+
53
+ def test_fields_option_multiple
54
+ store [
55
+ {name: "Shark"}
56
+ ]
57
+ assert_suggest "shar", "shark", fields: [:name, :unknown]
58
+ end
59
+
60
+ def test_fields_partial_match
61
+ store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
62
+ assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark", fields: [{name: :word_start}]
63
+ end
64
+
65
+ def test_fields_partial_match_boost
66
+ store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
67
+ assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark", fields: [{"name^2" => :word_start}]
68
+ end
69
+
70
+ protected
71
+
72
+ def assert_suggest(term, expected, options = {})
73
+ result = Product.search(term, options.merge(suggest: true)).suggestions.first
74
+ if expected.nil?
75
+ assert_nil result
76
+ else
77
+ assert_equal expected, result
78
+ end
79
+ end
80
+
81
+ # any order
82
+ def assert_suggest_all(term, expected, options = {})
83
+ assert_equal expected.sort, Product.search(term, options.merge(suggest: true)).suggestions.sort
84
+ end
85
+ end
@@ -0,0 +1,67 @@
1
+ require_relative "test_helper"
2
+
3
+ class SynonymsTest < Minitest::Test
4
+ def test_bleach
5
+ store_names ["Clorox Bleach", "Kroger Bleach"]
6
+ assert_search "clorox", ["Clorox Bleach", "Kroger Bleach"]
7
+ end
8
+
9
+ def test_saran_wrap
10
+ store_names ["Saran Wrap", "Kroger Plastic Wrap"]
11
+ assert_search "saran wrap", ["Saran Wrap", "Kroger Plastic Wrap"]
12
+ end
13
+
14
+ def test_burger_buns
15
+ store_names ["Hamburger Buns"]
16
+ assert_search "burger buns", ["Hamburger Buns"]
17
+ end
18
+
19
+ def test_bandaids
20
+ store_names ["Band-Aid", "Kroger 12-Pack Bandages"]
21
+ assert_search "bandaids", ["Band-Aid", "Kroger 12-Pack Bandages"]
22
+ end
23
+
24
+ def test_qtips
25
+ store_names ["Q Tips", "Kroger Cotton Swabs"]
26
+ assert_search "q tips", ["Q Tips", "Kroger Cotton Swabs"]
27
+ end
28
+
29
+ def test_reverse
30
+ store_names ["Scallions"]
31
+ assert_search "green onions", ["Scallions"]
32
+ end
33
+
34
+ def test_exact
35
+ store_names ["Green Onions", "Yellow Onions"]
36
+ assert_search "scallion", ["Green Onions"]
37
+ end
38
+
39
+ def test_stemmed
40
+ store_names ["Green Onions", "Yellow Onions"]
41
+ assert_search "scallions", ["Green Onions"]
42
+ end
43
+
44
+ def test_word_start
45
+ store_names ["Clorox Bleach", "Kroger Bleach"]
46
+ assert_search "clorox", ["Clorox Bleach", "Kroger Bleach"], fields: [{name: :word_start}]
47
+ end
48
+
49
+ def test_wordnet
50
+ skip unless ENV["TEST_WORDNET"]
51
+ store_names ["Creature", "Beast", "Dragon"], Animal
52
+ assert_search "animal", ["Creature", "Beast"], {}, Animal
53
+ end
54
+
55
+ def test_directional
56
+ store_names ["Lightbulb", "Green Onions", "Led"]
57
+ assert_search "led", ["Lightbulb", "Led"]
58
+ assert_search "Lightbulb", ["Lightbulb"]
59
+ assert_search "Halogen Lamp", ["Lightbulb"]
60
+ assert_search "onions", ["Green Onions"]
61
+ end
62
+
63
+ def test_case
64
+ store_names ["Uppercase"]
65
+ assert_search "lowercase", ["Uppercase"]
66
+ end
67
+ end