searchkick 2.3.2 → 4.4.1

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.
Files changed (80) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +251 -84
  3. data/LICENSE.txt +1 -1
  4. data/README.md +552 -432
  5. data/lib/searchkick/bulk_indexer.rb +173 -0
  6. data/lib/searchkick/bulk_reindex_job.rb +2 -2
  7. data/lib/searchkick/hash_wrapper.rb +12 -0
  8. data/lib/searchkick/index.rb +187 -348
  9. data/lib/searchkick/index_options.rb +494 -282
  10. data/lib/searchkick/logging.rb +17 -13
  11. data/lib/searchkick/model.rb +52 -97
  12. data/lib/searchkick/multi_search.rb +9 -10
  13. data/lib/searchkick/process_batch_job.rb +17 -4
  14. data/lib/searchkick/process_queue_job.rb +20 -12
  15. data/lib/searchkick/query.rb +415 -199
  16. data/lib/searchkick/railtie.rb +7 -0
  17. data/lib/searchkick/record_data.rb +128 -0
  18. data/lib/searchkick/record_indexer.rb +79 -0
  19. data/lib/searchkick/reindex_queue.rb +1 -1
  20. data/lib/searchkick/reindex_v2_job.rb +14 -12
  21. data/lib/searchkick/results.rb +135 -41
  22. data/lib/searchkick/version.rb +1 -1
  23. data/lib/searchkick.rb +130 -61
  24. data/lib/tasks/searchkick.rake +34 -0
  25. metadata +18 -162
  26. data/.gitignore +0 -22
  27. data/.travis.yml +0 -39
  28. data/Gemfile +0 -16
  29. data/Rakefile +0 -20
  30. data/benchmark/Gemfile +0 -23
  31. data/benchmark/benchmark.rb +0 -97
  32. data/lib/searchkick/tasks.rb +0 -33
  33. data/searchkick.gemspec +0 -28
  34. data/test/aggs_test.rb +0 -197
  35. data/test/autocomplete_test.rb +0 -75
  36. data/test/boost_test.rb +0 -202
  37. data/test/callbacks_test.rb +0 -59
  38. data/test/ci/before_install.sh +0 -17
  39. data/test/errors_test.rb +0 -19
  40. data/test/gemfiles/activerecord31.gemfile +0 -7
  41. data/test/gemfiles/activerecord32.gemfile +0 -7
  42. data/test/gemfiles/activerecord40.gemfile +0 -8
  43. data/test/gemfiles/activerecord41.gemfile +0 -8
  44. data/test/gemfiles/activerecord42.gemfile +0 -7
  45. data/test/gemfiles/activerecord50.gemfile +0 -7
  46. data/test/gemfiles/apartment.gemfile +0 -8
  47. data/test/gemfiles/cequel.gemfile +0 -8
  48. data/test/gemfiles/mongoid2.gemfile +0 -7
  49. data/test/gemfiles/mongoid3.gemfile +0 -6
  50. data/test/gemfiles/mongoid4.gemfile +0 -7
  51. data/test/gemfiles/mongoid5.gemfile +0 -7
  52. data/test/gemfiles/mongoid6.gemfile +0 -12
  53. data/test/gemfiles/nobrainer.gemfile +0 -8
  54. data/test/gemfiles/parallel_tests.gemfile +0 -8
  55. data/test/geo_shape_test.rb +0 -175
  56. data/test/highlight_test.rb +0 -78
  57. data/test/index_test.rb +0 -166
  58. data/test/inheritance_test.rb +0 -83
  59. data/test/marshal_test.rb +0 -8
  60. data/test/match_test.rb +0 -276
  61. data/test/misspellings_test.rb +0 -56
  62. data/test/model_test.rb +0 -42
  63. data/test/multi_search_test.rb +0 -36
  64. data/test/multi_tenancy_test.rb +0 -22
  65. data/test/order_test.rb +0 -46
  66. data/test/pagination_test.rb +0 -70
  67. data/test/partial_reindex_test.rb +0 -58
  68. data/test/query_test.rb +0 -35
  69. data/test/records_test.rb +0 -10
  70. data/test/reindex_test.rb +0 -64
  71. data/test/reindex_v2_job_test.rb +0 -32
  72. data/test/routing_test.rb +0 -23
  73. data/test/should_index_test.rb +0 -32
  74. data/test/similar_test.rb +0 -28
  75. data/test/sql_test.rb +0 -214
  76. data/test/suggest_test.rb +0 -95
  77. data/test/support/kaminari.yml +0 -21
  78. data/test/synonyms_test.rb +0 -67
  79. data/test/test_helper.rb +0 -567
  80. data/test/where_test.rb +0 -223
