# Riak Ruby Client (riak-client) [![Build Status](https://secure.travis-ci.org/basho/riak-ruby-client.png)](http://travis-ci.org/basho/riak-ruby-client) `riak-client` is a rich Ruby client/toolkit for Riak, Basho's distributed database that contains a basic wrapper around typical operations, including bucket manipulation, object CRUD, link-walking, and map-reduce. ## Dependencies `riak-client` requires i18n, builder, beefcake, and multi_json. For higher performance on HTTP requests, install the 'excon' gem. The cache store implementation requires ActiveSupport 3 or later. Development dependencies are handled with bundler. Install bundler (`gem install bundler`) and run this command in each sub-project to get started: ``` bash $ bundle install ``` Run the RSpec suite using `bundle exec`: ``` bash $ bundle exec rake ``` ## Basic Example ``` ruby require 'riak' # Create a client interface client = Riak::Client.new # Create a client interface that uses Excon client = Riak::Client.new(:http_backend => :Excon) # Create a client that uses Protocol Buffers client = Riak::Client.new(:protocol => "pbc") # Automatically balance between multiple nodes client = Riak::Client.new(:nodes => [ {:host => '10.0.0.1'}, {:host => '10.0.0.2', :pb_port => 1234}, {:host => '10.0.0.3', :http_port => 5678} ]) # Retrieve a bucket bucket = client.bucket("doc") # a Riak::Bucket # Get an object from the bucket object = bucket.get_or_new("index.html") # a Riak::RObject # Change the object's data and save object.raw_data = "
Hello, world!" object.content_type = "text/html" object.store # Reload an object you already have object.reload # Works if you have the key and vclock, using conditional GET object.reload :force => true # Reloads whether you have the vclock or not # Access more like a hash, client[bucket][key] client['doc']['index.html'] # the Riak::RObject # Create a new object new_one = Riak::RObject.new(bucket, "application.js") new_one.content_type = "application/javascript" # You must set the content type. new_one.raw_data = "alert('Hello, World!')" new_one.store ``` ## Map-Reduce Example ``` ruby # Assuming you've already instantiated a client, get the album titles for The Beatles results = Riak::MapReduce.new(client). add("artists","Beatles"). link(:bucket => "albums"). map("function(v){ return [JSON.parse(v.values[0].data).title]; }", :keep => true).run p results # => ["Please Please Me", "With The Beatles", "A Hard Day's Night", # "Beatles For Sale", "Help!", "Rubber Soul", # "Revolver", "Sgt. Pepper's Lonely Hearts Club Band", "Magical Mystery Tour", # "The Beatles", "Yellow Submarine", "Abbey Road", "Let It Be"] ``` ## Riak Search Examples For more information about Riak Search, see [the Basho wiki](http://wiki.basho.com/Riak-Search.html). ``` ruby # Create a client, specifying the Solr-compatible endpoint # When connecting to Riak 0.14 and later, the Solr endpoint configuration option is not necessary. client = Riak::Client.new :solr => "/solr" # Search the default index for documents result = client.search("title:Yesterday") # Returns a vivified JSON object # containing 'responseHeaders' and 'response' keys result['response']['numFound'] # total number of results result['response']['start'] # offset into the total result set result['response']['docs'] # the list of indexed documents # Search the 'users' index for documents client.search("users", "name:Sean") # Add a document to an index client.index("users", {:id => "sean@basho.com", :name => "Sean Cribbs"}) # adds to the 'users' index client.index({:id => "index.html", :content => "Hello, world!"}) # adds to the default index client.index({:id => 1, :name => "one"}, {:id => 2, :name => "two"}) # adds multiple docs # Remove document(s) from an index client.remove({:id => 1}) # removes the document with ID 1 client.remove({:query => "archived"}) # removes all documents matching query client.remove({:id => 1}, {:id => 5}) # removes multiple docs client.remove("users", {:id => "sean@basho.com"}) # removes from the 'users' index # Seed MapReduce with search results Riak::MapReduce.new(client). search("users","email:basho"). map("Riak.mapValuesJson", :keep => true). run # Detect whether a bucket has auto-indexing client['users'].is_indexed? # Enable auto-indexing on a bucket client['users'].enable_index! # Disable auto-indexing on a bucket client['users'].disable_index! ``` ## Secondary Index Examples Riak supports secondary indexes. Secondary indexing, or "2i," gives you the ability to tag objects with multiple queryable values at write time, and then query them later. * [Using Secondary Indexes](http://docs.basho.com/riak/latest/dev/using/2i/) * [Secondary Index implementation notes](http://docs.basho.com/riak/latest/dev/advanced/2i/) ### Tagging Objects Objects are tagged with a hash kept behind the `indexes` method. Secondary index storage logic is in `lib/riak/rcontent.rb`. ```ruby object = bucket.get_or_new 'cobb.salad' # Indexes end with the "_bin" suffix to indicate they're binary or string # indexes. They can have multiple values. object.indexes['ingredients_bin'] = %w{lettuce tomato bacon egg chives} # Indexes ending with the "_int" suffix are indexed as integers. They can # have multiple values too. object.indexes['calories_int'] = [220] # You must re-save the object to store indexes. object.store ``` ### Finding Objects Secondary index queries return a list of keys exactly matching a scalar or within a range. ```ruby # The Bucket#get_index method allows querying by scalar... bucket.get_index 'calories_int', 220 # => ['cobb.salad'] # or range. bucket.get_index 'calories_int', 100..300 # => ['cobb.salad'] # Binary indexes also support both ranges and scalars. bucket.get_index 'ingredients_bin', 'tomata'..'tomatz' # => ['cobb.salad'] # The collection from #get_index also provides a continuation for pagination: c = bucket.get_index 'ingredients_bin', 'lettuce', max_results: 5 c.length # => 5 c.continuation # => "g2gCbQAAA=" # You can use that continuation to get the next page of results: c2 = bucket.get_index 'ingredients_bin', 'lettuce', max_results: 5, continuation: c.continuation # More complicated operations may benefit by using the `SecondaryIndex` object: q = Riak::SecondaryIndex.new bucket, 'ingredients_bin', 'lettuce', max_results: 5 # SecondaryIndex objects give you access to the keys... q.keys # => ['cobb.salad', 'wedge.salad', 'buffalo_chicken.wrap', ...] # but can also fetch values for you in parallel. q.values # => [