searchkick 0.2.4 → 0.2.5

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: f7e8d412864f6c87ba170611a9b2cdfb6d6f6cc8
4
- data.tar.gz: 98d9385aa9ad6c967ccdae9924f15d8bf0c1ee69
3
+ metadata.gz: 81763af637b2e95a2eebbcecf303a23274b46221
4
+ data.tar.gz: dee89361eb8976c550ad20f413fc8ca42c5a696b
5
5
  SHA512:
6
- metadata.gz: 00cfd0a2da2ce78127466636d5176c89356ef90311335b26f0050d58375cd3eb082113255a7eb3c71a5e0860e5c2b45a0a463363d1665e8e765ce14bb0d4d371
7
- data.tar.gz: a90e126bfe9c460538ef89570e1da4512b93c804b45d43b01384c0bd5cb29d128db88668c3fa2fd009dcdc5abd4870f9216b6b6b3f4f580833703c42709e5d35
6
+ metadata.gz: bdf78091a6aa79ae75eed94e54b0f0e5c53e9515adfd4914e82b92882dfe4308af5d9cd1c4333586244f94eef69ef4c921ff53c77188f47cb1db16a4467b9087
7
+ data.tar.gz: 18773058d6ba94a0f1b2da546e426884483f45c50428babd4e172178ad0804f219648fe5de97d82c55a723886cef4d9d39b053cedc0b2d5a66d0c1cf58b3edd3
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 0.2.5
2
+
3
+ - Added geospartial searches
4
+ - Create alias before importing document if no alias exists
5
+ - Fixed exception when :per_page option is a string
6
+ - Check `RAILS_ENV` if `RACK_ENV` is not set
7
+
1
8
  ## 0.2.4
2
9
 
3
10
  - Use `to_hash` instead of `as_json` for default `search_data` method
data/README.md CHANGED
@@ -341,6 +341,24 @@ product = Product.first
341
341
  product.similar(fields: ["name"])
342
342
  ```
343
343
 
344
+ ### Geospatial Searches
345
+
346
+ ```ruby
347
+ class City < ActiveRecord::Base
348
+ searchkick locations: ["location"]
349
+
350
+ def search_data
351
+ to_hash.merge location: [latitude.to_f, longitude.to_f]
352
+ end
353
+ end
354
+ ```
355
+
356
+ Reindex and search with:
357
+
358
+ ```ruby
359
+ City.search "san", where: {location: {near: [37, -114], within: "100mi"}} # or 160km
360
+ ```
361
+
344
362
  ## Deployment
345
363
 
346
364
  Searchkick uses `ENV["ELASTICSEARCH_URL"]` for the Elasticsearch server. This defaults to `http://localhost:9200`.
@@ -468,12 +486,17 @@ class Product < ActiveRecord::Base
468
486
  end