data/benchmark/Gemfile DELETED
@@ -1,23 +0,0 @@
1
- source "https://rubygems.org"
2
-
3
- # Specify your gem's dependencies in searchkick.gemspec
4
- gemspec path: "../"
5
-
6
- # gem "sqlite3"
7
- gem "pg"
8
- gem "activerecord", "~> 5.0.0"
9
- gem "activerecord-import"
10
- gem "activejob"
11
- gem "redis"
12
- gem "sidekiq"
13
-
14
- # performance
15
- gem "typhoeus"
16
- gem "oj"
17
-
18
- # profiling
19
- gem "ruby-prof"
20
- gem "allocation_stats"
21
- gem "get_process_mem"
22
- gem "memory_profiler"
23
- gem "allocation_tracer"
@@ -1,97 +0,0 @@
1
- require "bundler/setup"
2
- Bundler.require(:default)
3
- require "active_record"
4
- require "benchmark"
5
- require "active_support/notifications"
6
-
7
- ActiveSupport::Notifications.subscribe "request.searchkick" do |*args|
8
- event = ActiveSupport::Notifications::Event.new(*args)
9
- p event.duration
10
- end
11
-
12
- ActiveJob::Base.queue_adapter = :sidekiq
13
-
14
- Searchkick.redis = Redis.new
15
-
16
- ActiveRecord::Base.default_timezone = :utc
17
- ActiveRecord::Base.time_zone_aware_attributes = true
18
- # ActiveRecord::Base.establish_connection adapter: "sqlite3", database: "/tmp/searchkick"
19
- ActiveRecord::Base.establish_connection "postgresql://localhost/searchkick_demo_development"
20
- # ActiveRecord::Base.logger = Logger.new(STDOUT)
21
-
22
- ActiveJob::Base.logger = nil
23
-
24
- class Product < ActiveRecord::Base
25
- searchkick batch_size: 1000
26
-
27
- def search_data
28
- {
29
- name: name,
30
- color: color,
31
- store_id: store_id
32
- }
33
- end
34
- end
35
-
36
- total_docs = 100000
37
-
38
- # ActiveRecord::Migration.create_table :products, force: :cascade do |t|
39
- # t.string :name
40
- # t.string :color
41
- # t.integer :store_id
42
- # end
43
-
44
- # Product.import ["name", "color", "store_id"], total_docs.times.map { |i| ["Product #{i}", ["red", "blue"].sample, rand(10)] }
45
-
46
- puts "Imported"
47
-
48
- result = nil
49
- report = nil
50
- stats = nil
51
-
52
- # p GetProcessMem.new.mb
53
-
54
- Product.searchkick_index.delete rescue nil
55
-
56
- time =
57
- Benchmark.realtime do
58
- # result = RubyProf.profile do
59
- # report = MemoryProfiler.report do
60
- # stats = AllocationStats.trace do
61
- reindex = Product.reindex(async: true)
62
- p reindex
63
- # end
64
-
65
- 60.times do |i|
66
- if reindex.is_a?(Hash)
67
- docs = Searchkick::Index.new(reindex[:index_name]).total_docs
68
- else
69
- docs = Product.searchkick_index.total_docs
70
- end
71
- puts "#{i}: #{docs}"
72
- if docs == total_docs
73
- break
74
- end
75
- p Searchkick.reindex_status(reindex[:index_name]) if reindex.is_a?(Hash)
76
- sleep(1)
77
- # Product.searchkick_index.refresh
78
- end
79
- end
80
-
81
- # p GetProcessMem.new.mb
82
-
83
- puts time.round(1)
84
-
85
-
86
- if result
87
- printer = RubyProf::GraphPrinter.new(result)
88
- printer.print(STDOUT, min_percent: 5)
89
- end
90
-
91
- if report
92
- puts report.pretty_print
93
- end
94
-
95
- if stats
96
- puts result.allocations(alias_paths: true).group_by(:sourcefile, :class).to_text
97
- end
@@ -1,33 +0,0 @@
1
- require "rake"
2
-
3
- namespace :searchkick do
4
- desc "reindex model"
5
- task reindex: :environment do
6
- if ENV["CLASS"]
7
- klass = ENV["CLASS"].constantize rescue nil
8
- if klass
9
- klass.reindex
10
- else
11
- abort "Could not find class: #{ENV['CLASS']}"
12
- end
13
- else
14
- abort "USAGE: rake searchkick:reindex CLASS=Product"
15
- end
16
- end
17
-
18
- if defined?(Rails)
19
-
20
- namespace :reindex do
21
- desc "reindex all models"
22
- task all: :environment do
23
- Rails.application.eager_load!
24
- Searchkick.models.each do |model|
25
- puts "Reindexing #{model.name}..."
26
- model.reindex
27
- end
28
- puts "Reindex complete"
29
- end
30
- end
31
-
32
- end
33
- end
data/searchkick.gemspec DELETED
@@ -1,28 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path("../lib", __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "searchkick/version"
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "searchkick"
8
- spec.version = Searchkick::VERSION
9
- spec.authors = ["Andrew Kane"]
10
- spec.email = ["andrew@chartkick.com"]
11
- spec.description = "Intelligent search made easy"
12
- spec.summary = "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."
13
- spec.homepage = "https://github.com/ankane/searchkick"
14
- spec.license = "MIT"
15
-
16
- spec.files = `git ls-files`.split($/)
17
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features|benchmark)/})
19
- spec.require_paths = ["lib"]
20
-
21
- spec.add_dependency "activemodel", ">= 4.1"
22
- spec.add_dependency "elasticsearch", ">= 1"
23
- spec.add_dependency "hashie"
24
-
25
- spec.add_development_dependency "bundler"
26
- spec.add_development_dependency "rake"
27
- spec.add_development_dependency "minitest"
28
- end
data/test/aggs_test.rb DELETED
@@ -1,197 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class AggsTest < Minitest::Test
4
- def setup
5
- super
6
- store [
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
- {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, 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
- ]
12
- end
13
-
14
- def test_basic
15
- assert_equal ({1 => 1, 2 => 2}), store_agg(aggs: [:store_id])
16
- end
17
-
18
- def test_where
19
- assert_equal ({1 => 1}), store_agg(aggs: {store_id: {where: {in_stock: true}}})
20
- end
21
-
22
- def test_order
23
- agg = Product.search("Product", aggs: {color: {order: {"_term" => "desc"}}}).aggs["color"]
24
- assert_equal %w(red green blue), agg["buckets"].map { |b| b["key"] }
25
- end
26
-
27
- def test_field
28
- assert_equal ({1 => 1, 2 => 2}), store_agg(aggs: {store_id: {}})
29
- assert_equal ({1 => 1, 2 => 2}), store_agg(aggs: {store_id: {field: "store_id"}})
30
- assert_equal ({1 => 1, 2 => 2}), store_agg({aggs: {store_id_new: {field: "store_id"}}}, "store_id_new")
31
- end
32
-
33
- def test_min_doc_count
34
- assert_equal ({2 => 2}), store_agg(aggs: {store_id: {min_doc_count: 2}})
35
- end
36
-
37
- def test_no_aggs
38
- assert_nil Product.search("*").aggs
39
- end
40
-
41
- def test_limit
42
- agg = Product.search("Product", aggs: {store_id: {limit: 1}}).aggs["store_id"]
43
- assert_equal 1, agg["buckets"].size
44
- # assert_equal 3, agg["doc_count"]
45
- assert_equal(1, agg["sum_other_doc_count"])
46
- end
47
-
48
- def test_ranges
49
- price_ranges = [{to: 10}, {from: 10, to: 20}, {from: 20}]
50
- agg = Product.search("Product", aggs: {price: {ranges: price_ranges}}).aggs["price"]
51
-
52
- assert_equal 3, agg["buckets"].size
53
- assert_equal 10.0, agg["buckets"][0]["to"]
54
- assert_equal 20.0, agg["buckets"][2]["from"]
55
- assert_equal 1, agg["buckets"][0]["doc_count"]
56
- assert_equal 0, agg["buckets"][1]["doc_count"]
57
- assert_equal 2, agg["buckets"][2]["doc_count"]
58
- end
59
-
60
- def test_date_ranges
61
- ranges = [{to: 1.day.ago}, {from: 1.day.ago, to: 1.day.from_now}, {from: 1.day.from_now}]
62
- agg = Product.search("Product", aggs: {created_at: {date_ranges: ranges}}).aggs["created_at"]
63
-
64
- assert_equal 1, agg["buckets"][0]["doc_count"]
65
- assert_equal 1, agg["buckets"][1]["doc_count"]
66
- assert_equal 1, agg["buckets"][2]["doc_count"]
67
- end
68
-
69
- def test_query_where
70
- assert_equal ({1 => 1}), store_agg(where: {in_stock: true}, aggs: [:store_id])
71
- end
72
-
73
- def test_two_wheres
74
- assert_equal ({2 => 1}), store_agg(where: {color: "red"}, aggs: {store_id: {where: {in_stock: false}}})
75
- end
76
-
77
- def test_where_override
78
- assert_equal ({}), store_agg(where: {color: "red"}, aggs: {store_id: {where: {in_stock: false, color: "blue"}}})
79
- assert_equal ({2 => 1}), store_agg(where: {color: "blue"}, aggs: {store_id: {where: {in_stock: false, color: "red"}}})
80
- end
81
-
82
- def test_skip
83
- assert_equal ({1 => 1, 2 => 2}), store_agg(where: {store_id: 2}, aggs: [:store_id])
84
- end
85
-
86
- def test_skip_complex
87
- assert_equal ({1 => 1, 2 => 1}), store_agg(where: {store_id: 2, price: {gt: 5}}, aggs: [:store_id])
88
- end
89
-
90
- def test_multiple
91
- assert_equal ({"store_id" => {1 => 1, 2 => 2}, "color" => {"blue" => 1, "green" => 1, "red" => 1}}), store_multiple_aggs(aggs: [:store_id, :color])
92
- end
93
-
94
- def test_smart_aggs_false
95
- assert_equal ({2 => 2}), store_agg(where: {color: "red"}, aggs: {store_id: {where: {in_stock: false}}}, smart_aggs: false)
96
- assert_equal ({2 => 2}), store_agg(where: {color: "blue"}, aggs: {store_id: {where: {in_stock: false}}}, smart_aggs: false)
97
- end
98
-
99
- def test_aggs_group_by_date
100
- store [{name: "Old Product", created_at: 3.years.ago}]
101
- products =
102
- Product.search("Product", {
103
- where: {
104
- created_at: {lt: Time.now}
105
- },
106
- aggs: {
107
- products_per_year: {
108
- date_histogram: {
109
- field: :created_at,
110
- interval: :year
111
- }
112
- }
113
- }
114
- })
115
-
116
- assert_equal 4, products.aggs["products_per_year"]["buckets"].size
117
- end
118
-
119
- def test_aggs_avg
120
- products =
121
- Product.search("*", {
122
- aggs: {
123
- avg_price: {
124
- avg: {
125
- field: :price
126
- }
127
- }
128
- }
129
- })
130
- assert_equal 16.5, products.aggs["avg_price"]["value"]
131
- end
132
-
133
- def test_aggs_cardinality
134
- products =
135
- Product.search("*", {
136
- aggs: {
137
- total_stores: {
138
- cardinality: {
139
- field: :store_id
140
- }
141
- }
142
- }
143
- })
144
- assert_equal 3, products.aggs["total_stores"]["value"]
145
- end
146
-
147
- def test_aggs_min_max
148
- products =
149
- Product.search("*", {
150
- aggs: {
151
- min_price: {
152
- min: {
153
- field: :price
154
- }
155
- },
156
- max_price: {
157
- max: {
158
- field: :price
159
- }
160
- }
161
- }
162
- })
163
- assert_equal 5, products.aggs["min_price"]["value"]
164
- assert_equal 25, products.aggs["max_price"]["value"]
165
- end
166
-
167
- def test_aggs_sum
168
- products =
169
- Product.search("*", {
170
- aggs: {
171
- sum_price: {
172
- sum: {
173
- field: :price
174
- }
175
- }
176
- }
177
- })
178
- assert_equal 66, products.aggs["sum_price"]["value"]
179
- end
180
-
181
- protected
182
-
183
- def buckets_as_hash(agg)
184
- Hash[agg["buckets"].map { |v| [v["key"], v["doc_count"]] }]
185
- end
186
-
187
- def store_agg(options, agg_key = "store_id")
188
- buckets = Product.search("Product", options).aggs[agg_key]
189
- buckets_as_hash(buckets)
190
- end
191
-
192
- def store_multiple_aggs(options)
193
- Hash[Product.search("Product", options).aggs.map do |field, filtered_agg|
194
- [field, buckets_as_hash(filtered_agg)]
195
- end]
196
- end
197
- end
@@ -1,75 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class AutocompleteTest < Minitest::Test
4
- def test_autocomplete
5
- store_names ["Hummus"]
6
- assert_search "hum", ["Hummus"], match: :text_start
7
- end
8
-
9
- def test_autocomplete_two_words
10
- store_names ["Organic Hummus"]
11
- assert_search "hum", [], match: :text_start
12
- end
13
-
14
- def test_autocomplete_fields
15
- store_names ["Hummus"]
16
- assert_search "hum", ["Hummus"], match: :text_start, fields: [:name]
17
- end
18
-
19
- def test_text_start
20
- store_names ["Where in the World is Carmen San Diego"]
21
- assert_search "where in the world is", ["Where in the World is Carmen San Diego"], fields: [{name: :text_start}]
22
- assert_search "in the world", [], fields: [{name: :text_start}]
23
- end
24
-
25
- def test_text_middle
26
- store_names ["Where in the World is Carmen San Diego"]
27
- assert_search "where in the world is", ["Where in the World is Carmen San Diego"], fields: [{name: :text_middle}]
28
- assert_search "n the wor", ["Where in the World is Carmen San Diego"], fields: [{name: :text_middle}]
29
- assert_search "men san diego", ["Where in the World is Carmen San Diego"], fields: [{name: :text_middle}]
30
- assert_search "world carmen", [], fields: [{name: :text_middle}]
31
- end
32
-
33
- def test_text_end
34
- store_names ["Where in the World is Carmen San Diego"]
35
- assert_search "men san diego", ["Where in the World is Carmen San Diego"], fields: [{name: :text_end}]
36
- assert_search "carmen san", [], fields: [{name: :text_end}]
37
- end
38
-
39
- def test_word_start
40
- store_names ["Where in the World is Carmen San Diego"]
41
- assert_search "car san wor", ["Where in the World is Carmen San Diego"], fields: [{name: :word_start}]
42
- end
43
-
44
- def test_word_middle
45
- store_names ["Where in the World is Carmen San Diego"]
46
- assert_search "orl", ["Where in the World is Carmen San Diego"], fields: [{name: :word_middle}]
47
- end
48
-
49
- def test_word_end
50
- store_names ["Where in the World is Carmen San Diego"]
51
- assert_search "rld men ego", ["Where in the World is Carmen San Diego"], fields: [{name: :word_end}]
52
- end
53
-
54
- def test_word_start_multiple_words
55
- store_names ["Dark Grey", "Dark Blue"]
56
- assert_search "dark grey", ["Dark Grey"], fields: [{name: :word_start}]
57
- end
58
-
59
- def test_word_start_exact
60
- store_names ["Back Scratcher", "Backpack"]
61
- assert_order "back", ["Back Scratcher", "Backpack"], fields: [{name: :word_start}]
62
- end
63
-
64
- def test_word_start_exact_martin
65
- store_names ["Martina", "Martin"]
66
- assert_order "martin", ["Martin", "Martina"], fields: [{name: :word_start}]
67
- end
68
-
69
- # TODO find a better place
70
-
71
- def test_exact
72
- store_names ["hi@example.org"]
73
- assert_search "hi@example.org", ["hi@example.org"], fields: [{name: :exact}]
74
- end
75
- end
data/test/boost_test.rb DELETED
@@ -1,202 +0,0 @@
1
- require_relative "test_helper"
2
-
3
- class BoostTest < Minitest::Test
4
- # conversions
5
-
6
- def test_conversions
7
- store [
8
- {name: "Tomato A", conversions: {"tomato" => 1}},
9
- {name: "Tomato B", conversions: {"tomato" => 2}},
10
- {name: "Tomato C", conversions: {"tomato" => 3}}
11
- ]
12
- assert_order "tomato", ["Tomato C", "Tomato B", "Tomato A"]
13
- assert_equal_scores "tomato", conversions: false
14
- end
15
-
16
- def test_multiple_conversions
17
- store [
18
- {name: "Speaker A", conversions_a: {"speaker" => 1}, conversions_b: {"speaker" => 6}},
19
- {name: "Speaker B", conversions_a: {"speaker" => 2}, conversions_b: {"speaker" => 5}},
20
- {name: "Speaker C", conversions_a: {"speaker" => 3}, conversions_b: {"speaker" => 4}}
21
- ], Speaker
22
-
23
- assert_equal_scores "speaker", {conversions: false}, Speaker
24
- assert_equal_scores "speaker", {}, Speaker
25
- assert_equal_scores "speaker", {conversions: ["conversions_a", "conversions_b"]}, Speaker
26
- assert_equal_scores "speaker", {conversions: ["conversions_b", "conversions_a"]}, Speaker
27
- assert_order "speaker", ["Speaker C", "Speaker B", "Speaker A"], {conversions: "conversions_a"}, Speaker
28
- assert_order "speaker", ["Speaker A", "Speaker B", "Speaker C"], {conversions: "conversions_b"}, Speaker
29
- end
30
-
31
- def test_multiple_conversions_with_boost_term
32
- store [
33
- {name: "Speaker A", conversions_a: {"speaker" => 4, "speaker_1" => 1}},
34
- {name: "Speaker B", conversions_a: {"speaker" => 3, "speaker_1" => 2}},
35
- {name: "Speaker C", conversions_a: {"speaker" => 2, "speaker_1" => 3}},
36
- {name: "Speaker D", conversions_a: {"speaker" => 1, "speaker_1" => 4}}
37
- ], Speaker
38
-
39
- assert_order "speaker", ["Speaker A", "Speaker B", "Speaker C", "Speaker D"], {conversions: "conversions_a"}, Speaker
40
- assert_order "speaker", ["Speaker D", "Speaker C", "Speaker B", "Speaker A"], {conversions: "conversions_a", conversions_term: "speaker_1"}, Speaker
41
- end
42
-
43
- def test_conversions_stemmed
44
- store [
45
- {name: "Tomato A", conversions: {"tomato" => 1, "tomatos" => 1, "Tomatoes" => 1}},
46
- {name: "Tomato B", conversions: {"tomato" => 2}}
47
- ]
48
- assert_order "tomato", ["Tomato A", "Tomato B"]
49
- end
50
-
51
- # global boost
52
-
53
- def test_boost
54
- store [
55
- {name: "Tomato A"},
56
- {name: "Tomato B", orders_count: 10},
57
- {name: "Tomato C", orders_count: 100}
58
- ]
59
- assert_order "tomato", ["Tomato C", "Tomato B", "Tomato A"], boost: "orders_count"
60
- end
61
-
62
- def test_boost_zero
63
- store [
64
- {name: "Zero Boost", orders_count: 0}
65
- ]
66
- assert_order "zero", ["Zero Boost"], boost: "orders_count"
67
- end
68
-
69
- def test_conversions_weight
70
- store [
71
- {name: "Product Boost", orders_count: 20},
72
- {name: "Product Conversions", conversions: {"product" => 10}}
73
- ]
74
- assert_order "product", ["Product Conversions", "Product Boost"], boost: "orders_count"
75
- end
76
-
77
- def test_boost_fields
78
- store [
79
- {name: "Red", color: "White"},
80
- {name: "White", color: "Red Red Red"}
81
- ]
82
- assert_order "red", ["Red", "White"], fields: ["name^10", "color"]
83
- end
84
-
85
- def test_boost_fields_decimal
86
- store [
87
- {name: "Red", color: "White"},
88
- {name: "White", color: "Red Red Red"}
89
- ]
90
- assert_order "red", ["Red", "White"], fields: ["name^10.5", "color"]
91
- end
92
-
93
- def test_boost_fields_word_start
94
- store [
95
- {name: "Red", color: "White"},
96
- {name: "White", color: "Red Red Red"}
97
- ]
98
- assert_order "red", ["Red", "White"], fields: [{"name^10" => :word_start}, "color"]
99
- end
100
-
101
- # for issue #855
102
- def test_apostrophes
103
- store_names ["Valentine's Day Special"]
104
- assert_search "Valentines", ["Valentine's Day Special"], fields: ["name^5"]
105
- assert_search "Valentine's", ["Valentine's Day Special"], fields: ["name^5"]
106
- assert_search "Valentine", ["Valentine's Day Special"], fields: ["name^5"]
107
- end
108
-
109
- def test_boost_by
110
- store [
111
- {name: "Tomato A"},
112
- {name: "Tomato B", orders_count: 10},
113
- {name: "Tomato C", orders_count: 100}
114
- ]
115
- assert_order "tomato", ["Tomato C", "Tomato B", "Tomato A"], boost_by: [:orders_count]
116
- assert_order "tomato", ["Tomato C", "Tomato B", "Tomato A"], boost_by: {orders_count: {factor: 10}}
117
- end
118
-
119
- def test_boost_by_missing
120
- store [
121
- {name: "Tomato A"},
122
- {name: "Tomato B", orders_count: 10},
123
- ]
124
-
125
- if elasticsearch_below50?
126
- assert_raises(ArgumentError) do
127
- assert_order "tomato", ["Tomato A", "Tomato B"], boost_by: {orders_count: {missing: 100}}
128
- end
129
- else
130
- assert_order "tomato", ["Tomato A", "Tomato B"], boost_by: {orders_count: {missing: 100}}
131
- end
132
- end
133
-
134
- def test_boost_by_boost_mode_multiply
135
- store [
136
- {name: "Tomato A", found_rate: 0.9},
137
- {name: "Tomato B"},
138
- {name: "Tomato C", found_rate: 0.5}
139
- ]
140
-
141
- assert_order "tomato", ["Tomato B", "Tomato A", "Tomato C"], boost_by: {found_rate: {boost_mode: "multiply"}}
142
- end
143
-
144
- def test_boost_where
145
- store [
146
- {name: "Tomato A"},
147
- {name: "Tomato B", user_ids: [1, 2]},
148
- {name: "Tomato C", user_ids: [3]}
149
- ]
150
- assert_first "tomato", "Tomato B", boost_where: {user_ids: 2}
151
- assert_first "tomato", "Tomato B", boost_where: {user_ids: 1..2}
152
- assert_first "tomato", "Tomato B", boost_where: {user_ids: [1, 4]}
153
- assert_first "tomato", "Tomato B", boost_where: {user_ids: {value: 2, factor: 10}}
154
- assert_first "tomato", "Tomato B", boost_where: {user_ids: {value: [1, 4], factor: 10}}
155
- assert_order "tomato", ["Tomato C", "Tomato B", "Tomato A"], boost_where: {user_ids: [{value: 1, factor: 10}, {value: 3, factor: 20}]}
156
- end
157
-
158
- def test_boost_by_distance
159
- store [
160
- {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
161
- {name: "San Antonio", latitude: 29.4167, longitude: -98.5000},
162
- {name: "San Marino", latitude: 43.9333, longitude: 12.4667}
163
- ]
164
- assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by_distance: {field: :location, origin: [37, -122], scale: "1000mi"}
165
- end
166
-
167
- def test_boost_by_distance_hash
168
- store [
169
- {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
170
- {name: "San Antonio", latitude: 29.4167, longitude: -98.5000},
171
- {name: "San Marino", latitude: 43.9333, longitude: 12.4667}
172
- ]
173
- assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by_distance: {field: :location, origin: {lat: 37, lon: -122}, scale: "1000mi"}
174
- end
175
-
176
- def test_boost_by_distance_v2
177
- store [
178
- {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
179
- {name: "San Antonio", latitude: 29.4167, longitude: -98.5000},
180
- {name: "San Marino", latitude: 43.9333, longitude: 12.4667}
181
- ]
182
- assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by_distance: {location: {origin: [37, -122], scale: "1000mi"}}
183
- end
184
-
185
- def test_boost_by_distance_v2_hash
186
- store [
187
- {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
188
- {name: "San Antonio", latitude: 29.4167, longitude: -98.5000},
189
- {name: "San Marino", latitude: 43.9333, longitude: 12.4667}
190
- ]
191
- assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by_distance: {location: {origin: {lat: 37, lon: -122}, scale: "1000mi"}}
192
- end
193
-
194
- def test_boost_by_indices
195
- skip if cequel?
196
-
197
- store_names ["Rex"], Animal
198
- store_names ["Rexx"], Product
199
-
200
- assert_order "Rex", ["Rexx", "Rex"], {index_name: [Animal, Product], indices_boost: {Animal => 1, Product => 200}, fields: [:name]}, Store
201
- end
202
- end