searchkick 0.2.4 → 0.2.5

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: 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