index-tanked 0.6.0 → 0.7.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.
- 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
|