searchkick 2.4.0 → 2.5.0
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 +4 -4
- data/.travis.yml +4 -1
- data/CHANGELOG.md +11 -0
- data/CONTRIBUTING.md +51 -0
- data/README.md +37 -23
- data/lib/searchkick/bulk_reindex_job.rb +1 -1
- data/lib/searchkick/hash_wrapper.rb +12 -0
- data/lib/searchkick/index_options.rb +2 -1
- data/lib/searchkick/process_batch_job.rb +1 -1
- data/lib/searchkick/process_queue_job.rb +1 -1
- data/lib/searchkick/query.rb +42 -14
- data/lib/searchkick/results.rb +12 -2
- data/lib/searchkick/version.rb +1 -1
- data/lib/searchkick.rb +27 -7
- data/test/aggs_test.rb +20 -0
- data/test/boost_test.rb +11 -0
- data/test/ci/before_install.sh +1 -1
- data/test/multi_search_test.rb +8 -0
- data/test/sql_test.rb +7 -0
- data/test/suggest_test.rb +5 -0
- data/test/test_helper.rb +1 -1
- data/test/where_test.rb +16 -0
- 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: 48b011f59eaeb3f3b2213e20bf2206d4963f7bb0
|
4
|
+
data.tar.gz: d3ffbd07eda7ca733915c251ce8b1e1c9c146e44
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 910eaa5810045780efabe7874e0c4e6bb669ad30c3f1bead3c37ab1f817e21a5e73c55acfcf7ffeacc63be95e163ddb5470b4912967379062afab45413d9d8ea
|
7
|
+
data.tar.gz: eae561c188d98071116695b8997f95ac31f1d0229fc56f968193aaac423020ee1219344568c61e2e1d7ddeee94f583189300845b5f5927a7122ab2cf5305f127
|
data/.travis.yml
CHANGED
@@ -20,7 +20,7 @@ gemfile:
|
|
20
20
|
- test/gemfiles/mongoid5.gemfile
|
21
21
|
- test/gemfiles/mongoid6.gemfile
|
22
22
|
env:
|
23
|
-
- ELASTICSEARCH_VERSION=6.
|
23
|
+
- ELASTICSEARCH_VERSION=6.2.1
|
24
24
|
jdk: oraclejdk8
|
25
25
|
matrix:
|
26
26
|
include:
|
@@ -36,3 +36,6 @@ matrix:
|
|
36
36
|
- gemfile: Gemfile
|
37
37
|
env: ELASTICSEARCH_VERSION=5.6.4
|
38
38
|
jdk: oraclejdk8
|
39
|
+
- gemfile: Gemfile
|
40
|
+
env: ELASTICSEARCH_VERSION=6.0.0
|
41
|
+
jdk: oraclejdk8
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 2.5.0
|
2
|
+
|
3
|
+
- Try requests 3 times before raising error
|
4
|
+
- Better exception when trying to access results for failed multi-search query
|
5
|
+
- More efficient aggregations with `where` clauses
|
6
|
+
- Added support for `faraday_middleware-aws-sigv4`
|
7
|
+
- Added `credentials` option to `aws_credentials`
|
8
|
+
- Added `modifier` option to `boost_by`
|
9
|
+
- Added `scope_results` option
|
10
|
+
- Added `factor` option to `boost_by_distance`
|
11
|
+
|
1
12
|
## 2.4.0
|
2
13
|
|
3
14
|
- Fixed `similar` for Elasticsearch 6
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
First, thanks for wanting to contribute. You’re awesome! :heart:
|
4
|
+
|
5
|
+
## Questions
|
6
|
+
|
7
|
+
Use [Stack Overflow](https://stackoverflow.com/) with the tag `searchkick`.
|
8
|
+
|
9
|
+
## Feature Requests
|
10
|
+
|
11
|
+
Create an issue. Start the title with `[Idea]`.
|
12
|
+
|
13
|
+
## Issues
|
14
|
+
|
15
|
+
Think you’ve discovered an issue?
|
16
|
+
|
17
|
+
1. Search existing issues to see if it’s been reported.
|
18
|
+
2. Try the `master` branch to make sure it hasn’t been fixed.
|
19
|
+
|
20
|
+
```rb
|
21
|
+
gem "searchkick", github: "ankane/searchkick"
|
22
|
+
```
|
23
|
+
|
24
|
+
3. Try the `debug` option when searching. This can reveal useful info.
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
Product.search("something", debug: true)
|
28
|
+
```
|
29
|
+
|
30
|
+
If the above steps don’t help, create an issue.
|
31
|
+
|
32
|
+
- For incorrect search results, recreate the problem by forking [this gist](https://gist.github.com/ankane/f80b0923d9ae2c077f41997f7b704e5c). Include a link to your gist and the output in the issue.
|
33
|
+
- For exceptions, include the complete backtrace.
|
34
|
+
|
35
|
+
## Pull Requests
|
36
|
+
|
37
|
+
Fork the project and create a pull request. A few tips:
|
38
|
+
|
39
|
+
- Keep changes to a minimum. If you have multiple features or fixes, submit multiple pull requests.
|
40
|
+
- Follow the existing style. The code should read like it’s written by a single person.
|
41
|
+
- Add one or more tests if possible. Make sure existing tests pass with:
|
42
|
+
|
43
|
+
```sh
|
44
|
+
bundle exec rake test
|
45
|
+
```
|
46
|
+
|
47
|
+
Feel free to open an issue to get feedback on your idea before spending too much time on it.
|
48
|
+
|
49
|
+
---
|
50
|
+
|
51
|
+
This contributing guide is released under [CCO](https://creativecommons.org/publicdomain/zero/1.0/) (public domain). Use it for your own project without attribution.
|
data/README.md
CHANGED
@@ -299,6 +299,8 @@ end
|
|
299
299
|
|
300
300
|
Call `Product.reindex` after changing synonyms.
|
301
301
|
|
302
|
+
Synonyms cannot be more than two words at the moment.
|
303
|
+
|
302
304
|
To read synonyms from a file, use:
|
303
305
|
|
304
306
|
```ruby
|
@@ -759,6 +761,12 @@ Date histogram
|
|
759
761
|
Product.search "pear", aggs: {products_per_year: {date_histogram: {field: :created_at, interval: :year}}}
|
760
762
|
```
|
761
763
|
|
764
|
+
For other aggregation types, including sub-aggregations, use `body_options`:
|
765
|
+
|
766
|
+
```ruby
|
767
|
+
Product.search "orange", body_options: {aggs: {price: {histogram: {field: :price, interval: 10}}}
|
768
|
+
```
|
769
|
+
|
762
770
|
#### Moving From Facets
|
763
771
|
|
764
772
|
1. Replace `facets` with `aggs` in searches. **Note:** Stats facets are not supported at this time.
|
@@ -895,6 +903,8 @@ Bounded by a box
|
|
895
903
|
Restaurant.search "sushi", where: {location: {top_left: {lat: 38, lon: -123}, bottom_right: {lat: 37, lon: -122}}}
|
896
904
|
```
|
897
905
|
|
906
|
+
**Note:** `top_right` and `bottom_left` also work
|
907
|
+
|
898
908
|
Bounded by a polygon
|
899
909
|
|
900
910
|
```ruby
|
@@ -1047,20 +1057,32 @@ Searchkick uses `ENV["ELASTICSEARCH_URL"]` for the Elasticsearch server. This de
|
|
1047
1057
|
|
1048
1058
|
### Heroku
|
1049
1059
|
|
1050
|
-
Choose an add-on: [
|
1060
|
+
Choose an add-on: [Bonsai](https://elements.heroku.com/addons/bonsai) or [Elastic Cloud](https://elements.heroku.com/addons/foundelasticsearch). [SearchBox](https://elements.heroku.com/addons/searchbox) does not work at the moment.
|
1051
1061
|
|
1052
|
-
|
1053
|
-
# SearchBox
|
1054
|
-
heroku addons:create searchbox:starter
|
1055
|
-
heroku config:set ELASTICSEARCH_URL=`heroku config:get SEARCHBOX_URL`
|
1062
|
+
For Bonsai:
|
1056
1063
|
|
1057
|
-
|
1064
|
+
```sh
|
1058
1065
|
heroku addons:create bonsai
|
1059
1066
|
heroku config:set ELASTICSEARCH_URL=`heroku config:get BONSAI_URL`
|
1067
|
+
```
|
1068
|
+
|
1069
|
+
For Found:
|
1060
1070
|
|
1061
|
-
|
1071
|
+
```sh
|
1062
1072
|
heroku addons:create foundelasticsearch
|
1063
|
-
heroku
|
1073
|
+
heroku addons:open foundelasticsearch
|
1074
|
+
```
|
1075
|
+
|
1076
|
+
Visit the Shield page and reset your password. You’ll need to add the username and password to your url. Get the existing url with:
|
1077
|
+
|
1078
|
+
```sh
|
1079
|
+
heroku config:get FOUNDELASTICSEARCH_URL
|
1080
|
+
```
|
1081
|
+
|
1082
|
+
And add `elastic:password@` right after `https://`:
|
1083
|
+
|
1084
|
+
```sh
|
1085
|
+
heroku config:set ELASTICSEARCH_URL=https://elastic:password@12345.us-east-1.aws.found.io
|
1064
1086
|
```
|
1065
1087
|
|
1066
1088
|
Then deploy and reindex:
|
@@ -1415,7 +1437,7 @@ class Product < ApplicationRecord
|
|
1415
1437
|
searchkick mappings: {
|
1416
1438
|
product: {
|
1417
1439
|
properties: {
|
1418
|
-
name: {type: "
|
1440
|
+
name: {type: "keyword"}
|
1419
1441
|
}
|
1420
1442
|
}
|
1421
1443
|
}
|
@@ -1506,20 +1528,6 @@ To query nested data, use dot notation.
|
|
1506
1528
|
User.search "san", fields: ["address.city"], where: {"address.zip_code" => 12345}
|
1507
1529
|
```
|
1508
1530
|
|
1509
|
-
## Search Concepts
|
1510
|
-
|
1511
|
-
### Precision and Recall
|
1512
|
-
|
1513
|
-
[Precision and recall](https://en.wikipedia.org/wiki/Precision_and_recall) are two key concepts in search (also known as *information retrieval*). To help illustrate, let’s walk through an example.
|
1514
|
-
|
1515
|
-
You have a store with 16 types of apples. A user searches for `apples` gets 10 results. 8 of the results are for apples, and 2 are for apple juice.
|
1516
|
-
|
1517
|
-
**Precision** is the fraction of documents in the results that are relevant. There are 10 results and 8 are relevant, so precision is 80%.
|
1518
|
-
|
1519
|
-
**Recall** is the fraction of relevant documents in the results out of all relevant documents. There are 16 apples and only 8 in the results, so recall is 50%.
|
1520
|
-
|
1521
|
-
There’s typically a trade-off between the two. As you tweak your search to increase precision (not return irrelevant documents), there’s are greater chance a relevant document also isn’t returned, which decreases recall. The opposite also applies. As you try to increase recall (return a higher number of relevent documents), there’s a greater chance you also return an irrelevant document, decreasing precision.
|
1522
|
-
|
1523
1531
|
## Reference
|
1524
1532
|
|
1525
1533
|
Reindex one record
|
@@ -1658,6 +1666,12 @@ Eager load different associations by model
|
|
1658
1666
|
Searchkick.search("*", index_name: [Product, Store], model_includes: {Product => [:store], Store => [:product]})
|
1659
1667
|
```
|
1660
1668
|
|
1669
|
+
Run additional scopes on results [master]
|
1670
|
+
|
1671
|
+
```ruby
|
1672
|
+
Product.search "milk", scope_results: ->(r) { r.with_attached_images }
|
1673
|
+
```
|
1674
|
+
|
1661
1675
|
Specify default fields to search
|
1662
1676
|
|
1663
1677
|
```ruby
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Searchkick
|
2
2
|
class BulkReindexJob < ActiveJob::Base
|
3
|
-
queue_as
|
3
|
+
queue_as { Searchkick.queue_name }
|
4
4
|
|
5
5
|
def perform(class_name:, record_ids: nil, index_name: nil, method_name: nil, batch_id: nil, min_id: nil, max_id: nil)
|
6
6
|
klass = class_name.constantize
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Searchkick
|
2
|
+
# Subclass of `Hashie::Mash` to wrap Hash-like structures
|
3
|
+
# (responses from Elasticsearch)
|
4
|
+
#
|
5
|
+
# The primary goal of the subclass is to disable the
|
6
|
+
# warning being printed by Hashie for re-defined
|
7
|
+
# methods, such as `sort`.
|
8
|
+
#
|
9
|
+
class HashWrapper < ::Hashie::Mash
|
10
|
+
disable_warnings if respond_to?(:disable_warnings)
|
11
|
+
end
|
12
|
+
end
|
@@ -174,7 +174,8 @@ module Searchkick
|
|
174
174
|
if synonyms.any?
|
175
175
|
settings[:analysis][:filter][:searchkick_synonym] = {
|
176
176
|
type: "synonym",
|
177
|
-
|
177
|
+
# only remove a single space from synonyms so three-word synonyms will fail noisily instead of silently
|
178
|
+
synonyms: synonyms.select { |s| s.size > 1 }.map { |s| s.is_a?(Array) ? s.map { |s| s.sub(/\s+/, "") }.join(",") : s }.map(&:downcase)
|
178
179
|
}
|
179
180
|
# choosing a place for the synonym filter when stemming is not easy
|
180
181
|
# https://groups.google.com/forum/#!topic/elasticsearch/p7qcQlgHdB8
|
data/lib/searchkick/query.rb
CHANGED
@@ -19,7 +19,7 @@ module Searchkick
|
|
19
19
|
:boost_by, :boost_by_distance, :boost_where, :conversions, :conversions_term, :debug, :emoji, :exclude, :execute, :explain,
|
20
20
|
:fields, :highlight, :includes, :index_name, :indices_boost, :limit, :load,
|
21
21
|
:match, :misspellings, :model_includes, :offset, :operator, :order, :padding, :page, :per_page, :profile,
|
22
|
-
:request_params, :routing, :select, :similar, :smart_aggs, :suggest, :track, :type, :where]
|
22
|
+
:request_params, :routing, :scope_results, :select, :similar, :smart_aggs, :suggest, :track, :type, :where]
|
23
23
|
raise ArgumentError, "unknown keywords: #{unknown_keywords.join(", ")}" if unknown_keywords.any?
|
24
24
|
|
25
25
|
term = term.to_s
|
@@ -98,7 +98,7 @@ module Searchkick
|
|
98
98
|
# no easy way to tell which host the client will use
|
99
99
|
host = Searchkick.client.transport.hosts.first
|
100
100
|
credentials = host[:user] || host[:password] ? "#{host[:user]}:#{host[:password]}@" : nil
|
101
|
-
"curl #{host[:protocol]}://#{credentials}#{host[:host]}:#{host[:port]}/#{CGI.escape(index)}#{type ? "/#{type.map { |t| CGI.escape(t) }.join(',')}" : ''}/_search?pretty -d '#{query[:body].to_json}'"
|
101
|
+
"curl #{host[:protocol]}://#{credentials}#{host[:host]}:#{host[:port]}/#{CGI.escape(index)}#{type ? "/#{type.map { |t| CGI.escape(t) }.join(',')}" : ''}/_search?pretty -H 'Content-Type: application/json' -d '#{query[:body].to_json}'"
|
102
102
|
end
|
103
103
|
|
104
104
|
def handle_response(response)
|
@@ -112,7 +112,9 @@ module Searchkick
|
|
112
112
|
json: !@json.nil?,
|
113
113
|
match_suffix: @match_suffix,
|
114
114
|
highlighted_fields: @highlighted_fields || [],
|
115
|
-
misspellings: @misspellings
|
115
|
+
misspellings: @misspellings,
|
116
|
+
term: term,
|
117
|
+
scope_results: options[:scope_results]
|
116
118
|
}
|
117
119
|
|
118
120
|
if options[:debug]
|
@@ -455,12 +457,16 @@ module Searchkick
|
|
455
457
|
where[:type] = [options[:type] || klass].flatten.map { |v| searchkick_index.klass_document_type(v, true) }
|
456
458
|
end
|
457
459
|
|
458
|
-
# filters
|
460
|
+
# start everything as efficient filters
|
461
|
+
# move to post_filters as aggs demand
|
459
462
|
filters = where_filters(where)
|
460
|
-
|
463
|
+
post_filters = []
|
461
464
|
|
462
465
|
# aggregations
|
463
|
-
set_aggregations(payload) if options[:aggs]
|
466
|
+
set_aggregations(payload, filters, post_filters) if options[:aggs]
|
467
|
+
|
468
|
+
# filters
|
469
|
+
set_filters(payload, filters, post_filters)
|
464
470
|
|
465
471
|
# suggestions
|
466
472
|
set_suggestions(payload, options[:suggest]) if options[:suggest]
|
@@ -545,6 +551,7 @@ module Searchkick
|
|
545
551
|
function_params = attributes.select { |k, _| [:origin, :scale, :offset, :decay].include?(k) }
|
546
552
|
function_params[:origin] = location_value(function_params[:origin])
|
547
553
|
custom_filters << {
|
554
|
+
weight: attributes[:factor] || 1,
|
548
555
|
attributes[:function] => {
|
549
556
|
field => function_params
|
550
557
|
}
|
@@ -653,12 +660,11 @@ module Searchkick
|
|
653
660
|
@highlighted_fields = payload[:highlight][:fields].keys
|
654
661
|
end
|
655
662
|
|
656
|
-
def set_aggregations(payload)
|
663
|
+
def set_aggregations(payload, filters, post_filters)
|
657
664
|
aggs = options[:aggs]
|
658
665
|
payload[:aggs] = {}
|
659
666
|
|
660
667
|
aggs = Hash[aggs.map { |f| [f, {}] }] if aggs.is_a?(Array) # convert to more advanced syntax
|
661
|
-
|
662
668
|
aggs.each do |field, agg_options|
|
663
669
|
size = agg_options[:limit] ? agg_options[:limit] : 1_000
|
664
670
|
shared_agg_options = agg_options.slice(:order, :min_doc_count)
|
@@ -703,6 +709,17 @@ module Searchkick
|
|
703
709
|
where = {}
|
704
710
|
where = (options[:where] || {}).reject { |k| k == field } unless options[:smart_aggs] == false
|
705
711
|
agg_filters = where_filters(where.merge(agg_options[:where] || {}))
|
712
|
+
|
713
|
+
# only do one level comparison for simplicity
|
714
|
+
filters.select! do |filter|
|
715
|
+
if agg_filters.include?(filter)
|
716
|
+
true
|
717
|
+
else
|
718
|
+
post_filters << filter
|
719
|
+
false
|
720
|
+
end
|
721
|
+
end
|
722
|
+
|
706
723
|
if agg_filters.any?
|
707
724
|
payload[:aggs][field] = {
|
708
725
|
filter: {
|
@@ -718,14 +735,16 @@ module Searchkick
|
|
718
735
|
end
|
719
736
|
end
|
720
737
|
|
721
|
-
def set_filters(payload, filters)
|
722
|
-
if
|
738
|
+
def set_filters(payload, filters, post_filters)
|
739
|
+
if post_filters.any?
|
723
740
|
payload[:post_filter] = {
|
724
741
|
bool: {
|
725
|
-
filter:
|
742
|
+
filter: post_filters
|
726
743
|
}
|
727
744
|
}
|
728
|
-
|
745
|
+
end
|
746
|
+
|
747
|
+
if filters.any?
|
729
748
|
# more efficient query if no aggs
|
730
749
|
payload[:query] = {
|
731
750
|
bool: {
|
@@ -769,7 +788,7 @@ module Searchkick
|
|
769
788
|
if value.is_a?(Hash)
|
770
789
|
value.each do |op, op_value|
|
771
790
|
case op
|
772
|
-
when :within, :bottom_right
|
791
|
+
when :within, :bottom_right, :bottom_left
|
773
792
|
# do nothing
|
774
793
|
when :near
|
775
794
|
filters << {
|
@@ -804,6 +823,15 @@ module Searchkick
|
|
804
823
|
}
|
805
824
|
}
|
806
825
|
}
|
826
|
+
when :top_right
|
827
|
+
filters << {
|
828
|
+
geo_bounding_box: {
|
829
|
+
field => {
|
830
|
+
top_right: location_value(op_value),
|
831
|
+
bottom_left: location_value(value[:bottom_left])
|
832
|
+
}
|
833
|
+
}
|
834
|
+
}
|
807
835
|
when :regexp # support for regexp queries without using a regexp ruby object
|
808
836
|
filters << {regexp: {field => {value: op_value}}}
|
809
837
|
when :not # not equal
|
@@ -886,7 +914,7 @@ module Searchkick
|
|
886
914
|
field_value_factor: {
|
887
915
|
field: field,
|
888
916
|
factor: value[:factor].to_f,
|
889
|
-
modifier: log ? "ln2p" : nil
|
917
|
+
modifier: value[:modifier] || (log ? "ln2p" : nil)
|
890
918
|
}
|
891
919
|
}
|
892
920
|
|
data/lib/searchkick/results.rb
CHANGED
@@ -68,7 +68,7 @@ module Searchkick
|
|
68
68
|
end
|
69
69
|
|
70
70
|
result["id"] ||= result["_id"] # needed for legacy reasons
|
71
|
-
|
71
|
+
HashWrapper.new(result)
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
@@ -77,6 +77,8 @@ module Searchkick
|
|
77
77
|
def suggestions
|
78
78
|
if response["suggest"]
|
79
79
|
response["suggest"].values.flat_map { |v| v.first["options"] }.sort_by { |o| -o["score"] }.map { |o| o["text"] }.uniq
|
80
|
+
elsif options[:term] == "*"
|
81
|
+
[]
|
80
82
|
else
|
81
83
|
raise "Pass `suggest: true` to the search method for suggestions"
|
82
84
|
end
|
@@ -187,7 +189,11 @@ module Searchkick
|
|
187
189
|
end
|
188
190
|
|
189
191
|
def hits
|
190
|
-
|
192
|
+
if error
|
193
|
+
raise Searchkick::Error, "Query error - use the error method to view it"
|
194
|
+
else
|
195
|
+
@response["hits"]["hits"]
|
196
|
+
end
|
191
197
|
end
|
192
198
|
|
193
199
|
def misspellings?
|
@@ -215,6 +221,10 @@ module Searchkick
|
|
215
221
|
end
|
216
222
|
end
|
217
223
|
|
224
|
+
if options[:scope_results]
|
225
|
+
records = options[:scope_results].call(records)
|
226
|
+
end
|
227
|
+
|
218
228
|
Searchkick.load_records(records, ids)
|
219
229
|
end
|
220
230
|
|
data/lib/searchkick/version.rb
CHANGED
data/lib/searchkick.rb
CHANGED
@@ -6,6 +6,7 @@ require "searchkick/index_options"
|
|
6
6
|
require "searchkick/index"
|
7
7
|
require "searchkick/indexer"
|
8
8
|
require "searchkick/reindex_queue"
|
9
|
+
require "searchkick/hash_wrapper"
|
9
10
|
require "searchkick/results"
|
10
11
|
require "searchkick/query"
|
11
12
|
require "searchkick/multi_search"
|
@@ -54,14 +55,11 @@ module Searchkick
|
|
54
55
|
|
55
56
|
Elasticsearch::Client.new({
|
56
57
|
url: ENV["ELASTICSEARCH_URL"],
|
57
|
-
transport_options: {request: {timeout: timeout}, headers: {content_type: "application/json"}}
|
58
|
+
transport_options: {request: {timeout: timeout}, headers: {content_type: "application/json"}},
|
59
|
+
retry_on_failure: 2
|
58
60
|
}.deep_merge(client_options)) do |f|
|
59
61
|
f.use Searchkick::Middleware
|
60
|
-
f.request
|
61
|
-
credentials: Aws::Credentials.new(aws_credentials[:access_key_id], aws_credentials[:secret_access_key]),
|
62
|
-
service_name: "es",
|
63
|
-
region: aws_credentials[:region] || "us-east-1"
|
64
|
-
} if aws_credentials
|
62
|
+
f.request signer_middleware_key, signer_middleware_aws_params if aws_credentials
|
65
63
|
end
|
66
64
|
end
|
67
65
|
end
|
@@ -136,7 +134,11 @@ module Searchkick
|
|
136
134
|
end
|
137
135
|
|
138
136
|
def self.aws_credentials=(creds)
|
139
|
-
|
137
|
+
begin
|
138
|
+
require "faraday_middleware/aws_signers_v4"
|
139
|
+
rescue LoadError
|
140
|
+
require "faraday_middleware/aws_sigv4"
|
141
|
+
end
|
140
142
|
@aws_credentials = creds
|
141
143
|
@client = nil # reset client
|
142
144
|
end
|
@@ -200,6 +202,24 @@ module Searchkick
|
|
200
202
|
def self.callbacks_value=(value)
|
201
203
|
Thread.current[:searchkick_callbacks_enabled] = value
|
202
204
|
end
|
205
|
+
|
206
|
+
# private
|
207
|
+
def self.signer_middleware_key
|
208
|
+
defined?(FaradayMiddleware::AwsSignersV4) ? :aws_signers_v4 : :aws_sigv4
|
209
|
+
end
|
210
|
+
|
211
|
+
# private
|
212
|
+
def self.signer_middleware_aws_params
|
213
|
+
if signer_middleware_key == :aws_sigv4
|
214
|
+
{service: "es", region: "us-east-1"}.merge(aws_credentials)
|
215
|
+
else
|
216
|
+
{
|
217
|
+
credentials: aws_credentials[:credentials] || Aws::Credentials.new(aws_credentials[:access_key_id], aws_credentials[:secret_access_key]),
|
218
|
+
service_name: "es",
|
219
|
+
region: aws_credentials[:region] || "us-east-1"
|
220
|
+
}
|
221
|
+
end
|
222
|
+
end
|
203
223
|
end
|
204
224
|
|
205
225
|
# TODO find better ActiveModel hook
|
data/test/aggs_test.rb
CHANGED
@@ -178,6 +178,26 @@ class AggsTest < Minitest::Test
|
|
178
178
|
assert_equal 66, products.aggs["sum_price"]["value"]
|
179
179
|
end
|
180
180
|
|
181
|
+
def test_body_options
|
182
|
+
products =
|
183
|
+
Product.search("*",
|
184
|
+
body_options: {
|
185
|
+
aggs: {
|
186
|
+
price: {
|
187
|
+
histogram: {field: :price, interval: 10}
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}
|
191
|
+
)
|
192
|
+
|
193
|
+
expected = [
|
194
|
+
{"key" => 0.0, "doc_count" => 1},
|
195
|
+
{"key" => 10.0, "doc_count" => 1},
|
196
|
+
{"key" => 20.0, "doc_count" => 2}
|
197
|
+
]
|
198
|
+
assert_equal products.aggs["price"]["buckets"], expected
|
199
|
+
end
|
200
|
+
|
181
201
|
protected
|
182
202
|
|
183
203
|
def buckets_as_hash(agg)
|
data/test/boost_test.rb
CHANGED
@@ -191,6 +191,17 @@ class BoostTest < Minitest::Test
|
|
191
191
|
assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by_distance: {location: {origin: {lat: 37, lon: -122}, scale: "1000mi"}}
|
192
192
|
end
|
193
193
|
|
194
|
+
def test_boost_by_distance_v2_factor
|
195
|
+
store [
|
196
|
+
{name: "San Francisco", latitude: 37.7833, longitude: -122.4167, found_rate: 0.1},
|
197
|
+
{name: "San Antonio", latitude: 29.4167, longitude: -98.5000, found_rate: 0.99},
|
198
|
+
{name: "San Marino", latitude: 43.9333, longitude: 12.4667, found_rate: 0.2}
|
199
|
+
]
|
200
|
+
|
201
|
+
assert_order "san", ["San Antonio","San Francisco", "San Marino"], boost_by: {found_rate: {factor: 100}}, boost_by_distance: {location: {origin: [37, -122], scale: "1000mi"}}
|
202
|
+
assert_order "san", ["San Francisco", "San Antonio", "San Marino"], boost_by: {found_rate: {factor: 100}}, boost_by_distance: {location: {origin: [37, -122], scale: "1000mi", factor: 100}}
|
203
|
+
end
|
204
|
+
|
194
205
|
def test_boost_by_indices
|
195
206
|
skip if cequel?
|
196
207
|
|
data/test/ci/before_install.sh
CHANGED
@@ -14,4 +14,4 @@ fi
|
|
14
14
|
tar -xvf elasticsearch-$ELASTICSEARCH_VERSION.tar.gz
|
15
15
|
cd elasticsearch-$ELASTICSEARCH_VERSION/bin
|
16
16
|
./elasticsearch -d
|
17
|
-
wget -O- --waitretry=1 --tries=
|
17
|
+
wget -O- --waitretry=1 --tries=60 --retry-connrefused -v http://127.0.0.1:9200/
|
data/test/multi_search_test.rb
CHANGED
@@ -33,4 +33,12 @@ class MultiSearchTest < Minitest::Test
|
|
33
33
|
Searchkick.multi_search([products], retry_misspellings: true)
|
34
34
|
assert_equal ["abc", "abd"], products.map(&:name)
|
35
35
|
end
|
36
|
+
|
37
|
+
def test_error
|
38
|
+
products = Product.search("*", order: {bad_column: :asc}, execute: false)
|
39
|
+
Searchkick.multi_search([products])
|
40
|
+
assert products.error
|
41
|
+
error = assert_raises(Searchkick::Error) { products.results }
|
42
|
+
assert_equal error.message, "Query error - use the error method to view it"
|
43
|
+
end
|
36
44
|
end
|
data/test/sql_test.rb
CHANGED
@@ -211,4 +211,11 @@ class SqlTest < Minitest::Test
|
|
211
211
|
assert records.first.association(associations[klass].first).loaded?
|
212
212
|
end
|
213
213
|
end
|
214
|
+
|
215
|
+
def test_scope_results
|
216
|
+
skip unless defined?(ActiveRecord)
|
217
|
+
|
218
|
+
store_names ["Product A", "Product B"]
|
219
|
+
assert_search "product", ["Product A"], scope_results: ->(r) { r.where(name: "Product A") }
|
220
|
+
end
|
214
221
|
end
|
data/test/suggest_test.rb
CHANGED
@@ -68,6 +68,7 @@ class SuggestTest < Minitest::Test
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def test_multiple_models
|
71
|
+
skip # flaky test
|
71
72
|
store_names ["Great White Shark", "Hammerhead Shark", "Tiger Shark"]
|
72
73
|
assert_equal "how big is a tiger shark", Searchkick.search("How Big is a Tigre Shar", suggest: [:name], fields: [:name]).suggestions.first
|
73
74
|
end
|
@@ -77,6 +78,10 @@ class SuggestTest < Minitest::Test
|
|
77
78
|
assert_raises(ArgumentError) { Searchkick.search("How Big is a Tigre Shar", suggest: true) }
|
78
79
|
end
|
79
80
|
|
81
|
+
def test_star
|
82
|
+
assert_equal [], Product.search("*", suggest: true).suggestions
|
83
|
+
end
|
84
|
+
|
80
85
|
protected
|
81
86
|
|
82
87
|
def assert_suggest(term, expected, options = {})
|
data/test/test_helper.rb
CHANGED
data/test/where_test.rb
CHANGED
@@ -189,6 +189,22 @@ class WhereTest < Minitest::Test
|
|
189
189
|
assert_search "san", ["San Francisco"], where: {location: {top_left: {lat: 38, lon: -123}, bottom_right: {lat: 37, lon: -122}}}
|
190
190
|
end
|
191
191
|
|
192
|
+
def test_top_right_bottom_left
|
193
|
+
store [
|
194
|
+
{name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
|
195
|
+
{name: "San Antonio", latitude: 29.4167, longitude: -98.5000}
|
196
|
+
]
|
197
|
+
assert_search "san", ["San Francisco"], where: {location: {top_right: [38, -122], bottom_left: [37, -123]}}
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_top_right_bottom_left_hash
|
201
|
+
store [
|
202
|
+
{name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
|
203
|
+
{name: "San Antonio", latitude: 29.4167, longitude: -98.5000}
|
204
|
+
]
|
205
|
+
assert_search "san", ["San Francisco"], where: {location: {top_right: {lat: 38, lon: -122}, bottom_left: {lat: 37, lon: -123}}}
|
206
|
+
end
|
207
|
+
|
192
208
|
def test_multiple_locations
|
193
209
|
store [
|
194
210
|
{name: "San Francisco", latitude: 37.7833, longitude: -122.4167},
|
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: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -104,6 +104,7 @@ files:
|
|
104
104
|
- ".gitignore"
|
105
105
|
- ".travis.yml"
|
106
106
|
- CHANGELOG.md
|
107
|
+
- CONTRIBUTING.md
|
107
108
|
- Gemfile
|
108
109
|
- LICENSE.txt
|
109
110
|
- README.md
|
@@ -112,6 +113,7 @@ files:
|
|
112
113
|
- benchmark/benchmark.rb
|
113
114
|
- lib/searchkick.rb
|
114
115
|
- lib/searchkick/bulk_reindex_job.rb
|
116
|
+
- lib/searchkick/hash_wrapper.rb
|
115
117
|
- lib/searchkick/index.rb
|
116
118
|
- lib/searchkick/index_options.rb
|
117
119
|
- lib/searchkick/indexer.rb
|