Riak Precommit Hooks

A few nights ago, I hit my first real challenge with Riak.  Until now, it’s been smooth sailing, but this was a fun one.  I have a bucket which is going to get pretty large, write once, rarely read data.  I wanted to create a secondary index on a field so that when I want to look up the data, it doesn’t require a full M/R to do.  The great Riak Handbook showed a couple of examples of creating a secondary index, and it looked simple enough.  It actually is pretty simple, but the documentation and examples are few and far between, so I’m going to share my experience.

The bucket name I wanted to change was named “feedback”.  Whenever an item is created in this bucket, I want a secondary index based on the app.  I never update items in this bucket, only create.  In fact, I never delete these items either, but figured my code should handle that case.

To start, I added a foreign key (named “app”) to the JSON object being stored.  I’m using the PB client in Erlang and that was simple enough.

Object = mochijson:encode({struct, [{"platform", State#state.platform},
{"app", State#state.app_key},
{"createdOn", lio_support:nice_timestamp()},
{"message",  Message},
{"detectedSettings", {struct, State#state.detected_settings}},
{"emailAddress", Email_Address}]}))),

Now, all I need to do is create a precommit hook to the `feedback` bucket in Riak to create the index.

**Step 1: Modify Riak to include a new path**

In the app.config file for Riak, find the `riak_kv` section and insert a new value, if not already present:

{riak_kv, [
{add_paths, ["/some_path_to_modules/"]},

**Step 2: Create a new hook module**

Create a new file, named `feedback.erl` in this folder, and paste the following in it:

-module(feedback).

-export([precommit/1]).

-define(MD_DELETED,<<"X-Riak-Deleted">>).

precommit(Object) ->
case is_deleted(Object) of
false ->
riak_object:bucket(Object),
Key = riak_object:key(Object),
{struct, Properties} = mochijson2:decode(riak_object:get_value(Object)),
{<<;"app">>, App_Key} = lists:keyfind(<<"app">>, 1, (Poperties),
Updated_Meta = dict:store(<<"index">>, [{"app_bin", App_Key}], riak_object:get_metadata(Object)),
riak_object:update_metadata(Object, Updated_Meta);
true -> Object
end.

is_deleted(Object) ->
..(pretty straightforward to write this)..

**Step 3: Install the module**

You need to use the HTTP protocol to do this step.  Here’s the cURL script I wrote for this one:

curl -X PUT -H "content-type:application/json" http://localhost:8098/riak/feedback --data @- {"props":{"precommit":[{"mod": "feedback", "fun": "precommit"}]}}

Now, I’m the first to admit that I’m not a Riak expert (yet).  But this worked, and seems to be a pretty straightforward and simple solution.  If any Riak pros have anything to add, let me know - I’m always open to improving my code and skills!

 
  1. startup-tech posted this