searchkick 0.3.1 → 0.3.2

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: 1da092cc431fe04831d998435718459f8bebf261
4
- data.tar.gz: 21a86486b94f81e6b9b9061fb6cf051ac7672650
3
+ metadata.gz: ff1b17b6561440bad2ebe3c20d1606b13d579310
4
+ data.tar.gz: 50475abfd988e11bca0b04385a4ec264bac80467
5
5
  SHA512:
6
- metadata.gz: 2b8bbdb5158b5c39994277ab80e46a14b222b5dd24a22204dcc3acb8d3b853b50b692e77a1b634774e5611ca930b1e495428200e9ddcd726254af7db3820a251
7
- data.tar.gz: 3661b1fbb97fd864e524745b2f7435486aeb4cec005381e01a7c37ed6683b38e55b5a5921d60635d46d1700012d18b7662abb99545ee655c635882b9b5b322d4
6
+ metadata.gz: 19e25e2f81fb811f7bf1964cb59a5deccfc6386d10640279bfe6cfb7bb81a1611691ebd6ccb8879c7dcbec4f530d5ccf2fae089e19cc8f783409985092d2315b
7
+ data.tar.gz: be76d99160e570515a3120ecb517a6faef29f2b3b95eb4ebc6556cbe2839d3554faa7295ff72ccc14caf82fb817b65e2286a74377fd95137d68c6666383bc26f
@@ -1,3 +1,8 @@
1
+ ## 0.3.2
2
+
3
+ - Added support for single table inheritance
4
+ - Removed Tire::Model::Search
5
+
1
6
  ## 0.3.1
2
7
 
3
8
  - Added index_prefix option
data/README.md CHANGED
@@ -360,7 +360,7 @@ class City < ActiveRecord::Base
360
360
  searchkick locations: ["location"]
361
361
 
362
362
  def search_data
363
- to_hash.merge location: [latitude.to_f, longitude.to_f]
363
+ to_hash.merge location: [latitude, longitude]
364
364
  end
365
365
  end
366
366
  ```
@@ -419,6 +419,29 @@ Then deploy and reindex:
419
419
  rake searchkick:reindex CLASS=Product
420
420
  ```
421
421
 
422
+ ## Inheritance
423
+
424
+ Searchkick supports single table inheritance.
425
+
426
+ ```ruby
427
+ class Dog < Animal
428
+ end
429
+ ```
430
+
431
+ The parent and child model can both reindex.
432
+
433
+ ```ruby
434
+ Animal.reindex
435
+ Dog.reindex # equivalent
436
+ ```
437
+
438
+ And to search, use:
439
+
440
+ ```ruby
441
+ Animal.search "*" # all animals
442
+ Dog.search "*" # just dogs
443
+ ```
444
+
422
445
  ## Reference
423
446
 
424
447
  Searchkick requires Elasticsearch `0.90.0` or higher.
@@ -2,26 +2,39 @@ module Searchkick
2
2
  module Model
3
3
 
4
4
  def searchkick(options = {})
5
- @searchkick_options = options.dup
6
- @searchkick_env = ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
7
- searchkick_env = @searchkick_env # for class_eval
8
-
9
5
  class_eval do
6
+ cattr_reader :searchkick_options, :searchkick_env, :searchkick_klass, :searchkick_index
7
+
8
+ class_variable_set :@@searchkick_options, options.dup
9
+ class_variable_set :@@searchkick_env, ENV["RACK_ENV"] || ENV["RAILS_ENV"] || "development"
10
+ class_variable_set :@@searchkick_klass, self
11
+
12
+ # set index name
13
+ # TODO support proc
14
+ index_name = options[:index_name] || [options[:index_prefix], model_name.plural, searchkick_env].compact.join("_")
15
+ class_variable_set :@@searchkick_index, Tire::Index.new(index_name)
16
+
10
17
  extend Searchkick::Search
11
18
  extend Searchkick::Reindex
12
19
  include Searchkick::Similar
13
- include Tire::Model::Search
14
- include Tire::Model::Callbacks unless options[:callbacks] == false
15
- tire do
16
- index_name options[:index_name] || [options[:index_prefix], klass.model_name.plural, searchkick_env].compact.join("_")
17
- end
18
20
 
19
21
  def reindex
