seomoz-riak-client 1.0.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +27 -0
- data/Guardfile +14 -0
- data/Rakefile +76 -0
- data/erl_src/riak_kv_test_backend.beam +0 -0
- data/erl_src/riak_kv_test_backend.erl +174 -0
- data/erl_src/riak_search_test_backend.beam +0 -0
- data/erl_src/riak_search_test_backend.erl +175 -0
- data/lib/active_support/cache/riak_store.rb +2 -0
- data/lib/riak.rb +21 -0
- data/lib/riak/bucket.rb +215 -0
- data/lib/riak/cache_store.rb +84 -0
- data/lib/riak/client.rb +415 -0
- data/lib/riak/client/beefcake/messages.rb +147 -0
- data/lib/riak/client/beefcake/object_methods.rb +92 -0
- data/lib/riak/client/beefcake_protobuffs_backend.rb +176 -0
- data/lib/riak/client/excon_backend.rb +65 -0
- data/lib/riak/client/http_backend.rb +203 -0
- data/lib/riak/client/http_backend/configuration.rb +46 -0
- data/lib/riak/client/http_backend/key_streamer.rb +43 -0
- data/lib/riak/client/http_backend/object_methods.rb +94 -0
- data/lib/riak/client/http_backend/request_headers.rb +34 -0
- data/lib/riak/client/http_backend/transport_methods.rb +218 -0
- data/lib/riak/client/net_http_backend.rb +79 -0
- data/lib/riak/client/protobuffs_backend.rb +97 -0
- data/lib/riak/client/pump.rb +30 -0
- data/lib/riak/client/search.rb +94 -0
- data/lib/riak/core_ext.rb +6 -0
- data/lib/riak/core_ext/blank.rb +53 -0
- data/lib/riak/core_ext/extract_options.rb +7 -0
- data/lib/riak/core_ext/json.rb +15 -0
- data/lib/riak/core_ext/slice.rb +18 -0
- data/lib/riak/core_ext/stringify_keys.rb +10 -0
- data/lib/riak/core_ext/symbolize_keys.rb +10 -0
- data/lib/riak/core_ext/to_param.rb +31 -0
- data/lib/riak/encoding.rb +6 -0
- data/lib/riak/failed_request.rb +81 -0
- data/lib/riak/i18n.rb +3 -0
- data/lib/riak/json.rb +28 -0
- data/lib/riak/link.rb +85 -0
- data/lib/riak/locale/en.yml +48 -0
- data/lib/riak/map_reduce.rb +206 -0
- data/lib/riak/map_reduce/filter_builder.rb +94 -0
- data/lib/riak/map_reduce/phase.rb +98 -0
- data/lib/riak/map_reduce_error.rb +7 -0
- data/lib/riak/robject.rb +290 -0
- data/lib/riak/search.rb +3 -0
- data/lib/riak/serializers.rb +74 -0
- data/lib/riak/stamp.rb +77 -0
- data/lib/riak/test_server.rb +252 -0
- data/lib/riak/util/escape.rb +45 -0
- data/lib/riak/util/fiber1.8.rb +48 -0
- data/lib/riak/util/headers.rb +53 -0
- data/lib/riak/util/multipart.rb +52 -0
- data/lib/riak/util/multipart/stream_parser.rb +62 -0
- data/lib/riak/util/tcp_socket_extensions.rb +58 -0
- data/lib/riak/util/translation.rb +19 -0
- data/lib/riak/walk_spec.rb +105 -0
- data/riak-client.gemspec +55 -0
- data/seomoz-riak-client.gemspec +55 -0
- data/spec/fixtures/cat.jpg +0 -0
- data/spec/fixtures/multipart-blank.txt +7 -0
- data/spec/fixtures/multipart-mapreduce.txt +10 -0
- data/spec/fixtures/multipart-with-body.txt +16 -0
- data/spec/fixtures/server.cert.crt +15 -0
- data/spec/fixtures/server.cert.key +15 -0
- data/spec/fixtures/test.pem +1 -0
- data/spec/integration/riak/cache_store_spec.rb +154 -0
- data/spec/integration/riak/http_backends_spec.rb +58 -0
- data/spec/integration/riak/protobuffs_backends_spec.rb +32 -0
- data/spec/integration/riak/test_server_spec.rb +161 -0
- data/spec/riak/beefcake_protobuffs_backend_spec.rb +59 -0
- data/spec/riak/bucket_spec.rb +205 -0
- data/spec/riak/client_spec.rb +517 -0
- data/spec/riak/core_ext/to_param_spec.rb +15 -0
- data/spec/riak/escape_spec.rb +69 -0
- data/spec/riak/excon_backend_spec.rb +64 -0
- data/spec/riak/headers_spec.rb +38 -0
- data/spec/riak/http_backend/configuration_spec.rb +51 -0
- data/spec/riak/http_backend/object_methods_spec.rb +217 -0
- data/spec/riak/http_backend/transport_methods_spec.rb +117 -0
- data/spec/riak/http_backend_spec.rb +269 -0
- data/spec/riak/link_spec.rb +71 -0
- data/spec/riak/map_reduce/filter_builder_spec.rb +32 -0
- data/spec/riak/map_reduce/phase_spec.rb +136 -0
- data/spec/riak/map_reduce_spec.rb +310 -0
- data/spec/riak/multipart_spec.rb +23 -0
- data/spec/riak/net_http_backend_spec.rb +16 -0
- data/spec/riak/robject_spec.rb +427 -0
- data/spec/riak/search_spec.rb +178 -0
- data/spec/riak/serializers_spec.rb +93 -0
- data/spec/riak/stamp_spec.rb +54 -0
- data/spec/riak/stream_parser_spec.rb +53 -0
- data/spec/riak/walk_spec_spec.rb +195 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/drb_mock_server.rb +39 -0
- data/spec/support/http_backend_implementation_examples.rb +266 -0
- data/spec/support/integration_setup.rb +10 -0
- data/spec/support/mock_server.rb +81 -0
- data/spec/support/mocks.rb +4 -0
- data/spec/support/test_server.yml.example +2 -0
- data/spec/support/unified_backend_examples.rb +255 -0
- metadata +271 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
require 'riak/util/translation'
|
3
|
+
require 'riak/json'
|
4
|
+
|
5
|
+
module Riak
|
6
|
+
# Exception raised when receiving an unexpected client response from
|
7
|
+
# Riak.
|
8
|
+
class FailedRequest < StandardError
|
9
|
+
include Util::Translation
|
10
|
+
|
11
|
+
def initialize(message)
|
12
|
+
super(message || t('failed_request'))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Exception raised when the expected HTTP response code from Riak
|
17
|
+
# fails to match the actual response code.
|
18
|
+
class HTTPFailedRequest < FailedRequest
|
19
|
+
# @return [Symbol] the HTTP method, one of :head, :get, :post, :put, :delete
|
20
|
+
attr_reader :method
|
21
|
+
# @return [Fixnum] the expected response code
|
22
|
+
attr_reader :expected
|
23
|
+
# @return [Fixnum] the received response code
|
24
|
+
attr_reader :code
|
25
|
+
# @return [Hash] the response headers
|
26
|
+
attr_reader :headers
|
27
|
+
# @return [String] the response body, if present
|
28
|
+
attr_reader :body
|
29
|
+
|
30
|
+
def initialize(method, expected_code, received_code, headers, body)
|
31
|
+
@method, @expected, @code, @headers, @body = method, expected_code, received_code, headers, body
|
32
|
+
super t("http_failed_request", :expected => @expected.inspect, :code => @code, :body => @body)
|
33
|
+
end
|
34
|
+
|
35
|
+
def is_json?
|
36
|
+
headers['content-type'].include?('application/json')
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [true,false] whether the error represents a "not found" response
|
40
|
+
def not_found?
|
41
|
+
@code.to_i == 404
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [true,false] whether the error represents an internal
|
45
|
+
# server error
|
46
|
+
def server_error?
|
47
|
+
@code.to_i == 500
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Exception raised when receiving an unexpected Protocol Buffers response from Riak
|
52
|
+
class ProtobuffsFailedRequest < FailedRequest
|
53
|
+
def initialize(code, message)
|
54
|
+
super t('protobuffs_failed_request', :code => code, :body => message)
|
55
|
+
@original_message = message
|
56
|
+
@not_found = code == :not_found
|
57
|
+
@server_error = code == :server_error
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [true, false] whether the error response is in JSON
|
61
|
+
def is_json?
|
62
|
+
begin
|
63
|
+
JSON.parse(original_message)
|
64
|
+
true
|
65
|
+
rescue
|
66
|
+
false
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [true,false] whether the error represents a "not found" response
|
71
|
+
def not_found?
|
72
|
+
@not_found
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [true,false] whether the error represents an internal
|
76
|
+
# server error
|
77
|
+
def server_error?
|
78
|
+
@server_error
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/lib/riak/i18n.rb
ADDED
data/lib/riak/json.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'multi_json'
|
2
|
+
MultiJson.engine # Force loading of an engine
|
3
|
+
require 'riak/core_ext/json'
|
4
|
+
|
5
|
+
module Riak
|
6
|
+
class << self
|
7
|
+
# Options that will be passed to the JSON parser and encoder.
|
8
|
+
# Defaults to {:max_nesting => 20}
|
9
|
+
attr_accessor :json_options
|
10
|
+
end
|
11
|
+
self.json_options = {:max_nesting => 20}
|
12
|
+
|
13
|
+
# JSON module for internal use inside riak-client
|
14
|
+
module JSON
|
15
|
+
class << self
|
16
|
+
# Parse a JSON string
|
17
|
+
def parse(str)
|
18
|
+
MultiJson.decode(str, Riak.json_options)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Generate a JSON string
|
22
|
+
def encode(obj)
|
23
|
+
MultiJson.encode(obj)
|
24
|
+
end
|
25
|
+
alias :dump :encode
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/riak/link.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
require 'riak/util/translation'
|
3
|
+
require 'riak/util/escape'
|
4
|
+
require 'riak/walk_spec'
|
5
|
+
|
6
|
+
module Riak
|
7
|
+
# Represents a link from one object to another in Riak
|
8
|
+
class Link
|
9
|
+
include Util::Translation
|
10
|
+
include Util::Escape
|
11
|
+
|
12
|
+
# @return [String] the relationship tag (or "rel") of the other resource to this one
|
13
|
+
attr_accessor :tag
|
14
|
+
alias_method :rel, :tag
|
15
|
+
alias_method :rel=, :tag=
|
16
|
+
|
17
|
+
# @return [String] the bucket of the related resource
|
18
|
+
attr_accessor :bucket
|
19
|
+
|
20
|
+
# @return [String] the key of the related resource
|
21
|
+
attr_accessor :key
|
22
|
+
|
23
|
+
%w{bucket key}.each do |m|
|
24
|
+
class_eval %{ def #{m}=(value); @url = nil; @#{m} = value; end }
|
25
|
+
end
|
26
|
+
|
27
|
+
# @param [String] header_string the string value of the Link: HTTP header from a Riak response
|
28
|
+
# @return [Array<Link>] an array of Riak::Link structs parsed from the header
|
29
|
+
def self.parse(header_string)
|
30
|
+
header_string.scan(%r{<([^>]+)>\s*;\s*(?:rel|riaktag)=\"([^\"]+)\"}).map do |match|
|
31
|
+
new(match[0], match[1])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# @overload initialize(url, tag)
|
36
|
+
# @param [String] url the url of the related resource
|
37
|
+
# @param [String] tag the tag for the related resource
|
38
|
+
# @overload initialize(bucket, key, tag)
|
39
|
+
# @param [String] bucket the bucket of the related resource
|
40
|
+
# @param [String] key the key of the related resource
|
41
|
+
# @param [String] tag the tag for the related resource
|
42
|
+
def initialize(*args)
|
43
|
+
raise ArgumentError unless (2..3).include?(args.size)
|
44
|
+
if args.size == 2
|
45
|
+
self.url, @tag = args
|
46
|
+
else
|
47
|
+
@bucket, @key, @tag = args
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [String] the URL (relative or absolute) of the related resource
|
52
|
+
def url
|
53
|
+
@url ||= "/riak/#{escape(bucket)}" + (key.blank? ? "" : "/#{escape(key)}")
|
54
|
+
end
|
55
|
+
|
56
|
+
def url=(value)
|
57
|
+
@url = value
|
58
|
+
@bucket = unescape($1) if value =~ %r{^/[^/]+/([^/]+)/?}
|
59
|
+
@key = unescape($1) if value =~ %r{^/[^/]+/[^/]+/([^/]+)/?}
|
60
|
+
end
|
61
|
+
|
62
|
+
def inspect; to_s; end
|
63
|
+
|
64
|
+
def to_s
|
65
|
+
%Q[<#{url}>; riaktag="#{tag}"]
|
66
|
+
end
|
67
|
+
|
68
|
+
def hash
|
69
|
+
self.to_s.hash
|
70
|
+
end
|
71
|
+
|
72
|
+
def eql?(other)
|
73
|
+
self == other
|
74
|
+
end
|
75
|
+
|
76
|
+
def ==(other)
|
77
|
+
other.is_a?(Link) && url == other.url && tag == other.tag
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_walk_spec
|
81
|
+
raise t("bucket_link_conversion") if tag == "up" || key.nil?
|
82
|
+
WalkSpec.new(:bucket => bucket, :tag => tag)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
en:
|
2
|
+
riak:
|
3
|
+
backwards_clock: "System clock moved backwards, ID generation will fail for %{delay} more milliseconds."
|
4
|
+
bucket_link_conversion: "Can't convert a bucket link to a walk spec"
|
5
|
+
client_type: "invalid argument %{client} is not a Riak::Client"
|
6
|
+
conflict_resolver_invalid: "The given resolver (%{resolver}) did not respond to :call"
|
7
|
+
content_type_undefined: "content_type is not defined!"
|
8
|
+
deprecated:
|
9
|
+
port: "DEPRECATION: Riak::Client#port has been deprecated, use #http_port or #pb_port for the appropriate protocol.\n%{backtrace}"
|
10
|
+
search: "DEPRECATION: Riak Search features are included in the main client, you no longer need to require 'riak/search'.\n%{backtrace}"
|
11
|
+
empty_map_reduce_query: "Specify one or more query phases to your MapReduce."
|
12
|
+
failed_request: "Client request failed."
|
13
|
+
filter_needs_block: "Filter %{filter} expects a block."
|
14
|
+
filter_arity_mismatch: "Filter %{filter} expects %{expected} arguments but %{received} were given."
|
15
|
+
full_bucket_mapred: "Full-bucket MapReduce, including key filters, invokes list-keys which is an expensive operation that should not be used in production.\n %{backtrace}"
|
16
|
+
hash_type: "invalid argument %{hash} is not a Hash"
|
17
|
+
http_configuration: "The %{backend} HTTP backend cannot be used. Please check its requirements."
|
18
|
+
http_failed_request: "Expected %{expected} from Riak but received %{code}. %{body}"
|
19
|
+
hostname_invalid: "host must be a valid hostname"
|
20
|
+
protocol_invalid: "'%{invalid}' is not a valid protocol, valid values are %{valid}"
|
21
|
+
invalid_basic_auth: "basic auth must be set using 'user:pass'"
|
22
|
+
invalid_client_id: "Invalid client ID, must be a string or between 0 and %{max_id}"
|
23
|
+
invalid_io_object: "Invalid IO-like object assigned to RObject#data. It should be assigned to raw_data instead."
|
24
|
+
invalid_function_value: "invalid value for function: %{value}"
|
25
|
+
invalid_options: "Invalid configuration options given."
|
26
|
+
invalid_phase_type: "type must be :map, :reduce, or :link"
|
27
|
+
invalid_ssl_verify_mode: "%{invalid} is not a valid :verify_mode option for SSL. Valid options are 'peer' and 'none'."
|
28
|
+
loading_bucket: "while loading bucket '%{name}'"
|
29
|
+
list_buckets: "Riak::Client#buckets is an expensive operation that should not be used in production.\n %{backtrace}"
|
30
|
+
list_keys: "Riak::Bucket#keys is an expensive operation that should not be used in production.\n %{backtrace}"
|
31
|
+
missing_block: "A block must be given."
|
32
|
+
missing_host_and_port: "You must specify a host and port, or use the defaults of 127.0.0.1:8098"
|
33
|
+
module_function_pair_required: "function must have two elements when an array"
|
34
|
+
not_found: "The requested object was not found."
|
35
|
+
path_and_body_required: "You must supply both a resource path and a body."
|
36
|
+
port_invalid: "port must be an integer between 0 and 65535"
|
37
|
+
protobuffs_failed_request: "Expected success from Riak but received %{code}. %{body}"
|
38
|
+
request_body_type: "Request body must be a String or respond to :read."
|
39
|
+
resource_path_short: "Resource path too short"
|
40
|
+
search_docs_require_id: "Search index documents must include the 'id' field."
|
41
|
+
search_remove_requires_id_or_query: "Search index documents to be removed must have 'id' or 'query' keys."
|
42
|
+
serializer_not_implemented: "No serializer has been registered for content type %{content_type}"
|
43
|
+
stale_write_prevented: "Stale write prevented by client."
|
44
|
+
stored_function_invalid: "function must have :bucket and :key when a hash"
|
45
|
+
string_type: "invalid_argument %{string} is not a String"
|
46
|
+
too_few_arguments: "too few arguments: %{params}"
|
47
|
+
walk_spec_invalid_unless_link: "WalkSpec is only valid for a function when the type is :link"
|
48
|
+
wrong_argument_count_walk_spec: "wrong number of arguments (one Hash or bucket,tag,keep required)"
|
@@ -0,0 +1,206 @@
|
|
1
|
+
|
2
|
+
require 'riak/util/translation'
|
3
|
+
require 'riak/util/escape'
|
4
|
+
require 'riak/json'
|
5
|
+
require 'riak/client'
|
6
|
+
require 'riak/bucket'
|
7
|
+
require 'riak/robject'
|
8
|
+
require 'riak/walk_spec'
|
9
|
+
require 'riak/failed_request'
|
10
|
+
require 'riak/map_reduce_error'
|
11
|
+
require 'riak/map_reduce/phase'
|
12
|
+
require 'riak/map_reduce/filter_builder'
|
13
|
+
|
14
|
+
module Riak
|
15
|
+
# Class for invoking map-reduce jobs using the HTTP interface.
|
16
|
+
class MapReduce
|
17
|
+
include Util::Translation
|
18
|
+
include Util::Escape
|
19
|
+
|
20
|
+
# @return [Array<[bucket,key]>,String,Hash<:bucket,:filters>] The
|
21
|
+
# bucket/keys for input to the job, or the bucket (all
|
22
|
+
# keys), or a hash containing the bucket and key-filters.
|
23
|
+
# @see #add
|
24
|
+
attr_accessor :inputs
|
25
|
+
|
26
|
+
# @return [Array<Phase>] The map and reduce phases that will be executed
|
27
|
+
# @see #map
|
28
|
+
# @see #reduce
|
29
|
+
# @see #link
|
30
|
+
attr_accessor :query
|
31
|
+
|
32
|
+
# Creates a new map-reduce job.
|
33
|
+
# @param [Client] client the Riak::Client interface
|
34
|
+
# @yield [self] helpful for initializing the job
|
35
|
+
def initialize(client)
|
36
|
+
@client, @inputs, @query = client, [], []
|
37
|
+
yield self if block_given?
|
38
|
+
end
|
39
|
+
|
40
|
+
# Add or replace inputs for the job.
|
41
|
+
# @overload add(bucket)
|
42
|
+
# Run the job across all keys in the bucket. This will replace any other inputs previously added.
|
43
|
+
# @param [String, Bucket] bucket the bucket to run the job on
|
44
|
+
# @overload add(bucket,key)
|
45
|
+
# Add a bucket/key pair to the job.
|
46
|
+
# @param [String,Bucket] bucket the bucket of the object
|
47
|
+
# @param [String] key the key of the object
|
48
|
+
# @overload add(object)
|
49
|
+
# Add an object to the job (by its bucket/key)
|
50
|
+
# @param [RObject] object the object to add to the inputs
|
51
|
+
# @overload add(bucket, key, keydata)
|
52
|
+
# @param [String,Bucket] bucket the bucket of the object
|
53
|
+
# @param [String] key the key of the object
|
54
|
+
# @param [String] keydata extra data to pass along with the object to the job
|
55
|
+
# @overload add(bucket, filters)
|
56
|
+
# Run the job across all keys in the bucket, with the given
|
57
|
+
# key-filters. This will replace any other inputs previously
|
58
|
+
# added. (Requires Riak 0.14)
|
59
|
+
# @param [String,Bucket] bucket the bucket to filter keys from
|
60
|
+
# @param [Array<Array>] filters a list of key-filters to apply
|
61
|
+
# to the key list
|
62
|
+
# @return [MapReduce] self
|
63
|
+
def add(*params)
|
64
|
+
params = params.dup
|
65
|
+
params = params.first if Array === params.first
|
66
|
+
case params.size
|
67
|
+
when 1
|
68
|
+
p = params.first
|
69
|
+
case p
|
70
|
+
when Bucket
|
71
|
+
warn(t('full_bucket_mapred', :backtrace => caller.join("\n "))) unless Riak.disable_list_keys_warnings
|
72
|
+
@inputs = escape(p.name)
|
73
|
+
when RObject
|
74
|
+
@inputs << [escape(p.bucket.name), escape(p.key)]
|
75
|
+
when String
|
76
|
+
warn(t('full_bucket_mapred', :backtrace => caller.join("\n "))) unless Riak.disable_list_keys_warnings
|
77
|
+
@inputs = escape(p)
|
78
|
+
end
|
79
|
+
when 2..3
|
80
|
+
bucket = params.shift
|
81
|
+
bucket = bucket.name if Bucket === bucket
|
82
|
+
if Array === params.first
|
83
|
+
warn(t('full_bucket_mapred', :backtrace => caller.join("\n "))) unless Riak.disable_list_keys_warnings
|
84
|
+
@inputs = {:bucket => escape(bucket), :key_filters => params.first }
|
85
|
+
else
|
86
|
+
key = params.shift
|
87
|
+
@inputs << params.unshift(escape(key)).unshift(escape(bucket))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
self
|
91
|
+
end
|
92
|
+
alias :<< :add
|
93
|
+
alias :include :add
|
94
|
+
|
95
|
+
# Adds a bucket and key-filters built by the given
|
96
|
+
# block. Equivalent to #add with a list of filters.
|
97
|
+
# @param [String] bucket the bucket to apply key-filters to
|
98
|
+
# @yield [] builder block - instance_eval'ed into a FilterBuilder
|
99
|
+
# @return [MapReduce] self
|
100
|
+
# @see MapReduce#add
|
101
|
+
def filter(bucket, &block)
|
102
|
+
add(bucket, FilterBuilder.new(&block).to_a)
|
103
|
+
end
|
104
|
+
|
105
|
+
# (Riak Search) Use a search query to start a map/reduce job.
|
106
|
+
# @param [String, Bucket] bucket the bucket/index to search
|
107
|
+
# @param [String] query the query to run
|
108
|
+
# @return [MapReduce] self
|
109
|
+
def search(bucket, query)
|
110
|
+
bucket = bucket.name if bucket.respond_to?(:name)
|
111
|
+
@inputs = {:module => "riak_search", :function => "mapred_search", :arg => [bucket, query]}
|
112
|
+
self
|
113
|
+
end
|
114
|
+
|
115
|
+
# Add a map phase to the job.
|
116
|
+
# @overload map(function)
|
117
|
+
# @param [String, Array] function a Javascript function that represents the phase, or an Erlang [module,function] pair
|
118
|
+
# @overload map(function?, options)
|
119
|
+
# @param [String, Array] function a Javascript function that represents the phase, or an Erlang [module, function] pair
|
120
|
+
# @param [Hash] options extra options for the phase (see {Phase#initialize})
|
121
|
+
# @return [MapReduce] self
|
122
|
+
# @see Phase#initialize
|
123
|
+
def map(*params)
|
124
|
+
options = params.extract_options!
|
125
|
+
@query << Phase.new({:type => :map, :function => params.shift}.merge(options))
|
126
|
+
self
|
127
|
+
end
|
128
|
+
|
129
|
+
# Add a reduce phase to the job.
|
130
|
+
# @overload reduce(function)
|
131
|
+
# @param [String, Array] function a Javascript function that represents the phase, or an Erlang [module,function] pair
|
132
|
+
# @overload reduce(function?, options)
|
133
|
+
# @param [String, Array] function a Javascript function that represents the phase, or an Erlang [module, function] pair
|
134
|
+
# @param [Hash] options extra options for the phase (see {Phase#initialize})
|
135
|
+
# @return [MapReduce] self
|
136
|
+
# @see Phase#initialize
|
137
|
+
def reduce(*params)
|
138
|
+
options = params.extract_options!
|
139
|
+
@query << Phase.new({:type => :reduce, :function => params.shift}.merge(options))
|
140
|
+
self
|
141
|
+
end
|
142
|
+
|
143
|
+
# Add a link phase to the job. Link phases follow links attached to objects automatically (a special case of map).
|
144
|
+
# @overload link(walk_spec, options={})
|
145
|
+
# @param [WalkSpec] walk_spec a WalkSpec that represents the types of links to follow
|
146
|
+
# @param [Hash] options extra options for the phase (see {Phase#initialize})
|
147
|
+
# @overload link(bucket, tag, keep, options={})
|
148
|
+
# @param [String, nil] bucket the bucket to limit links to
|
149
|
+
# @param [String, nil] tag the tag to limit links to
|
150
|
+
# @param [Boolean] keep whether to keep results of this phase (overrides the phase options)
|
151
|
+
# @param [Hash] options extra options for the phase (see {Phase#initialize})
|
152
|
+
# @overload link(options)
|
153
|
+
# @param [Hash] options options for both the walk spec and link phase
|
154
|
+
# @see WalkSpec#initialize
|
155
|
+
# @return [MapReduce] self
|
156
|
+
# @see Phase#initialize
|
157
|
+
def link(*params)
|
158
|
+
options = params.extract_options!
|
159
|
+
walk_spec_options = options.slice!(:type, :function, :language, :arg) unless params.first
|
160
|
+
walk_spec = WalkSpec.normalize(params.shift || walk_spec_options).first
|
161
|
+
@query << Phase.new({:type => :link, :function => walk_spec}.merge(options))
|
162
|
+
self
|
163
|
+
end
|
164
|
+
|
165
|
+
# Sets the timeout for the map-reduce job.
|
166
|
+
# @param [Fixnum] value the job timeout, in milliseconds
|
167
|
+
def timeout(value)
|
168
|
+
@timeout = value
|
169
|
+
return self
|
170
|
+
end
|
171
|
+
alias :timeout= :timeout
|
172
|
+
|
173
|
+
# Convert the job to JSON for submission over the HTTP interface.
|
174
|
+
# @return [String] the JSON representation
|
175
|
+
def to_json(*a)
|
176
|
+
hash = {"inputs" => inputs, "query" => query.map(&:as_json)}
|
177
|
+
hash['timeout'] = @timeout.to_i if @timeout
|
178
|
+
hash.to_json(*a)
|
179
|
+
end
|
180
|
+
|
181
|
+
# Executes this map-reduce job.
|
182
|
+
# @overload run
|
183
|
+
# Return the entire collection of results.
|
184
|
+
# @return [Array<Array>] similar to link-walking, each element is
|
185
|
+
# an array of results from a phase where "keep" is true. If there
|
186
|
+
# is only one "keep" phase, only the results from that phase will
|
187
|
+
# be returned.
|
188
|
+
# @overload run
|
189
|
+
# Stream the results through the given block without accumulating.
|
190
|
+
# @yield [phase, data] A block to stream results through
|
191
|
+
# @yieldparam [Fixnum] phase the phase from which the results were
|
192
|
+
# generated
|
193
|
+
# @yieldparam [Array] data a list of results from the phase
|
194
|
+
# @return [nil] nothing
|
195
|
+
def run(&block)
|
196
|
+
raise MapReduceError.new(t("empty_map_reduce_query")) if @query.empty?
|
197
|
+
@client.backend.mapred(self, &block)
|
198
|
+
rescue FailedRequest => fr
|
199
|
+
if fr.server_error? && fr.is_json?
|
200
|
+
raise MapReduceError.new(fr.body)
|
201
|
+
else
|
202
|
+
raise fr
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|