searchkick 0.2.3 → 0.2.4

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: 275937983ec78c77a0d7f25fa26a9fbe067a5154
4
- data.tar.gz: 31783a30cf0b0d6170d94a99daf2c0022d20008d
3
+ metadata.gz: f7e8d412864f6c87ba170611a9b2cdfb6d6f6cc8
4
+ data.tar.gz: 98d9385aa9ad6c967ccdae9924f15d8bf0c1ee69
5
5
  SHA512:
6
- metadata.gz: 636392d9b685813dbdcfd6d8b9f9aa715be73515e089f32a1c95a870c3c0ff17a3a336c3605318b9f8ea6ca406927493752fa6d603762f70a77777de41306144
7
- data.tar.gz: 954203fe3c5a0e48d404322c7a270cde965bbd5f69e32e285da9e1582546cd5257bd87b616315c3e997db9402838f4966920fd5c0e10c195502b0b54214a64ff
6
+ metadata.gz: 00cfd0a2da2ce78127466636d5176c89356ef90311335b26f0050d58375cd3eb082113255a7eb3c71a5e0860e5c2b45a0a463363d1665e8e765ce14bb0d4d371
7
+ data.tar.gz: a90e126bfe9c460538ef89570e1da4512b93c804b45d43b01384c0bd5cb29d128db88668c3fa2fd009dcdc5abd4870f9216b6b6b3f4f580833703c42709e5d35
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.2.4
2
+
3
+ - Use `to_hash` instead of `as_json` for default `search_data` method
4
+ - Works for Mongoid 1.3
5
+ - Use one shard in test environment for consistent scores
6
+
1
7
  ## 0.2.3
2
8
 
3
9
  - Setup Travis
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in searchkick.gemspec
4
4
  gemspec
5
+
6
+ # gem "mongoid", github: "mongoid/mongoid"
7
+ # gem "mongoid", "~> 3.1.0"
8
+ # gem "activerecord", "~> 3.2.0"
9
+ # gem "activerecord", "~> 3.1.0"
data/README.md CHANGED
@@ -19,6 +19,7 @@ Plus:
19
19
  - easily personalize results for each user
20
20
  - autocomplete
21
21
  - “Did you mean” suggestions
22
+ - works with ActiveRecord and Mongoid
22
23
 
