searchkick 0.7.7 → 0.7.8

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