searchkick 0.5.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fdf75cc3dce90b3109799a5ee97e30c319d450ac
4
- data.tar.gz: 646d884beeb278d6a056f662d9a9df6de2e0b6a4
3
+ metadata.gz: c2afa6ea99c2995b003f51cbe409392097fdfa8e
4
+ data.tar.gz: dc2e4add51195454636f94db1ae6417c2a8933bb
5
5
  SHA512:
6
- metadata.gz: 3f97d141a413008ecb2ce03db8c29bd09aa0127af473f40428d0c21b350e4a0266931e347164f978c695a25ebd4c26b57cfd921ce39768355821387ffccad52e
7
- data.tar.gz: 91b030868ca63ad185a67b91062d682a414d942f1e17b6af3aa1ff5dd6392831c240507cf0eb18bf025f4dc3522a40b042d411420608df85a2de6227a4be5378
6
+ metadata.gz: 1895d905c2b916de3e5e5fb5640d8132318f0dccffa553cfd6770d1c38d84bcd5dc9c92d1749711fa16f0bfdf677962318a5ec50e366f91e0dd1324121bf169f
7
+ data.tar.gz: 8c9bc21cf09a320ee676d2307f7ebbdbf1cc2f2dce37633e799f6282ee2f3f1d8e5ba0af1696c23c2271f401ca1173b4803779f6f50f43cd8674db15c7483620
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.5.1
2
+
3
+ - Replaced stop words with common terms query
4
+ - Added language option
5
+ - Fixed bug with empty array in where clause
6
+ - Fixed bug with MongoDB integer _id
7
+ - Fixed reindex bug when callbacks disabled
8
+
1
9
  ## 0.5.0
2
10
 
3
11
  - Better control over partial matches
data/README.md CHANGED
@@ -21,12 +21,14 @@ Plus:
21
21
  - “Did you mean” suggestions
22
22
  - works with ActiveRecord and Mongoid
23
23
 
