searchkick 0.7.7 → 0.7.8

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: 4a044b56c37732d857fe1dfa7109dc1b87259f15
4
- data.tar.gz: 6fa27e15c4317b20e87f81c22e0ca0f3e69d68cc
3
+ metadata.gz: bb8ada9111159102b2327b5344afe0876aac137d
4
+ data.tar.gz: 3e3e655a723d06f6b741b0938d3fde6d02d5c7ab
5
5
  SHA512:
6
- metadata.gz: 6669b630d244570056a3c2373dda6d99c0c59e25af9c4a716401b9b3178b8867d572a7b553156d69e0b7728fa2ba24e256d347ef39597033d845b9d15e05e7d6
7
- data.tar.gz: b351f5f4d832e80dd9e16acbbebbeb2db89a9ac0ea470394391f033ab66da728e811ee9b25f99de6bb0a65c6bedf5d2e572b10eef879d4f225d488f2cf2b3453
6
+ metadata.gz: fdb99efc9149d644dd126456c9ab2e753a6f67a77feb90e07ad20dcbea75dd7152705136a2e30cfd0fd9e1a38a0ba35b1f05d0b8dd6c986ba248aa90a82126b2
7
+ data.tar.gz: 04a2c3229e5f40a866fa8cc2aed8832d361d680ef9a88fe75d1e3b8dc72875524961056f2f00bf2edd7bcd07989864118367547006198588b5f3af3e0e81ee96
data/CHANGELOG.md CHANGED
@@ -1,7 +1,13 @@
1
+ ## 0.7.8
2
+
3
+ - Added `boost_by` and `boost_where` options
4
+ - Added ability to boost fields - `name^10`
5
+ - Added `select` option for `load: false`
6
+
1
7
  ## 0.7.7
2
8
 
3
9
  - Added support for automatic failover
4
- - Fixed default operator for partial queries
10
+ - Fixed `operator` option (and default) for partial matches
5
11
 
6
12
  ## 0.7.6
7
13
 
data/README.md CHANGED
@@ -116,10 +116,26 @@ Limit / offset
116
116
  limit: 20, offset: 40
117
117
  ```
118
118
 
119
- Boost by a field
119
+ ### Boosting
120
+
121
+ Boost important fields
122
+
123
+ ```ruby
124
+ fields: ["title^10", "description"]
125
+ ```
126
+
127
+ Boost by the value of a field
120
128
 
121
129
  ```ruby
122
- boost: "orders_count" # give popular documents a little boost
130
+ boost_by: [:orders_count] # give popular documents a little boost
131
+ boost_by: {orders_count: {factor: 10}}
132
+ ```
133
+
134
+ Boost matching documents
135
+
136
+ ```ruby
137
+ boost_where: {user_id: 1}
138
+ boost_where: {user_id: {value: 1, factor: 100}}
123
139
  ```
124
140
 
125
141
  ### Get Everything
@@ -164,7 +180,7 @@ class Product < ActiveRecord::Base
164
180
  end
165
181
  ```
166
182
 
167
- And to search:
183
+ And to search (after you reindex):
168
184
 
169
185
  ```ruby
170
186
  Product.search "back", fields: [{name: :word_start}]
@@ -182,6 +198,12 @@ Available options are:
182
198
  :text_end
183
199
  ```
184
200
 
201
+ To boost fields, use:
202
+
203
+ ```ruby
204
+ fields: [{"name^2" => :word_start}] # better interface on the way
205
+ ```
206
+
185
207
  ### Language
186
208
 
187
209
  Searchkick defaults to English for stemming. To change this, use:
@@ -281,7 +303,7 @@ end
281
303
 
282
304
  You do **not** need to clean up the search queries. Searchkick automatically treats `apple` and `APPLES` the same.
283
305
 
284
- Next, add conversions to the index. You must specify the conversions field as of version `0.2.0`.
306
+ Next, add conversions to the index.
285
307
 
286
308
  ```ruby
287
309
  class Product < ActiveRecord::Base
@@ -311,22 +333,21 @@ Order results differently for each user. For example, show a user’s previousl
311
333
 
312
334
  ```ruby
313
335
  class Product < ActiveRecord::Base
314
- searchkick personalize: "user_ids"
315
336
 
316
337
  def search_data
317
338
  {
318
339
  name: name,
319
340
  user_ids: orders.pluck(:user_id) # boost this product for these users
320
- # [4, 8, 15, 16, 23, 42]
321
341
  }
322
342
  end
343
+
323
344
  end
324
345
  ```
325
346
 
326
347
  Reindex and search with:
327
348
 
328
349
  ```ruby
