Webinar Recap - MapReduce Querying in Riak

July 27, 2010 at 05:00 PM | categories: Riak, Map/Reduce, NoSQL, Database

Thank you to all who attended the webinar last Thursday, it was a great turnout with awesome engagement. Like before, we're recapping the questions below for everyone's sake (in no particular order). If you missed the webinar, want some more information, or want to ask us some more questions, we've prepared a resource page for you. As always, you can also get ahold of us directly.

Q: Say I want to perform two-fold link walking but don't want to keep the "walk-through" results, including the initial one. Can I do something to keep only the last result?

In a MapReduce query, you can specify any number of phases to keep or ignore using the "keep" parameter on the phase. Usually you only want to keep the final phase. If you're using the link-walker resource, it'll return results from any phases whose specs end in "1". See the REST API wiki page for more information on link-walking.

Q: Will Riak Search work along with MapReduce, for example, to avoid queries over entire bucket? Will there be a webinar about Riak Search?

Yes, we intend to have this feature in the Generally Available release of Riak Search. We will definitely have a webinar about Riak Search close to its public release.

Q: Are there still problems with executing "qfun" functions from Erlang during MapReduce?

"qfun" phases (that use anonymous Erlang functions) will work on a one-node cluster, but not across a multi-node cluster. You can use them in development but it's best to switch to a compiled module function or Javascript function when moving to production.

Q: Although streams weren't mentioned, do you have any recommendations on when to use streaming map/reduce versus normal map/reduce?

Streaming MapReduce sends results back as they get produced from the last phase, in a multipart/mixed format. To invoke this, add ?chunked=true to the URL when you submit the job. Streaming might be appropriate when you expect the result set to be very large and have constructed your application such that incomplete results are useful to it. For example, in an AJAX web application, it might make sense to send some results to the browser before the entire query is complete.

Q: How do you indicate to Riak that the input key is a list of keys rather than a key whose value should be passed to the map function?

A custom map function could accomplish this, like the Javascript example below. The example assumes its input has a JSON Array of keys in the target bucket, and that the target bucket is the key of the input object.

function(object, keyData, arg){
  var keys = Riak.mapValuesJson(object)[0];
  return keys.map(function(item){ return [object.key, item] });
}

There's more to this issue — we discuss it in the next question.

Q: Which way is faster: storing a lot of links or storing the target keys in the value as a list? Are there any limits to the maximum number of links on a key?

How the links are stored will likely not have a huge impact on performance. If you choose to store a key list in a document, both methods would work. There are two relevant operations that would be performed with the key list document (updating and traversal).

The update process would involve retrieving the list, adding a value, and saving the list. If you are using the REST interface you will need to be aware of limitations in the number of allowed headers and the allowed header length. Mochiweb restricts the number of allowed headers to 1000. Header length is limited to 8192 characters. This imposes an upper limit for the number of Links that can be set through the REST interface.

The best method for updating a key list would be to write a post commit hook that performed the update. This avoids the need to access the key list using the REST interface so header limitations are no longer a concern. However, the post-commit hook could become a bottleneck in your update path if number of links grows large.

Traversal involves retrieving the key list document, collecting the related keys, and outputting a bucket/key list to be used in proceeding map phases. A built-in function is provided to process links. If you were to store keys in the value you would need to write a custom function to parse the keys and generate a bucket/key list. (see above question)

Q: Are you planning to run distributed reduce phases in the future?

Yes, here are two relevant feature requests you can track:

Q: What's the benefit of passing an arg to a map or reduce phase? Couldn't you just send the function body with the arg value filled in? Can I pass in a list of args or an arbitrary number of args?

When you have a lot of queries that are similar but with minor differences, you might be able to generalize a map or reduce function so that it can vary based on the 'arg' parameter. Then you could store that function in a built-ins library (see the question below) so it's preloaded rather than evaluated at query-time. The arg parameter can be any valid JSON value.

Q: What's the behavior if the map function is missing from one or more nodes but present on others?

The entire query will fail. It's best to make sure, perhaps via automated deployment, that all of your functions are available on all nodes. Alternatively, you can store Javascript functions directly in Riak and use them in a phase with "bucket" and "key" instead of "source" or "name".

Q: If there are 2 map phases, for example, then does that mean that both phases will be run back to back on each individual node and *then* it's all sent back for reduce? Or is there some back and forth between phases?

It's more like a pipeline, one phase feeds the next. All results from one phase are sent back to the coordinating node, which then initiates the subsequent phase once all participating nodes have replied.

Q: Would it be possible to send a function which acts as both a map predicate and an updater?

In general we don't recommend modifying objects as part of a MapReduce job because it can add latency to the request. However, you may be able to implement this with a map function in Erlang. Erlang MapReduce functions have full access to Riak including being able to read and write data.