469
487
  ```
470
488
 
489
+ For convenience, this is set by default in the test environment.
490
+
471
491
  ## Thanks
472
492
 
473
493
  Thanks to Karel Minarik for [Tire](https://github.com/karmi/tire), Jaroslav Kalistsuk for [zero downtime reindexing](https://gist.github.com/jarosan/3124884), and Alex Leschenko for [Elasticsearch autocomplete](https://github.com/leschenko/elasticsearch_autocomplete).
474
494
 
475
495
  ## TODO
476
496
 
497
+ - Analytics for searches and conversions
498
+ - Generate autocomplete predictions from past search queries
499
+ - Automatic failover
477
500
  - Make Searchkick work with any language
478
501
 
479
502
  ## History
@@ -3,6 +3,8 @@ module Searchkick
3
3
 
4
4
  def searchkick(options = {})
5
5
  @searchkick_options = options.dup
6
+ @searchkick_env = ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
7
+ searchkick_env = @searchkick_env # for class_eval
6
8
 
7
9
  class_eval do
8
10
  extend Searchkick::Search
@@ -11,7 +13,7 @@ module Searchkick
11
13
  include Tire::Model::Search
12
14
  include Tire::Model::Callbacks
13
15
  tire do
14
- index_name options[:index_name] || [klass.model_name.plural, ENV["RACK_ENV"] || "development"].join("_")
16
+ index_name options[:index_name] || [klass.model_name.plural, searchkick_env].join("_")
15
17
  end
16
18
 
17
19
  def reindex
@@ -12,41 +12,30 @@ module Searchkick
12
12
  success = index.create searchkick_index_options
13
13
  raise index.response.to_s if !success
14
14
 
15
- # use scope for import
16
- scope = respond_to?(:search_import) ? search_import : self
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
33
- end
34
-
35
15
  if a = Tire::Alias.find(alias_name)
36
- a.indices.each do |index|
37
- a.indices.delete index
16
+ searchkick_import(index) # import before swap
17
+
18
+ a.indices.each do |i|
19
+ a.indices.delete i
38
20
  end
39
21
 
40
22
  a.indices.add new_index
41
23
  response = a.save
42
24
 
43
- clean_indices if response.success?
25
+ if response.success?
26
+ clean_indices
27
+ else
28
+ raise response.to_s
29
+ end
44
30
  else
45
31
  tire.index.delete if tire.index.exists?
46
32
  response = Tire::Alias.create(name: alias_name, indices: [new_index])
33
+ raise response.to_s if !response.success?
34
+
35
+ searchkick_import(index) # import after swap
47
36
  end
48
37
 
49
- response.success? || (raise response.to_s)
38
+ true
50
39
  end
51
40
 
52
41
  # remove old indices that start w/ index_name
@@ -65,6 +54,28 @@ module Searchkick
65
54
 
66
55
  private
67
56
 
57
+ def searchkick_import(index)
58
+ # use scope for import
59
+ scope = respond_to?(:search_import) ? search_import : self
60
+ if scope.respond_to?(:find_in_batches)
61
+ scope.find_in_batches do |batch|
62
+ index.import batch
63
+ end
64
+ else
65
+ # https://github.com/karmi/tire/blob/master/lib/tire/model/import.rb
66
+ # use cursor for Mongoid
67
+ items = []
68
+ scope.all.each do |item|
69
+ items << item
70
+ if items.length % 1000 == 0
71
+ index.import items
72
+ items = []
73
+ end
74
+ end
75
+ index.import items
76
+ end
77
+ end
78
+
68
79
  def searchkick_index_options
69
80
  options = @searchkick_options
70
81
 
@@ -137,7 +148,7 @@ module Searchkick
137
148
  }
138
149
  }
139
150
 
140
- if ENV["RACK_ENV"] == "test"
151
+ if @searchkick_env == "test"
141
152
  settings.merge!(number_of_shards: 1, number_of_replicas: 0)
142
153
  end
143
154
 
@@ -196,6 +207,12 @@ module Searchkick
196
207
  mapping[field] = field_mapping
197
208
  end
198
209
 
210
+ (options[:locations] || []).each do |field|
211
+ mapping[field] = {
212
+ type: "geo_point"
213
+ }
214
+ end
215
+
199
216
  mappings = {
200
217
  document_type.to_sym => {
201
218
  properties: mapping,
@@ -26,7 +26,7 @@ module Searchkick
26
26
 
27
27
  # pagination
28
28
  page = [options[:page].to_i, 1].max
29
- per_page = options[:limit] || options[:per_page] || 100000
29
+ per_page = (options[:limit] || options[:per_page] || 100000).to_i
30
30
  offset = options[:offset] || (page - 1) * per_page
31
31
  index_name = options[:index_name] || tire.index.name
32
32
 
@@ -168,6 +168,15 @@ module Searchkick
168
168
  if value.is_a?(Array) # in query
169
169
  filters << {terms: {field => value}}
170
170
  elsif value.is_a?(Hash)
171
+ if value[:near]
172
+ filters << {
173
+ geo_distance: {
174
+ field => value.delete(:near),
175
+ distance: value.delete(:within) || "50mi"
176
+ }
177
+ }
178
+ end
179
+
171
180
  value.each do |op, op_value|
172
181
  if op == :not # not equal
173
182
  if op_value.is_a?(Array)
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
  end
data/test/sql_test.rb CHANGED
@@ -72,6 +72,23 @@ class TestSql < Minitest::Unit::TestCase
72
72
  assert_search "product", ["Product A"], where: {color: ["RED"]}
73
73
  end
74
74
 
75
+ def test_near
76
+ store [
77
+ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
78
+ {name: "San Antonio", latitude: 29.4167, longitude: -98.5000}
79
+ ]
80
+ assert_search "san", ["San Francisco"], where: {location: {near: [37, -122]}}
81
+ end
82
+
83
+ def test_near_within
84
+ store [
85
+ {name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
86
+ {name: "San Antonio", latitude: 29.4167, longitude: -98.5000},
87
+ {name: "San Marino", latitude: 43.9333, longitude: 12.4667}
88
+ ]
89
+ assert_search "san", ["San Francisco", "San Antonio"], where: {location: {near: [37, -122], within: "2000mi"}}
90
+ end
91
+
75
92
  def test_order_hash
76
93
  store_names ["Product A", "Product B", "Product C", "Product D"]
77
94
  assert_order "product", ["Product D", "Product C", "Product B", "Product A"], order: {name: :desc}
data/test/test_helper.rb CHANGED
@@ -44,6 +44,8 @@ else
44
44
  t.boolean :backordered
45
45
  t.integer :orders_count
46
46
  t.string :color
47
+ t.decimal :latitude, precision: 10, scale: 7
48
+ t.decimal :longitude, precision: 10, scale: 7
47
49
  t.timestamps
48
50
  end
49
51
 
@@ -72,12 +74,13 @@ class Product
72
74
  autocomplete: [:name],
73
75
  suggest: [:name, :color],
74
76
  conversions: "conversions",
75
- personalize: "user_ids"
77
+ personalize: "user_ids",
78
+ locations: ["location"]
76
79
 
77
80
  attr_accessor :conversions, :user_ids
78
81
 
79
82
  def search_data
80
- to_hash.merge conversions: conversions, user_ids: user_ids
83
+ to_hash.merge conversions: conversions, user_ids: user_ids, location: [latitude.to_f, longitude.to_f]
81
84
  end
82
85
  end
83
86
 
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.4
4
+ version: 0.2.5
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-21 00:00:00.000000000 Z
11
+ date: 2013-08-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tire