{"id":106,"date":"2014-12-16T19:33:53","date_gmt":"2014-12-16T19:33:52","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/"},"modified":"2014-12-16T19:33:53","modified_gmt":"2014-12-16T19:33:52","slug":"incremental-mapreduce-analytics-r","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/pt\/incremental-mapreduce-analytics-r\/","title":{"rendered":"Incremental Mapreduce for Analytics with R"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><span><em>[This post also appears on Dustin&#8217;s github blog.]<\/em><\/span><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I&#8217;ve been wanting to describe some of my work with using R to help me understand data I&#8217;m collecting in Couchbase Server<sup>\u2020<\/sup> because I find it quite interesting, useful and easy. However, it&#8217;s been difficult for me to figure out a good starting point because I don&#8217;t know who the audience would be. That is, finding the right set of assumptions to get going has been quite hard.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Last week, however, I spoke to a really awesome guy in a media company who had a specific question: \u201cHow can my analyists report on all the wonderful data I\u2019m storing in <a href=\"https:\/\/www.couchbase.com\/\">Couchbase<\/a>?\u201d I dug deeper. Who are these analysts? What tools do they use?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><sup>\u2020<\/sup> the incremental Map Reduce Views are identical to Apache CouchDB views, so everything will also work with CouchDB<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">My Audience<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Turns out, the analysists pretty close to what I would imagine. They often use some kind of data warehousing tools from Oracle that do all kinds of great magic, and then fall over really hard if you drift outside of bounds they\u2019re comfortable with. This sounded like something I could ignore. But then he said something that gave me a pretty solid foothold. While they\u2019re not programmers, they do use <a href=\"https:\/\/www.r-project.org\/\">R<\/a> as part of their data analysis.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Because this question was asked by a Couchbase user who wanted to know how to get his data out, I\u2019m going to assume anyone reading this knows R a bit better than Couchbase.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">About Views<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">There are a lot of things you can read if you want to understand the couch view concept. The view chapter of the <em>Couchbase Server Manual<\/em> covers the concept pretty well. If you want to know everything you can know, then dig through that, but for most of my uses, it really comes down to three things:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Extract the useful information.<\/li>\n\n\n<li>Sort it, putting like things together.<\/li>\n\n\n<li>Do some basic aggregation.<\/li>\n\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">That\u2019s how I take a lot of data and turn it into useful information most of the time. Hopefully the examples that follow will help you do the same.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The Data<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The hardest part of any data grokking tutorial is that it\u2019s never about your data. This simultaneously makes it less interesting to the reader and often makes it a bit harder to apply to your own problems.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unfortunately, the most interesting data I regularly extract for reporting is somewhat sensitive, so I can\u2019t share the things that I\u2019ve got the most use out of, but I\u2019m hoping this will help lead you to something interesting.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The data I\u2019ve chosen to work with is the SFPD Reported incidents set from the <a href=\"https:\/\/data.sfgov.org\/\">SF Data Website<\/a> web site. It\u2019s pretty much everything that the SFPD has reported since 2003.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">These documents are pretty regular and flat. Your data may be more complicated, but the techniques are the same. Let\u2019s begin by looking at an example document from the SFPD data set:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">{<br>\n&#8220;category&#8221;: &#8220;Prostitution&#8221;,<br>\n&#8220;incident_id&#8221;: 90096348,<br>\n&#8220;district&#8221;: &#8220;Tenderloin&#8221;,<br>\n&#8220;timestamp&#8221;: &#8220;2009-01-27T04:03:00&#8221;,<br>\n&#8220;lon&#8221;: -122.416261836834,<br>\n&#8220;lat&#8221;: 37.7853750846376,<br>\n&#8220;location&#8221;: &#8220;Ofarrell St \/ Hyde St&#8221;,<br>\n&#8220;time&#8221;: &#8220;04:03&#8221;,<br>\n&#8220;date&#8221;: &#8220;2009-01-27&#8221;,<br>\n&#8220;resolution&#8221;: &#8220;Arrest, Cited&#8221;,<br>\n&#8220;day&#8221;: &#8220;Tuesday&#8221;,<br>\n&#8220;desc&#8221;: &#8220;Solicits To Visit House Of Prostitution&#8221;<br>\n}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I think I can understand what all these things are, so let\u2019s get to work.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Getting Data into R<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">There are a few packages I\u2019ll be using here, so let\u2019s make sure we get those into your R before we go:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">install.packages(c(&#8216;rjson&#8217;, &#8216;ggplot2&#8217;, &#8216;reshape&#8217;),<br>\ndependencies=TRUE)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">require(rjson)<br>\nrequire(reshape)<br>\nrequire(RColorBrewer)<br>\nrequire(ggplot2)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As R likes \u201csquare\u201d data, I tend to have the output of my views be very regular, which also means I can have very simple functions for taking a view and pulling it back out. For this purpose, I have some basic common setup in my R scripts that looks like this:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># Pointer to your couchbase view base. \u00a0This is where you find your<br>\n# own data<br>\nurlBase<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># This is your basic GET request -&gt; parsed JSON.<br>\ngetData \u00a0 \u00a0 \u00a0 \u00a0 fromJSON(file=paste(urlBase, subpath, sep=&#8221;))$rows<br>\n}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># And this flattens it into a data frame, optionaly naming the<br>\n# columns.<br>\ngetFlatData \u00a0 \u00a0 \u00a0 \u00a0 b \u00a0 \u00a0 \u00a0 \u00a0 if (!is.null(n)) {<br>\nnames(b) \u00a0 \u00a0 \u00a0 \u00a0 }<br>\nb<br>\n}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># Also, I&#8217;m going to be working with days of week, so I need these:<br>\ndow \u00a0 \u00a0 \u00a0 \u00a0 \u00a0&#8216;Thursday&#8217;, &#8216;Friday&#8217;, &#8216;Saturday&#8217;)<br>\nshortdow<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Overall Crime Report Count<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">As with most data sets, I don\u2019t actually even know where to start, so first let\u2019s just see what kinds of crimes we\u2019ve got. I\u2019m interested in total counts and counts by day of week. The nice thing is that with couch views, I can build a single view that will tell me either. Let\u2019s look at the view source:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">function(doc) {<br>\nemit([doc.category, doc.day], null);<br>\n}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Looks really simple, but combined with the <code>_count<\/code>built-in reducer, this can do a lot of neat things when grouping. With <code>group_level=1<\/code>, we get crime count by category. Let\u2019s plot that and see what\u2019s popular. Assuming we saved that in a design document called <code>categories<\/code>with the view name of <code>byday<\/code>here\u2019s what you tell R:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># Get a dataframe containing the categories and their respective counts<br>\ncat \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0c(&#8216;cat&#8217;, &#8216;count&#8217;))<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># The columns come back as strings and requires fixes to make it useful<br>\ncat$cat cat$count # Also, I found sorting it by count made it easier to understand<br>\ncat$cat<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># Now plot it.<br>\nggplot(cat, aes(cat, count, alpha=count)) +<br>\ngeom_bar(fill=&#8217;#333399&#8242;, stat=&#8217;identity&#8217;) +<br>\nscale_alpha(to=c(0.4, 0.9), legend=FALSE) +<br>\nscale_y_continuous(formatter=&#8221;comma&#8221;) +<br>\nlabs(x=&#8221;, y=&#8221;) +<br>\nopts(title=&#8217;Total Crime Reports&#8217;) +<br>\ncoord_flip() +<br>\ntheme_bw()<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then R will give you this:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><img decoding=\"async\" src=\"https:\/\/dustin.github.com\/images\/r\/sfpd_cats.png\" alt=\"all cats\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">By Day of Week<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I found this to be somewhat interesting, so I wanted to know what the distribution was by day of week. I can use the same view above with <code>group_level=2<\/code>, but since the rates are tremendously different, I had R compute the relative variance across the data frame for each category by day of week and then plotted that. Here\u2019s the R code:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># Grab the same data, but separated by day of week.<br>\ncat_byday \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0c(&#8216;cat&#8217;, &#8216;day&#8217;, &#8216;count&#8217;))<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># I&#8217;m doing similar fixup to the above, but with another ordering and<br>\n# a couple views of day of week (much for playing around)<br>\ncat_byday$cat cat_byday$cat cat_byday$count cat_byday$cat_by_count cat_byday$day cat_byday$shortdow<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># Compute the percentage of each category by its day of week<br>\na1 a2 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 sum)<br>\ntotal_per_day cat_byday$perc<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># Let&#8217;s see what this looks like<br>\nggplot(cat_byday, aes(shortdow, cat, size=perc, alpha=perc)) +<br>\ngeom_point(color=&#8217;#333399&#8242;) +<br>\nscale_alpha(legend=FALSE) +<br>\nscale_size(legend=FALSE) +<br>\nscale_y_discrete(limits=rev(levels(cat_byday$cat))) +<br>\nlabs(x=&#8221;, y=&#8221;) +<br>\ntheme_bw()<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That seems like a lot of setup, but it was mostly just type setup and stuff. We\u2019ll reuse some below. At this point, we\u2019ve got something to look at, though:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><img decoding=\"async\" src=\"https:\/\/dustin.github.com\/images\/r\/sfpd_all_by_day.png\" alt=\"all cats by day\"><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Focused Subset<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">There\u2019s a lot of data here and it\u2019s all relative making it hard to kind of see how to compare things. I wanted to really look at a couple of areas and figure out what kinds of correlations existed. As I already had the data loaded, I figured I\u2019d just grab a subset of what was already requested and facet plot it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># Pick a few categories of interest<br>\ninteresting \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0&#8216;Prostitution&#8217;,<br>\n&#8216;Drunkenness&#8217;,<br>\n&#8216;Disorderly Conduct&#8217;)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># Extract just this subset and refactor the categories<br>\nsex_and_drugs sex_and_drugs$cat<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">ggplot(sex_and_drugs, aes(shortdow, count)) +<br>\nfacet_wrap(~cat, scales=&#8217;free_y&#8217;) +<br>\ngeom_bar(fill=&#8217;#333399&#8242;, stat=&#8217;identity&#8217;) +<br>\nscale_y_continuous(formatter=&#8221;comma&#8221;) +<br>\nlabs(x=&#8221;, y=&#8221;) +<br>\nopts(title=&#8217;Select Crime Reports by Day&#8217;) +<br>\ntheme_bw()<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">And that should show me a lot more detail on these individual categories.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><img decoding=\"async\" src=\"https:\/\/dustin.github.com\/images\/r\/sfpd_sex_and_drugs.png\" alt=\"sex and drugs\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Personally, I found the lack of correlation between alcohol related incidents and others quite interesting. Alcohol seems to be the anti-drug. Maybe prostitutes don\u2019t like drunks. Who knows\u2026<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Over Time<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">At this point, I realized the data\u2019s going back to 2003 and I haven\u2019t even considered whether things are getting better or worse. I didn\u2019t really explore this very much, but wanted to get a quick feel for whether things are getting better or worse. Here\u2019s a view that will tell us incident rates by year and category:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">function(doc) {<br>\nvar ymd = doc.date.split(&#8216;-&#8216;);<br>\nemit([parseInt(ymd[0], 10), doc.category], null);<br>\n}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">As in all these examples, I combine this with the <code>_count<\/code>built-in reduce. Let\u2019s just chart up the yearly rates with the following R:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">byyear \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 c(&#8216;year&#8217;, &#8216;count&#8217;))<br>\nbyyear$year<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># There&#8217;s not enough 2012 here, so let&#8217;s ignore that for this chart.<br>\nggplot(byyear[byyear$year &lt; 2012,], aes(year, count)) +<br>\nstat_smooth(fill=&#8217;#333399&#8242;) +<br>\nlabs(y=&#8221;, x=&#8221;) +<br>\nscale_y_continuous(formatter=comma) +<br>\nopts(title=&#8221;Total Incident Reports by Year&#8221;) +<br>\ntheme_bw()<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">What\u2019s this tell us?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><img decoding=\"async\" src=\"https:\/\/dustin.github.com\/images\/r\/sfpd_byyear.png\" alt=\"by year\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Looks like things are getting better (or police are getting lazier). I could dig into this a bit more to find out whether it\u2019s true for all categories, but I\u2019m not that interested, so let\u2019s look at something else.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Crime by Area<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I was interested in knowing whether certain crimes were more popular in some areas than others. I\u2019m using the doc\u2019s <code>district<\/code>property for this (rather than the built-in coordinates) and thought it might be a good use case for a heatmap.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">One thing I noticed is that some reports don\u2019t have a district associated with them. I chose to ignore those for this report, but you can quite easily see how you might substitute it with a custom value if you wanted to specifically consider it. Let\u2019s begin with the following view code:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">function(doc) {<br>\nif (doc.district != null) {<br>\nemit([doc.category, doc.district], null);<br>\n}<br>\n}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Of course, we\u2019ll use the <code>_count<\/code>built-in again. One thing I should note about this is that while I did originally plot <em>all<\/em> data, I later decided that I wasn\u2019t interested in any area that had less than 1,000 crimes reported. As this is the <em>output<\/em> of the filter, I needed to apply that in R as we have no means of requesting that from couch a view (since the views are materialized and the map function did not include a filter before the reduce was applied). Ideally, we\u2019d support this in the actual view request, but in the meantime, we can extract it easily in post:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">by_region \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 c(&#8216;cat&#8217;, &#8216;region&#8217;, &#8216;count&#8217;))<br>\nby_region$count by_region$region<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"># Ignore anything that doesn&#8217;t have at least 1,000 incidents<br>\npop_regions 1000,]<br>\npop_regions$cat # And have the hottest crimes float to the top<br>\npop_regions$cat<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">ggplot(pop_regions, aes(x=region, y=cat, fill=count, alpha=count)) +<br>\ngeom_tile() +<br>\nscale_fill_continuous(&#8216;Incidents&#8217;,<br>\nformatter=function(x)<br>\nsprintf(&#8220;%dk&#8221;, x \/ 1000)) +<br>\nscale_alpha_continuous(legend=FALSE, to=c(0.7, 1.0)) +<br>\nlabs(x=&#8221;, y=&#8221;) +<br>\ntheme_bw() +<br>\nopts(title=&#8217;Crime Types by District&#8217;,<br>\naxis.text.x=theme_text(angle=-90),<br>\nlegend.position=&#8217;right&#8217;)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That gives us the following heatmap:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><img decoding=\"async\" src=\"https:\/\/dustin.github.com\/images\/r\/sfpd_regions.png\" alt=\"regions\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The blank areas didn\u2019t have 1,000 incidents of the specified type of crime in the indicated area since 2003. The lighter blue areas have had some incidents. The bright red have the most. Looks like I want to avoid the southern district.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How Many Does the DA Refuse?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">As an example of pulling a server-side aggregate on part of the data, I found the \u201cDistrict Attorney Refuses To Prosecute\u201d resolution type particularly interesting, so I wanted to know how often this happens. Again, we start with a simple view:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">function(doc) {<br>\nemit([doc.resolution, doc.category], null);<br>\n}<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Then we do our normal <code>_count<\/code>thing. However, the difference here is that when I do the request, I want to use the <code>start_key<\/code>and <code>end_key<\/code>parameters to find only things that were resolved in this way. I happen to know that the list of resolutions goes from \u201cDistrict Attorney Refuses To Prosecute\u201d to \u201cExceptional Clearance\u201d, so I can just look for things that start with \u201cDi\u201d and end with things that start with \u201cDj\u201d. These are also arrays I\u2019m emitting, so it\u2019s really based on the first element of the array. The R code then looks like this:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">by_resolution \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0&#8216;?group_level=2&amp;start_key=[&#8220;Di]&#8217;,<br>\n&#8216;&amp;end_key=[&#8220;Dj&#8221;]&#8217;, sep=&#8221;&#8221;),<br>\nc(&#8216;resolution&#8217;, &#8216;cat&#8217;, &#8216;count&#8217;))<br>\nby_resolution$count by_resolution$cat by_resolution$cat<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">ggplot(by_resolution, aes(cat, count, alpha=count)) +<br>\nscale_alpha(to=c(0.4, 0.9), legend=FALSE) +<br>\ncoord_flip() +<br>\ngeom_bar(fill=&#8217;#333399&#8242;, stat=&#8217;identity&#8217;) +<br>\nlabs(x=&#8221;, y=&#8221;) +<br>\nopts(title=&#8217;Crimes the DA Refused to Prosecute&#8217;) +<br>\ntheme_bw()<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">R then gives us the following:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><img decoding=\"async\" src=\"https:\/\/dustin.github.com\/images\/r\/sfpd_da_refused.png\" alt=\"regions\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Do note that these are <em>absolute<\/em> numbers. Don\u2019t call up SF and complain because they don\u2019t care about assault as they care about vandalism. There are simply more of those cases. I\u2019ll leave as an exercise to the reader evaluating resolution types by category and deciding what to think about them.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">In Conclusion<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">I could obviously keep going with this for days, but just wanted to help people understand my process. In most places I use this, the patterns are similar. Data sets may grow very large, but the aggregations remain small. Incremental processing of the views means my sorted and aggregated answers continue to arrive quickly and processing remains cheap.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>[This post also appears on Dustin&#8217;s github blog.] I&#8217;ve been wanting to describe some of my work with using R to help me understand data I&#8217;m collecting in Couchbase Server\u2020 because I find it quite interesting, useful and easy. However, it&#8217;s been difficult for me to figure out a good starting point because I don&#8217;t [&hellip;]<\/p>\n","protected":false},"author":34,"featured_media":18,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"_acf":"","footnotes":""},"categories":[1],"tags":[],"ppma_author":[59],"class_list":["post-106","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.6 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Incremental Mapreduce for Analytics with R - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/pt\/incremental-mapreduce-analytics-r\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Incremental Mapreduce for Analytics with R\" \/>\n<meta property=\"og:description\" content=\"[This post also appears on Dustin&#8217;s github blog.] I&#8217;ve been wanting to describe some of my work with using R to help me understand data I&#8217;m collecting in Couchbase Server\u2020 because I find it quite interesting, useful and easy. However, it&#8217;s been difficult for me to figure out a good starting point because I don&#8217;t [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/pt\/incremental-mapreduce-analytics-r\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2014-12-16T19:33:52+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Dustin Sallings, Chief Architect, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dustin Sallings, Chief Architect, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/\"},\"author\":{\"name\":\"Dustin Sallings, Chief Architect, Couchbase\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/e68b6f4489072ef4a84f60bc437c07d0\"},\"headline\":\"Incremental Mapreduce for Analytics with R\",\"datePublished\":\"2014-12-16T19:33:52+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/\"},\"wordCount\":2230,\"commentCount\":6,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Uncategorized\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/\",\"name\":\"Incremental Mapreduce for Analytics with R - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2014-12-16T19:33:52+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/05\\\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/incremental-mapreduce-analytics-r\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Incremental Mapreduce for Analytics with R\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/5\\\/2026\\\/06\\\/logo.svg\",\"width\":\"1024\",\"height\":\"1024\",\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/e68b6f4489072ef4a84f60bc437c07d0\",\"name\":\"Dustin Sallings, Chief Architect, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=gc5bddc8d7dab8b5c9121282556b0dbff\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=g\",\"caption\":\"Dustin Sallings, Chief Architect, Couchbase\"},\"description\":\"Dustin Sallings is a Chief Architect at Couchbase. Dustin is an Author of spymemcached and core contributor to Couchbase and Memcached projects.\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/pt\\\/author\\\/dustin-sallings\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Incremental Mapreduce for Analytics with R - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/pt\/incremental-mapreduce-analytics-r\/","og_locale":"pt_BR","og_type":"article","og_title":"Incremental Mapreduce for Analytics with R","og_description":"[This post also appears on Dustin&#8217;s github blog.] I&#8217;ve been wanting to describe some of my work with using R to help me understand data I&#8217;m collecting in Couchbase Server\u2020 because I find it quite interesting, useful and easy. However, it&#8217;s been difficult for me to figure out a good starting point because I don&#8217;t [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/pt\/incremental-mapreduce-analytics-r\/","og_site_name":"The Couchbase Blog","article_published_time":"2014-12-16T19:33:52+00:00","og_image":[{"width":1800,"height":630,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","type":"image\/png"}],"author":"Dustin Sallings, Chief Architect, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Dustin Sallings, Chief Architect, Couchbase","Est. reading time":"11 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/"},"author":{"name":"Dustin Sallings, Chief Architect, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/e68b6f4489072ef4a84f60bc437c07d0"},"headline":"Incremental Mapreduce for Analytics with R","datePublished":"2014-12-16T19:33:52+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/"},"wordCount":2230,"commentCount":6,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","articleSection":["Uncategorized"],"inLanguage":"pt-BR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/","url":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/","name":"Incremental Mapreduce for Analytics with R - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","datePublished":"2014-12-16T19:33:52+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/05\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/incremental-mapreduce-analytics-r\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Incremental Mapreduce for Analytics with R"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/5\/2026\/06\/logo.svg","width":"1024","height":"1024","caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/e68b6f4489072ef4a84f60bc437c07d0","name":"Dustin Sallings, Chief Architect, Couchbase","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/secure.gravatar.com\/avatar\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=gc5bddc8d7dab8b5c9121282556b0dbff","url":"https:\/\/secure.gravatar.com\/avatar\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=g","caption":"Dustin Sallings, Chief Architect, Couchbase"},"description":"Dustin Sallings is a Chief Architect at Couchbase. Dustin is an Author of spymemcached and core contributor to Couchbase and Memcached projects.","url":"https:\/\/www.couchbase.com\/blog\/pt\/author\/dustin-sallings\/"}]}},"acf":[],"authors":[{"term_id":59,"user_id":34,"is_guest":0,"slug":"dustin-sallings","display_name":"Dustin Sallings, Chief Architect, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/?s=96&d=mm&r=g","author_category":"","first_name":"Dustin","last_name":"Sallings","user_url":"","job_title":"","description":"Dustin Sallings is a Chief Architect at Couchbase. Dustin is an Author of spymemcached and core contributor to Couchbase and <a href=\"https:\/\/developer.couchbase.com\/documentation\/server\/3.x\/developer\/dev-guide-3.0\/memcached.html#projects\">Memcached projects.<\/a>"}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/106","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/34"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=106"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/106\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/18"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=106"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=106"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=106"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=106"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}