23
24
  :tangerine: Battle-tested at [Instacart](https://www.instacart.com)
24
25
 
@@ -134,24 +135,6 @@ To change this, use:
134
135
  Product.search "fresh honey", partial: true # fresh OR honey
135
136
  ```
136
137
 
137
- ### Autocomplete
138
-
139
- ![Autocomplete](http://ankane.github.io/searchkick/autocomplete.png)
140
-
141
- You must specify which fields use this feature since this can increase the index size significantly. Don’t worry - this gives you blazing faster queries.
142
-
143
- ```ruby
144
- class Website < ActiveRecord::Base
145
- searchkick autocomplete: ["title"]
146
- end
147
- ```
148
-
149
- Reindex and search with:
150
-
151
- ```ruby
152
- Website.search "where", autocomplete: true
153
- ```
154
-
155
138
  ### Synonyms
156
139
 
157
140
  ```ruby
@@ -187,6 +170,19 @@ class Product < ActiveRecord::Base
187
170
  end
188
171
  ```
189
172
 
173
+ ### To Reindex, or Not to Reindex
174
+
175
+ #### Reindex
176
+
177
+ - when you install or upgrade searchkick
178
+ - change the `search_data` method
179
+ - change the `searchkick` method
180
+
181
+ #### No need to reindex
182
+
183
+ - App starts
184
+ - Records are inserted, updated or deleted (syncs automatically)
185
+
190
186
  ### Keep Getting Better
191
187
 
192
188
  Searchkick uses conversion data to learn what users are looking for. If a user searches for “ice cream” and adds Ben & Jerry’s Chunky Monkey to the cart (our conversion metric at Instacart), that item gets a little more weight for similar searches.
@@ -250,6 +246,58 @@ Reindex and search with:
250
246
  Product.search "milk", user_id: 8
251
247
  ```
252
248
 
249
+ ### Autocomplete
250
+
251
+ Autocomplete predicts what a user will type, making the search experience faster and easier.
252
+
253
+ ![Autocomplete](http://ankane.github.io/searchkick/autocomplete.png)
254
+
255
+ First, specify which fields use this feature. This is necessary since autocomplete can increase the index size significantly, but don’t worry - this gives you blazing faster queries.
256
+
257
+ ```ruby
258
+ class City < ActiveRecord::Base
259
+ searchkick autocomplete: ["name"]
260
+ end
261
+ ```
262
+
263
+ Reindex and search with:
264
+
265
+ ```ruby
266
+ City.search "san fr", autocomplete: true
267
+ ```
268
+
269
+ Typically, you want to use a Javascript library like [typeahead.js](http://twitter.github.io/typeahead.js/) or [jQuery UI](http://jqueryui.com/autocomplete/).
270
+
271
+ #### Here’s how to make it work with Rails
272
+
273
+ First, add a controller action.
274
+
275
+ ```ruby
276
+ # app/controllers/cities_controller.rb
277
+ class CitiesController < ApplicationController
278
+
279
+ def autocomplete
280
+ render json: City.search(params[:q], autocomplete: true, limit: 10).map(&:name)
281
+ end
282
+
283
+ end
284
+ ```
285
+
286
+ Then add the search box and Javascript code to a view.
287
+
288
+ ```html
289
+ <input type="text" id="q" name="q" />
290
+
291
+ <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
292
+ <script src="//cdnjs.cloudflare.com/ajax/libs/typeahead.js/0.9.3/typeahead.min.js"></script>
293
+ <script>
294
+ $("#q").typeahead({
295
+ name: "city",
296
+ remote: "/cities/autocomplete?q=%QUERY"
297
+ });
298
+ </script>
299
+ ```
300
+
253
301
  ### Suggestions
254
302
 
255
303
  ![Suggest](http://ankane.github.io/searchkick/recursion.png)
data/lib/searchkick.rb CHANGED
@@ -9,5 +9,5 @@ require "searchkick/tasks"
9
9
  require "searchkick/logger" if defined?(Rails)
10
10
 
11
11
  # TODO find better ActiveModel hook
12
- ActiveModel::AttributeMethods::ClassMethods.send(:include, Searchkick::Model)
12
+ ActiveModel::Callbacks.send(:include, Searchkick::Model)
13
13
  ActiveRecord::Base.send(:extend, Searchkick::Model) if defined?(ActiveRecord)
@@ -19,7 +19,7 @@ module Searchkick
19
19
  end
20
20
 
21
21
  def search_data
22
- as_json
22
+ to_hash.reject{|k, v| k == "id" }
23
23
  end
24
24
 
25
25
  def to_indexed_json
@@ -14,8 +14,22 @@ module Searchkick
14
14
 
15
15
  # use scope for import
16
16
  scope = respond_to?(:search_import) ? search_import : self
17
- scope.find_in_batches do |batch|
18
- index.import batch
17
+ if scope.respond_to?(:find_in_batches)
18
+ scope.find_in_batches do |batch|
19
+ index.import batch
20
+ end
21
+ else
22
+ # https://github.com/karmi/tire/blob/master/lib/tire/model/import.rb
23
+ # use cursor for Mongoid
24
+ items = []
25
+ scope.all.each do |item|
26
+ items << item
27
+ if items.length % 1000 == 0
28
+ index.import items
29
+ items = []
30
+ end
31
+ end
32
+ index.import items
19
33
  end
20
34
 
21
35
  if a = Tire::Alias.find(alias_name)
@@ -121,7 +135,13 @@ module Searchkick
121
135
  }
122
136
  }
123
137
  }
124
- }.merge(options[:settings] || {})
138
+ }
139
+
140
+ if ENV["RACK_ENV"] == "test"
141
+ settings.merge!(number_of_shards: 1, number_of_replicas: 0)
142
+ end
143
+
144
+ settings.merge!(options[:settings] || {})
125
145
 
126
146
  # synonyms
127
147
  synonyms = options[:synonyms] || []
@@ -28,7 +28,7 @@ module Searchkick
28
28
  page = [options[:page].to_i, 1].max
29
29
  per_page = options[:limit] || options[:per_page] || 100000
30
30
  offset = options[:offset] || (page - 1) * per_page
31
- index_name = options[:index_name] || index.name
31
+ index_name = options[:index_name] || tire.index.name
32
32
 
33
33
  conversions_field = @searchkick_options[:conversions]
34
34
  personalize_field = @searchkick_options[:personalize]
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "0.2.3"
2
+ VERSION = "0.2.4"
3
3
  end
data/test/index_test.rb CHANGED
@@ -12,7 +12,7 @@ class TestIndex < Minitest::Unit::TestCase
12
12
 
13
13
  Product.clean_indices
14
14
 
15
- assert Product.index.exists?
15
+ assert Product.tire.index.exists?
16
16
  assert different_index.exists?
17
17
  assert !old_index.exists?
18
18
  end
data/test/similar_test.rb CHANGED
@@ -4,7 +4,7 @@ class TestSimilar < Minitest::Unit::TestCase
4
4
 
5
5
  def test_fields
6
6
  store_names ["1% Organic Milk", "2% Organic Milk", "Popcorn"]
