stretchy 0.1.1 → 0.1.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 +4 -4
- data/bin/console +0 -0
- data/bin/setup +0 -0
- data/lib/stretchy/boosts/base.rb +17 -0
- data/lib/stretchy/boosts/filter_boost.rb +5 -1
- data/lib/stretchy/boosts/geo_boost.rb +9 -1
- data/lib/stretchy/boosts/random_boost.rb +5 -1
- data/lib/stretchy/errors/contract_error.rb +5 -0
- data/lib/stretchy/filters/and_filter.rb +4 -1
- data/lib/stretchy/filters/base.rb +17 -0
- data/lib/stretchy/filters/bool_filter.rb +7 -1
- data/lib/stretchy/filters/exists_filter.rb +1 -1
- data/lib/stretchy/filters/geo_filter.rb +8 -1
- data/lib/stretchy/filters/not_filter.rb +5 -1
- data/lib/stretchy/filters/query_filter.rb +4 -1
- data/lib/stretchy/filters/range_filter.rb +6 -1
- data/lib/stretchy/filters/terms_filter.rb +5 -1
- data/lib/stretchy/queries/base.rb +17 -0
- data/lib/stretchy/queries/filtered_query.rb +5 -1
- data/lib/stretchy/queries/function_score_query.rb +14 -24
- data/lib/stretchy/queries/match_all_query.rb +5 -1
- data/lib/stretchy/queries/match_query.rb +8 -1
- data/lib/stretchy/query.rb +1 -1
- data/lib/stretchy/utils/client_actions.rb +63 -0
- data/lib/stretchy/utils/configuration.rb +36 -0
- data/lib/stretchy/utils/contract.rb +100 -0
- data/lib/stretchy/version.rb +1 -1
- data/lib/stretchy.rb +11 -3
- metadata +9 -4
- data/lib/stretchy/client_actions.rb +0 -61
- data/lib/stretchy/configuration.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28c98af055eaf32fb6c23460780f168e66c894bb
|
4
|
+
data.tar.gz: 54af860b9fca236b64c2d95f3acbd13bde7b5f47
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1a8077918cd57cb1294f9340716d2b20d14ce4ebaf01c96eb6e535011ebe4dafcccc013ae4ce201120f5fabe75498c823b29825a1471bf8cdc11cbe99204b23
|
7
|
+
data.tar.gz: ab509f01cfc5f0a97dd522a3ad1bd9ba34bd1c0bbdc4b863d81b78ec386f8f86fc1d3d947d53c748af5ba71f4e27ed195b80f5000e64da8be8ec8c098381064a
|
data/bin/console
CHANGED
File without changes
|
data/bin/setup
CHANGED
File without changes
|
@@ -1,12 +1,16 @@
|
|
1
1
|
module Stretchy
|
2
2
|
module Boosts
|
3
|
-
class FilterBoost
|
3
|
+
class FilterBoost < Base
|
4
4
|
|
5
5
|
DEFAULT_WEIGHT = 1.2
|
6
6
|
|
7
|
+
contract filter: {type: Stretchy::Filters::Base},
|
8
|
+
weight: {type: Numeric}
|
9
|
+
|
7
10
|
def initialize(filter:, weight: DEFAULT_WEIGHT)
|
8
11
|
@filter = filter
|
9
12
|
@weight = weight
|
13
|
+
validate!
|
10
14
|
end
|
11
15
|
|
12
16
|
def to_search
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Stretchy
|
2
2
|
module Boosts
|
3
|
-
class GeoBoost
|
3
|
+
class GeoBoost < Base
|
4
4
|
|
5
5
|
DEFAULTS = {
|
6
6
|
field: 'coords',
|
@@ -10,6 +10,13 @@ module Stretchy
|
|
10
10
|
weight: 1.2
|
11
11
|
}.freeze
|
12
12
|
|
13
|
+
contract offset: {type: :distance},
|
14
|
+
scale: {type: :distance},
|
15
|
+
decay: {type: Numeric},
|
16
|
+
weight: {type: Numeric},
|
17
|
+
lat: {type: :lat},
|
18
|
+
lng: {type: :lng}
|
19
|
+
|
13
20
|
def initialize(options = {})
|
14
21
|
@field = options[:field] || DEFAULTS[:field]
|
15
22
|
@offset = options[:offset] || DEFAULTS[:offset]
|
@@ -18,6 +25,7 @@ module Stretchy
|
|
18
25
|
@weight = options[:weight] || DEFAULTS[:weight]
|
19
26
|
@lat = options[:lat]
|
20
27
|
@lng = options[:lng]
|
28
|
+
validate!
|
21
29
|
end
|
22
30
|
|
23
31
|
def to_search
|
@@ -1,15 +1,19 @@
|
|
1
1
|
module Stretchy
|
2
2
|
module Boosts
|
3
|
-
class RandomBoost
|
3
|
+
class RandomBoost < Base
|
4
4
|
|
5
5
|
DEFAULT_WEIGHT = 1.2
|
6
6
|
|
7
|
+
contract seed: {type: Numeric},
|
8
|
+
weight: {type: Numeric}
|
9
|
+
|
7
10
|
# randomizes order (somewhat) consistently per-user
|
8
11
|
# http://www.elastic.co/guide/en/elasticsearch/guide/current/random-scoring.html
|
9
12
|
|
10
13
|
def initialize(seed, weight = DEFAULT_WEIGHT)
|
11
14
|
@seed = seed
|
12
15
|
@weight = weight
|
16
|
+
validate!
|
13
17
|
end
|
14
18
|
|
15
19
|
def to_search
|
@@ -1,10 +1,16 @@
|
|
1
1
|
module Stretchy
|
2
2
|
module Filters
|
3
|
-
class BoolFilter
|
3
|
+
class BoolFilter < Base
|
4
|
+
|
5
|
+
contract must: {type: Base, array: true},
|
6
|
+
must_not: {type: Base, array: true},
|
7
|
+
should: {type: Base, array: true}
|
8
|
+
|
4
9
|
def initialize(must:, must_not:, should: nil)
|
5
10
|
@must = Array(must)
|
6
11
|
@must_not = Array(must_not)
|
7
12
|
@should = Array(should)
|
13
|
+
validate!
|
8
14
|
end
|
9
15
|
|
10
16
|
def to_search
|
@@ -1,11 +1,18 @@
|
|
1
1
|
module Stretchy
|
2
2
|
module Filters
|
3
|
-
class GeoFilter
|
3
|
+
class GeoFilter < Base
|
4
|
+
|
5
|
+
contract distance: {type: :distance},
|
6
|
+
lat: {type: :lat},
|
7
|
+
lng: {type: :lng},
|
8
|
+
field: {type: :field}
|
9
|
+
|
4
10
|
def initialize(field: 'coords', distance: '50km', lat:, lng:)
|
5
11
|
@field = field
|
6
12
|
@distance = distance
|
7
13
|
@lat = lat
|
8
14
|
@lng = lng
|
15
|
+
validate!
|
9
16
|
end
|
10
17
|
|
11
18
|
def to_search
|
@@ -1,6 +1,8 @@
|
|
1
1
|
module Stretchy
|
2
2
|
module Filters
|
3
|
-
class NotFilter
|
3
|
+
class NotFilter < Base
|
4
|
+
|
5
|
+
contract :filter, type: Base
|
4
6
|
|
5
7
|
def initialize(filters)
|
6
8
|
filters = Array(filters)
|
@@ -10,6 +12,8 @@ module Stretchy
|
|
10
12
|
else
|
11
13
|
@filter = AndFilter.new(filters)
|
12
14
|
end
|
15
|
+
|
16
|
+
validate!
|
13
17
|
end
|
14
18
|
|
15
19
|
def to_search
|
@@ -1,10 +1,14 @@
|
|
1
1
|
module Stretchy
|
2
2
|
module Filters
|
3
|
-
class TermsFilter
|
3
|
+
class TermsFilter < Base
|
4
|
+
|
5
|
+
contract field: {type: :field},
|
6
|
+
values: {type: Array}
|
4
7
|
|
5
8
|
def initialize(field:, values:)
|
6
9
|
@field = field
|
7
10
|
@values = Array(values)
|
11
|
+
validate!
|
8
12
|
end
|
9
13
|
|
10
14
|
def to_search
|
@@ -1,10 +1,14 @@
|
|
1
1
|
module Stretchy
|
2
2
|
module Queries
|
3
|
-
class FilteredQuery
|
3
|
+
class FilteredQuery < Base
|
4
|
+
|
5
|
+
contract query: {type: Base},
|
6
|
+
filter: {type: Stretchy::Filters::Base}
|
4
7
|
|
5
8
|
def initialize(query: nil, filter:)
|
6
9
|
@query = query
|
7
10
|
@filter = filter
|
11
|
+
validate!
|
8
12
|
end
|
9
13
|
|
10
14
|
def to_search
|
@@ -1,10 +1,19 @@
|
|
1
1
|
module Stretchy
|
2
2
|
module Queries
|
3
|
-
class FunctionScoreQuery
|
3
|
+
class FunctionScoreQuery < Base
|
4
4
|
|
5
5
|
SCORE_MODES = %w(multiply sum avg first max min)
|
6
6
|
BOOST_MODES = %w(multiply replace sum avg max min)
|
7
7
|
|
8
|
+
contract functions: {responds_to: :to_search, array: true},
|
9
|
+
query: {type: Base},
|
10
|
+
filter: {type: Stretchy::Filters::Base},
|
11
|
+
score_mode: {type: String, in: SCORE_MODES},
|
12
|
+
boost_mode: {type: String, in: BOOST_MODES},
|
13
|
+
min_score: {type: Numeric},
|
14
|
+
max_boost: {type: Numeric},
|
15
|
+
boost: {type: Numeric}
|
16
|
+
|
8
17
|
def initialize(options = {})
|
9
18
|
@functions = Array(options[:functions])
|
10
19
|
@query = options[:query]
|
@@ -13,36 +22,17 @@ module Stretchy
|
|
13
22
|
self.class.attributes.map do |field|
|
14
23
|
instance_variable_set("@#{field}", options[field])
|
15
24
|
end
|
16
|
-
validate
|
25
|
+
validate!
|
26
|
+
validate_query_or_filter
|
17
27
|
end
|
18
28
|
|
19
29
|
def self.attributes
|
20
30
|
[:boost, :max_boost, :score_mode, :boost_mode, :min_score]
|
21
31
|
end
|
22
32
|
|
23
|
-
def
|
33
|
+
def validate_query_or_filter
|
24
34
|
if @query && @filter
|
25
|
-
raise
|
26
|
-
end
|
27
|
-
|
28
|
-
if @boost && !@boost.is_a?(Numeric)
|
29
|
-
raise ArgumentError.new("Boost must be a number - it is the global boost for the whole query")
|
30
|
-
end
|
31
|
-
|
32
|
-
if @max_boost && !@max_boost.is_a?(Numeric)
|
33
|
-
raise ArgumentError.new("Max boost must be a number")
|
34
|
-
end
|
35
|
-
|
36
|
-
if @min_score && !@min_score.is_a?(Numeric)
|
37
|
-
raise ArgumentError.new("min_score must be a number - it is the global boost for the whole query")
|
38
|
-
end
|
39
|
-
|
40
|
-
if @score_mode && !SCORE_MODES.include?(@score_mode)
|
41
|
-
raise ArgumentError.new("Score mode must be one of #{SCORE_MODES.join(', ')}")
|
42
|
-
end
|
43
|
-
|
44
|
-
if @boost_mode && !BOOST_MODES.include?(@boost_mode)
|
45
|
-
raise ArgumentError.new("Score mode must be one of #{BOOST_MODES.join(', ')}")
|
35
|
+
raise Stretchy::Errors::ContractError.new "Cannot have both query and filter -- combine using a FilteredQuery"
|
46
36
|
end
|
47
37
|
end
|
48
38
|
|
@@ -1,11 +1,18 @@
|
|
1
1
|
module Stretchy
|
2
2
|
module Queries
|
3
|
-
class MatchQuery
|
3
|
+
class MatchQuery < Base
|
4
|
+
|
5
|
+
OPERATORS = ['and', 'or']
|
6
|
+
|
7
|
+
contract field: {type: :field},
|
8
|
+
operator: {type: String, in: OPERATORS},
|
9
|
+
string: {type: String}
|
4
10
|
|
5
11
|
def initialize(string, field: '_all', operator: 'and')
|
6
12
|
@field = field
|
7
13
|
@operator = operator
|
8
14
|
@string = string
|
15
|
+
validate!
|
9
16
|
end
|
10
17
|
|
11
18
|
def to_search
|
data/lib/stretchy/query.rb
CHANGED
@@ -145,7 +145,7 @@ module Stretchy
|
|
145
145
|
end
|
146
146
|
|
147
147
|
def match(string, options = {})
|
148
|
-
return self if string.empty?
|
148
|
+
return self if string.nil? || string.empty?
|
149
149
|
field = options[:field] || '_all'
|
150
150
|
operator = options[:operator] || 'and'
|
151
151
|
clone_with(match: Queries::MatchQuery.new(string, field: field, operator: operator))
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'json'
|
2
|
+
module Stretchy
|
3
|
+
module Utils
|
4
|
+
module ClientActions
|
5
|
+
|
6
|
+
def self.extended(base)
|
7
|
+
unless base.respond_to?(:client) && base.respond_to?(:index_name)
|
8
|
+
raise "ClientActions requires methods 'client' and 'index_name'"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# used for ensuring a concistent index in specs
|
13
|
+
def refresh
|
14
|
+
client.indices.refresh index: index_name
|
15
|
+
end
|
16
|
+
|
17
|
+
def count
|
18
|
+
client.cat.count(index: index_name).split(' ')[2].to_i
|
19
|
+
end
|
20
|
+
|
21
|
+
def search(type:, body:, fields: nil)
|
22
|
+
options = { index: index_name, type: type, body: body }
|
23
|
+
options[:fields] = fields if fields.is_a?(Array)
|
24
|
+
|
25
|
+
client.search(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def index(type:, body:, id: nil)
|
29
|
+
id ||= body['id'] || body['_id'] || body[:id] || body[:_id]
|
30
|
+
client.index(index: index_name, type: type, id: id, body: body)
|
31
|
+
end
|
32
|
+
|
33
|
+
def bulk(type:, documents:)
|
34
|
+
requests = documents.flat_map do |document|
|
35
|
+
id = document['id'] || document['_id'] || document[:id] || document[:_id]
|
36
|
+
[
|
37
|
+
{ index: { '_index' => index_name, '_type' => type, '_id' => id } },
|
38
|
+
document
|
39
|
+
]
|
40
|
+
end
|
41
|
+
client.bulk body: requests
|
42
|
+
end
|
43
|
+
|
44
|
+
def exists(_index_name = index_name)
|
45
|
+
client.indices.exists(index: _index_name)
|
46
|
+
end
|
47
|
+
alias :exists? :exists
|
48
|
+
|
49
|
+
def delete(_index_name = index_name)
|
50
|
+
client.indices.delete(index: _index_name) if exists?(_index_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
def create(_index_name = index_name)
|
54
|
+
client.indices.create(index: _index_name) unless exists?(_index_name)
|
55
|
+
end
|
56
|
+
|
57
|
+
def mapping(_index_name, _type, _body)
|
58
|
+
client.indices.put_mapping(index: _index_name, type: _type, body: _body)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Utils
|
3
|
+
module Configuration
|
4
|
+
|
5
|
+
attr_accessor :index_name, :logger, :url, :adapter, :client
|
6
|
+
|
7
|
+
def self.extended(base)
|
8
|
+
base.set_default_configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
def configure
|
12
|
+
yield self
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_default_configuration
|
16
|
+
self.index_name = 'myapp'
|
17
|
+
self.adapter = :excon
|
18
|
+
self.url = ENV['ELASTICSEARCH_URL']
|
19
|
+
end
|
20
|
+
|
21
|
+
def client_options
|
22
|
+
Hash[
|
23
|
+
index_name: index_name,
|
24
|
+
log: !!logger,
|
25
|
+
logger: logger,
|
26
|
+
adapter: adapter,
|
27
|
+
url: url
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
def client(options = {})
|
32
|
+
@client ||= Elasticsearch::Client.new(client_options.merge(options))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module Stretchy
|
2
|
+
module Utils
|
3
|
+
module Contract
|
4
|
+
|
5
|
+
ASSERTIONS = [:type, :responds_to, :in, :matches, :required]
|
6
|
+
DISTANCE_FORMAT = /^(\d+)(km|mi)$/
|
7
|
+
|
8
|
+
def self.included(base)
|
9
|
+
base.send(:extend, ClassMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
def validate!
|
13
|
+
self.class.contracts.each do |name, options|
|
14
|
+
value = instance_variable_get("@#{name}")
|
15
|
+
next if value.nil? && !options[:required]
|
16
|
+
|
17
|
+
if options[:array]
|
18
|
+
self.class.assert_type(name, value, type: Array)
|
19
|
+
end
|
20
|
+
|
21
|
+
ASSERTIONS.each do |assertion|
|
22
|
+
assertion_method = "assert_#{assertion}"
|
23
|
+
if options[:array]
|
24
|
+
value.each {|v| self.class.send(assertion_method, name, v, options) } unless options[assertion].nil?
|
25
|
+
else
|
26
|
+
self.class.send(assertion_method, name, value, options) unless options[assertion].nil?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module ClassMethods
|
33
|
+
|
34
|
+
attr_reader :contracts
|
35
|
+
|
36
|
+
def contract(var, options = {})
|
37
|
+
@contracts ||= {}
|
38
|
+
if var.is_a?(Hash)
|
39
|
+
var.each {|k,v| @contracts[k] = v }
|
40
|
+
else
|
41
|
+
@contracts[var] = options
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def fail_assertion(msg)
|
46
|
+
raise Stretchy::Errors::ContractError.new(msg)
|
47
|
+
end
|
48
|
+
|
49
|
+
def assert_required(name, value, options)
|
50
|
+
msg = "Expected to have param #{name}, but got nil"
|
51
|
+
fail_assertion(msg) if msg.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def assert_type(name, value, options)
|
55
|
+
type = options[:type]
|
56
|
+
case type
|
57
|
+
when :distance
|
58
|
+
msg = "Expected #{name} to be a distance measure, but #{value} is not a valid distance"
|
59
|
+
fail_assertion(msg) unless value.match(DISTANCE_FORMAT)
|
60
|
+
when :lat
|
61
|
+
msg = "Expected #{name} to be between 90 and -90, but was #{value}"
|
62
|
+
value = Float(value) rescue nil
|
63
|
+
fail_assertion(msg) unless value && value <= 90 && value >= -90
|
64
|
+
when :lng
|
65
|
+
msg = "Expected #{name} to be between 180 and -180, but was #{value}"
|
66
|
+
value = Float(value) rescue nil
|
67
|
+
fail_assertion(msg) unless value && value.to_f <= 180 && value.to_f >= -180
|
68
|
+
when :field
|
69
|
+
msg = "Expected #{name} to be a string, symbol, or number, but got #{value.class.name}"
|
70
|
+
fail_assertion(msg) unless value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric)
|
71
|
+
|
72
|
+
msg = "Expected #{name} to be a string, symbol, or number, but was blank"
|
73
|
+
fail_assertion(msg) if value.is_a?(String) && value.empty?
|
74
|
+
else
|
75
|
+
msg = "Expected #{name} to be of type #{type}, but found #{value.class.name}"
|
76
|
+
fail_assertion(msg) unless value.is_a?(type)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def assert_responds_to(name, value, options)
|
81
|
+
method = options[:responds_to]
|
82
|
+
msg = "Expected #{name} to respond_to #{method}, but #{value.class.name} does not"
|
83
|
+
fail_assertion(msg) unless value.respond_to?(method)
|
84
|
+
end
|
85
|
+
|
86
|
+
def assert_in(name, value, options)
|
87
|
+
collection = options[:in]
|
88
|
+
msg = "Expected #{name} to be one of #{collection}, but got #{value}"
|
89
|
+
fail_assertion(msg) unless collection.include?(value)
|
90
|
+
end
|
91
|
+
|
92
|
+
def assert_matches(name, value, options)
|
93
|
+
matcher = options[:matches]
|
94
|
+
msg = "Expected #{name} to match #{matcher}, but #{value} does not"
|
95
|
+
fail_assertion(msg) unless matcher.match(value)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/stretchy/version.rb
CHANGED
data/lib/stretchy.rb
CHANGED
@@ -3,12 +3,20 @@ require 'logger'
|
|
3
3
|
require 'excon'
|
4
4
|
require 'elasticsearch'
|
5
5
|
|
6
|
+
require 'stretchy/utils/contract'
|
7
|
+
require 'stretchy/utils/configuration'
|
8
|
+
require 'stretchy/utils/client_actions'
|
9
|
+
require 'stretchy/boosts/base'
|
10
|
+
require 'stretchy/filters/base'
|
11
|
+
require 'stretchy/queries/base'
|
12
|
+
|
6
13
|
Dir[File.join(File.dirname(__FILE__), 'stretchy', '**', '*.rb')].each do |path|
|
7
|
-
require path
|
14
|
+
require path unless path =~ /utils/ || path =~ /base/
|
8
15
|
end
|
9
16
|
|
10
17
|
module Stretchy
|
11
|
-
|
12
|
-
extend
|
18
|
+
|
19
|
+
extend Utils::Configuration
|
20
|
+
extend Utils::ClientActions
|
13
21
|
|
14
22
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stretchy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- agius
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: elasticsearch
|
@@ -109,12 +109,13 @@ files:
|
|
109
109
|
- bin/console
|
110
110
|
- bin/setup
|
111
111
|
- lib/stretchy.rb
|
112
|
+
- lib/stretchy/boosts/base.rb
|
112
113
|
- lib/stretchy/boosts/filter_boost.rb
|
113
114
|
- lib/stretchy/boosts/geo_boost.rb
|
114
115
|
- lib/stretchy/boosts/random_boost.rb
|
115
|
-
- lib/stretchy/
|
116
|
-
- lib/stretchy/configuration.rb
|
116
|
+
- lib/stretchy/errors/contract_error.rb
|
117
117
|
- lib/stretchy/filters/and_filter.rb
|
118
|
+
- lib/stretchy/filters/base.rb
|
118
119
|
- lib/stretchy/filters/bool_filter.rb
|
119
120
|
- lib/stretchy/filters/exists_filter.rb
|
120
121
|
- lib/stretchy/filters/geo_filter.rb
|
@@ -123,12 +124,16 @@ files:
|
|
123
124
|
- lib/stretchy/filters/range_filter.rb
|
124
125
|
- lib/stretchy/filters/terms_filter.rb
|
125
126
|
- lib/stretchy/null_query.rb
|
127
|
+
- lib/stretchy/queries/base.rb
|
126
128
|
- lib/stretchy/queries/filtered_query.rb
|
127
129
|
- lib/stretchy/queries/function_score_query.rb
|
128
130
|
- lib/stretchy/queries/match_all_query.rb
|
129
131
|
- lib/stretchy/queries/match_query.rb
|
130
132
|
- lib/stretchy/query.rb
|
131
133
|
- lib/stretchy/request_body.rb
|
134
|
+
- lib/stretchy/utils/client_actions.rb
|
135
|
+
- lib/stretchy/utils/configuration.rb
|
136
|
+
- lib/stretchy/utils/contract.rb
|
132
137
|
- lib/stretchy/version.rb
|
133
138
|
- stretchy.gemspec
|
134
139
|
homepage: https://github.com/hired/stretchy
|
@@ -1,61 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
module Stretchy
|
3
|
-
module ClientActions
|
4
|
-
|
5
|
-
def self.extended(base)
|
6
|
-
unless base.respond_to?(:client) && base.respond_to?(:index_name)
|
7
|
-
raise "ClientActions requires methods 'client' and 'index_name'"
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
# used for ensuring a concistent index in specs
|
12
|
-
def refresh
|
13
|
-
client.indices.refresh index: index_name
|
14
|
-
end
|
15
|
-
|
16
|
-
def count
|
17
|
-
client.cat.count(index: index_name).split(' ')[2].to_i
|
18
|
-
end
|
19
|
-
|
20
|
-
def search(type:, body:, fields: nil)
|
21
|
-
options = { index: index_name, type: type, body: body }
|
22
|
-
options[:fields] = fields if fields.is_a?(Array)
|
23
|
-
|
24
|
-
client.search(options)
|
25
|
-
end
|
26
|
-
|
27
|
-
def index(type:, body:, id: nil)
|
28
|
-
id ||= body['id'] || body['_id'] || body[:id] || body[:_id]
|
29
|
-
client.index(index: index_name, type: type, id: id, body: body)
|
30
|
-
end
|
31
|
-
|
32
|
-
def bulk(type:, documents:)
|
33
|
-
requests = documents.flat_map do |document|
|
34
|
-
id = document['id'] || document['_id'] || document[:id] || document[:_id]
|
35
|
-
[
|
36
|
-
{ index: { '_index' => index_name, '_type' => type, '_id' => id } },
|
37
|
-
document
|
38
|
-
]
|
39
|
-
end
|
40
|
-
client.bulk body: requests
|
41
|
-
end
|
42
|
-
|
43
|
-
def exists(_index_name = index_name)
|
44
|
-
client.indices.exists(index: _index_name)
|
45
|
-
end
|
46
|
-
alias :exists? :exists
|
47
|
-
|
48
|
-
def delete(_index_name = index_name)
|
49
|
-
client.indices.delete(index: _index_name) if exists?(_index_name)
|
50
|
-
end
|
51
|
-
|
52
|
-
def create(_index_name = index_name)
|
53
|
-
client.indices.create(index: _index_name) unless exists?(_index_name)
|
54
|
-
end
|
55
|
-
|
56
|
-
def mapping(_index_name, _type, _body)
|
57
|
-
client.indices.put_mapping(index: _index_name, type: _type, body: _body)
|
58
|
-
end
|
59
|
-
|
60
|
-
end
|
61
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Stretchy
|
2
|
-
module Configuration
|
3
|
-
|
4
|
-
attr_accessor :index_name, :logger, :url, :adapter, :client
|
5
|
-
|
6
|
-
def self.extended(base)
|
7
|
-
base.set_default_configuration
|
8
|
-
end
|
9
|
-
|
10
|
-
def configure
|
11
|
-
yield self
|
12
|
-
end
|
13
|
-
|
14
|
-
def set_default_configuration
|
15
|
-
self.index_name = 'myapp'
|
16
|
-
self.adapter = :excon
|
17
|
-
self.url = ENV['ELASTICSEARCH_URL']
|
18
|
-
end
|
19
|
-
|
20
|
-
def client_options
|
21
|
-
Hash[
|
22
|
-
index_name: index_name,
|
23
|
-
log: !!logger,
|
24
|
-
logger: logger,
|
25
|
-
adapter: adapter,
|
26
|
-
url: url
|
27
|
-
]
|
28
|
-
end
|
29
|
-
|
30
|
-
def client(options = {})
|
31
|
-
@client ||= Elasticsearch::Client.new(client_options.merge(options))
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|