-
Notifications
You must be signed in to change notification settings - Fork 158
Fetching Data from Riak (v2.0)
Note: This document is for the 2.x Java Client series.
Unless you're already familiar with CAP Theorem and eventual consistency, taking the time to read through at least Why Riak would be well worth your while.
It's ok, we'll wait.
Ok! Now that you've read through that and understand that Riak is a system that favors AP with eventual C, this might make some sense to you.
In Riak data is stored in buckets, and buckets can be grouped further by an optional bucket type. Buckets and bucket types have a number of options and tunable parameters, one of which is whether or not to allow sibling records. If you are using a bucket in the default bucket type, that bucket won't allow sibling creation by default. If you are using a bucket in a specific bucket type, that bucket will allow sibling creation by default.
The Riak Java client is built to support both scenarios, you can simply say "fetch the data associated with this key", and by calling .getValue()
you can fetch the data associated with the single object. You can also get all the sibling's values by calling .getValues()
and all the siblings will be returned.
This of course does not reflect how you must use the client if your application is doing a typical read/modify/write cycle and you have multiple threads or instances of your application causing concurrency. We'll discuss that in the advanced section below.
With that in mind, the following basic examples show how you can retrieve data from Riak.
Basic Example #1: Fetch data as a String
Basic Example #2: Fetch JSON data, map to POJO
Basic Example #3: Changing query parameters
import com.basho.riak.client.api.RiakClient;
import com.basho.riak.client.api.commands.kv.FetchValue;
import com.basho.riak.client.api.commands.kv.StoreValue;
import com.basho.riak.client.core.query.Location;
import com.basho.riak.client.core.query.Namespace;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutionException;
public class FetchObject {
public static void main(String [] args) throws UnknownHostException, ExecutionException, InterruptedException {
RiakClient client = RiakClient.newClient(10017, "127.0.0.1");
Location location = new Location(new Namespace("TestBucket"),"TestKey");
FetchValue fv = new FetchValue.Builder(location).build();
FetchValue.Response response = client.execute(fv);
// Fetch object as String
String value = response.getValue(String.class);
System.out.println(value);
client.shutdown();
}
}
By default, the Riak Java client provides a default Converter (see the advanced section below for more on this) that will automatically map JSON stored in Riak to a POJO class you provide.
import com.basho.riak.client.api.RiakClient;
import com.basho.riak.client.api.commands.kv.FetchValue;
import com.basho.riak.client.api.commands.kv.StoreValue;
import com.basho.riak.client.core.query.Location;
import com.basho.riak.client.core.query.Namespace;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutionException;
public class FetchObject {
// { "foo":"Some String", "bar":"some other string","foobar":5 }
static class Pojo {
public String foo;
public String bar;
public int foobar;
}
public static void main(String [] args) throws UnknownHostException, ExecutionException, InterruptedException {
RiakClient client = RiakClient.newClient(10017, "127.0.0.1");
Location location = new Location(new Namespace("TestBucket"), "TestKey");
FetchValue fv = new FetchValue.Builder(location).build();
FetchValue.Response response = client.execute(fv);
// Fetch object as Pojo class (map json to object)
Pojo myObject = response.getValue(Pojo.class);
System.out.println(myObject.foo);
client.shutdown();
}
}
import java.net.UnknownHostException; import java.util.concurrent.ExecutionException; public static void main(String [] args) throws UnknownHostException, ExecutionException, InterruptedException {
RiakClient client = RiakClient.newClient(10017, "127.0.0.1");
Location location = new Location(new Namespace("TestBucket"), "TestKey");
FetchValue fv = new FetchValue.Builder(location)
.withOption(StoreValue.Option.R, Quorum.oneQuorum())
.withOption(StoreValue.Option.PR, Quorum.oneQuorum()).build();
FetchValue.Response response = client.execute(fv);
// Fetch object as Pojo class (map json to object)
Pojo myObject = response.getValue(Pojo.class);
System.out.println(myObject.foo);
client.shutdown();
}
}
<hr>
<a name="advanced"/>
# The Hard Way
## Eventual Consistency; Resolvers, and Converters
In many environments, you're going to configure your buckets to allow siblings and write the code that deals with them.
It's worth mentioning here that there's two ways to handle a read/modify/write cycle with the Java client; either doing a fetch, modifying the object, then storing it back to Riak in a separate store operation or encapsulating the entire read/modify/write cycle in the store operation. Note that if you plan to do the former and your own POJO you must include a `byte[]` or `VClock` field annotated with the `@RiakVClock` annotation. This preserves the vector clock in your POJO and is used during the subsequent store operation. For more information on this please see the section on [Storing data in Riak](https://github.com/basho/riak-java-client/wiki/Storing-data-in-riak). **(Note: This is a new feature of the 1.0.6 client release. Previous versions do not have this functionality and the read/modify/write cycle must be encapsulated in the store operation.)**
There are two Interfaces you're going to be using:
* [ConflictResolver<T>](http://basho.github.com/riak-java-client/1.0.5/com/basho/riak/client/cap/ConflictResolver.html)<BR>
This Interface is used to resolve sibling records returned by Riak
* [Converter<T>](http://basho.github.com/riak-java-client/1.0.5/com/basho/riak/client/convert/Converter.html)<br>
This interface is used to serialize/deserialize data to/from Riak
Here's the anatomy of making a fetch request using the Bucket interface and the returned FetchObject:
<a name="figure1"/>
### Figure 1
![Riak fetch](http://dl.dropbox.com/u/74693818/RJC-fetch-v2.png)
There are three versions of fetch() available via the Bucket interface.
The first takes only a (String) key as an argument and returns a FetchObject<IRiakObject>. If you don't wish to do conversion to/from a POJO and instead deal with the raw data, this is what you want to use.
The second takes a (String) key and your POJO class (e.g. MyPojo.class) as arguments. The <T> Generic is inferred from this (see above), providing you with a FetchObject<MyPojo>.
The third takes an instance of your POJO class with a String field annotated with @RiakKey which contains the key. Again, the <T> is inferred from this and you are returned a FetchObject<MyPojo>.
If you do not provide a ConflictResolver, an instance of [DefaultResolver<T>](http://basho.github.com/riak-java-client/1.0.5/com/basho/riak/client/cap/DefaultResolver.html) is provided. This is actually not really a resolver at all; it throws an exception if siblings are present. If you do not provide a Converter, the [JSONConverter<T>](http://basho.github.com/riak-java-client/1.0.5/com/basho/riak/client/convert/JSONConverter.html) is provided. This Converter uses the Jackson JSON library to deserialize your POJO from JSON stored in Riak. For an example of implementing a customer converter that uses a different serialization library, check out [[using a customer converter|Using-a-custom-Converter]].
The following example demonstrates the use of these interfaces and your own POJO. These are the same implementations we use for our [[Advanced Examples for storing data in Riak|Storing-data-in-riak#wiki-advanced]] and model a game "leaderboard" system.
// TODO