searchkick 2.0.0 → 2.0.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 +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +5 -0
- data/README.md +21 -15
- data/Rakefile +4 -0
- data/benchmark/Gemfile +19 -0
- data/benchmark/benchmark.rb +63 -0
- data/lib/searchkick/index.rb +29 -20
- data/lib/searchkick/index_options.rb +2 -18
- data/lib/searchkick/results.rb +31 -16
- data/lib/searchkick/version.rb +1 -1
- data/searchkick.gemspec +1 -1
- data/test/aggs_test.rb +16 -13
- data/test/highlight_test.rb +17 -12
- 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: 17c7f39c1470d38bc637340ae0031997a0b0134c
|
4
|
+
data.tar.gz: 0167c2d1448536bf5b2b48120f56e992c22aed8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a6bf61245813c31fc922a29c5aa4998df13c9c1f51eba6c248ea1bfbba435f048de37a069d23cad6fc041618a235974895cb7466c08ee24cb14eb39296fc908d
|
7
|
+
data.tar.gz: b50909d603658acd1c9562470c2fd1de404cffd2f93a22c1ca926003afaaabcf33ea70a14ba69d96e3b94b50af241b91cbd267492c079416e2b9ae500c6cf32e
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -254,7 +254,7 @@ Available options are:
|
|
254
254
|
### Exact Matches
|
255
255
|
|
256
256
|
```ruby
|
257
|
-
User.search
|
257
|
+
User.search query, fields: [{email: :exact}, :name]
|
258
258
|
```
|
259
259
|
|
260
260
|
### Phrase Matches
|
@@ -431,7 +431,7 @@ Product.reindex(resume: true)
|
|
431
431
|
|
432
432
|
#### No need to reindex
|
433
433
|
|
434
|
-
-
|
434
|
+
- app starts
|
435
435
|
|
436
436
|
### Stay Synced
|
437
437
|
|
@@ -784,8 +784,8 @@ bands = Band.search "cinema", fields: [:name], highlight: true
|
|
784
784
|
View the highlighted fields with:
|
785
785
|
|
786
786
|
```ruby
|
787
|
-
bands.
|
788
|
-
|
787
|
+
bands.each do |band|
|
788
|
+
band.search_highlights[:name] # "Two Door <em>Cinema</em> Club"
|
789
789
|
end
|
790
790
|
```
|
791
791
|
|
@@ -1013,7 +1013,7 @@ heroku run rake searchkick:reindex CLASS=Product
|
|
1013
1013
|
Include `elasticsearch 1.0.15` or greater in your Gemfile.
|
1014
1014
|
|
1015
1015
|
```ruby
|
1016
|
-
gem
|
1016
|
+
gem 'elasticsearch', '>= 1.0.15'
|
1017
1017
|
```
|
1018
1018
|
|
1019
1019
|
Create an initializer `config/initializers/elasticsearch.rb` with:
|
@@ -1088,15 +1088,23 @@ See [Production Rails](https://github.com/ankane/production_rails) for other goo
|
|
1088
1088
|
|
1089
1089
|
## Performance
|
1090
1090
|
|
1091
|
+
### JSON Generation
|
1092
|
+
|
1093
|
+
Significantly increase performance with faster JSON generation. Add [Oj](https://github.com/ohler55/oj) to your Gemfile.
|
1094
|
+
|
1095
|
+
```ruby
|
1096
|
+
gem 'oj'
|
1097
|
+
```
|
1098
|
+
|
1091
1099
|
### Persistent HTTP Connections
|
1092
1100
|
|
1093
|
-
|
1101
|
+
Significantly increase performance with persistent HTTP connections. Add [Typhoeus](https://github.com/typhoeus/typhoeus) to your Gemfile.
|
1094
1102
|
|
1095
1103
|
```ruby
|
1096
1104
|
gem 'typhoeus'
|
1097
1105
|
```
|
1098
1106
|
|
1099
|
-
|
1107
|
+
To reduce log noise, create an initializer with:
|
1100
1108
|
|
1101
1109
|
```ruby
|
1102
1110
|
Ethon.logger = Logger.new("/dev/null")
|
@@ -1126,7 +1134,7 @@ end
|
|
1126
1134
|
|
1127
1135
|
### Routing
|
1128
1136
|
|
1129
|
-
Searchkick supports [Elasticsearch’s routing feature](https://www.elastic.co/blog/customizing-your-document-routing).
|
1137
|
+
Searchkick supports [Elasticsearch’s routing feature](https://www.elastic.co/blog/customizing-your-document-routing), which can significantly speed up searches.
|
1130
1138
|
|
1131
1139
|
```ruby
|
1132
1140
|
class Business < ActiveRecord::Base
|
@@ -1245,24 +1253,22 @@ User.search "san", fields: ["address.city"], where: {"address.zip_code" => 12345
|
|
1245
1253
|
Reindex one record
|
1246
1254
|
|
1247
1255
|
```ruby
|
1248
|
-
product = Product.find
|
1256
|
+
product = Product.find(1)
|
1249
1257
|
product.reindex
|
1250
1258
|
# or to reindex in the background
|
1251
1259
|
product.reindex_async
|
1252
1260
|
```
|
1253
1261
|
|
1254
|
-
Reindex
|
1262
|
+
Reindex multiple records
|
1255
1263
|
|
1256
1264
|
```ruby
|
1257
|
-
|
1265
|
+
Product.where(store_id: 1).reindex
|
1258
1266
|
```
|
1259
1267
|
|
1260
|
-
Reindex
|
1268
|
+
Reindex associations
|
1261
1269
|
|
1262
1270
|
```ruby
|
1263
|
-
|
1264
|
-
Product.searchkick_index.import(batch)
|
1265
|
-
end
|
1271
|
+
store.products.reindex
|
1266
1272
|
```
|
1267
1273
|
|
1268
1274
|
Reindex a subset of attributes (partial reindex)
|
data/Rakefile
CHANGED
data/benchmark/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in searchkick.gemspec
|
4
|
+
gemspec path: "../"
|
5
|
+
|
6
|
+
gem "sqlite3"
|
7
|
+
gem "activerecord", "~> 5.0.0"
|
8
|
+
gem "activerecord-import"
|
9
|
+
|
10
|
+
# performance
|
11
|
+
gem "typhoeus"
|
12
|
+
gem "oj"
|
13
|
+
|
14
|
+
# profiling
|
15
|
+
gem "ruby-prof"
|
16
|
+
gem "allocation_stats"
|
17
|
+
gem "get_process_mem"
|
18
|
+
gem "memory_profiler"
|
19
|
+
gem "allocation_tracer"
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
Bundler.require(:default)
|
3
|
+
require "active_record"
|
4
|
+
require "benchmark"
|
5
|
+
|
6
|
+
ActiveRecord::Base.default_timezone = :utc
|
7
|
+
ActiveRecord::Base.time_zone_aware_attributes = true
|
8
|
+
ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
|
9
|
+
|
10
|
+
ActiveRecord::Migration.create_table :products do |t|
|
11
|
+
t.string :name
|
12
|
+
t.string :color
|
13
|
+
t.integer :store_id
|
14
|
+
end
|
15
|
+
|
16
|
+
class Product < ActiveRecord::Base
|
17
|
+
searchkick batch_size: 100
|
18
|
+
|
19
|
+
def search_data
|
20
|
+
{
|
21
|
+
name: name,
|
22
|
+
color: color,
|
23
|
+
store_id: store_id
|
24
|
+
}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Product.import ["name", "color", "store_id"], 20000.times.map { |i| ["Product #{i}", ["red", "blue"].sample, rand(10)] }
|
29
|
+
|
30
|
+
puts "Imported"
|
31
|
+
|
32
|
+
result = nil
|
33
|
+
report = nil
|
34
|
+
stats = nil
|
35
|
+
|
36
|
+
# p GetProcessMem.new.mb
|
37
|
+
|
38
|
+
time =
|
39
|
+
Benchmark.realtime do
|
40
|
+
# result = RubyProf.profile do
|
41
|
+
# report = MemoryProfiler.report do
|
42
|
+
# stats = AllocationStats.trace do
|
43
|
+
Product.reindex
|
44
|
+
# end
|
45
|
+
end
|
46
|
+
|
47
|
+
# p GetProcessMem.new.mb
|
48
|
+
|
49
|
+
puts time.round(1)
|
50
|
+
puts Product.searchkick_index.total_docs
|
51
|
+
|
52
|
+
if result
|
53
|
+
printer = RubyProf::GraphPrinter.new(result)
|
54
|
+
printer.print(STDOUT, min_percent: 5)
|
55
|
+
end
|
56
|
+
|
57
|
+
if report
|
58
|
+
puts report.pretty_print
|
59
|
+
end
|
60
|
+
|
61
|
+
if stats
|
62
|
+
puts result.allocations(alias_paths: true).group_by(:sourcefile, :class).to_text
|
63
|
+
end
|
data/lib/searchkick/index.rb
CHANGED
@@ -7,6 +7,7 @@ module Searchkick
|
|
7
7
|
def initialize(name, options = {})
|
8
8
|
@name = name
|
9
9
|
@options = options
|
10
|
+
@klass_document_type = {} # cache
|
10
11
|
end
|
11
12
|
|
12
13
|
def create(body = {})
|
@@ -270,10 +271,12 @@ module Searchkick
|
|
270
271
|
end
|
271
272
|
|
272
273
|
def klass_document_type(klass)
|
273
|
-
|
274
|
-
klass.document_type
|
275
|
-
|
276
|
-
|
274
|
+
@klass_document_type[klass] ||= begin
|
275
|
+
if klass.respond_to?(:document_type)
|
276
|
+
klass.document_type
|
277
|
+
else
|
278
|
+
klass.model_name.to_s.underscore
|
279
|
+
end
|
277
280
|
end
|
278
281
|
end
|
279
282
|
|
@@ -296,42 +299,48 @@ module Searchkick
|
|
296
299
|
id.is_a?(Numeric) ? id : id.to_s
|
297
300
|
end
|
298
301
|
|
302
|
+
EXCLUDED_ATTRIBUTES = ["_id", "_type"]
|
303
|
+
|
299
304
|
def search_data(record, method_name = nil)
|
300
305
|
partial_reindex = !method_name.nil?
|
301
|
-
source = record.send(method_name || :search_data)
|
302
306
|
options = record.class.searchkick_options
|
303
307
|
|
304
|
-
# stringify fields
|
305
308
|
# remove _id since search_id is used instead
|
306
|
-
source =
|
309
|
+
source = record.send(method_name || :search_data).each_with_object({}) { |(k, v), memo| memo[k.to_s] = v; memo }.except(*EXCLUDED_ATTRIBUTES)
|
307
310
|
|
308
311
|
# conversions
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
+
if options[:conversions]
|
313
|
+
Array(options[:conversions]).map(&:to_s).each do |conversions_field|
|
314
|
+
if source[conversions_field]
|
315
|
+
source[conversions_field] = source[conversions_field].map { |k, v| {query: k, count: v} }
|
316
|
+
end
|
312
317
|
end
|
313
318
|
end
|
314
319
|
|
315
320
|
# hack to prevent generator field doesn't exist error
|
316
|
-
|
317
|
-
|
321
|
+
if options[:suggest]
|
322
|
+
options[:suggest].map(&:to_s).each do |field|
|
323
|
+
source[field] = nil if !source[field] && !partial_reindex
|
324
|
+
end
|
318
325
|
end
|
319
326
|
|
320
327
|
# locations
|
321
|
-
|
322
|
-
|
323
|
-
if
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
+
if options[:locations]
|
329
|
+
options[:locations].map(&:to_s).each do |field|
|
330
|
+
if source[field]
|
331
|
+
if !source[field].is_a?(Hash) && (source[field].first.is_a?(Array) || source[field].first.is_a?(Hash))
|
332
|
+
# multiple locations
|
333
|
+
source[field] = source[field].map { |a| location_value(a) }
|
334
|
+
else
|
335
|
+
source[field] = location_value(source[field])
|
336
|
+
end
|
328
337
|
end
|
329
338
|
end
|
330
339
|
end
|
331
340
|
|
332
341
|
cast_big_decimal(source)
|
333
342
|
|
334
|
-
source
|
343
|
+
source
|
335
344
|
end
|
336
345
|
|
337
346
|
def location_value(value)
|
@@ -252,15 +252,7 @@ module Searchkick
|
|
252
252
|
end
|
253
253
|
end
|
254
254
|
|
255
|
-
mapping[field] =
|
256
|
-
if below50
|
257
|
-
{
|
258
|
-
type: "multi_field",
|
259
|
-
fields: fields
|
260
|
-
}
|
261
|
-
elsif fields[field]
|
262
|
-
fields[field].merge(fields: fields.except(field))
|
263
|
-
end
|
255
|
+
mapping[field] = fields[field].merge(fields: fields.except(field))
|
264
256
|
end
|
265
257
|
|
266
258
|
(options[:locations] || []).map(&:to_s).each do |field|
|
@@ -307,15 +299,7 @@ module Searchkick
|
|
307
299
|
end
|
308
300
|
|
309
301
|
# http://www.elasticsearch.org/guide/reference/mapping/multi-field-type/
|
310
|
-
multi_field =
|
311
|
-
if below50
|
312
|
-
{
|
313
|
-
type: "multi_field",
|
314
|
-
fields: dynamic_fields
|
315
|
-
}
|
316
|
-
else
|
317
|
-
dynamic_fields["{name}"].merge(fields: dynamic_fields.except("{name}"))
|
318
|
-
end
|
302
|
+
multi_field = dynamic_fields["{name}"].merge(fields: dynamic_fields.except("{name}"))
|
319
303
|
|
320
304
|
all_enabled = !options[:searchable] || options[:searchable].to_a.include?("_all")
|
321
305
|
|
data/lib/searchkick/results.rb
CHANGED
@@ -32,7 +32,22 @@ module Searchkick
|
|
32
32
|
|
33
33
|
# sort
|
34
34
|
hits.map do |hit|
|
35
|
-
results[hit["_type"]][hit["_id"].to_s]
|
35
|
+
result = results[hit["_type"]][hit["_id"].to_s]
|
36
|
+
if result
|
37
|
+
unless result.respond_to?(:search_hit)
|
38
|
+
result.define_singleton_method(:search_hit) do
|
39
|
+
hit
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
if hit["highlight"] && !result.respond_to?(:search_highlights)
|
44
|
+
highlights = Hash[hit["highlight"].map { |k, v| [(options[:json] ? k : k.sub(/\.#{@options[:match_suffix]}\z/, "")).to_sym, v.first] }]
|
45
|
+
result.define_singleton_method(:search_highlights) do
|
46
|
+
highlights
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
result
|
36
51
|
end.compact
|
37
52
|
else
|
38
53
|
hits.map do |hit|
|
@@ -187,21 +202,21 @@ module Searchkick
|
|
187
202
|
end
|
188
203
|
end
|
189
204
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
+
records =
|
206
|
+
if records.respond_to?(:primary_key)
|
207
|
+
# ActiveRecord
|
208
|
+
records.where(records.primary_key => ids) if records.primary_key
|
209
|
+
elsif records.respond_to?(:queryable)
|
210
|
+
# Mongoid 3+
|
211
|
+
records.queryable.for_ids(ids)
|
212
|
+
elsif records.respond_to?(:unscoped) && :id.respond_to?(:in)
|
213
|
+
# Nobrainer
|
214
|
+
records.unscoped.where(:id.in => ids)
|
215
|
+
end
|
216
|
+
|
217
|
+
raise Searchkick::Error, "Not sure how to load records" if !records
|
218
|
+
|
219
|
+
records
|
205
220
|
end
|
206
221
|
|
207
222
|
def base_field(k)
|
data/lib/searchkick/version.rb
CHANGED
data/searchkick.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
|
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
17
17
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features|benchmark)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency "activemodel", ">= 4.1"
|
data/test/aggs_test.rb
CHANGED
@@ -98,19 +98,22 @@ class AggsTest < Minitest::Test
|
|
98
98
|
|
99
99
|
def test_aggs_group_by_date
|
100
100
|
store [{name: "Old Product", created_at: 3.years.ago}]
|
101
|
-
|
102
|
-
"Product",
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
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
|
114
117
|
end
|
115
118
|
|
116
119
|
protected
|
data/test/highlight_test.rb
CHANGED
@@ -3,42 +3,42 @@ require_relative "test_helper"
|
|
3
3
|
class HighlightTest < Minitest::Test
|
4
4
|
def test_basic
|
5
5
|
store_names ["Two Door Cinema Club"]
|
6
|
-
assert_equal "Two Door <em>Cinema</em> Club", Product.search("cinema", fields: [:name], highlight: true).
|
6
|
+
assert_equal "Two Door <em>Cinema</em> Club", Product.search("cinema", fields: [:name], highlight: true).first.search_highlights[:name]
|
7
7
|
end
|
8
8
|
|
9
9
|
def test_tag
|
10
10
|
store_names ["Two Door Cinema Club"]
|
11
|
-
assert_equal "Two Door <strong>Cinema</strong> Club", Product.search("cinema", fields: [:name], highlight: {tag: "<strong>"}).
|
11
|
+
assert_equal "Two Door <strong>Cinema</strong> Club", Product.search("cinema", fields: [:name], highlight: {tag: "<strong>"}).first.search_highlights[:name]
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_multiple_fields
|
15
15
|
store [{name: "Two Door Cinema Club", color: "Cinema Orange"}]
|
16
|
-
|
17
|
-
assert_equal "Two Door <em>Cinema</em> Club",
|
18
|
-
assert_equal "<em>Cinema</em> Orange",
|
16
|
+
highlights = Product.search("cinema", fields: [:name, :color], highlight: true).first.search_highlights
|
17
|
+
assert_equal "Two Door <em>Cinema</em> Club", highlights[:name]
|
18
|
+
assert_equal "<em>Cinema</em> Orange", highlights[:color]
|
19
19
|
end
|
20
20
|
|
21
21
|
def test_fields
|
22
22
|
store [{name: "Two Door Cinema Club", color: "Cinema Orange"}]
|
23
|
-
|
24
|
-
assert_equal "Two Door <em>Cinema</em> Club",
|
25
|
-
assert_nil
|
23
|
+
highlights = Product.search("cinema", fields: [:name, :color], highlight: {fields: [:name]}).first.search_highlights
|
24
|
+
assert_equal "Two Door <em>Cinema</em> Club", highlights[:name]
|
25
|
+
assert_nil highlights[:color]
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_field_options
|
29
29
|
store_names ["Two Door Cinema Club are a Northern Irish indie rock band"]
|
30
30
|
fragment_size = ENV["MATCH"] == "word_start" ? 26 : 20
|
31
|
-
assert_equal "Two Door <em>Cinema</em> Club are", Product.search("cinema", fields: [:name], highlight: {fields: {name: {fragment_size: fragment_size}}}).
|
31
|
+
assert_equal "Two Door <em>Cinema</em> Club are", Product.search("cinema", fields: [:name], highlight: {fields: {name: {fragment_size: fragment_size}}}).first.search_highlights[:name]
|
32
32
|
end
|
33
33
|
|
34
34
|
def test_multiple_words
|
35
35
|
store_names ["Hello World Hello"]
|
36
|
-
assert_equal "<em>Hello</em> World <em>Hello</em>", Product.search("hello", fields: [:name], highlight: true).
|
36
|
+
assert_equal "<em>Hello</em> World <em>Hello</em>", Product.search("hello", fields: [:name], highlight: true).first.search_highlights[:name]
|
37
37
|
end
|
38
38
|
|
39
39
|
def test_encoder
|
40
40
|
store_names ["<b>Hello</b>"]
|
41
|
-
assert_equal "<b><em>Hello</em></b>", Product.search("hello", fields: [:name], highlight: {encoder: "html"}, misspellings: false).
|
41
|
+
assert_equal "<b><em>Hello</em></b>", Product.search("hello", fields: [:name], highlight: {encoder: "html"}, misspellings: false).first.search_highlights[:name]
|
42
42
|
end
|
43
43
|
|
44
44
|
def test_body
|
@@ -58,6 +58,11 @@ class HighlightTest < Minitest::Test
|
|
58
58
|
}
|
59
59
|
}
|
60
60
|
}
|
61
|
-
assert_equal "Two Door <strong>Cinema</strong> Club", Product.search(body: body).
|
61
|
+
assert_equal "Two Door <strong>Cinema</strong> Club", Product.search(body: body).first.search_highlights[:"name.analyzed"]
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_legacy
|
65
|
+
store_names ["Two Door Cinema Club"]
|
66
|
+
assert_equal "Two Door <em>Cinema</em> Club", Product.search("cinema", fields: [:name], highlight: true).with_details.first[1][:highlight][:name]
|
62
67
|
end
|
63
68
|
end
|
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.0.
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -108,6 +108,8 @@ files:
|
|
108
108
|
- LICENSE.txt
|
109
109
|
- README.md
|
110
110
|
- Rakefile
|
111
|
+
- benchmark/Gemfile
|
112
|
+
- benchmark/benchmark.rb
|
111
113
|
- lib/searchkick.rb
|
112
114
|
- lib/searchkick/index.rb
|
113
115
|
- lib/searchkick/index_options.rb
|
@@ -190,6 +192,8 @@ summary: Searchkick learns what your users are looking for. As more people searc
|
|
190
192
|
it gets smarter and the results get better. It’s friendly for developers - and magical
|
191
193
|
for your users.
|
192
194
|
test_files:
|
195
|
+
- benchmark/Gemfile
|
196
|
+
- benchmark/benchmark.rb
|
193
197
|
- test/aggs_test.rb
|
194
198
|
- test/autocomplete_test.rb
|
195
199
|
- test/boost_test.rb
|