eagle_search 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Rakefile +1 -0
- data/lib/eagle_search/field.rb +54 -0
- data/lib/eagle_search/index.rb +121 -0
- data/lib/eagle_search/interpreter/filter.rb +55 -0
- data/lib/eagle_search/interpreter/query.rb +112 -0
- data/lib/eagle_search/interpreter.rb +56 -0
- data/lib/eagle_search/model.rb +62 -0
- data/lib/eagle_search/response.rb +44 -0
- data/lib/eagle_search/version.rb +3 -0
- data/lib/eagle_search.rb +25 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 95f2c540d8392becd307b86370b410a014938ad8
|
4
|
+
data.tar.gz: 08278f066fe793bf2d8e13bcc41830d5b19dbb6d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0f63b0ca08028e9fd056220efa3731aaf6a902bc5152b2ec6f73887bdb1fecfc75f4e809bfd16ce5fb1846a86799cba7d2fc549be88274d30c4a20b569e1e6ed
|
7
|
+
data.tar.gz: b460acef98b7274ae245c4c8f75f565d07d7e710d8c1726bb35e35d0e9c80bf405f3d7c8b6e317c4cd248c0e8293dbabd42d52ededec6ff2c925679827ea534d
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module EagleSearch
|
2
|
+
class Field
|
3
|
+
def initialize(index, column)
|
4
|
+
@index = index
|
5
|
+
@column = column
|
6
|
+
end
|
7
|
+
|
8
|
+
def mapping
|
9
|
+
mapping = { type: type }
|
10
|
+
index_settings = @index.settings
|
11
|
+
|
12
|
+
if index_settings[:unsearchable_fields] && (index_settings[:unsearchable_fields].include?(@column.name) || index_settings[:unsearchable_fields].include?(@column.name.to_sym))
|
13
|
+
mapping[:index] = "no"
|
14
|
+
else
|
15
|
+
if type == "string"
|
16
|
+
if index_settings[:exact_match_fields] && (index_settings[:exact_match_fields].include?(@column.name) || index_settings[:exact_match_fields].include?(@column.name.to_sym))
|
17
|
+
mapping[:index] = "not_analyzed"
|
18
|
+
else
|
19
|
+
mapping[:index] = "analyzed"
|
20
|
+
mapping[:analyzer] = index_settings[:language] || "english"
|
21
|
+
mapping[:fields] = {
|
22
|
+
shingle: {
|
23
|
+
type: "string",
|
24
|
+
analyzer: "eagle_search_shingle_analyzer"
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
mapping
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def type
|
36
|
+
case @column.type
|
37
|
+
when :integer
|
38
|
+
if @column.limit.to_i <= 8
|
39
|
+
"integer"
|
40
|
+
else
|
41
|
+
"long"
|
42
|
+
end
|
43
|
+
when :date, :datetime
|
44
|
+
"date"
|
45
|
+
when :boolean
|
46
|
+
"boolean"
|
47
|
+
when :decimal, :float
|
48
|
+
"float"
|
49
|
+
else
|
50
|
+
"string"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module EagleSearch
|
4
|
+
class Index
|
5
|
+
attr_reader :settings, :alias_name
|
6
|
+
delegate :columns, to: :klass
|
7
|
+
|
8
|
+
def initialize(klass, settings)
|
9
|
+
@klass = klass
|
10
|
+
@settings = settings
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
EagleSearch.client.indices.create index: name, body: body
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete
|
18
|
+
EagleSearch.client.indices.delete index: alias_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def refresh
|
22
|
+
EagleSearch.client.indices.refresh index: alias_name
|
23
|
+
end
|
24
|
+
|
25
|
+
def info
|
26
|
+
EagleSearch.client.indices.get index: alias_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def name
|
30
|
+
@name ||= @settings[:index_name] || "#{ alias_name }_#{ DateTime.now.strftime('%Q') }"
|
31
|
+
end
|
32
|
+
|
33
|
+
def alias_name
|
34
|
+
@alias_name ||= @settings[:index_name] || "#{ @klass.model_name.route_key.downcase }_#{ EagleSearch.env }"
|
35
|
+
end
|
36
|
+
|
37
|
+
def type_name
|
38
|
+
if @settings[:mappings]
|
39
|
+
@settings[:mappings].keys.first.downcase
|
40
|
+
else
|
41
|
+
@klass.model_name.param_key
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def reindex
|
46
|
+
client = EagleSearch.client
|
47
|
+
begin
|
48
|
+
aliases = client.indices.get_alias name: alias_name
|
49
|
+
client.indices.delete index: aliases.keys.join(",")
|
50
|
+
rescue
|
51
|
+
#do something
|
52
|
+
ensure
|
53
|
+
create
|
54
|
+
bulk = []
|
55
|
+
@klass.all.each do |record|
|
56
|
+
bulk << { index: { _index: alias_name, _type: type_name, _id: record.id } }
|
57
|
+
bulk << record.index_data
|
58
|
+
end
|
59
|
+
client.bulk body: bulk
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def mappings
|
64
|
+
if @settings[:mappings]
|
65
|
+
@settings[:mappings]
|
66
|
+
else
|
67
|
+
base_mappings = {
|
68
|
+
type_name => {
|
69
|
+
properties: {}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
columns.each do |column|
|
74
|
+
base_mappings[type_name][:properties][column.name] = EagleSearch::Field.new(self, column).mapping
|
75
|
+
end
|
76
|
+
|
77
|
+
base_mappings
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
def body
|
83
|
+
body = {
|
84
|
+
mappings: mappings,
|
85
|
+
aliases: { alias_name => {} },
|
86
|
+
settings: {
|
87
|
+
analysis: analysis_settings
|
88
|
+
}
|
89
|
+
}
|
90
|
+
body[:settings][:number_of_shards] = 1 if EagleSearch.env == "test" || EagleSearch.env == "development"
|
91
|
+
body
|
92
|
+
end
|
93
|
+
|
94
|
+
def analysis_settings
|
95
|
+
{
|
96
|
+
filter: {
|
97
|
+
eagle_search_shingle_filter: {
|
98
|
+
type: "shingle",
|
99
|
+
min_shingle_size: 2,
|
100
|
+
max_shingle_size: 2,
|
101
|
+
output_unigrams: false
|
102
|
+
}
|
103
|
+
},
|
104
|
+
analyzer: {
|
105
|
+
eagle_search_shingle_analyzer: {
|
106
|
+
type: "custom",
|
107
|
+
tokenizer: "standard",
|
108
|
+
filter: [
|
109
|
+
"lowercase",
|
110
|
+
"eagle_search_shingle_filter"
|
111
|
+
]
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def klass
|
118
|
+
@klass
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module EagleSearch
|
2
|
+
class Interpreter::Filter
|
3
|
+
attr_reader :payload
|
4
|
+
|
5
|
+
LOGICAL_OPERATORS = { and: :must, not: :must_not, or: :should }
|
6
|
+
|
7
|
+
def initialize(filters)
|
8
|
+
@filters = filters
|
9
|
+
end
|
10
|
+
|
11
|
+
def payload
|
12
|
+
@payload ||= generate_payload(@filters)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def generate_payload(filters)
|
17
|
+
payload = {}
|
18
|
+
|
19
|
+
filters.each do |key, value|
|
20
|
+
key = key.to_sym
|
21
|
+
|
22
|
+
if LOGICAL_OPERATORS.include?(key)
|
23
|
+
payload = { bool: { LOGICAL_OPERATORS[key] => [] } }
|
24
|
+
|
25
|
+
if value.is_a?(Array)
|
26
|
+
value.each { |filter| payload[:bool][LOGICAL_OPERATORS[key]] << generate_payload(filter) }
|
27
|
+
else
|
28
|
+
value.each { |field, field_value| payload[:bool][LOGICAL_OPERATORS[key]] << generate_payload({ field => field_value }) }
|
29
|
+
end
|
30
|
+
else
|
31
|
+
payload = elasticsearch_filter_hash(key, value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
payload
|
36
|
+
end
|
37
|
+
|
38
|
+
def elasticsearch_filter_hash(field, field_value)
|
39
|
+
case field_value
|
40
|
+
when Array
|
41
|
+
{ terms: { field => field_value } }
|
42
|
+
when Hash
|
43
|
+
if field_value.keys.any? { |key| %i(lt gt lte gte).include?(key.to_sym) }
|
44
|
+
{ range: { field => field_value } }
|
45
|
+
end
|
46
|
+
when Range
|
47
|
+
{ range: { field => { gte: field_value.min, lte: field_value.max } } }
|
48
|
+
when Regexp
|
49
|
+
{ regexp: { field => field_value.source } }
|
50
|
+
else
|
51
|
+
{ term: { field => field_value } }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module EagleSearch
|
2
|
+
class Interpreter::Query
|
3
|
+
|
4
|
+
def initialize(index, query, options)
|
5
|
+
@index = index
|
6
|
+
@query = query
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def payload
|
11
|
+
case @query
|
12
|
+
when String
|
13
|
+
if @query == "*"
|
14
|
+
{ match_all: {} }
|
15
|
+
else
|
16
|
+
query_payload
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def properties
|
23
|
+
@index.mappings[@index.type_name][:properties]
|
24
|
+
end
|
25
|
+
|
26
|
+
def analyzed_properties
|
27
|
+
properties.select { |field_name, field_hash| field_hash[:type] == "string" && field_hash[:index] == "analyzed" }
|
28
|
+
end
|
29
|
+
|
30
|
+
def not_analyzed_properties
|
31
|
+
properties.select { |field_name, field_hash| field_hash[:type] == "string" && field_hash[:index] == "not_analyzed" }
|
32
|
+
end
|
33
|
+
|
34
|
+
def query_payload
|
35
|
+
@query_payload = {}
|
36
|
+
build_multi_match_query
|
37
|
+
build_match_queries
|
38
|
+
build_term_queries
|
39
|
+
@query_payload
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_multi_match_query
|
43
|
+
if analyzed_properties
|
44
|
+
@query_payload = {
|
45
|
+
bool: {
|
46
|
+
should: []
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
@query_payload[:bool][:should] << {
|
51
|
+
multi_match: {
|
52
|
+
query: @query,
|
53
|
+
fields: @options[:fields] || analyzed_properties.keys,
|
54
|
+
tie_breaker: 0.3
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def build_match_queries
|
61
|
+
return unless analyzed_properties
|
62
|
+
|
63
|
+
match_queries = []
|
64
|
+
analyzed_properties.keys.each do |field_name|
|
65
|
+
match_queries << {
|
66
|
+
match: {
|
67
|
+
"#{ field_name }.shingle" => {
|
68
|
+
query: @query,
|
69
|
+
boost: 3
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
payload = {
|
76
|
+
bool: {
|
77
|
+
should: match_queries
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
@query_payload[:bool] ? @query_payload[:bool][:should] << payload : @query_payload[:bool][:should] = payload
|
82
|
+
end
|
83
|
+
|
84
|
+
def build_term_queries
|
85
|
+
return unless not_analyzed_properties
|
86
|
+
|
87
|
+
term_queries = []
|
88
|
+
not_analyzed_properties.keys.each do |field_name|
|
89
|
+
term_queries << {
|
90
|
+
term: {
|
91
|
+
field_name => {
|
92
|
+
value: @query,
|
93
|
+
boost: 5
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
payload = {
|
100
|
+
bool: {
|
101
|
+
should: term_queries
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
if @query_payload[:bool]
|
106
|
+
@query_payload[:bool][:should][1][:bool][:should] << payload
|
107
|
+
else
|
108
|
+
@query_payload = payload
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module EagleSearch
|
2
|
+
class Interpreter
|
3
|
+
def initialize(index, query, options)
|
4
|
+
@index = index
|
5
|
+
@query = query
|
6
|
+
@options = options
|
7
|
+
@options[:page] = @options[:page].to_i if @options[:page]
|
8
|
+
@options[:per_page] = @options[:per_page].to_i if @options[:per_page]
|
9
|
+
end
|
10
|
+
|
11
|
+
def payload
|
12
|
+
return @options[:custom_payload] if @options[:custom_payload]
|
13
|
+
|
14
|
+
payload = {
|
15
|
+
query: {
|
16
|
+
filtered: {
|
17
|
+
query: query_payload,
|
18
|
+
filter: filter_payload
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
payload.merge!({ sort: @options[:sort] }) if @options[:sort]
|
24
|
+
|
25
|
+
# from
|
26
|
+
if @options[:page] && @options[:page] > 1
|
27
|
+
from = (@options[:page] - 1) * (@options[:per_page] || 10)
|
28
|
+
payload.merge!({ from: from })
|
29
|
+
end
|
30
|
+
|
31
|
+
#size
|
32
|
+
payload.merge!({ size: @options[:per_page] }) if @options[:per_page]
|
33
|
+
|
34
|
+
payload
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def query_payload
|
39
|
+
if @options[:custom_query]
|
40
|
+
@options[:custom_query]
|
41
|
+
else
|
42
|
+
EagleSearch::Interpreter::Query.new(@index, @query, @options).payload
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def filter_payload
|
47
|
+
if @options[:filters]
|
48
|
+
EagleSearch::Interpreter::Filter.new(@options[:filters]).payload
|
49
|
+
elsif @options[:custom_filters]
|
50
|
+
@options[:custom_filters]
|
51
|
+
else
|
52
|
+
{}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module EagleSearch
|
2
|
+
class Model
|
3
|
+
module ClassMethods
|
4
|
+
def eagle_search(settings = {})
|
5
|
+
@index = EagleSearch::Index.new(self, settings)
|
6
|
+
end
|
7
|
+
|
8
|
+
def eagle_search_index
|
9
|
+
@index
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_index
|
13
|
+
eagle_search_index.create
|
14
|
+
end
|
15
|
+
|
16
|
+
def delete_index
|
17
|
+
eagle_search_index.delete
|
18
|
+
end
|
19
|
+
|
20
|
+
def refresh_index
|
21
|
+
eagle_search_index.refresh
|
22
|
+
end
|
23
|
+
|
24
|
+
def index_info
|
25
|
+
eagle_search_index.info
|
26
|
+
end
|
27
|
+
|
28
|
+
def search(term, options = {})
|
29
|
+
interpreter = EagleSearch::Interpreter.new(@index, term, options)
|
30
|
+
search_response = EagleSearch.client.search index: eagle_search_index.alias_name, body: interpreter.payload
|
31
|
+
EagleSearch::Response.new(self, search_response, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def reindex
|
35
|
+
eagle_search_index.reindex
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module InstanceMethods
|
40
|
+
def reindex
|
41
|
+
index = self.class.eagle_search_index
|
42
|
+
reindex_option = index.settings[:reindex]
|
43
|
+
|
44
|
+
if reindex_option.nil? || reindex_option
|
45
|
+
begin
|
46
|
+
index.info
|
47
|
+
rescue Elasticsearch::Transport::Transport::Errors::NotFound
|
48
|
+
index.create
|
49
|
+
ensure
|
50
|
+
index.refresh
|
51
|
+
EagleSearch.client.index(
|
52
|
+
index: index.alias_name,
|
53
|
+
type: index.type_name,
|
54
|
+
id: id,
|
55
|
+
body: index_data
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module EagleSearch
|
2
|
+
class Response
|
3
|
+
def initialize(klass, response, options)
|
4
|
+
@klass = klass
|
5
|
+
@response = response
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def records
|
10
|
+
ids = hits.map { |hit| hit["_id"] }
|
11
|
+
#avoids n+1
|
12
|
+
@klass.includes(@options[:includes]) if @options[:includes]
|
13
|
+
@klass.where(@klass.primary_key => ids)
|
14
|
+
end
|
15
|
+
|
16
|
+
def each
|
17
|
+
if block_given?
|
18
|
+
records.each { |e| yield(e) }
|
19
|
+
else
|
20
|
+
records.to_enum
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def total_hits
|
25
|
+
@response["hits"]["total"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def hits
|
29
|
+
@response["hits"]["hits"]
|
30
|
+
end
|
31
|
+
|
32
|
+
def current_page
|
33
|
+
@options[:page] || 1
|
34
|
+
end
|
35
|
+
|
36
|
+
def total_pages
|
37
|
+
(total_hits / limit_value.to_f).ceil
|
38
|
+
end
|
39
|
+
|
40
|
+
def limit_value
|
41
|
+
@options[:per_page] || 25
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/eagle_search.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "eagle_search/version"
|
2
|
+
require "eagle_search/model"
|
3
|
+
require "eagle_search/index"
|
4
|
+
require "eagle_search/field"
|
5
|
+
require "eagle_search/response"
|
6
|
+
require "eagle_search/interpreter"
|
7
|
+
require "eagle_search/interpreter/query"
|
8
|
+
require "eagle_search/interpreter/filter"
|
9
|
+
require "elasticsearch"
|
10
|
+
|
11
|
+
module EagleSearch
|
12
|
+
def self.included(base)
|
13
|
+
base.extend(EagleSearch::Model::ClassMethods)
|
14
|
+
base.include(EagleSearch::Model::InstanceMethods)
|
15
|
+
base.after_commit :reindex, on: [:create, :update]
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.client
|
19
|
+
@client ||= Elasticsearch::Client.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.env
|
23
|
+
@env ||= ENV['RAILS_ENV'] || "development"
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,138 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: eagle_search
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Igor Belo
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-11-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: elasticsearch
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activerecord
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.2'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.10'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.10'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.3'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.3'
|
97
|
+
description: Rails Model integration for Elasticsearch.
|
98
|
+
email:
|
99
|
+
- igorcoura@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- Rakefile
|
105
|
+
- lib/eagle_search.rb
|
106
|
+
- lib/eagle_search/field.rb
|
107
|
+
- lib/eagle_search/index.rb
|
108
|
+
- lib/eagle_search/interpreter.rb
|
109
|
+
- lib/eagle_search/interpreter/filter.rb
|
110
|
+
- lib/eagle_search/interpreter/query.rb
|
111
|
+
- lib/eagle_search/model.rb
|
112
|
+
- lib/eagle_search/response.rb
|
113
|
+
- lib/eagle_search/version.rb
|
114
|
+
homepage: https://github.com/igorbelo/eagle_search
|
115
|
+
licenses:
|
116
|
+
- MIT
|
117
|
+
metadata: {}
|
118
|
+
post_install_message:
|
119
|
+
rdoc_options: []
|
120
|
+
require_paths:
|
121
|
+
- lib
|
122
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
requirements: []
|
133
|
+
rubyforge_project:
|
134
|
+
rubygems_version: 2.4.6
|
135
|
+
signing_key:
|
136
|
+
specification_version: 4
|
137
|
+
summary: Rails Model integration for Elasticsearch.
|
138
|
+
test_files: []
|