searchkick 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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