329
- Product.search "milk", user_id: 8
350
+ Product.search "milk", boost_where: {user_id: 8}
330
351
  ```
331
352
 
332
353
  ### Autocomplete
@@ -484,8 +505,6 @@ product.similar(fields: ["name"])
484
505
 
485
506
  ### Geospatial Searches
486
507
 
487
- **Note:** Before `0.3.0`, locations were indexed incorrectly. When upgrading, be sure to reindex immediately.
488
-
489
508
  ```ruby
490
509
  class City < ActiveRecord::Base
491
510
  searchkick locations: ["location"]
@@ -785,10 +804,20 @@ rake searchkick:reindex:all
785
804
 
786
805
  4. Once it finishes, replace search calls w/ searchkick calls
787
806
 
788
- ## Note about 0.6.0 and 0.7.0
807
+ ## Upgrading
808
+
809
+ View the [changelog](https://github.com/ankane/searchkick/blob/master/CHANGELOG.md).
810
+
811
+ Important notes are listed below.
812
+
813
+ ### 0.6.0 and 0.7.0
789
814
 
790
815
  If running Searchkick `0.6.0` or `0.7.0` and Elasticsearch `0.90`, we recommend upgrading to Searchkick `0.6.1` or `0.7.1` to fix an issue that causes downtime when reindexing.
791
816
 
817
+ ### 0.3.0
818
+
819
+ Before `0.3.0`, locations were indexed incorrectly. When upgrading, be sure to reindex immediately.
820
+
792
821
  ## Elasticsearch Gotchas
793
822
 
794
823
  ### Inconsistent Scores
@@ -816,10 +845,6 @@ Thanks to Karel Minarik for [Elasticsearch Ruby](https://github.com/elasticsearc
816
845
  - Much finer customization
817
846
  - More transparency into generated queries (for advanced use)
818
847
 
819
- ## History
820
-
821
- View the [changelog](https://github.com/ankane/searchkick/blob/master/CHANGELOG.md)
822
-
823
848
  ## Contributing
824
849
 
825
850
  Everyone is encouraged to help improve this project. Here are a few ways you can help:
@@ -15,6 +15,7 @@ module Searchkick
15
15
  @term = term
16
16
  @options = options
17
17
 
18
+ boost_fields = {}
18
19
  fields =
19
20
  if options[:fields]
20
21
  if options[:autocomplete]
@@ -22,7 +23,10 @@ module Searchkick
22
23
  else
23
24
  options[:fields].map do |value|
24
25
  k, v = value.is_a?(Hash) ? value.to_a.first : [value, :word]
25
- "#{k}.#{v == :word ? "analyzed" : v}"
26
+ k2, boost = k.to_s.split("^", 2)
27
+ field = "#{k2}.#{v == :word ? "analyzed" : v}"
28
+ boost_fields[field] = boost.to_i if boost
29
+ field
26
30
  end
27
31
  end
28
32
  else
@@ -74,17 +78,19 @@ module Searchkick
74
78
  else
75
79
  queries = []
76
80
  fields.each do |field|
81
+ factor = boost_fields[field] || 1
77
82
  shared_options = {
78
83
  fields: [field],
79
84
  query: term,
80
85
  use_dis_max: false,
81
- operator: operator
86
+ operator: operator,
87
+ boost: factor
82
88
  }
83
89
  if field == "_all" or field.end_with?(".analyzed")
84
90
  shared_options[:cutoff_frequency] = 0.001 unless operator == "and"
85
91
  queries.concat [
86
- {multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search")},
87
- {multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search2")}
92
+ {multi_match: shared_options.merge(boost: 10 * factor, analyzer: "searchkick_search")},
93
+ {multi_match: shared_options.merge(boost: 10 * factor, analyzer: "searchkick_search2")}
88
94
  ]
89
95
  if options[:misspellings] != false
90
96
  distance = (options[:misspellings].is_a?(Hash) && options[:misspellings][:distance]) || 1
@@ -137,36 +143,45 @@ module Searchkick
137
143
 
138
144
  custom_filters = []
139
145
 
146
+ boost_by = options[:boost_by] || {}
147
+ if boost_by.is_a?(Array)
148
+ boost_by = Hash[ boost_by.map{|f| [f, {factor: 1}] } ]
149
+ end
140
150
  if options[:boost]
151
+ boost_by[options[:boost]] = {factor: 1}
152
+ end
153
+
154
+ boost_by.each do |field, value|
141
155
  custom_filters << {
142
156
  filter: {
143
157
  exists: {
144
- field: options[:boost]
158
+ field: field
145
159
  }
146
160
  },
147
161
  script_score: {
148
- script: "log(doc['#{options[:boost]}'].value + 2.718281828)"
162
+ script: "#{value[:factor].to_f} * log(doc['#{field}'].value + 2.718281828)"
149
163
  }
150
164
  }
151
165
  end
152
166
 
167
+ boost_where = options[:boost_where] || {}
153
168
  if options[:user_id] and personalize_field
154
- custom_filters << {
155
- filter: {
156
- term: {
157
- personalize_field => options[:user_id]
158
- }
159
- },
160
- boost_factor: 100
161
- }
169
+ boost_where[personalize_field] = options[:user_id]
162
170
  end
163
-
164
171
  if options[:personalize]
172
+ boost_where.merge!(options[:personalize])
173
+ end
174
+ boost_where.each do |field, value|
175
+ if value.is_a?(Hash)
176
+ value, factor = value[:value], value[:factor]
177
+ else
178
+ factor = 1000
179
+ end
165
180
  custom_filters << {
166
181
  filter: {
167
- term: options[:personalize]
182
+ term: {field => value}
168
183
  },
169
- boost_factor: 100
184
+ boost_factor: factor
170
185
  }
171
186
  end
172
187
 
@@ -292,7 +307,11 @@ module Searchkick
292
307
 
293
308
  # An empty array will cause only the _id and _type for each hit to be returned
294
309
  # http://www.elasticsearch.org/guide/reference/api/search/fields/
295
- payload[:fields] = [] if load
310
+ if load
311
+ payload[:fields] = []
312
+ elsif options[:select]
313
+ payload[:fields] = options[:select]
314
+ end
296
315
 
297
316
  if options[:type] or klass != searchkick_klass
298
317
  @type = [options[:type] || klass].flatten.map{|v| searchkick_index.klass_document_type(v) }
@@ -38,7 +38,12 @@ module Searchkick
38
38
  end.compact
39
39
  else
40
40
  hits.map do |hit|
41
- result = hit.except("_source").merge(hit["_source"])
41
+ result =
42
+ if hit["_source"]
43
+ hit.except("_source").merge(hit["_source"])
44
+ else
45
+ hit.except("fields").merge(hit["fields"])
46
+ end
42
47
  result["id"] ||= result["_id"] # needed for legacy reasons
43
48
  Hashie::Mash.new(result)
44
49
  end
@@ -1,3 +1,3 @@
1
1
  module Searchkick
2
- VERSION = "0.7.7"
2
+ VERSION = "0.7.8"
3
3
  end
data/test/boost_test.rb CHANGED
@@ -67,4 +67,41 @@ class TestBoost < Minitest::Unit::TestCase
67
67
  assert_first "tomato", "Tomato B", personalize: {user_ids: 2}
68
68
  end
69
69
 
70
+ def test_boost_fields
71
+ store [
72
+ {name: "Red", color: "White"},
73
+ {name: "White", color: "Red Red Red"}
74
+ ]
75
+ assert_order "red", ["Red", "White"], fields: ["name^10", "color"]
76
+ end
77
+
78
+ def test_boost_fields_word_start
79
+ store [
80
+ {name: "Red", color: "White"},
81
+ {name: "White", color: "Red Red Red"}
82
+ ]
83
+ assert_order "red", ["Red", "White"], fields: [{"name^10" => :word_start}, "color"]
84
+ end
85
+
86
+ def test_boost_by
87
+ store [
88
+ {name: "Tomato A"},
89
+ {name: "Tomato B", orders_count: 10},
90
+ {name: "Tomato C", orders_count: 100}
91
+ ]
92
+ assert_order "tomato", ["Tomato C", "Tomato B", "Tomato A"], boost_by: [:orders_count]
93
+ assert_order "tomato", ["Tomato C", "Tomato B", "Tomato A"], boost_by: {orders_count: {factor: 10}}
94
+ end
95
+
96
+ def test_boost_where
97
+ store [
98
+ {name: "Tomato A"},
99
+ {name: "Tomato B", user_ids: [1, 2, 3]},
100
+ {name: "Tomato C"},
101
+ {name: "Tomato D"}
102
+ ]
103
+ assert_first "tomato", "Tomato B", boost_where: {user_ids: 2}
104
+ assert_first "tomato", "Tomato B", boost_where: {user_ids: {value: 2, factor: 10}}
105
+ end
106
+
70
107
  end
data/test/sql_test.rb CHANGED
@@ -274,6 +274,13 @@ class TestSql < Minitest::Unit::TestCase
274
274
  assert_kind_of Hash, Product.search("product", load: false, include: [:store]).first
275
275
  end
276
276
 
277
+ # select
278
+
279
+ def test_select
280
+ store [{name: "Product A", store_id: 1}]
281
+ assert_equal %w[id name store_id], Product.search("product", load: false, select: [:name, :store_id]).first.keys.reject{|k| k.start_with?("_") }.sort
282
+ end
283
+
277
284
  # TODO see if Mongoid is loaded
278
285
  if !defined?(Mongoid)
279
286
  def test_include
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.7.7
4
+ version: 0.7.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kane
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-11 00:00:00.000000000 Z
11
+ date: 2014-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel