searchkick 2.0.1 → 2.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 17c7f39c1470d38bc637340ae0031997a0b0134c
4
- data.tar.gz: 0167c2d1448536bf5b2b48120f56e992c22aed8e
3
+ metadata.gz: 01c193778cc86142dca494a2aa0b0ac8c6474d0b
4
+ data.tar.gz: 7ff77b2f385a8004acaf1dabb4935f90d61c26f8
5
5
  SHA512:
6
- metadata.gz: a6bf61245813c31fc922a29c5aa4998df13c9c1f51eba6c248ea1bfbba435f048de37a069d23cad6fc041618a235974895cb7466c08ee24cb14eb39296fc908d
7
- data.tar.gz: b50909d603658acd1c9562470c2fd1de404cffd2f93a22c1ca926003afaaabcf33ea70a14ba69d96e3b94b50af241b91cbd267492c079416e2b9ae500c6cf32e
6
+ metadata.gz: cbeefdbb0c40dfb0c32789e7468d3b570c7014fe9b27a202fca7b310820fd3c223264e360456ea68ca5bb13378e3770f448b3237abb9f61385f22d72942b09b0
7
+ data.tar.gz: 199fb639bcc0d883e87848009e35d2ed0e62e491c5ada17d0eeab3844539513f27c09af46ebb17051f402973dabed86e46e8d6bd08e18b9b3dc43ce3ac2d74e0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 2.0.2
2
+
3
+ - Added `retain` option to `reindex`
4
+ - Added support for attributes in highlight tags
5
+ - Fixed potentially silent errors in reindex job
6
+ - Improved syntax for `boost_by_distance`
7
+
1
8
  ## 2.0.1
2
9
 
3
10
  - Added `search_hit` and `search_highlights` methods to models
data/Gemfile CHANGED
@@ -7,3 +7,4 @@ gem "sqlite3"
7
7
  gem "activerecord", "~> 5.0.0"
8
8
  gem "gemoji-parser"
9
9
  gem "typhoeus"
10
+ gem "activejob"
data/README.md CHANGED
@@ -119,7 +119,7 @@ limit: 20, offset: 40
119
119
  Select
120
120
 
121
121
  ```ruby
122
- select: ["name"]
122
+ select: [:name]
123
123
  ```
124
124
 
125
125
  ### Results
@@ -497,7 +497,7 @@ end
497
497
 
498
498
  ### Analytics
499
499
 
500
- We highly recommend tracking searches and conversions.
500
+ The best starting point to improve your search **by far** is to track searches and conversions.
501
501
 
