index-tanked 0.6.0 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +15 -3
- data/lib/index-tanked.rb +1 -1
- data/lib/index-tanked/active_record_defaults/queue/worker.rb +1 -1
- data/lib/index-tanked/class_companion.rb +1 -1
- data/lib/index-tanked/indextank/client.rb +55 -0
- data/lib/index-tanked/indextank/document.rb +89 -0
- data/lib/index-tanked/indextank/exceptions.rb +13 -0
- data/lib/index-tanked/indextank/function.rb +46 -0
- data/lib/index-tanked/indextank/index.rb +341 -0
- data/lib/index-tanked/indextank/indextank.rb +24 -0
- data/lib/index-tanked/search_result.rb +1 -1
- data/lib/index-tanked/version.rb +1 -1
- metadata +93 -32
data/Rakefile
CHANGED
@@ -13,10 +13,22 @@ task :default => :test
|
|
13
13
|
require 'rdoc/task'
|
14
14
|
|
15
15
|
Rake::RDocTask.new do |rdoc|
|
16
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
17
|
-
|
18
16
|
rdoc.rdoc_dir = 'rdoc'
|
19
|
-
rdoc.title = "
|
17
|
+
rdoc.title = "index-tanked"
|
20
18
|
rdoc.rdoc_files.include('README*')
|
21
19
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
22
20
|
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
require 'rcov/rcovtask'
|
24
|
+
Rcov::RcovTask.new do |test|
|
25
|
+
test.libs << 'test'
|
26
|
+
test.pattern = 'test/**/*_test.rb'
|
27
|
+
test.verbose = true
|
28
|
+
test.rcov_opts << '--exclude "gems/*"'
|
29
|
+
end
|
30
|
+
rescue LoadError
|
31
|
+
task :rcov do
|
32
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install rcov"
|
33
|
+
end
|
34
|
+
end
|
data/lib/index-tanked.rb
CHANGED
@@ -65,7 +65,7 @@ module IndexTanked
|
|
65
65
|
begin
|
66
66
|
this_batch = partitioned_documents[companion_key]
|
67
67
|
Queue::Document.index_tanked(companion_key).index.batch_insert(this_batch)
|
68
|
-
rescue IndexTank::InvalidArgument => e
|
68
|
+
rescue IndexTanked::IndexTank::InvalidArgument => e
|
69
69
|
bad_document_number = e.message.scan(/in document #(\d+) of \d+/).flatten.first
|
70
70
|
bad_document_number = bad_document_number && (bad_document_number.to_i - 1)
|
71
71
|
if bad_document_number
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'index-tanked/indextank/index'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module IndexTanked
|
5
|
+
module IndexTank
|
6
|
+
class Client
|
7
|
+
attr_reader :uri
|
8
|
+
|
9
|
+
def initialize(api_url)
|
10
|
+
@uri = api_url
|
11
|
+
@conn = IndexTanked::IndexTank.setup_connection(api_url) do |faraday|
|
12
|
+
faraday.use ClientResponseMiddleware
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def indexes(name = nil)
|
17
|
+
if name.nil?
|
18
|
+
list_indexes
|
19
|
+
else
|
20
|
+
get_index(name)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
def list_indexes
|
26
|
+
indexes = Hash.new
|
27
|
+
|
28
|
+
@conn.get("/v1/indexes").body.each do |name, metadata|
|
29
|
+
indexes[name] = Index.new("#{@uri}/v1/indexes/#{name}", metadata)
|
30
|
+
end
|
31
|
+
|
32
|
+
indexes
|
33
|
+
end
|
34
|
+
|
35
|
+
def get_index(name)
|
36
|
+
Index.new("#{@uri}/v1/indexes/#{name}")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class ClientResponseMiddleware < FaradayMiddleware::ResponseMiddleware
|
41
|
+
def process_response(env)
|
42
|
+
case env[:status]
|
43
|
+
when 200
|
44
|
+
nil # this is the expected return code
|
45
|
+
when 204
|
46
|
+
nil # this is the expected return code for empty responses
|
47
|
+
when 401
|
48
|
+
raise InvalidApiKey
|
49
|
+
else
|
50
|
+
raise UnexpectedHTTPException, env[:body]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'yajl/json_gem'
|
2
|
+
require 'faraday'
|
3
|
+
|
4
|
+
module IndexTanked
|
5
|
+
module IndexTank
|
6
|
+
class Document
|
7
|
+
attr_reader :docid
|
8
|
+
|
9
|
+
# :docid => a String or Symbol, that is no longer than 1024 bytes when UTF-8 encoded
|
10
|
+
def initialize(document_url, docid)
|
11
|
+
raise InvalidArgument , "docid too long. max is 1024 bytes and got #{String(docid).bytesize}" unless String(docid).bytesize <= 1024
|
12
|
+
@docid = docid
|
13
|
+
@conn = IndexTanked::IndexTank.setup_connection(document_url) do |faraday|
|
14
|
+
faraday.use DocumentResponseMiddleware
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# the options argument may contain a :variables key
|
19
|
+
# with a Hash from variable numbers to their float values
|
20
|
+
# this variables can be used in the scoring functions
|
21
|
+
# when sorting a search
|
22
|
+
def add(fields, options = {})
|
23
|
+
options.merge!(:docid => self.docid, :fields => fields)
|
24
|
+
|
25
|
+
resp = @conn.put do |req|
|
26
|
+
req.url ""
|
27
|
+
req.body = options.to_json
|
28
|
+
end
|
29
|
+
|
30
|
+
resp.status
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete(options = {})
|
34
|
+
options.merge!(:docid => self.docid)
|
35
|
+
resp = @conn.delete do |req|
|
36
|
+
req.url ""
|
37
|
+
req.body = options.to_json
|
38
|
+
end
|
39
|
+
|
40
|
+
resp.status
|
41
|
+
end
|
42
|
+
|
43
|
+
def update_variables(variables, options = {})
|
44
|
+
options.merge!(:docid => self.docid, :variables => variables)
|
45
|
+
resp = @conn.put do |req|
|
46
|
+
req.url "variables"
|
47
|
+
req.body = options.to_json
|
48
|
+
end
|
49
|
+
|
50
|
+
resp.status
|
51
|
+
end
|
52
|
+
|
53
|
+
# updates the categories of a given document
|
54
|
+
# the categories argument should be a Hash from string
|
55
|
+
# to string defining the value for each category defined
|
56
|
+
# by this document.
|
57
|
+
def update_categories(categories, options = {} )
|
58
|
+
options.merge!(:docid => self.docid, :categories => categories)
|
59
|
+
resp = @conn.put do |req|
|
60
|
+
req.url "categories"
|
61
|
+
req.body = options.to_json
|
62
|
+
end
|
63
|
+
|
64
|
+
resp.status
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class DocumentResponseMiddleware < FaradayMiddleware::ResponseMiddleware
|
69
|
+
def process_response(env)
|
70
|
+
case env[:status]
|
71
|
+
when 200
|
72
|
+
nil # this is the expected code
|
73
|
+
when 204
|
74
|
+
nil # this is another expected code, for empty responses
|
75
|
+
when 401
|
76
|
+
raise InvalidApiKey
|
77
|
+
when 409
|
78
|
+
raise IndexInitializing
|
79
|
+
when 404
|
80
|
+
raise NonExistentIndex
|
81
|
+
when 400
|
82
|
+
raise InvalidArgument, env[:body]
|
83
|
+
else
|
84
|
+
raise UnexpectedHTTPException, env[:body]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module IndexTanked
|
2
|
+
module IndexTank
|
3
|
+
class IndexAlreadyExists < StandardError; end
|
4
|
+
class NonExistentIndex < StandardError; end
|
5
|
+
class TooManyIndexes < StandardError; end
|
6
|
+
class MissingFunctionDefinition < StandardError; end
|
7
|
+
class InvalidApiKey < StandardError; end
|
8
|
+
class InvalidQuery < StandardError; end
|
9
|
+
class IndexInitializing < StandardError; end
|
10
|
+
class InvalidArgument < StandardError; end
|
11
|
+
class UnexpectedHTTPException < StandardError; end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'yajl/json_gem'
|
2
|
+
|
3
|
+
module IndexTanked
|
4
|
+
module IndexTank
|
5
|
+
class Function
|
6
|
+
attr_reader :uri, :index, :definition
|
7
|
+
|
8
|
+
def initialize(function_url, index, definition)
|
9
|
+
@uri = "#{function_url}/#{index}"
|
10
|
+
@index = index
|
11
|
+
@definition = definition
|
12
|
+
@conn = IndexTanked::IndexTank.setup_connection(@uri) do |faraday|
|
13
|
+
# Function and Document have the same Response statuses
|
14
|
+
faraday.use IndexTanked::IndexTank::DocumentResponseMiddleware
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(options = {})
|
19
|
+
raise MissingFunctionDefinition unless self.definition
|
20
|
+
|
21
|
+
options.merge!(:definition => self.definition)
|
22
|
+
response = @conn.put do |req|
|
23
|
+
req.url ''
|
24
|
+
req.body = options.to_json
|
25
|
+
end
|
26
|
+
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete(options = {})
|
31
|
+
resp = @conn.delete do |req|
|
32
|
+
req.url ''
|
33
|
+
req.body = options.to_json
|
34
|
+
end
|
35
|
+
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
def ==(other)
|
40
|
+
self.uri == other.uri and
|
41
|
+
self.index == other.index
|
42
|
+
self.definition == other.definition
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,341 @@
|
|
1
|
+
require 'index-tanked/indextank/exceptions'
|
2
|
+
require 'index-tanked/indextank/document'
|
3
|
+
require 'index-tanked/indextank/function'
|
4
|
+
require 'yajl/json_gem'
|
5
|
+
|
6
|
+
module IndexTanked
|
7
|
+
module IndexTank
|
8
|
+
class Index
|
9
|
+
def initialize(index_url, metadata = nil)
|
10
|
+
@uri = index_url
|
11
|
+
@conn = IndexTanked::IndexTank.setup_connection(index_url)
|
12
|
+
@metadata = metadata
|
13
|
+
end
|
14
|
+
|
15
|
+
def add( options = {} )
|
16
|
+
|
17
|
+
if self.exists?
|
18
|
+
raise IndexAlreadyExists
|
19
|
+
end
|
20
|
+
|
21
|
+
response = @conn.put do |req|
|
22
|
+
req.url ""
|
23
|
+
req.body = options.to_json unless options.length == 0
|
24
|
+
end
|
25
|
+
case response.status
|
26
|
+
when 201
|
27
|
+
true
|
28
|
+
when 409
|
29
|
+
raise TooManyIndexes
|
30
|
+
when 401
|
31
|
+
raise InvalidApiKey
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def update( options )
|
36
|
+
|
37
|
+
if not self.exists?
|
38
|
+
raise NonExistentIndex
|
39
|
+
end
|
40
|
+
|
41
|
+
response = @conn.put do |req|
|
42
|
+
req.url ""
|
43
|
+
req.body = options.to_json
|
44
|
+
end
|
45
|
+
case response.status
|
46
|
+
when 204
|
47
|
+
true
|
48
|
+
when 401
|
49
|
+
raise InvalidApiKey
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def refresh
|
54
|
+
response = @conn.get('')
|
55
|
+
if response.status == 200
|
56
|
+
@metadata = response.body
|
57
|
+
end
|
58
|
+
|
59
|
+
response
|
60
|
+
end
|
61
|
+
|
62
|
+
def delete
|
63
|
+
response = @conn.delete('')
|
64
|
+
case response.status
|
65
|
+
when 204
|
66
|
+
raise NonExistentIndex
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def running?
|
71
|
+
refresh
|
72
|
+
@metadata['started']
|
73
|
+
end
|
74
|
+
|
75
|
+
def method_missing(sym, *args, &block)
|
76
|
+
refresh if @metadata.nil?
|
77
|
+
@metadata[sym.to_s]
|
78
|
+
end
|
79
|
+
|
80
|
+
def exists?
|
81
|
+
refresh.status != 404
|
82
|
+
end
|
83
|
+
|
84
|
+
def public_search_enabled?
|
85
|
+
refresh
|
86
|
+
@metadata['public_search']
|
87
|
+
end
|
88
|
+
|
89
|
+
def batch_insert(documents)
|
90
|
+
resp = @conn.put do |req|
|
91
|
+
req.url "docs"
|
92
|
+
req.body = documents.to_json
|
93
|
+
end
|
94
|
+
case resp.status
|
95
|
+
when 200
|
96
|
+
resp.body
|
97
|
+
when 401
|
98
|
+
raise InvalidApiKey
|
99
|
+
when 409
|
100
|
+
raise IndexInitializing
|
101
|
+
when 404
|
102
|
+
raise NonExistentIndex
|
103
|
+
when 400
|
104
|
+
raise InvalidArgument, resp.body
|
105
|
+
else
|
106
|
+
raise UnexpectedHTTPException, resp.body
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def bulk_delete(docids)
|
111
|
+
data = []
|
112
|
+
docids.each do |docid|
|
113
|
+
data << {'docid' => docid}
|
114
|
+
end
|
115
|
+
resp = @conn.delete do |req|
|
116
|
+
req.url "docs"
|
117
|
+
req.body = data.to_json
|
118
|
+
end
|
119
|
+
case resp.status
|
120
|
+
when 200
|
121
|
+
resp.body
|
122
|
+
when 401
|
123
|
+
raise InvalidApiKey
|
124
|
+
when 409
|
125
|
+
raise IndexInitializing
|
126
|
+
when 404
|
127
|
+
raise NonExistentIndex
|
128
|
+
when 400
|
129
|
+
raise InvalidArgument, resp.body
|
130
|
+
else
|
131
|
+
raise UnexpectedHTTPException, resp.body
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# the options argument may contain an :index_code definition to override
|
136
|
+
# this instance's default index_code
|
137
|
+
# it can also contain any of the following:
|
138
|
+
# :start => an int with the number of results to skip
|
139
|
+
# :len => an int with the number of results to return
|
140
|
+
# :snippet => a comma separated list of field names for which a snippet
|
141
|
+
# should be returned. (requires an index that supports snippets)
|
142
|
+
# :fetch => a comma separated list of field names for which its content
|
143
|
+
# should be returned. (requires an index that supports storage)
|
144
|
+
# :function => an int with the index of the scoring function to be used
|
145
|
+
# for this query
|
146
|
+
# :variables => a hash int => float, with variables that can be later
|
147
|
+
# used in scoring :function
|
148
|
+
# :category_filters => a hash to filter the query based on document categories. Keys represent category names.
|
149
|
+
# see http://indextank.com/documentation/ruby-client#faceting
|
150
|
+
#
|
151
|
+
# Example:
|
152
|
+
# category_filters => {:size => "big", :price => "expensive"}
|
153
|
+
# means that only documents that have "big" as size category and "expensive" as price category
|
154
|
+
# will match the query
|
155
|
+
# :docvar_filters => a hash with int keys and Array values to filter the query based on document variables.
|
156
|
+
# see http://indextank.com/documentation/ruby-client#range_queries
|
157
|
+
#
|
158
|
+
# Example:
|
159
|
+
# docvar_filters = { 1 => [ [2, 3], [5, nil] ]}
|
160
|
+
# means that only documents with document variable number 1 between 2 and 3 or bigger than 5
|
161
|
+
# will match the query.
|
162
|
+
# :function_filters => a hash with int keys and Array values to filter the query based on scoring functions.
|
163
|
+
# see http://indextank.com/documentation/ruby-client#range_queries
|
164
|
+
#
|
165
|
+
# Example:
|
166
|
+
# function_filters = { 3 => [ [nil, 2], [5, 7], [8,14] ]}
|
167
|
+
# means that only documents whose score calculated by scoring function 3 is lower than 2,
|
168
|
+
# between 5 and 7 or between 8 and 14 will match the query.
|
169
|
+
def search(query, options = {})
|
170
|
+
options = {:start => 0, :len => 10 }.merge(options).merge(:q => query)
|
171
|
+
if options[:variables]
|
172
|
+
options[:variables].each_pair { |k, v| options.merge!( :"var#{k}" => v ) }
|
173
|
+
options.delete :variables
|
174
|
+
end
|
175
|
+
|
176
|
+
if options[:docvar_filters]
|
177
|
+
# go from { 3 => [ [1, 3], [5, nil] ]} to filter_docvar3 => 1:3,5:*
|
178
|
+
options[:docvar_filters].each_pair { |k, v|
|
179
|
+
rng = v.map { |val|
|
180
|
+
raise ArgumentError, "using a range with bound count != 2" unless val.length == 2
|
181
|
+
"#{val[0] || '*'}:#{val[1] || '*'}"
|
182
|
+
}.join ","
|
183
|
+
options.merge!( :"filter_docvar#{k}" => rng )
|
184
|
+
}
|
185
|
+
options.delete :docvar_filters
|
186
|
+
end
|
187
|
+
|
188
|
+
if options[:function_filters]
|
189
|
+
# go from { 2 => [ [1 , 3],[5,8] ]} to filter_function2 => 1:3,5:8
|
190
|
+
options[:function_filters].each_pair { |k, v|
|
191
|
+
rng = v.map { |val|
|
192
|
+
raise ArgumentError, "using a range with bound count != 2" unless val.length == 2
|
193
|
+
"#{val[0] || '*'}:#{val[1] || '*'}"
|
194
|
+
}.join ","
|
195
|
+
options.merge!( :"filter_function#{k}" => rng )
|
196
|
+
}
|
197
|
+
options.delete :function_filters
|
198
|
+
end
|
199
|
+
|
200
|
+
if options[:category_filters]
|
201
|
+
options[:category_filters] = options[:category_filters].to_json
|
202
|
+
end
|
203
|
+
|
204
|
+
response = @conn.get do |req|
|
205
|
+
req.url 'search', options
|
206
|
+
end
|
207
|
+
case response.status
|
208
|
+
when 400
|
209
|
+
raise InvalidQuery
|
210
|
+
when 404
|
211
|
+
raise NonExistentIndex
|
212
|
+
when 409
|
213
|
+
raise IndexInitializing
|
214
|
+
end
|
215
|
+
|
216
|
+
response.body
|
217
|
+
end
|
218
|
+
|
219
|
+
# the options argument may contain an :index_code definition to override
|
220
|
+
# this instance's default index_code
|
221
|
+
# it can also contain any of the following:
|
222
|
+
# :start => an int with the number of results to skip
|
223
|
+
# :function => an int with the index of the scoring function to be used
|
224
|
+
# for this query
|
225
|
+
# :variables => a hash int => float, with variables that can be later
|
226
|
+
# used in scoring :function
|
227
|
+
# :category_filters => a hash to filter the query based on document categories. Keys represent category names.
|
228
|
+
# see http://indextank.com/documentation/ruby-client#faceting
|
229
|
+
#
|
230
|
+
# Example:
|
231
|
+
# category_filters => {:size => "big", :price => "expensive"}
|
232
|
+
# means that only documents that have "big" as size category and "expensive" as price category
|
233
|
+
# will match the query
|
234
|
+
# :docvar_filters => a hash with int keys and Array values to filter the query based on document variables.
|
235
|
+
# see http://indextank.com/documentation/ruby-client#range_queries
|
236
|
+
#
|
237
|
+
# Example:
|
238
|
+
# docvar_filters = { 1 => [ [2, 3], [5, nil] ]}
|
239
|
+
# means that only documents with document variable number 1 between 2 and 3 or bigger than 5
|
240
|
+
# will match the query.
|
241
|
+
# :function_filters => a hash with int keys and Array values to filter the query based on scoring functions.
|
242
|
+
# see http://indextank.com/documentation/ruby-client#range_queries
|
243
|
+
#
|
244
|
+
# Example:
|
245
|
+
# function_filters = { 3 => [ [nil, 2], [5, 7], [8,14] ]}
|
246
|
+
# means that only documents whose score calculated by scoring function 3 is lower than 2,
|
247
|
+
# between 5 and 7 or between 8 and 14 will match the query.
|
248
|
+
def delete_by_search(query, options = {})
|
249
|
+
options = {:start => 0}.merge(options).merge(:q => query)
|
250
|
+
if options[:variables]
|
251
|
+
options[:variables].each_pair { |k, v| options.merge!( :"var#{k}" => v ) }
|
252
|
+
options.delete :variables
|
253
|
+
end
|
254
|
+
|
255
|
+
if options[:docvar_filters]
|
256
|
+
# go from { 3 => [ [1, 3], [5, nil] ]} to filter_docvar3 => 1:3,5:*
|
257
|
+
options[:docvar_filters].each_pair { |k, v|
|
258
|
+
rng = v.map { |val|
|
259
|
+
raise ArgumentError, "using a range with bound count != 2" unless val.length == 2
|
260
|
+
"#{val[0] || '*'}:#{val[1] || '*'}"
|
261
|
+
}.join ","
|
262
|
+
options.merge!( :"filter_docvar#{k}" => rng )
|
263
|
+
}
|
264
|
+
options.delete :docvar_filters
|
265
|
+
end
|
266
|
+
|
267
|
+
if options[:function_filters]
|
268
|
+
# go from { 2 => [ [1 , 3],[5,8] ]} to filter_function2 => 1:3,5:8
|
269
|
+
options[:function_filters].each_pair { |k, v|
|
270
|
+
rng = v.map { |val|
|
271
|
+
raise ArgumentError, "using a range with bound count != 2" unless val.length == 2
|
272
|
+
"#{val[0] || '*'}:#{val[1] || '*'}"
|
273
|
+
}.join ","
|
274
|
+
options.merge!( :"filter_function#{k}" => rng )
|
275
|
+
}
|
276
|
+
options.delete :function_filters
|
277
|
+
end
|
278
|
+
|
279
|
+
if options[:category_filters]
|
280
|
+
options[:category_filters] = options[:category_filters].to_json
|
281
|
+
end
|
282
|
+
|
283
|
+
response = @conn.delete do |req|
|
284
|
+
req.url 'search', options
|
285
|
+
end
|
286
|
+
case response.status
|
287
|
+
when 400
|
288
|
+
raise InvalidQuery
|
289
|
+
when 404
|
290
|
+
raise NonExistentIndex
|
291
|
+
when 409
|
292
|
+
raise IndexInitializing
|
293
|
+
end
|
294
|
+
|
295
|
+
response.body
|
296
|
+
end
|
297
|
+
|
298
|
+
def suggest(query, options = {})
|
299
|
+
options.merge!({:query => query})
|
300
|
+
@conn.get do |req|
|
301
|
+
req.url 'autocomplete', options
|
302
|
+
end.body
|
303
|
+
end
|
304
|
+
|
305
|
+
# the options argument may contain an :index_code definition to override
|
306
|
+
# this instance's default index_code
|
307
|
+
def promote(docid, query, options={})
|
308
|
+
options.merge!( :docid => docid, :query => query )
|
309
|
+
resp = @conn.put do |req|
|
310
|
+
req.url 'promote'
|
311
|
+
req.body = options.to_json
|
312
|
+
end
|
313
|
+
|
314
|
+
case resp.status
|
315
|
+
when 409
|
316
|
+
raise IndexInitializing
|
317
|
+
when 404
|
318
|
+
raise NonExistentIndex
|
319
|
+
when 400
|
320
|
+
raise InvalidArgument, resp.body
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# creates a new document, identified by :docid
|
325
|
+
# :docid => a String or Symbol, with bytesize no longer than 1024 bytes
|
326
|
+
def document(docid)
|
327
|
+
Document.new("#{@uri}/docs", docid)
|
328
|
+
end
|
329
|
+
|
330
|
+
def functions(index = -1, formula = nil)
|
331
|
+
if index == -1
|
332
|
+
@conn.get("functions").body.sort.collect do |index, formula|
|
333
|
+
Function.new("#{@uri}/functions", index, formula)
|
334
|
+
end
|
335
|
+
else
|
336
|
+
Function.new("#{@uri}/functions", index, formula)
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'faraday_middleware'
|
2
|
+
require 'faraday_middleware/response_middleware'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
require 'index-tanked/indextank/client'
|
6
|
+
|
7
|
+
module IndexTanked
|
8
|
+
module IndexTank
|
9
|
+
VERSION = "1.0.12"
|
10
|
+
|
11
|
+
def self.setup_connection(url)
|
12
|
+
## in Faraday 0.8 or above:
|
13
|
+
@conn = Faraday.new(url) do |conn|
|
14
|
+
conn.response :json
|
15
|
+
yield conn if block_given?
|
16
|
+
conn.adapter Faraday.default_adapter
|
17
|
+
end
|
18
|
+
@uri = URI.parse(url)
|
19
|
+
@conn.basic_auth @uri.user,@uri.password
|
20
|
+
@conn.headers['User-Agent'] = "IndexTanked::IndexTank-Ruby/#{VERSION}"
|
21
|
+
@conn
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -46,7 +46,7 @@ module IndexTanked
|
|
46
46
|
@results ||= WillPaginate::Collection.create(@page, @per_page) do |pager|
|
47
47
|
begin
|
48
48
|
raise SearchingDisabledError, "index tank search is disabled in configuration" unless IndexTanked::Configuration.search_available?
|
49
|
-
raise IndexTanked::SearchError, "No or invalid index has been provided" unless @index.is_a? IndexTank::Index
|
49
|
+
raise IndexTanked::SearchError, "No or invalid index has been provided" unless @index.is_a? IndexTanked::IndexTank::Index
|
50
50
|
raise IndexTanked::SearchError, "No query provided" if @query.nil?
|
51
51
|
search_timeout = if IndexTanked::Configuration.search_timeout.is_a?(Proc)
|
52
52
|
IndexTanked::Configuration.search_timeout.call
|
data/lib/index-tanked/version.rb
CHANGED
metadata
CHANGED
@@ -1,67 +1,69 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: index-tanked
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 7
|
9
9
|
- 0
|
10
|
-
version: 0.
|
10
|
+
version: 0.7.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Adam Kittelson
|
14
14
|
- Brandon Arbini
|
15
|
+
- Nathan Sutton
|
15
16
|
autorequire:
|
16
17
|
bindir: bin
|
17
18
|
cert_chain: []
|
18
19
|
|
19
|
-
date:
|
20
|
+
date: 2013-02-06 00:00:00 Z
|
20
21
|
dependencies:
|
21
22
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
23
|
+
name: will_paginate
|
23
24
|
prerelease: false
|
24
25
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
26
|
none: false
|
26
27
|
requirements:
|
27
28
|
- - ~>
|
28
29
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
30
|
+
hash: 5
|
30
31
|
segments:
|
31
|
-
-
|
32
|
-
-
|
33
|
-
|
34
|
-
version: 1.0.12
|
32
|
+
- 2
|
33
|
+
- 3
|
34
|
+
version: "2.3"
|
35
35
|
type: :runtime
|
36
36
|
version_requirements: *id001
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
|
-
name:
|
38
|
+
name: faraday_middleware
|
39
39
|
prerelease: false
|
40
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
41
|
none: false
|
42
42
|
requirements:
|
43
43
|
- - ~>
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
hash:
|
45
|
+
hash: 59
|
46
46
|
segments:
|
47
|
-
- 3
|
48
47
|
- 0
|
49
|
-
|
48
|
+
- 9
|
49
|
+
- 0
|
50
|
+
version: 0.9.0
|
50
51
|
type: :runtime
|
51
52
|
version_requirements: *id002
|
52
53
|
- !ruby/object:Gem::Dependency
|
53
|
-
name:
|
54
|
+
name: yajl-ruby
|
54
55
|
prerelease: false
|
55
56
|
requirement: &id003 !ruby/object:Gem::Requirement
|
56
57
|
none: false
|
57
58
|
requirements:
|
58
59
|
- - ~>
|
59
60
|
- !ruby/object:Gem::Version
|
60
|
-
hash:
|
61
|
+
hash: 19
|
61
62
|
segments:
|
62
|
-
-
|
63
|
-
-
|
64
|
-
|
63
|
+
- 1
|
64
|
+
- 1
|
65
|
+
- 0
|
66
|
+
version: 1.1.0
|
65
67
|
type: :runtime
|
66
68
|
version_requirements: *id003
|
67
69
|
- !ruby/object:Gem::Dependency
|
@@ -70,14 +72,12 @@ dependencies:
|
|
70
72
|
requirement: &id004 !ruby/object:Gem::Requirement
|
71
73
|
none: false
|
72
74
|
requirements:
|
73
|
-
- - "
|
75
|
+
- - ">="
|
74
76
|
- !ruby/object:Gem::Version
|
75
|
-
hash:
|
77
|
+
hash: 3
|
76
78
|
segments:
|
77
|
-
-
|
78
|
-
|
79
|
-
- 3
|
80
|
-
version: 2.10.3
|
79
|
+
- 0
|
80
|
+
version: "0"
|
81
81
|
type: :development
|
82
82
|
version_requirements: *id004
|
83
83
|
- !ruby/object:Gem::Dependency
|
@@ -86,14 +86,12 @@ dependencies:
|
|
86
86
|
requirement: &id005 !ruby/object:Gem::Requirement
|
87
87
|
none: false
|
88
88
|
requirements:
|
89
|
-
- - "
|
89
|
+
- - ">="
|
90
90
|
- !ruby/object:Gem::Version
|
91
|
-
hash:
|
91
|
+
hash: 3
|
92
92
|
segments:
|
93
93
|
- 0
|
94
|
-
|
95
|
-
- 8
|
96
|
-
version: 0.9.8
|
94
|
+
version: "0"
|
97
95
|
type: :development
|
98
96
|
version_requirements: *id005
|
99
97
|
- !ruby/object:Gem::Dependency
|
@@ -111,9 +109,23 @@ dependencies:
|
|
111
109
|
type: :development
|
112
110
|
version_requirements: *id006
|
113
111
|
- !ruby/object:Gem::Dependency
|
114
|
-
name:
|
112
|
+
name: activerecord
|
115
113
|
prerelease: false
|
116
114
|
requirement: &id007 !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ~>
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
hash: 5
|
120
|
+
segments:
|
121
|
+
- 3
|
122
|
+
version: "3"
|
123
|
+
type: :development
|
124
|
+
version_requirements: *id007
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: sqlite3
|
127
|
+
prerelease: false
|
128
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
117
129
|
none: false
|
118
130
|
requirements:
|
119
131
|
- - ">="
|
@@ -123,11 +135,54 @@ dependencies:
|
|
123
135
|
- 0
|
124
136
|
version: "0"
|
125
137
|
type: :development
|
126
|
-
version_requirements: *
|
138
|
+
version_requirements: *id008
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rake
|
141
|
+
prerelease: false
|
142
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
143
|
+
none: false
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
hash: 3
|
148
|
+
segments:
|
149
|
+
- 0
|
150
|
+
version: "0"
|
151
|
+
type: :development
|
152
|
+
version_requirements: *id009
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rdoc
|
155
|
+
prerelease: false
|
156
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
157
|
+
none: false
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
hash: 3
|
162
|
+
segments:
|
163
|
+
- 0
|
164
|
+
version: "0"
|
165
|
+
type: :development
|
166
|
+
version_requirements: *id010
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: rcov
|
169
|
+
prerelease: false
|
170
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
171
|
+
none: false
|
172
|
+
requirements:
|
173
|
+
- - ">="
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
hash: 3
|
176
|
+
segments:
|
177
|
+
- 0
|
178
|
+
version: "0"
|
179
|
+
type: :development
|
180
|
+
version_requirements: *id011
|
127
181
|
description: Provides methods for indexing objects to Index Tank. Extra convenience methods included for Active Record objects.
|
128
182
|
email:
|
129
183
|
- adam@zencoder.com
|
130
184
|
- brandon@zencoder.com
|
185
|
+
- nate@zencoder.com
|
131
186
|
executables: []
|
132
187
|
|
133
188
|
extensions: []
|
@@ -149,6 +204,12 @@ files:
|
|
149
204
|
- lib/index-tanked/class_methods.rb
|
150
205
|
- lib/index-tanked/configuration.rb
|
151
206
|
- lib/index-tanked/index_tanked.rb
|
207
|
+
- lib/index-tanked/indextank/client.rb
|
208
|
+
- lib/index-tanked/indextank/document.rb
|
209
|
+
- lib/index-tanked/indextank/exceptions.rb
|
210
|
+
- lib/index-tanked/indextank/function.rb
|
211
|
+
- lib/index-tanked/indextank/index.rb
|
212
|
+
- lib/index-tanked/indextank/indextank.rb
|
152
213
|
- lib/index-tanked/instance_companion.rb
|
153
214
|
- lib/index-tanked/instance_methods.rb
|
154
215
|
- lib/index-tanked/search_result.rb
|