24
- :zap: Even better with [Searchjoy](http://ankane.github.io/searchjoy/)
25
-
26
24
  :tangerine: Battle-tested at [Instacart](https://www.instacart.com)
27
25
 
28
26
  [![Build Status](https://travis-ci.org/ankane/searchkick.png?branch=master)](https://travis-ci.org/ankane/searchkick)
29
27
 
28
+ We highly recommend tracking queries and conversions
29
+
30
+ :zap: [Searchjoy](http://ankane.github.io/searchjoy/) makes it easy
31
+
30
32
  ## Get Started
31
33
 
32
34
  [Install Elasticsearch](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup.html). For Homebrew, use:
@@ -174,6 +176,18 @@ Available options are:
174
176
  :text_end
175
177
  ```
176
178
 
179
+ ### Language
180
+
181
+ Searchkick defaults to English for stemming. To change this, use:
182
+
183
+ ```ruby
184
+ class Product < ActiveRecord::Base
185
+ searchkick language: "German"
186
+ end
187
+ ```
188
+
189
+ [See the list of languages](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-snowball-tokenfilter.html)
190
+
177
191
  ### Synonyms
178
192
 
179
193
  ```ruby
@@ -219,7 +233,7 @@ Searchkick uses `find_in_batches` to import documents. To eager load associatio
219
233
 
220
234
  ```ruby
221
235
  class Product < ActiveRecord::Base
222
- scope :search_import, includes(:searches)
236
+ scope :search_import, -> { includes(:searches) }
223
237
  end
224
238
  ```
225
239
 
@@ -556,7 +570,7 @@ And use the `query` option to search:
556
570
  Product.search query: {match: {name: "milk"}}
557
571
  ```
558
572
 
559
- [master] To keep the mappings and settings generated by Searchkick, use:
573
+ To keep the mappings and settings generated by Searchkick, use:
560
574
 
561
575
  ```ruby
562
576
  class Product < ActiveRecord::Base
@@ -608,9 +622,9 @@ end
608
622
  or temporarily
609
623
 
610
624
  ```ruby
611
- Product.disable_search_callbacks # use Searchkick.disable_callbacks for all models
625
+ Product.disable_search_callbacks # or use Searchkick.disable_callbacks for all models
612
626
  ExpensiveProductsTask.execute
613
- Product.enable_search_callbacks
627
+ Product.enable_search_callbacks # or use Searchkick.enable_callbacks for all models
614
628
  Product.reindex
615
629
  ```
616
630
 
@@ -635,7 +649,7 @@ class Product < ActiveRecord::Base
635
649
  end
636
650
  ```
637
651
 
638
- Change import batch size [master]
652
+ Change import batch size
639
653
 
640
654
  ```ruby
641
655
  class Product < ActiveRecord::Base
@@ -643,6 +657,35 @@ class Product < ActiveRecord::Base
643
657
  end
644
658
  ```
645
659
 
660
+ Reindex conditionally
661
+
662
+ ```ruby
663
+ class Product < ActiveRecord::Base
664
+ searchkick callbacks: false
665
+
666
+ # add the callbacks manually
667
+ after_save :reindex, if: proc{|model| model.name_changed? } # use your own condition
668
+ after_destroy :reindex
669
+ end
670
+ ```
671
+
672
+ Asynchronous reindexing
673
+
674
+ ```ruby
675
+ class Product < ActiveRecord::Base
676
+ searchkick callbacks: false
677
+
678
+ # add the callbacks manually
679
+ after_save :reindex_async
680
+ after_destroy :reindex_async
681
+
682
+ def reindex_async
683
+ # delayed job
684
+ delay.reindex
685
+ end
686
+ end
687
+ ```
688
+
646
689
  Reindex all models (Rails only)
647
690
 
648
691
  ```sh
@@ -19,8 +19,8 @@ module Searchkick
19
19
  extend Searchkick::Reindex
20
20
  include Searchkick::Similar
21
21
 
22
- after_save :reindex
23
- after_destroy :reindex
22
+ after_save :reindex, if: proc { self.class.search_callbacks? }
23
+ after_destroy :reindex, if: proc { self.class.search_callbacks? }
24
24
 
25
25
  def self.enable_search_callbacks
26
26
  class_variable_set :@@searchkick_callbacks, true
@@ -39,13 +39,11 @@ module Searchkick
39
39
  end
40
40
 
41
41
  def reindex
42
- if self.class.search_callbacks?
43
- index = self.class.searchkick_index
44
- if destroyed? or !should_index?
45
- index.remove self
46
- else
47
- index.store self
48
- end
42
+ index = self.class.searchkick_index
43
+ if destroyed? or !should_index?
44
+ index.remove self
45
+ else
46
+ index.store self
49
47
  end
50
48
  end
51
49
 
@@ -60,7 +58,9 @@ module Searchkick
60
58
  source = source.inject({}){|memo,(k,v)| memo[k.to_s] = v; memo}
61
59
 
62
60
  # Mongoid 4 hack
63
- source["_id"] = source["_id"].to_s if source["_id"]
61
+ if defined?(BSON::ObjectId) and source["_id"].is_a?(BSON::ObjectId)
62
+ source["_id"] = source["_id"].to_s
63
+ end
64
64
 
65
65
  options = self.class.searchkick_options
66
66
 
@@ -94,24 +94,24 @@ module Searchkick
94
94
  searchkick_keyword: {
95
95
  type: "custom",
96
96
  tokenizer: "keyword",
97
- filter: ["lowercase", "snowball"]
97
+ filter: ["lowercase", "searchkick_stemmer"]
98
98
  },
99
99
  default_index: {
100
100
  type: "custom",
101
101
  tokenizer: "standard",
102
102
  # synonym should come last, after stemming and shingle
103
- # shingle must come before snowball
104
- filter: ["standard", "lowercase", "asciifolding", "stop", "searchkick_index_shingle", "snowball"]
103
+ # shingle must come before searchkick_stemmer
104
+ filter: ["standard", "lowercase", "asciifolding", "searchkick_index_shingle", "searchkick_stemmer"]
105
105
  },
106
106
  searchkick_search: {
107
107
  type: "custom",
108
108
  tokenizer: "standard",
109
- filter: ["standard", "lowercase", "asciifolding", "stop", "searchkick_search_shingle", "snowball"]
109
+ filter: ["standard", "lowercase", "asciifolding", "searchkick_search_shingle", "searchkick_stemmer"]
110
110
  },
111
111
  searchkick_search2: {
112
112
  type: "custom",
113
113
  tokenizer: "standard",
114
- filter: ["standard", "lowercase", "asciifolding", "stop", "snowball"]
114
+ filter: ["standard", "lowercase", "asciifolding", "searchkick_stemmer"]
115
115
  },
116
116
  # https://github.com/leschenko/elasticsearch_autocomplete/blob/master/lib/elasticsearch_autocomplete/analyzers.rb
117
117
  searchkick_autocomplete_index: {
@@ -190,6 +190,10 @@ module Searchkick
190
190
  type: "nGram",
191
191
  min_gram: 1,
192
192
  max_gram: 50
193
+ },
194
+ searchkick_stemmer: {
195
+ type: "snowball",
196
+ language: options[:language] || "English"
193
197
  }
194
198
  },
195
199
  tokenizer: {
@@ -77,7 +77,8 @@ module Searchkick
77
77
  fields: [field],
78
78
  query: term,
79
79
  use_dis_max: false,
80
- operator: operator
80
+ operator: operator,
81
+ cutoff_frequency: 0.001
81
82
  }
82
83
  queries.concat [
83
84
  {multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search")},
@@ -178,13 +179,17 @@ module Searchkick
178
179
  # order
179
180
  if options[:order]
180
181
  order = options[:order].is_a?(Enumerable) ? options[:order] : {options[:order] => :asc}
181
- payload[:sort] = order
182
+ payload[:sort] = Hash[ order.map{|k, v| [k.to_s == "id" ? :_id : k, v] } ]
182
183
  end
183
184
 
184
185
  term_filters =
185
186
  proc do |field, value|
186
187
  if value.is_a?(Array) # in query
187
- {or: value.map{|v| term_filters.call(field, v) }}
188
+ if value.any?
189
+ {or: value.map{|v| term_filters.call(field, v) }}
190
+ else
191
+ {terms: {field => value}} # match nothing
192
+ end
188
193
  elsif value.nil?
189
194
  {missing: {"field" => field, existence: true, null_value: true}}
190
195
  else
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
data/test/match_test.rb CHANGED
@@ -139,4 +139,9 @@ class TestMatch < Minitest::Unit::TestCase
139
139
  assert_search "*", ["Product A", "Product B"]
140
140
  end
141
141
 
142
+ def test_to_be_or_not_to_be
143
+ store_names ["to be or not to be"]
144
+ assert_search "to be", ["to be or not to be"]
145
+ end
146
+
142
147
  end
data/test/sql_test.rb CHANGED
@@ -95,6 +95,16 @@ class TestSql < Minitest::Unit::TestCase
95
95
  assert_search "product", ["Product A"], where: {id: product.id.to_s}
96
96
  end
97
97
 
98
+ def test_where_empty
99
+ store_names ["Product A"]
100
+ assert_search "product", ["Product A"], where: {}
101
+ end
102
+
103
+ def test_where_empty_array
104
+ store_names ["Product A"]
105
+ assert_search "product", [], where: {store_id: []}
106
+ end
107
+
98
108
  def test_near
99
109
  store [
100
110
  {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
@@ -138,6 +148,22 @@ class TestSql < Minitest::Unit::TestCase
138
148
  assert_order "product", ["Product A", "Product B", "Product C", "Product D"], order: "name"
139
149
  end
140
150
 
151
+ def test_order_id
152
+ store_names ["Product A", "Product B"]
153
+ product_a = Product.where(name: "Product A").first
154
+ product_b = Product.where(name: "Product B").first
155
+ assert_order "product", [product_a, product_b].sort_by(&:id).map(&:name), order: {id: :asc}
156
+ end
157
+
158
+ def test_order_multiple
159
+ store [
160
+ {name: "Product A", color: "blue", store_id: 1},
161
+ {name: "Product B", color: "red", store_id: 3},
162
+ {name: "Product C", color: "red", store_id: 2}
163
+ ]
164
+ assert_order "product", ["Product A", "Product B", "Product C"], order: {color: :asc, store_id: :desc}
165
+ end
166
+
141
167
  def test_partial
142
168
  store_names ["Honey"]
143
169
  assert_search "fresh honey", []
data/test/test_helper.rb CHANGED
@@ -126,7 +126,7 @@ class Product
126
126
  attr_accessor :conversions, :user_ids
127
127
 
128
128
  def search_data
129
- serializable_hash.merge conversions: conversions, user_ids: user_ids, location: [latitude, longitude], multiple_locations: [[latitude, longitude], [0, 0]]
129
+ serializable_hash.except("id").merge conversions: conversions, user_ids: user_ids, location: [latitude, longitude], multiple_locations: [[latitude, longitude], [0, 0]]
130
130
  end
131
131
 
132
132
  def should_index?
@@ -159,6 +159,7 @@ class Minitest::Unit::TestCase
159
159
 
160
160
  def setup
161
161
  Product.destroy_all
162
+ Store.destroy_all
162
163
  Animal.destroy_all
163
164
  end
164
165
 
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: 0.5.0
4
+ version: 0.5.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: 2014-01-21 00:00:00.000000000 Z
11
+ date: 2014-02-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tire