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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +251 -84
- data/LICENSE.txt +1 -1
- data/README.md +552 -432
- data/lib/searchkick/bulk_indexer.rb +173 -0
- data/lib/searchkick/bulk_reindex_job.rb +2 -2
- data/lib/searchkick/hash_wrapper.rb +12 -0
- data/lib/searchkick/index.rb +187 -348
- data/lib/searchkick/index_options.rb +494 -282
- data/lib/searchkick/logging.rb +17 -13
- data/lib/searchkick/model.rb +52 -97
- data/lib/searchkick/multi_search.rb +9 -10
- data/lib/searchkick/process_batch_job.rb +17 -4
- data/lib/searchkick/process_queue_job.rb +20 -12
- data/lib/searchkick/query.rb +415 -199
- data/lib/searchkick/railtie.rb +7 -0
- data/lib/searchkick/record_data.rb +128 -0
- data/lib/searchkick/record_indexer.rb +79 -0
- data/lib/searchkick/reindex_queue.rb +1 -1
- data/lib/searchkick/reindex_v2_job.rb +14 -12
- data/lib/searchkick/results.rb +135 -41
- data/lib/searchkick/version.rb +1 -1
- data/lib/searchkick.rb +130 -61
- data/lib/tasks/searchkick.rake +34 -0
- metadata +18 -162
- data/.gitignore +0 -22
- data/.travis.yml +0 -39
- data/Gemfile +0 -16
- data/Rakefile +0 -20
- data/benchmark/Gemfile +0 -23
- data/benchmark/benchmark.rb +0 -97
- data/lib/searchkick/tasks.rb +0 -33
- data/searchkick.gemspec +0 -28
- data/test/aggs_test.rb +0 -197
- data/test/autocomplete_test.rb +0 -75
- data/test/boost_test.rb +0 -202
- data/test/callbacks_test.rb +0 -59
- data/test/ci/before_install.sh +0 -17
- data/test/errors_test.rb +0 -19
- data/test/gemfiles/activerecord31.gemfile +0 -7
- data/test/gemfiles/activerecord32.gemfile +0 -7
- data/test/gemfiles/activerecord40.gemfile +0 -8
- data/test/gemfiles/activerecord41.gemfile +0 -8
- data/test/gemfiles/activerecord42.gemfile +0 -7
- data/test/gemfiles/activerecord50.gemfile +0 -7
- data/test/gemfiles/apartment.gemfile +0 -8
- data/test/gemfiles/cequel.gemfile +0 -8
- data/test/gemfiles/mongoid2.gemfile +0 -7
- data/test/gemfiles/mongoid3.gemfile +0 -6
- data/test/gemfiles/mongoid4.gemfile +0 -7
- data/test/gemfiles/mongoid5.gemfile +0 -7
- data/test/gemfiles/mongoid6.gemfile +0 -12
- data/test/gemfiles/nobrainer.gemfile +0 -8
- data/test/gemfiles/parallel_tests.gemfile +0 -8
- data/test/geo_shape_test.rb +0 -175
- data/test/highlight_test.rb +0 -78
- data/test/index_test.rb +0 -166
- data/test/inheritance_test.rb +0 -83
- data/test/marshal_test.rb +0 -8
- data/test/match_test.rb +0 -276
- data/test/misspellings_test.rb +0 -56
- data/test/model_test.rb +0 -42
- data/test/multi_search_test.rb +0 -36
- data/test/multi_tenancy_test.rb +0 -22
- data/test/order_test.rb +0 -46
- data/test/pagination_test.rb +0 -70
- data/test/partial_reindex_test.rb +0 -58
- data/test/query_test.rb +0 -35
- data/test/records_test.rb +0 -10
- data/test/reindex_test.rb +0 -64
- data/test/reindex_v2_job_test.rb +0 -32
- data/test/routing_test.rb +0 -23
- data/test/should_index_test.rb +0 -32
- data/test/similar_test.rb +0 -28
- data/test/sql_test.rb +0 -214
- data/test/suggest_test.rb +0 -95
- data/test/support/kaminari.yml +0 -21
- data/test/synonyms_test.rb +0 -67
- data/test/test_helper.rb +0 -567
- 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"
|
data/benchmark/benchmark.rb
DELETED
@@ -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
|
data/lib/searchkick/tasks.rb
DELETED
@@ -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
|
data/test/autocomplete_test.rb
DELETED
@@ -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
|