20
- tire.update_index
22
+ index = self.class.searchkick_index
23
+ if destroyed?
24
+ index.remove self
25
+ else
26
+ index.store self
27
+ end
28
+ end
29
+
30
+ unless options[:callbacks] == false
31
+ # TODO ability to temporarily disable
32
+ after_save :reindex
33
+ after_destroy :reindex
21
34
  end
22
35
 
23
36
  def search_data
24
- to_hash.reject{|k, v| k == "id" }
37
+ respond_to?(:to_hash) ? to_hash : serializable_hash
25
38
  end
26
39
 
27
40
  def to_indexed_json
@@ -30,7 +43,7 @@ module Searchkick
30
43
  # stringify fields
31
44
  source = source.inject({}){|memo,(k,v)| memo[k.to_s] = v; memo}
32
45
 
33
- options = self.class.instance_variable_get("@searchkick_options")
46
+ options = self.class.searchkick_options
34
47
 
35
48
  # conversions
36
49
  conversions_field = options[:conversions]
@@ -45,11 +58,22 @@ module Searchkick
45
58
 
46
59
  # locations
47
60
  (options[:locations] || []).map(&:to_s).each do |field|
48
- source[field] = source[field].reverse if source[field]
61
+ source[field] = source[field].map(&:to_f).reverse if source[field]
49
62
  end
50
63
 
51
64
  source.to_json
52
65
  end
66
+
67
+ # TODO remove
68
+
69
+ def self.document_type
70
+ model_name.to_s.underscore
71
+ end
72
+
73
+ def document_type
74
+ self.class.document_type
75
+ end
76
+
53
77
  end
54
78
  end
55
79
 
@@ -3,7 +3,7 @@ module Searchkick
3
3
 
4
4
  # https://gist.github.com/jarosan/3124884
5
5
  def reindex
6
- alias_name = tire.index.name
6
+ alias_name = searchkick_index.name
7
7
  new_index = alias_name + "_" + Time.now.strftime("%Y%m%d%H%M%S%L")
8
8
  index = Tire::Index.new(new_index)
9
9
 
@@ -28,7 +28,7 @@ module Searchkick
28
28
  raise response.to_s
29
29
  end
30
30
  else
31
- tire.index.delete if tire.index.exists?
31
+ searchkick_index.delete if searchkick_index.exists?
32
32
  response = Tire::Alias.create(name: alias_name, indices: [new_index])
33
33
  raise response.to_s if !response.success?
34
34
 
@@ -41,7 +41,7 @@ module Searchkick
41
41
  # remove old indices that start w/ index_name
42
42
  def clean_indices
43
43
  all_indices = JSON.parse(Tire::Configuration.client.get("#{Tire::Configuration.url}/_aliases").body)