7
- assert_equal ["2% Organic Milk"], Product.find_by(name: "1% Organic Milk").similar(fields: ["name"]).map(&:name)
7
+ assert_equal ["2% Organic Milk"], Product.where(name: "1% Organic Milk").first.similar(fields: ["name"]).map(&:name)
8
8
  end
9
9
 
10
10
  end
data/test/test_helper.rb CHANGED
@@ -2,47 +2,65 @@ require "bundler/setup"
2
2
  Bundler.require(:default)
3
3
  require "minitest/autorun"
4
4
  require "minitest/pride"
5
- require "active_record"
6
5
 
7
6
  ENV["RACK_ENV"] = "test"
8
7
 
9
- # for debugging
10
- # ActiveRecord::Base.logger = Logger.new(STDOUT)
8
+ File.delete("elasticsearch.log") if File.exists?("elasticsearch.log")
9
+ Tire.configure do
10
+ logger "elasticsearch.log", :level => "debug"
11
+ pretty true
12
+ end
11
13
 
12
- # rails does this in activerecord/lib/active_record/railtie.rb
13
- ActiveRecord::Base.default_timezone = :utc
14
- ActiveRecord::Base.time_zone_aware_attributes = true
14
+ if ENV["MONGOID"]
15
+ Mongoid.configure do |config|
16
+ config.connect_to "searchkick_test"
17
+ end
15
18
 
16
- # migrations
17
- ActiveRecord::Base.establish_connection :adapter => "postgresql", :database => "searchkick_test"
19
+ class Product
20
+ include Mongoid::Document
21
+ # include Mongoid::Attributes::Dynamic
22
+ end
18
23
 
19
- ActiveRecord::Migration.create_table :products, :force => true do |t|
20
- t.string :name
21
- t.integer :store_id
22
- t.boolean :in_stock
23
- t.boolean :backordered
24
- t.integer :orders_count
25
- t.string :color
26
- t.timestamps
27
- end
24
+ class Store
25
+ include Mongoid::Document
26
+ end
27
+ else
28
+ require "active_record"
29
+
30
+ # for debugging
31
+ # ActiveRecord::Base.logger = Logger.new(STDOUT)
32
+
33
+ # rails does this in activerecord/lib/active_record/railtie.rb
34
+ ActiveRecord::Base.default_timezone = :utc
35
+ ActiveRecord::Base.time_zone_aware_attributes = true
36
+
37
+ # migrations
38
+ ActiveRecord::Base.establish_connection :adapter => "postgresql", :database => "searchkick_test"
39
+
40
+ ActiveRecord::Migration.create_table :products, :force => true do |t|
41
+ t.string :name
42
+ t.integer :store_id
43
+ t.boolean :in_stock
44
+ t.boolean :backordered
45
+ t.integer :orders_count
46
+ t.string :color
47
+ t.timestamps
48
+ end
28
49
 
29
- ActiveRecord::Migration.create_table :store, :force => true do |t|
30
- end
50
+ ActiveRecord::Migration.create_table :store, :force => true do |t|
51
+ end
31
52
 
32
- File.delete("elasticsearch.log") if File.exists?("elasticsearch.log")
33
- Tire.configure do
34
- logger "elasticsearch.log", :level => "debug"
35
- pretty true
53
+ class Product < ActiveRecord::Base
54
+ end
55
+
56
+ class Store < ActiveRecord::Base
57
+ end
36
58
  end
37
59
 
38
- class Product < ActiveRecord::Base
60
+ class Product
39
61
  belongs_to :store
40
62
 
41
63
  searchkick \
42
- settings: {
43
- number_of_shards: 1,
44
- number_of_replicas: 0
45
- },
46
64
  synonyms: [
47
65
  ["clorox", "bleach"],
48
66
  ["scallion", "greenonion"],
@@ -59,14 +77,11 @@ class Product < ActiveRecord::Base
59
77
  attr_accessor :conversions, :user_ids
60
78
 
61
79
  def search_data
62
- as_json.merge conversions: conversions, user_ids: user_ids
80
+ to_hash.merge conversions: conversions, user_ids: user_ids
63
81
  end
64
82
  end
65
83
 
66
- class Store < ActiveRecord::Base
67
- end
68
-
69
- Product.index.delete if Product.index.exists?
84
+ Product.tire.index.delete if Product.tire.index.exists?
70
85
  Product.reindex
71
86
  Product.reindex # run twice for both index paths
72
87
 
@@ -82,7 +97,7 @@ class MiniTest::Unit::TestCase
82
97
  documents.shuffle.each do |document|
83
98
  Product.create!(document)
84
99
  end
85
- Product.index.refresh
100
+ Product.tire.index.refresh
86
101
  end
87
102
 
88
103
  def store_names(names)
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.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-16 00:00:00.000000000 Z
11
+ date: 2013-08-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tire