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 +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +23 -0
- data/lib/searchkick/model.rb +3 -1
- data/lib/searchkick/reindex.rb +42 -25
- data/lib/searchkick/search.rb +10 -1
- data/lib/searchkick/version.rb +1 -1
- data/test/sql_test.rb +17 -0
- data/test/test_helper.rb +5 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81763af637b2e95a2eebbcecf303a23274b46221
|
4
|
+
data.tar.gz: dee89361eb8976c550ad20f413fc8ca42c5a696b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/searchkick/model.rb
CHANGED
@@ -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,
|
16
|
+
index_name options[:index_name] || [klass.model_name.plural, searchkick_env].join("_")
|
15
17
|
end
|
16
18
|
|
17
19
|
def reindex
|
data/lib/searchkick/reindex.rb
CHANGED
@@ -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
|
-
|
37
|
-
|
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
|
-
|
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
|
-
|
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
|
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,
|
data/lib/searchkick/search.rb
CHANGED
@@ -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)
|
data/lib/searchkick/version.rb
CHANGED
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
|
+
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-
|
11
|
+
date: 2013-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tire
|