%% Inside your own Erlang module
map_predicate_with_update(Value,_KeyData,_Arg) ->
  case predicate(Value) of
    true -> [update_passed_value(Value)];
    _ -> []
  end.

update_passed_value(Value) ->
  {ok, C} = riak:local_client(),
  %% modify your object here, store with C:put
  ModifiedValue.

This could come in handy for large updates instead of having to pull each object, update it and store it.

Q: Are Erlang named functions or JS named functions more performant? Which are faster — JS or Erlang functions?

There is a slight overhead when encoding the Riak object to JSON but otherwise the performance is comparable.

Q: Is there a way to use namespacing to define named Javascript functions? In other words, if I had a bunch of app-specific functions, what's the best way to handle that?

Yes, checkout the built-in Javascript MapReduce functions for an example.

Q: Can you specify how data is distributed among the cluster?

In short, no. Riak consistently hashes keys to determine where in the cluster data is located. This article explains how data is replicated and distributed throughout the cluster. In most production situations, your data will be evenly distributed.

Q: What is the reason for the nested list of inputs to a MapReduce query?

The nested list lets you specify multiple keys as inputs to your query, rather than a single bucket name or key. From the Erlang client, inputs are expressed as lists of tuples (fixed-length arrays) which have length of 2 (for bucket/key) or 3 (bucket/key/key-specific-data). Since JSON has no tuple type, we have to express the inputs as arrays of length 2 or 3 within an array.

Q: Is there a syntax requirement of JSON for Riak?

JSON is only required for the MapReduce query when submitted via HTTP, the objects you store can be in any format that your application will understand. JSON also happens to be a convenient format for MapReduce processing because it is accessible to both Erlang and Javascript. However, it is fairly common for Erlang-native applications to store data in Riak as serialized Erlang datatypes.

Q: Is there any significance to the name of file for how Riak finds the saved functions? I assume you can leave other languages in the same folder and it would be ignored as long as language is set to javascript? Additionally, is it possible/does it make sense to combine all your languages into a single folder?

Riak only looks for "*.js" files in the js_source_dir folder (see Configuration Files on the wiki). Erlang modules that contain map and reduce functions need to be on the code path, which could be completely separate from where the Javascript files are located.

Q: Would you point us to any best practices around matrix computations in Riak? I don't see any references to matrix in the riak wiki...

We don't have any specific support for matrix computations. We encourage you to find an appropriate Javascript or Erlang library to support your application.

Dan and Sean



Free Webinar - Map/Reduce Querying in Riak - July 22 @ 2PM Eastern

July 15, 2010 at 03:00 PM | categories: Riak, Map/Reduce, NoSQL, Database

Map-Reduce is a flexible and powerful alternative to declarative query languages like SQL that takes advantage of Riak's distributed architecture. However, it requires a whole new way of thinking about how to collect, process, and report your data, and is tightly coupled to how your data is stored in Riak.

We invite you to join us for a free webinar on Thursday, July 22 at 2:00PM Eastern Time (UTC-4) to talk about Map-Reduce Querying in Riak. We'll discuss:

  • How Riak's Map-Reduce differs from other systems and query languages
  • How to construct and submit Map-Reduce queries
  • Filtering, extracting, transforming, aggregating, and sorting data
  • Understanding the efficiency of various types of queries
  • Building and deploying reusable Map-Reduce function libraries

We'll cover the above topics in conjunction with practical examples from sample applications. The presentation will last 30 to 45 minutes, with time for questions at the end.

Fill in the form below if you want to get started building applications with Map/Reduce on top of Riak!Sorry, registration has closed!

The Basho Team



Practical Map-Reduce: Forwarding and Collecting

April 14, 2010 at 05:00 PM | categories: Riak, Map/Reduce, NoSQL, Database

This may be a familiar sight to people in the NoSQL world:

Luckily, the comic is in jest and Map-Reduce in Riak is actually pretty easy. This post is an example of how you can solve a practical querying problem in Riak with Map-Reduce.

The Problem

This query problem comes via Jakub Stastny (botanicus online), who is building a task/todolist app with Riak as the datastore. The question we want to answer is: for the logged-in user, find all of the tasks and their associated “tags”. The schema looks kind of like this:


The simple task-list schema

Each of our domain concepts has its own bucket – users, tasks and tags. User objects have links to their tasks, tasks link to their tags, which also link back to the tasks. We’ll assume the data inside each object is JSON.

The Solution

We’re going to take advantage of these features of the map-reduce interface to make our query happen:

  1. You can use link phases where you just need to follow links on an object.
  2. Inputs to map phases can include arbitrary key-specific data.
  3. You can have as many map, reduce, and link phases as you want in the same job.

Let’s construct the JSON job step-by-step, starting with the input – the user object.

Next, we’ll use a link phase to find my tasks.