44
- indices = all_indices.select{|k, v| v["aliases"].empty? && k =~ /\A#{Regexp.escape(tire.index.name)}_\d{14,17}\z/ }.keys
44
+ indices = all_indices.select{|k, v| v["aliases"].empty? && k =~ /\A#{Regexp.escape(searchkick_index.name)}_\d{14,17}\z/ }.keys
45
45
  indices.each do |index|
46
46
  Tire::Index.new(index).delete
47
47
  end
@@ -56,7 +56,8 @@ module Searchkick
56
56
 
57
57
  def searchkick_import(index)
58
58
  # use scope for import
59
- scope = respond_to?(:search_import) ? search_import : self
59
+ scope = searchkick_klass
60
+ scope = scope.search_import if scope.respond_to?(:search_import)
60
61
  if scope.respond_to?(:find_in_batches)
61
62
  scope.find_in_batches do |batch|
62
63
  index.import batch
@@ -77,7 +78,7 @@ module Searchkick
77
78
  end
78
79
 
79
80
  def searchkick_index_options
80
- options = @searchkick_options
81
+ options = searchkick_options
81
82
 
82
83
  settings = {
83
84
  analysis: {
@@ -148,7 +149,7 @@ module Searchkick
148
149
  }
149
150
  }
150
151
 
151
- if @searchkick_env == "test"
152
+ if searchkick_env == "test"
152
153
  settings.merge!(number_of_shards: 1, number_of_replicas: 0)
153
154
  end
154
155
 
@@ -220,7 +221,7 @@ module Searchkick
220
221
  end
221
222
 
222
223
  mappings = {
223
- document_type.to_sym => {
224
+ searchkick_klass.document_type.to_sym => {
224
225
  properties: mapping,
225
226
  # https://gist.github.com/kimchy/2898285
226
227
  dynamic_templates: [
@@ -12,7 +12,7 @@ module Searchkick
12
12
  end
13
13
  else
14
14
  if options[:autocomplete]
15
- (@searchkick_options[:autocomplete] || []).map{|f| "#{f}.autocomplete" }
15
+ (searchkick_options[:autocomplete] || []).map{|f| "#{f}.autocomplete" }
16
16
  else
17
17
  ["_all"]
18
18
  end
@@ -28,10 +28,10 @@ module Searchkick
28
28
  page = [options[:page].to_i, 1].max
29
29
  per_page = (options[:limit] || options[:per_page] || 100000).to_i
30
30
  offset = options[:offset] || (page - 1) * per_page
31
- index_name = options[:index_name] || tire.index.name
31
+ index_name = options[:index_name] || searchkick_index.name
32
32
 
33
- conversions_field = @searchkick_options[:conversions]
34
- personalize_field = @searchkick_options[:personalize]
33
+ conversions_field = searchkick_options[:conversions]
34
+ personalize_field = searchkick_options[:personalize]
35
35
 
36
36
  all = term == "*"
37
37
 
@@ -176,7 +176,7 @@ module Searchkick
176
176
  if value[:near]
177
177
  filters << {
178
178
  geo_distance: {
179
- field => value.delete(:near).reverse,
179
+ field => value.delete(:near).map(&:to_f).reverse,
180
180
  distance: value.delete(:within) || "50mi"
181
181
  }
182
182
  }
@@ -186,8 +186,8 @@ module Searchkick
186
186
  filters << {
187
187
  geo_bounding_box: {
188
188
  field => {
189
- top_left: value.delete(:top_left).reverse,
190
- bottom_right: value.delete(:bottom_right).reverse
189
+ top_left: value.delete(:top_left).map(&:to_f).reverse,
190
+ bottom_right: value.delete(:bottom_right).map(&:to_f).reverse
191
191
  }
192
192
  }
193
193
  }
@@ -269,7 +269,7 @@ module Searchkick
269
269
 
270
270
  # suggestions
271
271
  if options[:suggest]
272
- suggest_fields = (@searchkick_options[:suggest] || []).map(&:to_s)
272
+ suggest_fields = (searchkick_options[:suggest] || []).map(&:to_s)
273
273
  # intersection
274
274
  suggest_fields = suggest_fields & options[:fields].map(&:to_s) if options[:fields]
275
275
  if suggest_fields.any?
@@ -288,7 +288,9 @@ module Searchkick
288
288
  # http://www.elasticsearch.org/guide/reference/api/search/fields/
289
289
  payload[:fields] = [] if load
290
290
 
291
- search = Tire::Search::Search.new(index_name, load: load, payload: payload, size: per_page, from: offset)
291
+ tire_options = {load: load, payload: payload, size: per_page, from: offset}
292
+ tire_options[:type] = document_type if self != searchkick_klass
293
+ search = Tire::Search::Search.new(index_name, tire_options)
292
294
  response = search.json
293
295
 
294
296
  # apply facet limit in client due to
@@ -2,7 +2,7 @@ module Searchkick
2
2
  module Similar
3
3
 
4
4
  def similar(options = {})
5
- like_text = index.retrieve(document_type, id).to_hash
5
+ like_text = self.class.searchkick_index.retrieve(document_type, id).to_hash
6
6
  .keep_if{|k,v| k[0] != "_" and (!options[:fields] or options[:fields].map(&:to_sym).include?(k)) }
7
7
  .values.compact.join(" ")
8
8
 
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -12,7 +12,7 @@ class TestIndex < Minitest::Unit::TestCase
12
12
 
13
13
  Product.clean_indices
14
14
 
15
- assert Product.tire.index.exists?
15
+ assert Product.searchkick_index.exists?
16
16
  assert different_index.exists?
17
17
  assert !old_index.exists?
18
18
  end
@@ -0,0 +1,33 @@
1
+ require_relative "test_helper"
2
+
3
+ class TestInheritance < Minitest::Unit::TestCase
4
+
5
+ def setup
6
+ super
7
+ Animal.destroy_all
8
+ end
9
+
10
+ def test_child_reindex
11
+ store_names ["Max"], Cat
12
+ assert Dog.reindex
13
+ Animal.searchkick_index.refresh
14
+ assert_equal 1, Animal.search("*").size
15
+ end
16
+
17
+ def test_child_index_name
18
+ assert_equal "animals_test", Dog.searchkick_index.name
19
+ end
20
+
21
+ def test_child_search
22
+ store_names ["Bear"], Dog
23
+ store_names ["Bear"], Cat
24
+ assert_equal 1, Dog.search("bear").size
25
+ end
26
+
27
+ def test_parent_search
28
+ store_names ["Bear"], Dog
29
+ store_names ["Bear"], Cat
30
+ assert_equal 2, Animal.search("bear").size
31
+ end
32
+
33
+ end
@@ -24,6 +24,16 @@ if ENV["MONGOID"]
24
24
  class Store
25
25
  include Mongoid::Document
26
26
  end
27
+
28
+ class Animal
29
+ include Mongoid::Document
30
+ end
31
+
32
+ class Dog < Animal
33
+ end
34
+
35
+ class Cat < Animal
36
+ end
27
37
  else
28
38
  require "active_record"
29
39
 
@@ -49,7 +59,12 @@ else
49
59
  t.timestamps
50
60
  end
51
61
 
52
- ActiveRecord::Migration.create_table :store, :force => true do |t|
62
+ ActiveRecord::Migration.create_table :stores, :force => true do |t|
63
+ end
64
+
65
+ ActiveRecord::Migration.create_table :animals, :force => true do |t|
66
+ t.string :name
67
+ t.string :type
53
68
  end
54
69
 
55
70
  class Product < ActiveRecord::Base
@@ -57,6 +72,15 @@ else
57
72
 
58
73
  class Store < ActiveRecord::Base
59
74
  end
75
+
76
+ class Animal < ActiveRecord::Base
77
+ end
78
+
79
+ class Dog < Animal
80
+ end
81
+
82
+ class Cat < Animal
83
+ end
60
84
  end
61
85
 
62
86
  class Product
@@ -80,14 +104,20 @@ class Product
80
104
  attr_accessor :conversions, :user_ids
81
105
 
82
106
  def search_data
83
- to_hash.merge conversions: conversions, user_ids: user_ids, location: [latitude.to_f, longitude.to_f]
107
+ attributes.merge conversions: conversions, user_ids: user_ids, location: [latitude, longitude]
84
108
  end
85
109
  end
86
110
 
87
- Product.tire.index.delete if Product.tire.index.exists?
111
+ class Animal
112
+ searchkick
113
+ end
114
+
115
+ Product.searchkick_index.delete if Product.searchkick_index.exists?
88
116
  Product.reindex
89
117
  Product.reindex # run twice for both index paths
90
118
 
119
+ Animal.reindex
120
+
91
121
  class MiniTest::Unit::TestCase
92
122
 
93
123
  def setup
@@ -96,15 +126,15 @@ class MiniTest::Unit::TestCase
96
126
 
97
127
  protected
98
128
 
99
- def store(documents)
129
+ def store(documents, klass = Product)
100
130
  documents.shuffle.each do |document|
101
- Product.create!(document)
131
+ klass.create!(document)
102
132
  end
103
- Product.tire.index.refresh
133
+ klass.searchkick_index.refresh
104
134
  end
105
135
 
106
- def store_names(names)
107
- store names.map{|name| {name: name} }
136
+ def store_names(names, klass = Product)
137
+ store names.map{|name| {name: name} }, klass
108
138
  end
109
139
 
110
140
  # no order
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.3.1
4
+ version: 0.3.2
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-11-02 00:00:00.000000000 Z
11
+ date: 2013-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tire
@@ -136,6 +136,7 @@ files:
136
136
  - test/boost_test.rb
137
137
  - test/facets_test.rb
138
138
  - test/index_test.rb
139
+ - test/inheritance_test.rb
139
140
  - test/match_test.rb
140
141
  - test/similar_test.rb
141
142
  - test/sql_test.rb
@@ -171,6 +172,7 @@ test_files:
171
172
  - test/boost_test.rb
172
173
  - test/facets_test.rb
173
174
  - test/index_test.rb
175
+ - test/inheritance_test.rb
174
176
  - test/match_test.rb
175
177
  - test/similar_test.rb
176
178
  - test/sql_test.rb