502
502
  [Searchjoy](https://github.com/ankane/searchjoy) makes it easy.
503
503
 
@@ -815,14 +815,14 @@ Find similar items.
815
815
 
816
816
  ```ruby
817
817
  product = Product.first
818
- product.similar(fields: ["name"], where: {size: "12 oz"})
818
+ product.similar(fields: [:name], where: {size: "12 oz"})
819
819
  ```
820
820
 
821
821
  ### Geospatial Searches
822
822
 
823
823
  ```ruby
824
824
  class City < ActiveRecord::Base
825
- searchkick locations: ["location"]
825
+ searchkick locations: [:location]
826
826
 
827
827
  def search_data
828
828
  attributes.merge location: {lat: latitude, lon: longitude}
@@ -853,13 +853,13 @@ City.search "san", where: {location: {geo_polygon: {points: [{lat: 38, lon: -123
853
853
  Boost results by distance - closer results are boosted more
854
854
 
855
855
  ```ruby
856
- City.search "san", boost_by_distance: {field: :location, origin: {lat: 37, lon: -122}}
856
+ City.search "san", boost_by_distance: {location: {origin: {lat: 37, lon: -122}}}
857
857
  ```
858
858
 
859
859
  Also supports [additional options](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#_decay_functions)
860
860
 
861
861
  ```ruby
862
- City.search "san", boost_by_distance: {field: :location, origin: {lat: 37, lon: -122}, function: :linear, scale: "30mi", decay: 0.5}
862
+ City.search "san", boost_by_distance: {location: {origin: {lat: 37, lon: -122}, function: "linear", scale: "30mi", decay: 0.5}}
863
863
  ```
864
864
 
865
865
  ### Geo Shapes
data/Rakefile CHANGED
@@ -5,6 +5,7 @@ task default: :test
5
5
  Rake::TestTask.new do |t|
6
6
  t.libs << "test"
7
7
  t.pattern = "test/**/*_test.rb"
8
+ t.warning = false
8
9
  end
9
10
 
10
11
  task :benchmark do
@@ -38,7 +38,7 @@ module Searchkick
38
38
  client.indices.get_settings index: name
39
39
  end
40
40
 
41
- def swap(new_name)
41
+ def promote(new_name)
42
42
  old_indices =
43
43
  begin
44
44
  client.indices.get_alias(name: name).keys
@@ -48,6 +48,7 @@ module Searchkick
48
48
  actions = old_indices.map { |old_name| {remove: {index: old_name, alias: name}} } + [{add: {index: new_name, alias: name}}]
49
49
  client.indices.update_aliases body: {actions: actions}
50
50
  end
51
+ alias_method :swap, :promote
51
52
 
52
53
  # record based
53
54
 
@@ -186,30 +187,30 @@ module Searchkick
186
187
 
187
188
  # https://gist.github.com/jarosan/3124884
188
189
  # http://www.elasticsearch.org/blog/changing-mapping-with-zero-downtime/
189
- def reindex_scope(scope, import: true, resume: false)
190
+ def reindex_scope(scope, import: true, resume: false, retain: false)
190
191
  if resume
191
192
  index_name = all_indices.sort.last
192
193
  raise Searchkick::Error, "No index to resume" unless index_name
193
194
  index = Searchkick::Index.new(index_name)
194
195
  else
195
- clean_indices
196
+ clean_indices unless retain
196
197
 
197
198
  index = create_index(index_options: scope.searchkick_index_options)
198
199
  end
199
200
 
200
201
  # check if alias exists
201
202
  if alias_exists?
202
- # import before swap
203
+ # import before promotion
203
204
  index.import_scope(scope, resume: resume) if import
204
205
 
205
206
  # get existing indices to remove
206
- swap(index.name)
207
- clean_indices
207
+ promote(index.name)
208
+ clean_indices unless retain
208
209
  else
209
210
  delete if exists?
210
- swap(index.name)
211
+ promote(index.name)
211
212
 
212
- # import after swap
213
+ # import after promotion
213
214
  index.import_scope(scope, resume: resume) if import
214
215
  end
215
216
 
@@ -459,17 +459,25 @@ module Searchkick
459
459
 
460
460
  def set_boost_by_distance(custom_filters)
461
461
  boost_by_distance = options[:boost_by_distance] || {}
462
- boost_by_distance = {function: :gauss, scale: "5mi"}.merge(boost_by_distance)
463
- if !boost_by_distance[:field] || !boost_by_distance[:origin]
464
- raise ArgumentError, "boost_by_distance requires :field and :origin"
462
+
463
+ # legacy format
464
+ if boost_by_distance[:field]
465
+ boost_by_distance = {boost_by_distance[:field] => boost_by_distance.except(:field)}
465
466
  end
466
- function_params = boost_by_distance.select { |k, _| [:origin, :scale, :offset, :decay].include?(k) }
467
- function_params[:origin] = location_value(function_params[:origin])
468
- custom_filters << {
469
- boost_by_distance[:function] => {
470
- boost_by_distance[:field] => function_params
467
+
468
+ boost_by_distance.each do |field, attributes|
469
+ attributes = {function: :gauss, scale: "5mi"}.merge(attributes)
470
+ unless attributes[:origin]
471
+ raise ArgumentError, "boost_by_distance requires :origin"
472
+ end
473
+ function_params = attributes.select { |k, _| [:origin, :scale, :offset, :decay].include?(k) }
474
+ function_params[:origin] = location_value(function_params[:origin])
475
+ custom_filters << {
476
+ attributes[:function] => {
477
+ field => function_params
478
+ }
471
479
  }
472
- }
480
+ end
473
481
  end
474
482
 
475
483
  def set_boost_by(multiply_filters, custom_filters)
@@ -542,7 +550,7 @@ module Searchkick
542
550
  if options[:highlight].is_a?(Hash)
543
551
  if (tag = options[:highlight][:tag])
544
552
  payload[:highlight][:pre_tags] = [tag]
545
- payload[:highlight][:post_tags] = [tag.to_s.gsub(/\A</, "</")]
553
+ payload[:highlight][:post_tags] = [tag.to_s.gsub(/\A<(\w+).+/, "</\\1>")]
546
554
  end
547
555
 
548
556
  if (fragment_size = options[:highlight][:fragment_size])
@@ -770,7 +778,9 @@ module Searchkick
770
778
  if below50?
771
779
  {
772
780
  filter: {
773
- and: where_filters(field => value)
781
+ bool: {
782
+ must: where_filters(field => value)
783
+ }
774
784
  },
775
785
  boost_factor: factor
776
786
  }
@@ -1,10 +1,25 @@
1
1
  module Searchkick
2
2
  class ReindexV2Job < ActiveJob::Base
3
+ RECORD_NOT_FOUND_CLASSES = [
4
+ "ActiveRecord::RecordNotFound",
5
+ "Mongoid::Errors::DocumentNotFound",
6
+ "NoBrainer::Error::DocumentNotFound"
7
+ ]
8
+
3
9
  queue_as :searchkick
4
10
 
5
11
  def perform(klass, id)
6
12
  model = klass.constantize
7
- record = model.find(id) rescue nil # TODO fix lazy coding
13
+ record =
14
+ begin
15
+ model.find(id)
16
+ rescue => e
17
+ # check by name rather than rescue directly so we don't need
18
+ # to determine which classes are defined
19
+ raise e unless RECORD_NOT_FOUND_CLASSES.include?(e.class.name)
20
+ nil
21
+ end
22
+
8
23
  index = model.searchkick_index
9
24
  if !record || !record.should_index?
10
25
  # hacky
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "2.0.1"
2
+ VERSION = "2.0.2"
3
3
  end
data/test/boost_test.rb CHANGED
@@ -138,6 +138,24 @@ class BoostTest < Minitest::Test
138
138
  assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by_distance: {field: :location, origin: {lat: 37, lon: -122}, scale: "1000mi"}
139
139
  end
140
140
 
141
+ def test_boost_by_distance_v2
142
+ store [
143
+ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
144
+ {name: "San Antonio", latitude: 29.4167, longitude: -98.5000},
145
+ {name: "San Marino", latitude: 43.9333, longitude: 12.4667}
146
+ ]
147
+ assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by_distance: {location: {origin: [37, -122], scale: "1000mi"}}
148
+ end
149
+
150
+ def test_boost_by_distance_v2_hash
151
+ store [
152
+ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
153
+ {name: "San Antonio", latitude: 29.4167, longitude: -98.5000},
154
+ {name: "San Marino", latitude: 43.9333, longitude: 12.4667}
155
+ ]
156
+ assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by_distance: {location: {origin: {lat: 37, lon: -122}, scale: "1000mi"}}
157
+ end
158
+
141
159
  def test_boost_by_indices
142
160
  store_names ["Rex"], Animal
143
161
  store_names ["Rexx"], Product
@@ -4,3 +4,4 @@ source 'https://rubygems.org'
4
4
  gemspec path: "../../"
5
5
 
6
6
  gem "mongoid", "~> 6.0.0"
7
+ gem "activejob"
@@ -4,3 +4,4 @@ source 'https://rubygems.org'
4
4
  gemspec path: "../../"
5
5
 
6
6
  gem "nobrainer", ">= 0.21.0"
7
+ gem "activejob"
@@ -11,6 +11,11 @@ class HighlightTest < Minitest::Test
11
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
+ def test_tag_class
15
+ store_names ["Two Door Cinema Club"]
16
+ assert_equal "Two Door <strong class='classy'>Cinema</strong> Club", Product.search("cinema", fields: [:name], highlight: {tag: "<strong class='classy'>"}).first.search_highlights[:name]
17
+ end
18
+
14
19
  def test_multiple_fields
15
20
  store [{name: "Two Door Cinema Club", color: "Cinema Orange"}]
16
21
  highlights = Product.search("cinema", fields: [:name, :color], highlight: true).first.search_highlights
data/test/index_test.rb CHANGED
@@ -28,6 +28,13 @@ class IndexTest < Minitest::Test
28
28
  assert !old_index.exists?
29
29
  end
30
30
 
31
+ def test_retain
32
+ Product.reindex
33
+ assert_equal 1, Product.searchkick_index.all_indices.size
34
+ Product.reindex(retain: true)
35
+ assert_equal 2, Product.searchkick_index.all_indices.size
36
+ end
37
+
31
38
  def test_total_docs
32
39
  store_names ["Product A"]
33
40
  assert_equal 1, Product.searchkick_index.total_docs
@@ -107,10 +114,10 @@ class IndexTest < Minitest::Test
107
114
  store_names ["Product A"]
108
115
  raise ActiveRecord::Rollback
109
116
  end
110
- assert_search "product", []
117
+ assert_search "*", []
111
118
  end
112
119
 
113
- def test_analyzed_only
120
+ def test_filterable
114
121
  # skip for 5.0 since it throws
115
122
  # Cannot search on field [alt_description] since it is not indexed.
116
123
  skip unless elasticsearch_below50?
@@ -118,7 +125,7 @@ class IndexTest < Minitest::Test
118
125
  assert_search "*", [], where: {alt_description: "Hello"}
119
126
  end
120
127
 
121
- def test_analyzed_only_large_value
128
+ def test_large_value
122
129
  skip if nobrainer?
123
130
  large_value = 10000.times.map { "hello" }.join(" ")
124
131
  store [{name: "Product A", alt_description: large_value}]
data/test/test_helper.rb CHANGED
@@ -18,7 +18,11 @@ puts "Running against Elasticsearch #{Searchkick.server_version}"
18
18
 
19
19
  I18n.config.enforce_available_locales = true
20
20
 
21
- ActiveJob::Base.logger = nil if defined?(ActiveJob)
21
+ if defined?(ActiveJob)
22
+ ActiveJob::Base.logger = nil
23
+ ActiveJob::Base.queue_adapter = :inline
24
+ end
25
+
22
26
  ActiveSupport::LogSubscriber.logger = Logger.new(STDOUT) if ENV["NOTIFICATIONS"]
23
27
 
24
28
  def elasticsearch_below50?
data/test/where_test.rb CHANGED
@@ -184,6 +184,15 @@ class WhereTest < Minitest::Test
184
184
  assert_search "san", ["San Francisco"], where: {multiple_locations: {near: [37.5, -122.5]}}
185
185
  end
186
186
 
187
+ def test_multiple_locations_with_term_filter
188
+ store [
189
+ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
190
+ {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}
191
+ ]
192
+ assert_search "san", [], where: {multiple_locations: {near: [37.5, -122.5]}, name: "San Antonio"}
193
+ assert_search "san", ["San Francisco"], where: {multiple_locations: {near: [37.5, -122.5]}, name: "San Francisco"}
194
+ end
195
+
187
196
  def test_multiple_locations_hash
188
197
  store [
189
198
  {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
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.1
4
+ version: 2.0.2
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-31 00:00:00.000000000 Z
11
+ date: 2017-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -185,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
185
  version: '0'
186
186
  requirements: []
187
187
  rubyforge_project:
188
- rubygems_version: 2.5.1
188
+ rubygems_version: 2.6.8
189
189
  signing_key:
190
190
  specification_version: 4
191
191
  summary: Searchkick learns what your users are looking for. As more people search,