searchkick 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +33 -4
- data/lib/searchkick/model.rb +23 -0
- data/lib/searchkick/reindex.rb +2 -0
- data/lib/searchkick/results.rb +10 -0
- data/lib/searchkick/search.rb +14 -2
- data/lib/searchkick/tasks.rb +2 -0
- data/lib/searchkick/version.rb +1 -1
- data/test/highlight_test.rb +22 -0
- data/test/sql_test.rb +12 -0
- data/test/suggest_test.rb +3 -3
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d67265d1ad299d9e79b7f1020197f3b12f551535
|
4
|
+
data.tar.gz: b72d9fb064fad2f904db6d2cf69e9be96fb8c44e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ec7b5537539de163009b0857bd84a78829a0520b55b1f77544d0a65dee789dfce467b7afc63aa4aa54327d87be1dc3954178d3d209a35bb92e47c5179ad53a3
|
7
|
+
data.tar.gz: c9710769dd1045f5e8cfb1cd4cc86242df365289d28409bf8c47fe19e3b829b6d5b7ab6bed8ba890e56189ececacad520280c0940651bb2d8cdb2a0f78ac1356
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -29,7 +29,7 @@ Plus:
|
|
29
29
|
|
30
30
|
## Get Started
|
31
31
|
|
32
|
-
[Install Elasticsearch](http://www.elasticsearch.org/guide/reference/setup
|
32
|
+
[Install Elasticsearch](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/setup.html). For Homebrew, use:
|
33
33
|
|
34
34
|
```sh
|
35
35
|
brew install elasticsearch
|
@@ -152,7 +152,13 @@ Call `Product.reindex` after changing synonyms.
|
|
152
152
|
By default, Searchkick handles misspelled queries by returning results with an [edit distance](http://en.wikipedia.org/wiki/Levenshtein_distance) of one. To turn off this feature, use:
|
153
153
|
|
154
154
|
```ruby
|
155
|
-
Product.search "zuchini", misspellings: false
|
155
|
+
Product.search "zuchini", misspellings: false # no zucchini
|
156
|
+
```
|
157
|
+
|
158
|
+
You can also change the edit distance with:
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
Product.search "zucini", misspellings: {distance: 2} # zucchini
|
156
162
|
```
|
157
163
|
|
158
164
|
### Indexing
|
@@ -342,6 +348,30 @@ Advanced
|
|
342
348
|
Product.search "2% Milk", facets: {store_id: {where: {in_stock: true}, limit: 10}}
|
343
349
|
```
|
344
350
|
|
351
|
+
### Highlight
|
352
|
+
|
353
|
+
Highlight the search query in the results.
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
bands = Band.search "cinema", fields: [:name], highlight: true
|
357
|
+
```
|
358
|
+
|
359
|
+
**Note:** The `fields` option is required.
|
360
|
+
|
361
|
+
View the highlighted fields with:
|
362
|
+
|
363
|
+
```ruby
|
364
|
+
bands.with_details.each do |band, details|
|
365
|
+
puts details[:highlight][:name] # "Two Door <em>Cinema</em> Club"
|
366
|
+
end
|
367
|
+
```
|
368
|
+
|
369
|
+
To change the tag, use:
|
370
|
+
|
371
|
+
```ruby
|
372
|
+
Band.search "cinema", fields: [:name], highlight: {tag: "<strong>"}
|
373
|
+
```
|
374
|
+
|
345
375
|
### Similar Items
|
346
376
|
|
347
377
|
Find similar items.
|
@@ -528,7 +558,7 @@ rake searchkick:reindex:all
|
|
528
558
|
|
529
559
|
```ruby
|
530
560
|
class Product < ActiveRecord::Base
|
531
|
-
|
561
|
+
searchkick
|
532
562
|
end
|
533
563
|
```
|
534
564
|
|
@@ -560,7 +590,6 @@ Thanks to Karel Minarik for [Tire](https://github.com/karmi/tire), Jaroslav Kali
|
|
560
590
|
|
561
591
|
## TODO
|
562
592
|
|
563
|
-
- Analytics for searches and conversions
|
564
593
|
- Generate autocomplete predictions from past search queries
|
565
594
|
- Automatic failover
|
566
595
|
- Make Searchkick work with any language
|
data/lib/searchkick/model.rb
CHANGED
@@ -61,6 +61,29 @@ module Searchkick
|
|
61
61
|
source[field] = source[field].map(&:to_f).reverse if source[field]
|
62
62
|
end
|
63
63
|
|
64
|
+
# change all BigDecimal values to floats due to
|
65
|
+
# https://github.com/rails/rails/issues/6033
|
66
|
+
# possible loss of precision :/
|
67
|
+
cast_big_decimal =
|
68
|
+
proc do |obj|
|
69
|
+
case obj
|
70
|
+
when BigDecimal
|
71
|
+
obj.to_f
|
72
|
+
when Hash
|
73
|
+
obj.each do |k, v|
|
74
|
+
obj[k] = cast_big_decimal.call(v)
|
75
|
+
end
|
76
|
+
when Enumerable
|
77
|
+
obj.map! do |v|
|
78
|
+
cast_big_decimal.call(v)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
obj
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
cast_big_decimal.call(source)
|
86
|
+
|
64
87
|
source.to_json
|
65
88
|
end
|
66
89
|
|
data/lib/searchkick/reindex.rb
CHANGED
@@ -203,6 +203,8 @@ module Searchkick
|
|
203
203
|
fields: {
|
204
204
|
field => {type: "string", index: "not_analyzed"},
|
205
205
|
"analyzed" => {type: "string", index: "analyzed"}
|
206
|
+
# term_vector: "with_positions_offsets" for fast / correct highlighting
|
207
|
+
# http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-highlighting.html#_fast_vector_highlighter
|
206
208
|
}
|
207
209
|
}
|
208
210
|
if autocomplete.include?(field)
|
data/lib/searchkick/results.rb
CHANGED
@@ -9,6 +9,16 @@ module Searchkick
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
def with_details
|
13
|
+
each_with_hit.map do |model, hit|
|
14
|
+
details = {}
|
15
|
+
if hit["highlight"]
|
16
|
+
details[:highlight] = Hash[ hit["highlight"].map{|k, v| [k.sub(/\.analyzed\z/, "").to_sym, v.first] } ]
|
17
|
+
end
|
18
|
+
[model, details]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
12
22
|
# fixes deprecation warning
|
13
23
|
def __find_records_by_ids(klass, ids)
|
14
24
|
@options[:load] === true ? klass.find(ids) : klass.includes(@options[:load][:include]).find(ids)
|
data/lib/searchkick/search.rb
CHANGED
@@ -70,9 +70,10 @@ module Searchkick
|
|
70
70
|
{multi_match: shared_options.merge(boost: 10, analyzer: "searchkick_search2")}
|
71
71
|
]
|
72
72
|
if options[:misspellings] != false
|
73
|
+
distance = (options[:misspellings].is_a?(Hash) && options[:misspellings][:distance]) || 1
|
73
74
|
queries.concat [
|
74
|
-
{multi_match: shared_options.merge(fuzziness:
|
75
|
-
{multi_match: shared_options.merge(fuzziness:
|
75
|
+
{multi_match: shared_options.merge(fuzziness: distance, max_expansions: 3, analyzer: "searchkick_search")},
|
76
|
+
{multi_match: shared_options.merge(fuzziness: distance, max_expansions: 3, analyzer: "searchkick_search2")}
|
76
77
|
]
|
77
78
|
end
|
78
79
|
payload = {
|
@@ -288,6 +289,17 @@ module Searchkick
|
|
288
289
|
end
|
289
290
|
end
|
290
291
|
|
292
|
+
# highlight
|
293
|
+
if options[:highlight]
|
294
|
+
payload[:highlight] = {
|
295
|
+
fields: Hash[ fields.map{|f| [f, {}] } ]
|
296
|
+
}
|
297
|
+
if options[:highlight].is_a?(Hash) and tag = options[:highlight][:tag]
|
298
|
+
payload[:highlight][:pre_tags] = [tag]
|
299
|
+
payload[:highlight][:post_tags] = [tag.to_s.gsub(/\A</, "</")]
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
291
303
|
# An empty array will cause only the _id and _type for each hit to be returned
|
292
304
|
# http://www.elasticsearch.org/guide/reference/api/search/fields/
|
293
305
|
payload[:fields] = [] if load
|
data/lib/searchkick/tasks.rb
CHANGED
@@ -23,8 +23,10 @@ namespace :searchkick do
|
|
23
23
|
task :all => :environment do
|
24
24
|
Rails.application.eager_load!
|
25
25
|
(Searchkick::Reindex.instance_variable_get(:@descendents) || []).each do |model|
|
26
|
+
puts "Reindexing #{model.name}..."
|
26
27
|
model.reindex
|
27
28
|
end
|
29
|
+
puts "Reindex complete"
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
data/lib/searchkick/version.rb
CHANGED
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative "test_helper"
|
2
|
+
|
3
|
+
class TestHighlight < Minitest::Unit::TestCase
|
4
|
+
|
5
|
+
def test_basic
|
6
|
+
store_names ["Two Door Cinema Club"]
|
7
|
+
assert_equal "Two Door <em>Cinema</em> Club", Product.search("cinema", fields: [:name], highlight: true).with_details.first[1][:highlight][:name]
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_tag
|
11
|
+
store_names ["Two Door Cinema Club"]
|
12
|
+
assert_equal "Two Door <strong>Cinema</strong> Club", Product.search("cinema", fields: [:name], highlight: {tag: "<strong>"}).with_details.first[1][:highlight][:name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_multiple_fields
|
16
|
+
store [{name: "Two Door Cinema Club", color: "Cinema Orange"}]
|
17
|
+
highlight = Product.search("cinema", fields: [:name, :color], highlight: true).with_details.first[1][:highlight]
|
18
|
+
assert_equal "Two Door <em>Cinema</em> Club", highlight[:name]
|
19
|
+
assert_equal "<em>Cinema</em> Orange", highlight[:color]
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/test/sql_test.rb
CHANGED
@@ -129,6 +129,11 @@ class TestSql < Minitest::Unit::TestCase
|
|
129
129
|
assert_search "abc", ["abc"], misspellings: false
|
130
130
|
end
|
131
131
|
|
132
|
+
def test_misspellings_distance
|
133
|
+
store_names ["abbb", "aabb"]
|
134
|
+
assert_search "aaaa", ["aabb"], misspellings: {distance: 2}
|
135
|
+
end
|
136
|
+
|
132
137
|
def test_fields
|
133
138
|
store [
|
134
139
|
{name: "red", color: "light blue"},
|
@@ -150,6 +155,13 @@ class TestSql < Minitest::Unit::TestCase
|
|
150
155
|
assert_first "blue", "Blue B", fields: [:name, :color]
|
151
156
|
end
|
152
157
|
|
158
|
+
def test_big_decimal
|
159
|
+
store [
|
160
|
+
{name: "Product", latitude: 100.0}
|
161
|
+
]
|
162
|
+
assert_search "product", ["Product"], where: {latitude: {gt: 99}}
|
163
|
+
end
|
164
|
+
|
153
165
|
# load
|
154
166
|
|
155
167
|
def test_load_default
|
data/test/suggest_test.rb
CHANGED
@@ -4,17 +4,17 @@ class TestSuggest < Minitest::Unit::TestCase
|
|
4
4
|
|
5
5
|
def test_basic
|
6
6
|
store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
|
7
|
-
assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark"
|
7
|
+
assert_suggest "How Big is a Tigre Shar", "how big is a tiger shark", fields: [:name]
|
8
8
|
end
|
9
9
|
|
10
10
|
def test_perfect
|
11
11
|
store_names ["Tiger Shark", "Great White Shark"]
|
12
|
-
assert_suggest "Tiger Shark", nil # no correction
|
12
|
+
assert_suggest "Tiger Shark", nil, fields: [:name] # no correction
|
13
13
|
end
|
14
14
|
|
15
15
|
def test_phrase
|
16
16
|
store_names ["Big Tiger Shark", "Tiger Sharp Teeth", "Tiger Sharp Mind"]
|
17
|
-
assert_suggest "How to catch a big tiger shar", "how to catch a big tiger shark"
|
17
|
+
assert_suggest "How to catch a big tiger shar", "how to catch a big tiger shark", fields: [:name]
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_without_option
|
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.
|
4
|
+
version: 0.3.4
|
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-
|
11
|
+
date: 2013-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tire
|
@@ -135,6 +135,7 @@ files:
|
|
135
135
|
- test/autocomplete_test.rb
|
136
136
|
- test/boost_test.rb
|
137
137
|
- test/facets_test.rb
|
138
|
+
- test/highlight_test.rb
|
138
139
|
- test/index_test.rb
|
139
140
|
- test/inheritance_test.rb
|
140
141
|
- test/match_test.rb
|
@@ -171,6 +172,7 @@ test_files:
|
|
171
172
|
- test/autocomplete_test.rb
|
172
173
|
- test/boost_test.rb
|
173
174
|
- test/facets_test.rb
|
175
|
+
- test/highlight_test.rb
|
174
176
|
- test/index_test.rb
|
175
177
|
- test/inheritance_test.rb
|
176
178
|
- test/match_test.rb
|