Now that we’ve got all of my tasks, we’ll use this map function to extract the relevant data we need from the task — including the links to its tags — and pass them along to the next map phase as the keydata. Basically it reads the task data as JSON, filters the object’s links to those only in the “tags” bucket, and then uses those links combined with our custom data to feed the next phase.

Here’s the phase that uses that function:

Now in the next map phase (which operates over the associated tags that we discovered in the last phase) we’ll insert the tag object’s parsed JSON contents into the “tags” list of the keydata object that was passed along from the previous phase. That modified object will become the input for our final reduce phase.

Here’s the phase specification for this phase (basically the same as the previous except for the function):

Finally, we have a reduce phase to collate the resulting objects with their included tags into single objects based on the task name.

Our final phase needs to return the results, so we add "keep":true to the phase specification:

Here’s the final format of our Map/Reduce job, with indentation for clarity:

I input some sample data into my local Riak node, linked it up according to the schema described above and this is what I got:

Conclusion

What I’ve shown you above is just a taste of what you can do with Map/Reduce in Riak. If the above query became common in your application, you would want to store those phase functions we created as built-ins and refer to them by name rather than by their source. Happy querying!

Sean



Calling all Rubyists - Ripple has Arrived!

February 11, 2010 at 11:30 AM | categories: Riak, Ruby, Map/Reduce, NoSQL

The Basho Dev. Team has been very excited about working with the Ruby community for some time. The only problem was we were heads down on so many other projects that it was hard to make any progress. But, even with all that work on our plate, we were committed to showing some love to Rubyists and their frameworks.

Enter Sean Cribbs. As Sean details in his latest blog post, "You Got your Riak in my Ruby," Basho and the stellar team at Sonian made it possible for him to hack on Ripple, a one-of-a-kind client library and object mapper for Riak. The full feature set for Ripple can be found on Sean's blog, but highlights include a DataMapper-like API, an easy builder-style interface to Map/Reduce, and near-term integration with Rails 3.

And, in case you need any convincing that you should consider Riak as the primary datastore for your next Rails app, check out Sean's earlier post, "Why Riak should power your next Rails app."

So, if you've read enough and want to get your hands on Ripple, go check it out on GitHub.

If you don't have Riak downloaded and built yet, get on it.

Lastly, you are going to be seeing a lot more Riak in your Ruby. So stay tuned because we have some big plans.

Best,

Mark



The Release Riak 0.8 and JavaScript Map/Reduce

February 03, 2010 at 04:00 PM | categories: Riak, JavaScript, Map/Reduce, Screencast

We are happy to announce the release of Riak 0.8 available for download immediately. Riak 0.8 features a number of enhancements to the core map/reduce machinery that will make Riak more accessible to a wider audience. The biggest enhancement is the ability to write map/reduce queries in JavaScript. We're using our erlang_js project to integrate Mozilla's Spidermonkey engine directly into Riak to keep overhead to a minimum.

We've also built a spiffy REST API for submitting map/reduce queries. Queries are described in JSON and POST-ed to the Riak server. Results are sent back as JSON for your processing pleasure. And, the REST interface supports streaming results for large result sets, too.

To kick it all off, we've put together a short screencast demonstrating how to use Riak's flashy new features. You can watch it below, or view it on Vimeo. There's also a slew of bug fixes and optimizations included in Riak 0.8. See the release notes for all the juicy details.

Download and enjoy!

Kevin

View on Vimeo



Basho Podcast Two - An Introduction to erlang_js

January 19, 2010 at 09:10 AM | categories: Riak, Map/Reduce, NoSQL, Database, JavaScript, erlang_js, Scaling, Podcast

Check out the new Basho podcast featuring Kevin Smith and Bryan Fink that discusses erlang_js, a simple and easy-to-use binding between Erlang and JavaScript. It is packaged as an OTP application so developers can easily embed Javascript inside their own applications.

Once you are done with the podcast, go download erlang_js.

Enjoy,

Mark Phillips



Right click here to download the Podcast



Basho Podcast Number 1 - Justin Sheehy and Tony Falco on Scaling out with Riak and Riak Search.

December 11, 2009 at 09:10 AM | categories: , Search, Riak, Map/Reduce, Database, Scaling, Podcast, Distributed Systems

Just out: Basho’s first podcast discussing Riak. Justin Sheehy and Tony Falco revisit the definition of scalability Justin first discussed at NoSQL East 2009, discuss EC2, Riak, and Riak’s map/reduce and soon-to-be-released distributed search and indexing. As a special bonus, at 3:24 in the podcast, listen for the sound of Kevin Smith’s SMS accepting the job at Basho. The mic did not pick up Justin’s grimace. Of course, he didn’t miss a beat. "I just did, Bob...."

Enjoy,

Mark Phillips



Right click here to download the Podcast