Data Types |
Traditionally all data stored in Riak was an opaque binary type. Then in version 1.4 came the introduction of a counter
<legacy_counters>
, the first Convergent Data Type supported in Riak. In Riak 2.0, several additional Data Types were introduced. Riak "knows" about these data types, and conflicting writes to them will converge automatically without presenting sibling values
<siblings>
to the user.
Here is the list of current Data Types:
- :py
~riak.datatypes.Counter
increments or decrements integer values- :py
~riak.datatypes.Set
allows you to store multiple distinct opaque binary values against a key- :py
~riak.datatypes.Map
is a nested, recursive struct, or associative array. Think of it as a container for composing ad hoc data structures from multiple Data Types. Inside a map you may store sets, counters, flags, registers, and even other maps- :py
~riak.datatypes.Register
stores binaries accoring to last-write-wins logic within :py~riak.datatypes.Map
- :py
~riak.datatypes.Flag
is similar to a boolean and also must be within :py~riak.datatypes.Map
All Data Types must be stored in buckets bearing a ~riak.bucket.BucketType
that sets the ~riak.bucket.BucketType.datatype
property to one of "counter"
, "set"
, or "map"
. Note that the bucket must have the allow_mult
property set to true
.
These Data Types are stored just like RiakObjects
<riak.riak_object.RiakObject>
, so size constraints that apply to normal Riak values apply to Riak Data Types too.
An in-depth discussion of Data Types, also known as CRDTs, can be found at Data Types.
Examples of using Data Types can be found at Using Data Types.
Riak Data Types provide a further departure from Riak's usual operation, in that the API is operation-based. Rather than fetching the data structure, reconciling conflicts, mutating the result, and writing it back, you instead tell Riak what operations to perform on the Data Type. Here are some example operations:
- increment a
Counter
by10
- add
'joe'
to aSet
- remove the
Set
field called'friends'
from aMap
- enable the prepay
Flag
in aMap
Datatypes can be fetched and created just like ~riak.riak_object.RiakObject
instances, using RiakBucket.get <riak.bucket.RiakBucket.get>
and RiakBucket.new <riak.bucket.RiakBucket.new>
, except that the bucket must belong to a bucket-type that has a valid datatype property. If we have a bucket-type named "social-graph" that has the datatype "set", we would fetch a Set
like so:
graph = client.bucket_type('social-graph')
graph.datatype # => 'set'
myfollowers = graph.bucket('followers').get('seancribbs')
# => a Set datatype
Once we have a datatype, we can stage operations against it and then send those operations to Riak:
myfollowers.add('javajolt')
myfollowers.discard('roach')
myfollowers.update()
While this looks in code very similar to manipulating ~riak.riak_object.RiakObject
instances, only mutations are enqueued locally, not the new value.
In order for Riak Data Types to behave well, you must have an opaque context received from a read when you:
disable <Flag.disable>
aFlag
(set it tofalse
)- remove a field from a
Map
remove <Set.discard>
an element from a :pySet
The basic rule is "you cannot remove something you haven't seen", and the context tells Riak what you've actually seen, similar to the vclock
on ~riak.riak_object.RiakObject
. The Python client handles opaque contexts for you transparently as long as you fetch before performing one of these actions.
Datatype
value
context
modified
Datatype.reload
Datatype.update
Datatype.store(**params)
This is an alias for ~riak.datatypes.Datatype.update
.
Datatype.delete
Datatype.clear
Counter
Counter.value
The current value of the counter.
- rtype
int
Counter.increment
Counter.decrement
Set
Set.value
An immutable copy of the current value of the set.
- rtype
frozenset
Set.add
Set.discard
Map
Map.value
Map.counters
Filters keys in the map to only those of counter types. Example:
map.counters['views'].increment()
del map.counters['points']
Map.flags
Filters keys in the map to only those of flag types. Example:
map.flags['confirmed'].enable()
del map.flags['attending']
Map.maps
Filters keys in the map to only those of map types. Example:
map.maps['emails'].registers['home'].set("user@example.com")
del map.maps['spam']
Map.registers
Filters keys in the map to only those of register types. Example:
map.registers['username'].set_value("riak-user")
del map.registers['access_key']
Map.sets
Filters keys in the map to only those of set types. Example:
map.sets['friends'].add("brett")
del map.sets['favorites']
Two of the new Data Types may only be embedded in :pyMap <riak.datatypes.Map>
objects (in addition to :pyMap <riak.datatypes.Map>
itself):
Register
Register.value
Register.assign
Flag
Flag.value
The current value of the flag.
- rtype
bool, None
Flag.enable
Flag.disable