<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>DeGizmo</title>
	
	<link>http://degizmo.com</link>
	<description>tech, webdev, and etc</description>
	<lastBuildDate>Wed, 13 Jun 2012 08:58:29 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/degizmo_blog" /><feedburner:info uri="degizmo_blog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>It’s the little things that count the most</title>
		<link>http://feedproxy.google.com/~r/degizmo_blog/~3/NqH9AG3Lico/</link>
		<comments>http://degizmo.com/2012/06/13/its-the-little-things-that-count-the-most/#comments</comments>
		<pubDate>Wed, 13 Jun 2012 08:58:29 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[External Content]]></category>
		<category><![CDATA[Gizmodo]]></category>

		<guid isPermaLink="false">http://degizmo.com/?p=50</guid>
		<description><![CDATA[http://gizmodo.com/5917967/you-wont-believe-how-insane-this-tiny-new-detail-in-ios-6-is iOS6 Details &#8211; Gyroscopic Reflection I noticed today that the reflection on the metallic sliders in the iPod app actually change as you tilt the phone from side to side.]]></description>
				<content:encoded><![CDATA[<p><a href="http://gizmodo.com/5917967/you-wont-believe-how-insane-this-tiny-new-detail-in-ios-6-is  ">http://gizmodo.com/5917967/you-wont-believe-how-insane-this-tiny-new-detail-in-ios-6-is</a></p>
<p><a href="http://www.youtube.com/watch?feature=player_embedded&amp;v=c9X7D87uJ7Q">iOS6 Details &#8211; Gyroscopic Reflection</a><br />
<iframe src="http://www.youtube.com/embed/c9X7D87uJ7Q" frameborder="0" width="420" height="315"></iframe></p>
<blockquote><p>I noticed today that the reflection on the metallic sliders in the iPod app actually change as you tilt the phone from side to side.</p></blockquote>
<img src="http://feeds.feedburner.com/~r/degizmo_blog/~4/NqH9AG3Lico" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://degizmo.com/2012/06/13/its-the-little-things-that-count-the-most/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://degizmo.com/2012/06/13/its-the-little-things-that-count-the-most/</feedburner:origLink></item>
		<item>
		<title>What makes a good engineering culture</title>
		<link>http://feedproxy.google.com/~r/degizmo_blog/~3/HLyIHZNOUQQ/</link>
		<comments>http://degizmo.com/2012/06/13/what-makes-a-good-engineering-culture/#comments</comments>
		<pubDate>Wed, 13 Jun 2012 08:34:50 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[Quora]]></category>

		<guid isPermaLink="false">http://degizmo.com/?p=46</guid>
		<description><![CDATA[http://www.quora.com/What-makes-a-good-engineering-culture One of my favorite interview questions for engineering candidates is to tell me about one thing they liked and one thing they disliked about the engineering culture at their previous company. Over the course of a few hundred interviews, this interview question has given me a sense of what good engineers look for and [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.quora.com/What-makes-a-good-engineering-culture">http://www.quora.com/What-makes-a-good-engineering-culture</a></p>
<blockquote><p>One of my favorite interview questions for engineering candidates is to tell me about one thing they liked and one thing they disliked about the engineering culture at their previous company. Over the course of a few hundred interviews, this interview question has given me a sense of what good engineers look for and what they&#8217;re trying to avoid. I also reflected back on my own experiences from the past six years working across Google, Ooyala, and Quora and distilled some things that a team can do to build a good engineering culture:</p>
<p><strong>1. Optimize for iteration speed.</strong></p>
<p><strong>2. Push relentlessly toward automation.</strong></p>
<p><strong>3. Build the right software abstractions.</strong></p>
<p><strong>4. Develop a focus on high code quality with code reviews.</strong></p>
<p><strong>5. Maintain a respectful work environment.</strong></p>
<p><strong>6. Build shared ownership of code.</strong></p>
<p><strong>7. Invest in automated testing.</strong></p>
<p><strong>8. Allot 20% time.</strong></p>
<p><strong>9. Build a culture of learning and continuous improvement.</strong></p>
<p><strong>10. Hire the best.</strong></p></blockquote>
<img src="http://feeds.feedburner.com/~r/degizmo_blog/~4/HLyIHZNOUQQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://degizmo.com/2012/06/13/what-makes-a-good-engineering-culture/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://degizmo.com/2012/06/13/what-makes-a-good-engineering-culture/</feedburner:origLink></item>
		<item>
		<title>JavaScript: The new lingua franca of the internet</title>
		<link>http://feedproxy.google.com/~r/degizmo_blog/~3/tHd6yuKVwBY/</link>
		<comments>http://degizmo.com/2011/02/16/javascript-the-new-lingua-franca-of-the-internet/#comments</comments>
		<pubDate>Wed, 16 Feb 2011 14:35:36 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Javascript]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://degizmo.com/?p=44</guid>
		<description><![CDATA[&#38;yet has a great post today which is beginning to outline the the framework of a &#8220;Javascript&#8221; ecosystem for a complete web application written all the way through the stack with Javascript. The server-side models and DB structure usually have strong relations to the content being displayed in the browser. For a web store the [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://andyet.net/">&amp;yet</a> has a great <a href="http://andyet.net/blog/2011/feb/15/re-using-backbonejs-models-on-the-server-with-node/">post today </a>which is beginning to outline the the framework of a &#8220;Javascript&#8221; ecosystem for a complete web application written all the way through the stack with Javascript. The server-side models and DB structure usually have strong relations to the content being displayed in the browser. For a web store the item has a title, description, price, related items, etc. You have one application model written in one language, displayed in the browser in HTML with some fancy JavaScript to model the object again and handle all the changes. Why duplicate all this code over and over, in different languages? Write it once in backbone and be done.</p>
<p><a href="http://andyet.net/">&amp;yet</a> has taken the stack of</p>
<ul>
<li><a href="http://documentcloud.github.com/backbone/">backbone.js</a></li>
<li><a href="http://www.commonjs.org/">CommonJS</a></li>
<li><a href="http://socket.io/">Socket.io</a></li>
<li><a href="http://nodejs.org/">node.js</a></li>
</ul>
<p>If you are looking at a seamless JavaScript stack, and already are using CouchDB you should also take a look at <a href="https://github.com/janmonschke/backbone-couchdb">backbone-couchdb</a> which is taking a different approach to the same complete JavaScript stack concept.</p>
<img src="http://feeds.feedburner.com/~r/degizmo_blog/~4/tHd6yuKVwBY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://degizmo.com/2011/02/16/javascript-the-new-lingua-franca-of-the-internet/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://degizmo.com/2011/02/16/javascript-the-new-lingua-franca-of-the-internet/</feedburner:origLink></item>
		<item>
		<title>CoffeeScript: Why I’m never writing Javascript again</title>
		<link>http://feedproxy.google.com/~r/degizmo_blog/~3/Lge06ylZYYE/</link>
		<comments>http://degizmo.com/2011/02/14/coffeescript-why-im-never-writing-javascript-again/#comments</comments>
		<pubDate>Mon, 14 Feb 2011 14:22:53 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[CoffeeScript]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://degizmo.com/?p=42</guid>
		<description><![CDATA[If you program in Javascript and haven't heard of CoffeeScript yet, you are missing out. I'm not going to talk about installing it or the basic usage of it as the original documentation and a few blogs already have done it in depth.

What I want to talk about is why it's so amazing and why I can never write Javascript again. I've been programming Python for quite a while now and when  you do work on the web (like with Django) you will eventually have to deal with the browser and if you want to do anything beyond basic form processing you'll need to deal with Javascript.]]></description>
				<content:encoded><![CDATA[<p>If you program in Javascript and haven&#8217;t heard of <a href="http://jashkenas.github.com/coffee-script/">CoffeeScript</a> yet, you are missing out. I&#8217;m not going to talk about <a href="http://jashkenas.github.com/coffee-script/#installation">installing it</a> or the <a href="http://jashkenas.github.com/coffee-script/#language">basic usage of it</a> as the original documentation and a few blogs already have talked about it.</p>
<p>What I want to talk about is why it&#8217;s so amazing and why I can never write Javascript again. I&#8217;ve been programming <a href="http://degizmo.com/category/programming/python/">Python</a> for quite a while now and when  you do work on the web (like with <a href="http://degizmo.com/series-django-tutorials/">Django</a>) you will eventually have to deal with the browser and if you want to do anything beyond basic form processing you&#8217;ll need to deal with Javascript.</p>
<p>The maturation of libraries like <a href="http://jquery.com/">jQuery</a> has made life, infinitely easier but, Javascript itself is still a strange little language. It&#8217;s actually deceptively simple, it that any decent programmer can probably trial and error his/her way through a simple Javascript feature pretty quickly. This is actually one of the strongest features of the language, most people can write Javascript without actually knowing Javascript but, this lack of structure and ease of use is apart of it&#8217;s tricky nature. Once you begin to do complicated things the quirks of the language start to arise: undefined oddities, antiquated array manipulation, limited standard library, strange object models, and for me personally as a Python programmer the mess of braces and semi-colons peppering my code with distracting syntax.</p>
<p>CoffeeScript is essentially a combination of a Ruby-esque syntax and a healthy dose of <a href="http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742">just the good parts</a> from Javascript. What you get is a fairly clean language that always &#8220;compiles&#8221; into very readable and workable Javascript. Which means anywhere you need to use Javascript: in the <a href="http://www.google.com/chrome">browser</a>, in <a href="http://nodejs.org/">node.js</a>, on the <a href="http://www.appcelerator.com/products/titanium-mobile-application-development/">iPhone</a>; you can use CoffeeScript.</p>
<p>I&#8217;m going to be writing a few posts playing with CoffeeScript in the future but, right now I&#8217;ll give you a few &#8220;out-of-the-box&#8221; examples of CoffeScript that isn&#8217;t just a basic example</p>
<p><a href="http://dhotson.tumblr.com/post/634304174/node-js-chat-server-in-coffeescript">Node.js chat server in CoffeeScript</a></p>
<p><a href="https://github.com/johnthethird/titanium-coffeescript-sample">Appcelerator iPhone Application in CoffeeScript</a></p>
<div id="_mcePaste"><a href="http://zombie.labnotes.org/">Insanely fast, headless full-stack testing using Node.js</a></div>
<img src="http://feeds.feedburner.com/~r/degizmo_blog/~4/Lge06ylZYYE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://degizmo.com/2011/02/14/coffeescript-why-im-never-writing-javascript-again/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		<feedburner:origLink>http://degizmo.com/2011/02/14/coffeescript-why-im-never-writing-javascript-again/</feedburner:origLink></item>
		<item>
		<title>Simon Willison: Redis Workshop</title>
		<link>http://feedproxy.google.com/~r/degizmo_blog/~3/UIOVAoAuRsU/</link>
		<comments>http://degizmo.com/2010/04/26/simon-willison-redis-workshop/#comments</comments>
		<pubDate>Mon, 26 Apr 2010 12:05:51 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[Redis]]></category>

		<guid isPermaLink="false">http://degizmo.com/?p=35</guid>
		<description><![CDATA[Simon Willison had a great presentation at NoSQL EU recently and published his slides and notes. It&#8217;s quite a comprehensive presentation that&#8217;s a good read for both beginners and advanced users. He presents some great use cases based off of real world examples and utilization. http://simonwillison.net/2010/Apr/25/redis/]]></description>
				<content:encoded><![CDATA[<p>Simon Willison had a great presentation at <a href="http://nosqleu.com/">NoSQL EU</a> recently and published his <a href="http://simonwillison.net/static/2010/redis-tutorial/">slides and notes</a>. It&#8217;s quite a comprehensive presentation that&#8217;s a good read for both beginners and advanced users. He presents some great use cases based off of real world examples and utilization.</p>
<p><a href="http://simonwillison.net/2010/Apr/25/redis/">http://simonwillison.net/2010/Apr/25/redis/</a></p>
<p><a href="http://simonwillison.net/static/2010/redis-tutorial/"><img class="alignnone" title="Redis Workshop" src="http://i.imgur.com/NsBHV.jpg" alt="" width="450" height="337" /></a></p>
<img src="http://feeds.feedburner.com/~r/degizmo_blog/~4/UIOVAoAuRsU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://degizmo.com/2010/04/26/simon-willison-redis-workshop/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://degizmo.com/2010/04/26/simon-willison-redis-workshop/</feedburner:origLink></item>
		<item>
		<title>Why you should upstream cache your 404′s</title>
		<link>http://feedproxy.google.com/~r/degizmo_blog/~3/5qhS4JlAFdE/</link>
		<comments>http://degizmo.com/2010/03/25/why-you-should-upstream-cache-your-404s/#comments</comments>
		<pubDate>Thu, 25 Mar 2010 18:33:17 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Django]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://degizmo.com/?p=33</guid>
		<description><![CDATA[There&#8217;s a great reddit thread going with the Onion&#8217;s Tech team on their recent transition to Django and this gem is buried in the conversation Deep link to post And the biggest performance boost of all: caching 404s and sending Cache-Control headers to the CDN on 404. Upwards of 66% of our server time is spent on [...]]]></description>
				<content:encoded><![CDATA[<p>There&#8217;s a great <a href="http://www.reddit.com/r/django/comments/bhvhz/the_onion_uses_django_and_why_it_matters_to_us/">reddit thread</a> going with the Onion&#8217;s Tech team on their recent transition to Django and this gem is buried in the conversation</p>
<p><a href="http://www.reddit.com/r/django/comments/bhvhz/the_onion_uses_django_and_why_it_matters_to_us/c0mvow7">Deep link to post</a></p>
<blockquote><p>And the biggest performance boost of all: caching 404s and sending Cache-Control headers to the CDN on 404. Upwards of 66% of our server time is spent on serving 404s from spiders crawling invalid urls and from urls that exist out in the wild from 6-10 years ago. [Edit: We dropped our outgoing bandwidth by about 66% and our load average on our web server cluster by about 50% after implementing that change]</p></blockquote>
<p>Amazing result for such a simple change. Bang for your buck optimizations are always the best ones.</p>
<img src="http://feeds.feedburner.com/~r/degizmo_blog/~4/5qhS4JlAFdE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://degizmo.com/2010/03/25/why-you-should-upstream-cache-your-404s/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://degizmo.com/2010/03/25/why-you-should-upstream-cache-your-404s/</feedburner:origLink></item>
		<item>
		<title>Redis’ Virtual Memory Specifications Draft</title>
		<link>http://feedproxy.google.com/~r/degizmo_blog/~3/OFO4NyY1338/</link>
		<comments>http://degizmo.com/2010/03/25/redis-virtual-memory-specifications-draft/#comments</comments>
		<pubDate>Thu, 25 Mar 2010 13:00:54 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[Redis]]></category>

		<guid isPermaLink="false">http://degizmo.com/?p=32</guid>
		<description><![CDATA[Salvatore has posted &#8220;part 1&#8243; of the internals of Redis&#8217; Virtual Memory subsystem today. Below is the intro with the link to full documentation on Google Code below. This document details the internals of the Redis Virtual Memory subsystem. The intended audience is not the final user but programmers willing to understand or modify the [...]]]></description>
				<content:encoded><![CDATA[<p>Salvatore has <a href="https://twitter.com/antirez/status/11032342691">posted &#8220;part 1&#8243;</a> of the internals of Redis&#8217; Virtual Memory subsystem today. Below is the intro with the link to full documentation on Google Code below.</p>
<blockquote><p>This document details the internals of the Redis Virtual Memory subsystem. The intended audience is not the final user but programmers willing to understand or modify the Virtual Memory implementation.</p>
<h2>Keys vs Values: what is swapped out?</h2>
<p>The goal of the VM subsystem is to free memory transferring Redis Objects from memory to disk. This is a very generic command, but specifically, Redis transfers only objects associated with values. In order to understand better this concept we&#8217;ll show, using the DEBUG command, how a key holding a value looks from the point of view of the Redis internals.</p></blockquote>
<p><a href="http://code.google.com/p/redis/wiki/VirtualMemorySpecification">Read more</a></p>
<img src="http://feeds.feedburner.com/~r/degizmo_blog/~4/OFO4NyY1338" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://degizmo.com/2010/03/25/redis-virtual-memory-specifications-draft/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://degizmo.com/2010/03/25/redis-virtual-memory-specifications-draft/</feedburner:origLink></item>
		<item>
		<title>Redis: Relations in a NoSQL world: Using Hashes</title>
		<link>http://feedproxy.google.com/~r/degizmo_blog/~3/QRCmXo68qyg/</link>
		<comments>http://degizmo.com/2010/03/24/redis-relations-in-a-nosql-world-using-hashes/#comments</comments>
		<pubDate>Wed, 24 Mar 2010 13:35:45 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Database]]></category>
		<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Redis]]></category>

		<guid isPermaLink="false">http://degizmo.com/?p=30</guid>
		<description><![CDATA[So just yesterday we posted a tutorial on how to use redis to store relational despite relations not being supported. Soon after we published the documentation on the new redis hash type went online. Now hashes by themselves aren&#8217;t exactly relations but, more so an object field store. Extending the same concepts from our first [...]]]></description>
				<content:encoded><![CDATA[<p>So just yesterday we posted a tutorial on how to use redis to<a href="http://degizmo.com/2010/03/23/redis-relations-in-a-nosql-world/"> store relational despite relations not being supported</a>. Soon after we published the <a href="http://code.google.com/p/redis/wiki/Hashes">documentation on the new redis hash type went online</a>. Now hashes by themselves aren&#8217;t exactly relations but, more so an object field store. Extending the same concepts from our first article in namespace utilization and using hashes we can accomplish the same thing in a more formal fashion.</p>
<p>We will repeat the same exercise from the first article, creating a username password store, using hashes.</p>
<p><span id="more-30"></span></p>
<h2>Basic hash overview</h2>
<p>Without going into the technical details we can simplify the concept of redis&#8217;s as a way to store fields in a redis key. In Pythonic terms we can make a redis key into a basic Python <a href="http://docs.python.org/tutorial/datastructures.html#dictionaries">dictionary</a>.</p>
<p>[<strong>key</strong>] : {&#8216;field&#8217; -&gt; &#8216;value&#8217;, &#8216;field&#8217; -&gt; &#8216;value&#8217;, &#8216;field&#8217; -&gt; &#8216;value&#8217;}</p>
<h2>Basic hash usage</h2>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; r.hset(&quot;user:adam&quot;, &quot;fullname&quot;, &quot;Adam Smith&quot;)
1
&gt;&gt;&gt; r.hset(&quot;user:adam&quot;, &quot;password&quot;, &quot;thisisapassword&quot;)
1
&gt;&gt;&gt; r.hkeys(&quot;user:adam&quot;)
['fullname', 'password']
&gt;&gt;&gt; r.hvals(&quot;user:adam&quot;)
['Adam Smith', 'thisisapassword']
&gt;&gt;&gt; r.hgetall(&quot;user:adam&quot;)
{'fullname': 'Adam Smith', 'password': 'thisisapassword'}
</pre>
<p>We will break it down line by line here</p>
<ol>
<li>First we are going to make the redis key &#8220;user:adam&#8221; a hash and set the field &#8220;fullname&#8221; in that has to the value &#8220;Adam Smith&#8221; with the redis command hset (Hash Set)</li>
<li>Then we&#8217;ll do the same thing for the field &#8220;password&#8221; and set that field in the hash to it&#8217;s appropriate value.</li>
<li>With the hkeys command we can see all of the keys in the hash set on that redis key</li>
<li>hvals returns all of the values in the redis key</li>
<li>More useful, is the hgetall command. This will return a Python dictionary of all of the fields set in the key</li>
</ol>
<p>As you can see, this is an excellent way to store information about an object without &#8220;faking&#8221; a relation like in our previous tutorial.</p>
<p>As I mentioned in the conclusion of the last article, if we want to change how we store information in redis all we should have to do is to change is change the inner workings of the functions add_user, authenticate_user, delete_user and the rest of our fictitious application should operate without any changes.</p>
<h2>Creating a new user</h2>
<pre class="brush: python; title: ; notranslate">
r = redis.Redis(&quot;localhost&quot;)
from hashlib import md5

def add_user(username, fullname, password):
    if r.sadd(&quot;users&quot;, username):
        #r.set(&quot;user:%s:fullname&quot; % username, fullname)
        #r.set(&quot;user:%s:password&quot; % username, md5(password).hexdigest() )
        r.hset(&quot;user:%s&quot; % username, &quot;fullname&quot;, fullname)
        r.hset(&quot;user:%s&quot; % username, &quot;password&quot;, md5(password).hexdigest())
        return True
    else:
        return False
</pre>
<p>I left the original code in the function commented out so we can see the differences in the two methods here. In our original method we used the name space of redis itself to store the reference. In the updated fashion we are using redis&#8217;s hash data type to store the related fields.</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; add_user(&quot;adam&quot;, &quot;Adam Smith&quot;, &quot;wealthofnations&quot;)
True
&gt;&gt;&gt; add_user(&quot;adam&quot;, &quot;Adam Smith&quot;, &quot;wealthofnations&quot;)
False
</pre>
<p>This function operates in the same fashion as our old version did but, is using a different data structure in the backend.</p>
<h2>Logging a user in</h2>
<p>Now we&#8217;ll refactor our old authentication code to work with the new backend.</p>
<pre class="brush: python; title: ; notranslate">
def authenticate_user(username, password):
    #if username in r.smembers(&quot;users&quot;):
    if r.sismember(&quot;users&quot;, username&quot;):
        passhash = md5(password).hexdigest()
        #if passhash == r.get(&quot;user:%s:password&quot; % username):
        if passhash == r.hget(&quot;user:%s&quot; % username, &quot;password&quot;):
            return True
        else:
            return False
    else:
        return False
</pre>
<p>Just as in the add_user function, we just need to make a small change. Now instead of fetching the related redis key we simply fetch the field from the hash of &#8220;user:*username*&#8221;.</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; authenticate_user(&quot;adam&quot;, &quot;wealthofnations&quot;)
True
&gt;&gt;&gt; authenticate_user(&quot;adam&quot;, &quot;bad_password&quot;)
False
</pre>
<p>We can see the function again performs just like the old function but, it pulls the password from the hash object instead of the related key</p>
<h2>Deleting a user</h2>
<p>Deleting a user using the hash store is much easier than using the related key store, since everything is just stored in one key instead of being spread out across multiple keys.</p>
<pre class="brush: python; title: ; notranslate">
def delete_user(username):
    #if username in r.smembers(&quot;users&quot;):
    if r.sismembers(&quot;users&quot;, username):
        r.srem(&quot;users&quot;, username)
        r.delete(&quot;user:%s&quot; % username)
        #r.delete(&quot;user:%s:fullname&quot; % username)
        #r.delete(&quot;user:%s:password&quot; % username)
        return True
    else:
        return False
&lt;pre&gt;</pre>
<p>Now instead of having to delete the 2 related keys, we just need to delete the one key storing the hash of all of the user data</p>
<img src="http://feeds.feedburner.com/~r/degizmo_blog/~4/QRCmXo68qyg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://degizmo.com/2010/03/24/redis-relations-in-a-nosql-world-using-hashes/feed/</wfw:commentRss>
		<slash:comments>186</slash:comments>
		<feedburner:origLink>http://degizmo.com/2010/03/24/redis-relations-in-a-nosql-world-using-hashes/</feedburner:origLink></item>
		<item>
		<title>Redis: Relations in a NoSQL world</title>
		<link>http://feedproxy.google.com/~r/degizmo_blog/~3/8rAhz1ysZg8/</link>
		<comments>http://degizmo.com/2010/03/23/redis-relations-in-a-nosql-world/#comments</comments>
		<pubDate>Tue, 23 Mar 2010 16:55:11 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Redis]]></category>

		<guid isPermaLink="false">http://degizmo.com/?p=25</guid>
		<description><![CDATA[In the first article in our series on Redis we talked about how to get started and the basics of the simple data structures that are available in redis. The simple structures are good for basic operations like storing strings and keeping counters but, using it for anything more complex requires relating one set of [...]]]></description>
				<content:encoded><![CDATA[<p>In the <a href="http://degizmo.com/2010/03/22/getting-started-redis-and-python/">first article</a> in our series on <a href="http://code.google.com/p/redis/">Redis</a> we talked about how to get started and the basics of the simple data structures that are available in redis. The simple structures are good for basic operations like storing strings and keeping counters but, using it for anything more complex requires relating one set of data to another. At first glance this is a bit of a problem since redis by design is a flat dictionary with no relations but, with a bit of application code and adherence to some mental programming standards you can build some quite complex applications using redis.</p>
<p><span id="more-25"></span></p>
<p>We hinted at this style of structure in the first article when we got to talking about sets with our <a href="http://www.reddit.com/">reddit</a> like example of story voting.</p>
<pre class="brush: python; title: ; notranslate">
r_server.sadd(&quot;story:5419:upvotes&quot;, &quot;userid:9102&quot;)
</pre>
<p>Here we have a set in a redis called &#8220;story:5419:upvotes&#8221; and every element stored in the set is called &#8220;userid:xxxx&#8221;. This is an example of a basic relation.</p>
<p>Let&#8217;s make this example simpler and go with the concept of username / password storage for a website. Instead of using MySQL to store this information we will use redis.</p>
<h2>Relations in a NoSQL world</h2>
<p>We have to cheat in redis&#8217;s flat name space to make relations in our data. Redis isn&#8217;t going to be aware of these relations and unlike RDBMS (like MySQL), redis does nothing to help us out. No index&#8217;s, no nifty SQL syntax with WHERE or JOIN to do the work for us. We have to handle all of the relational logic in application code, which in turn means you (the developers) have to do extra documentation explaining just how everything fits together in redis or you are going to lose your data. The benefit you though is raw speed and flexibility during development. Don&#8217;t like the constraints one data model is giving you? Start over and just recode; no need to alter a DB schema or change a DB server; redis doesn&#8217;t care.</p>
<h2>Our requirements</h2>
<ul>
<li>Users have a username</li>
<li>Usernames have a password in a one-to-one fashion</li>
<li>We must be able to create a user and assign a password</li>
<li>Users must be able to login (check username against password)</li>
<li>We must be able to delete a username and their associated password</li>
</ul>
<h2>Designing our redis namespace</h2>
<p>This the format of the description of the redis namespace we&#8217;ll be using<br />
[<strong>key</strong>] &#8211; {<strong>datatype</strong>} &#8211; (example values)</p>
<p>We also will use the notation *variable* to denote that in a key name is a variable relating to something else.</p>
<p style="padding-left: 30px;">[users] &#8211; {set} &#8211; (&#8220;adam&#8221;, &#8220;bob&#8221;, &#8220;carol&#8221;)<br />
[user:*username*:fullname] &#8211; {string} &#8211; (&#8220;Adam Smith&#8221;, &#8220;Bob Barker&#8221;, &#8220;Carol Burnett&#8221;)<br />
[user:*username*:password] &#8211; {string} &#8211; (md5 hash password, no example)</p>
<p>That&#8217;s it. As long as we stick with this design pattern here we can keep track of all of the users in our system and handle logins.</p>
<h2>Creating a new user</h2>
<pre class="brush: python; title: ; notranslate">
r = redis.Redis(&quot;localhost&quot;)
from hashlib import md5

def add_user(username, fullname, password):
    if r.sadd(&quot;users&quot;, username):
        r.set(&quot;user:%s:fullname&quot; % username, fullname)
        r.set(&quot;user:%s:password&quot; % username, md5(password).hexdigest() )
        return True
    else:
        return False
</pre>
<p>We&#8217;ve created a function called add_user where we are taking in a username, the full name of the user, and password and will return True if we successfully create a new user and False if we don&#8217;t. Remember the redis command SADD (Set Add) returns False if the object already exists in the set, so if a user with that username already exists, we can&#8217;t create a new user so we return False; otherwise we add it to the set and then we set the associated keys &#8220;fullname&#8221; and &#8220;password&#8221; to the appropriate vaues. Hashing the password with a md5 hash since we never store passwords anywhere in plain text.</p>
<p>Let&#8217;s take a look at what this looks like being called.</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; add_user(&quot;bob&quot;, &quot;Bob Barker&quot;, &quot;priceisright&quot;)
True
&gt;&gt;&gt; add_user(&quot;bob&quot;, &quot;Bob Barker&quot;, &quot;priceisright&quot;)
False
</pre>
<p>The first time we try to add the username &#8220;bob&#8221; we succeed but, the second time it fails since there is already a user with that username. Let&#8217;s look at the data stored in redis.</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; r.smembers(&quot;users&quot;)
set(['bob'])
&gt;&gt;&gt; r.get(&quot;user:bob:fullname&quot;)
'Bob Barker'
&gt;&gt;&gt; r.get(&quot;user:bob:password&quot;)
'543f24fdc95f4e3f52fc7a4f2166167e'
</pre>
<p>We see our key &#8220;user&#8221; that has a set stored with only one element, our username &#8220;bob&#8221;. And now we have our related keys &#8220;user:*username*:fullname&#8221; and &#8220;user:*username*:password&#8221; which in practice are &#8220;user:bob:fullname&#8221; and &#8220;user:bob:password&#8221;. As long as we stick to the naming convention we should always know where everything is!</p>
<p>Let&#8217;s go ahead and create a few more users just for good measure</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; add_user(&quot;adam&quot;, &quot;Adam Smith&quot;, &quot;wealthofnations&quot;)
True
&gt;&gt;&gt; add_user(&quot;carol&quot;, &quot;Carol Burnett&quot;, &quot;eartug&quot;)
True
&gt;&gt;&gt; r.smembers(&quot;users&quot;)
set(['carol', 'bob', 'adam'])
</pre>
<h2>Logging a user in</h2>
<p>Now that we have created our relational data store in redis and have a few users in there, lets try to log one in.</p>
<pre class="brush: python; title: ; notranslate">
def authenticate_user(username, password):
    #if username in r.smembers(&quot;users&quot;):
    if r.sismember(&quot;user&quot;, username):
        passhash = md5(password).hexdigest()
        if passhash == r.get(&quot;user:%s:password&quot; % username):
            return True
        else:
            return False
    else:
        return False
</pre>
<p>First thing we do is check to see if the username is <a href="http://docs.python.org/tutorial/datastructures.html#more-on-conditions">i</a>n the set of all of the elements in the key &#8220;users&#8221; using the method sismember (set &#8211; is a member). If the username isn&#8217;t there we are going to return False since, that user doesn&#8217;t even exist. If the user does exist, I take a hash of their submitted password just like we did when we added the user, then we fetch that password from the related key and see if they are the same, if they are, we return True!</p>
<p>Let&#8217;s take a look at this in action</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; authenticate_user(&quot;ghost&quot;, &quot;idontexist!&quot;)
False
&gt;&gt;&gt; authenticate_user(&quot;adam&quot;, &quot;keynes&quot;)
False
&gt;&gt;&gt; authenticate_user(&quot;adam&quot;, &quot;wealthofnations&quot;)
True
&gt;&gt;&gt; authenticate_user(&quot;bob&quot;, &quot;priceisright&quot;)
True
</pre>
<p>So we can see here, a user that doesn&#8217;t exist is not authenticated. A user that does exist but, has the wrong password is denied. Given the right username and the right password a user gets in!. And just to show we can handle multiple users like a proper relational system should &#8220;bob&#8221; authenticates properly as well</p>
<h2>Deleting a user</h2>
<p>Eventually we are going to need to delete a user from our system and that is as easy everything else we have done as long as we stick to the same namespace we laid out before</p>
<pre class="brush: python; title: ; notranslate">
def delete_user(username):
    if username in r.smembers(&quot;users&quot;):
        r.srem(&quot;users&quot;, username)
        r.delete(&quot;user:%s:fullname&quot; % username)
        r.delete(&quot;user:%s:password&quot; % username)
        return True
    else:
        return False
</pre>
<p>Again the first thing we do is check that the user exists first, since if they don&#8217;t no need to do everything else. After we know the user exists, we remove them from the set of &#8220;users&#8221; then remove their related fullname and password keys. Let&#8217;s check this out in action</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; authenticate_user(&quot;adam&quot;, &quot;wealthofnations&quot;)
True
&gt;&gt;&gt; delete_user(&quot;adam&quot;)
True
&gt;&gt;&gt; authenticate_user(&quot;adam&quot;, &quot;wealthofnations&quot;)
False
&gt;&gt;&gt; delete_user(&quot;adam&quot;)
False
&gt;&gt;&gt; r.smembers(&quot;users&quot;)
set(['bob', 'carol'])
</pre>
<p>We can authenticate the user &#8220;adam&#8221; properly. Then we delete him, and now he can&#8217;t authenticate any more. If we try to delete him again we see that we can&#8217;t since he doesn&#8217;t exist.</p>
<h2>Wrapping Up</h2>
<p>We can make very complex relational data structures in redis as long as we document and properly use the name space. Keep everything as simple and as straight forward as possible and document everything throughly. Also make sure all your actions on redis can be keep as modular as possible by wrapping them in functions or classes, just like in this example. Then if for some reason you need to alter your &#8220;schema&#8221; you only have one place to change it in your application.</p>
<h3>Footnote:</h3>
<p>This is an example and is not a secure method for handling user submitted data and does no sanitization or sanity checks on the information. I am aware of this but, this post was not designed to be a comprehensive analysis of AAA methods just a quick example of how to do basic relations in a key-value store.</p>
<img src="http://feeds.feedburner.com/~r/degizmo_blog/~4/8rAhz1ysZg8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://degizmo.com/2010/03/23/redis-relations-in-a-nosql-world/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://degizmo.com/2010/03/23/redis-relations-in-a-nosql-world/</feedburner:origLink></item>
		<item>
		<title>Getting Started: Redis and Python</title>
		<link>http://feedproxy.google.com/~r/degizmo_blog/~3/zdp9PW9HyBU/</link>
		<comments>http://degizmo.com/2010/03/22/getting-started-redis-and-python/#comments</comments>
		<pubDate>Mon, 22 Mar 2010 17:03:55 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[NoSQL]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Redis]]></category>

		<guid isPermaLink="false">http://degizmo.com/?p=4</guid>
		<description><![CDATA[So if you have been following NoSQL movement, the migration of some types of data to non-relational datastores has recently picked up speed. For web (and other developers) this has lead to some impressive engineering resources developing some amazing tools being open sourced for the world to use. One that caught my eye recently has been Salvatore [...]]]></description>
				<content:encoded><![CDATA[<p>So if you have been following <a href="http://en.wikipedia.org/wiki/NoSQL" target="_blank">NoSQL</a> movement, the migration of some types of data to non-relational datastores has recently picked up speed. For web (and other developers) this has lead to some impressive engineering resources developing some amazing tools being open sourced for the world to use. One that caught my eye recently has been <a href="http://invece.org/" target="_blank">Salvatore Sanfilippo&#8217;s</a> <a href="http://code.google.com/p/redis/" target="_blank">redis</a> which has been taken under the wing of <a href="http://blogs.vmware.com/console/2010/03/vmware-hires-key-developer-for-redis.html" target="_blank">VMWare</a>, solidifying and validating the great work that Salavatore has done making redis an amazing tool in any developers arsenal.</p>
<p>A very simplified explanation of redis is that it is an in memory key-value store like <a href="http://memcached.org/" target="_blank">memcached</a> but, it is persistent on disk, unlike memcached which is volatile. Along with being disk-persistent redis also supports some basic <a href="http://code.google.com/p/redis/wiki/IntroductionToRedisDataTypes" target="_blank">data structures</a> like lists, sets, ordered sets, hashes, and of course basic key-value string storage like memcached. Redis, with disk-persistence and basic data structures, remains blazing fast with published benchmarks of <a href="http://code.google.com/p/redis/wiki/Benchmarks" target="_blank">110,000 SETs per second, about 81,000 GETs per second</a>.</p>
<p>This post is the start of a <a href="http://degizmo.com/series-redis-tutorials/" target="_self">series of articles on redis</a> for Python programmers. A prerequisite for this is going to be some basic Python knowledge, which if you haven&#8217;t used before I highly recommend the free web book <a href="http://www.diveintopython.org/toc/index.html">Dive Into Python</a>. This is going to be a simple overview of the basic data types and usage for Python programmers and we will slowly progress into more complex usages, so if you haven&#8217;t done anything with redis before this is a perfect start.</p>
<p><span id="more-4"></span></p>
<h2><strong>Installing Redis</strong></h2>
<p>Redis is extremely easy to install on POSIX systems (Linux, OSX, Cygwin for Windows). Simply download either a release version or checkout the trunk version of redis from the <a href="http://code.google.com/p/redis/" target="_blank">project home page</a>. Unpackage, make, and run. That&#8217;s it!</p>
<pre class="brush: bash; title: ; notranslate">
gettingstarted $ wget http://redis.googlecode.com/files/redis-1.2.5.tar.gz
gettingstarted $ gunzip redis-1.2.5.tar.gz
gettingstarted $ tar -xvf redis-1.2.5.tar
gettingstarted $ cd redis-1.2.5
redis-1.2.5 $ make
redis-1.2.5 $ ./redis-server
21 Mar 17:37:11 * Warning: no config file specified, using the default config. In order to specify a config file use 'redis-server /path/to/redis.conf'
21 Mar 17:37:11 - Server started, Redis version 1.2.5
21 Mar 17:37:11 - The server is now ready to accept connections on port 6379
21 Mar 17:37:11 . 0 clients connected (0 slaves), 832496 bytes in use, 0 shared objects
</pre>
<p>6 commands and redis is running and ready for a connection. Obviously this isn&#8217;t best practice for running redis in production but, it works well for just getting it up and running for some experimentation. Let&#8217;s leave that window open and open another for a Python console.</p>
<p>In every example below we only are covering the basic operations of each type. If you want to learn about all of the possible operations for redis read up on the redis <a href="http://code.google.com/p/redis/wiki/CommandReference" target="_blank">Command Reference</a>. This has all of the commands available to you.</p>
<h2><strong>Redis and Python</strong></h2>
<p>First thing we need is the <a href="http://github.com/andymccurdy/redis-py/" target="_blank">redis-py</a> module for Python. You can install this manually or just use easy_install.</p>
<pre class="brush: bash; title: ; notranslate">
easy_install redis
</pre>
<h3><strong>Everything has a place: keys</strong></h3>
<p>Redis is a <a href="http://en.wikipedia.org/wiki/Associative_array" target="_blank">key-value store</a> just like a <a href="http://docs.python.org/tutorial/datastructures.html#dictionaries" target="_blank">Python dictionary</a>. So everything that goes into redis no matter what it is, has a key (or location, or address, whatever makes sense to you). You can&#8217;t store something without a place for it to go</p>
<p>Now let&#8217;s open up a Python console and start to play with the basic data structures</p>
<h3><strong>Data structure: String</strong></h3>
<p>The most basic data structure in redis is the string. Simply, you have a key and it stores a string.</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; import redis
&gt;&gt;&gt; r_server = redis.Redis(&quot;localhost&quot;)
&gt;&gt;&gt; r_server.set(&quot;name&quot;, &quot;DeGizmo&quot;)
True
&gt;&gt;&gt; r_server.get(&quot;name&quot;)
'DeGizmo'
</pre>
<p>So, line by line let&#8217;s walk through what we&#8217;ve done here.</p>
<ol>
<li>import the redis module</li>
<li>create an object called &#8220;r_server&#8221; of redis.Redis type with the parameter &#8220;localhost&#8221; which is the network location of our running redis server</li>
<li>call the function &#8220;set&#8221; on the &#8220;r_server&#8221; object with the parameters &#8220;name&#8221; and &#8220;DeGizmo&#8221;. The first parameter &#8220;name&#8221; is the <strong>key</strong> and &#8220;DeGizmo&#8221; is the <strong>value</strong>. So in redis we created a key-value pair of &#8220;name&#8221; -&gt; &#8220;DeGizmo&#8221;</li>
<li>call the function &#8220;get&#8221; which will retrieve the value from the key which is passed as the parameter. We are getting the key &#8220;name&#8221; and redis returns the value &#8220;DeGizmo&#8221;</li>
</ol>
<p>That&#8217;s it. If you go and stop the redis server and restart it and run r_server.get(&#8220;name&#8221;) command again, it will return &#8220;DeGizmo&#8221; again due to redis&#8217;s persistent store.</p>
<h3><strong>Data structure: Integer</strong></h3>
<p>The second data type available is an integer.</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; r_server.set(&quot;hit_counter&quot;, 1)
True
&gt;&gt;&gt; r_server.incr(&quot;hit_counter&quot;)
2
&gt;&gt;&gt; r_server.get(&quot;hit_counter&quot;)
'2'
&gt;&gt;&gt; r_server.decr(&quot;hit_counter&quot;)
1
&gt;&gt;&gt; r_server.get(&quot;hit_counter&quot;)
'1'
</pre>
<p>Again using the &#8220;r_server&#8221; Redis object we run the following commands</p>
<ol>
<li>We set the redis key &#8220;hit_counter&#8221; to a value of 1 just like in the example above</li>
<li>Then we run the command &#8220;incr&#8221; on the key &#8220;hit_counter&#8221;. This will increment (incr) the key by 1</li>
<li>We get the value for the key &#8220;hit_counter&#8221; to verify that it was been incremented</li>
<li>Then we run the command &#8220;decr&#8221; on the key &#8220;hit_counter&#8221;. This will decrement (decr) the key by 1</li>
<li>We get the value for the key &#8220;hit_counter&#8221; to verify that it was been decremented</li>
</ol>
<p>Simple huh? Well remember that redis is a persistent store that can be accessed by multiple machines (or programs) simultaneously. If you have a horizontally scaled web farm with many different web servers running on separate machines, your web app can all call on and reference the same redis instance and all operate on the &#8220;hit_counter&#8221; key at the same time and increment it just like how you would use a MySQL database. You can kind of think of redis like a &#8220;shared&#8221; storage across different applications.</p>
<h3><strong>Data structure: Lists</strong></h3>
<p>Very similar to the built in <a href="http://docs.python.org/tutorial/datastructures.html#more-on-lists" target="_blank">Python list type</a>, the redis list type has a few basic methods that combined can quite powerful. We are only covering a tiny portion of the commands available, you can find all the commands in the redis <a href="http://code.google.com/p/redis/wiki/CommandReference" target="_blank">Command Reference</a>.</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; r_server.rpush(&quot;members&quot;, &quot;Adam&quot;)
True
&gt;&gt;&gt; r_server.rpush(&quot;members&quot;, &quot;Bob&quot;)
True
&gt;&gt;&gt; r_server.rpush(&quot;members&quot;, &quot;Carol&quot;)
True
&gt;&gt;&gt; r_server.lrange(&quot;members&quot;, 0, -1)
['Adam', 'Bob', 'Carol']
&gt;&gt;&gt; r_server.llen(&quot;members&quot;)
3
&gt;&gt;&gt; r_server.lindex(&quot;members&quot;, 1)
'Bob'
</pre>
<p>We don&#8217;t actually have to create or declare anything when using redis, we just use it and redis handles everything else for us. So we just go ahead and tell redis at the key &#8220;members&#8221; we are going to add (rpush, right push) the value &#8220;Adam&#8221;. Redis creates the list for us at key &#8220;members&#8221; and adds the value &#8220;Adam&#8221; to the list.</p>
<ol>
<li>With the r_server object again we call the method &#8220;rpush&#8221; which will add the value &#8220;Adam&#8221; to the newly created list &#8220;members&#8221;</li>
<li>We add &#8220;Bob&#8221; to the same list</li>
<li>Finally we&#8217;ll add &#8220;Carol&#8221;</li>
<li>With the lrange method we are asking redis to return all the objects in &#8220;members&#8221;. lrange takes 3 arguments: key, start index in list, end index in list. We are getting the objects from the key &#8220;members&#8221; starting at index 0 and ending at -1 (which is technically the -1, or last index in the list, which will return everything)</li>
<li>The llen method asks redis to return the length of the list at the key &#8220;members&#8221; which now has 3 objects</li>
<li>lindex method tells redis that we want the object from the key &#8220;members&#8221; at the index position of 1 (remember lists start at index 0), so redis returns &#8220;Bob&#8221;</li>
</ol>
<p>We&#8217;ve got some elements in the list at the key &#8220;members&#8221;; now lets get remove some elements.</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; r_server.rpop(&quot;members&quot;)
'Carol'
&gt;&gt;&gt; r_server.lrange(&quot;members&quot;, 0, -1)
['Adam', 'Bob']
&gt;&gt;&gt; r_server.lpop(&quot;members&quot;)
'Adam'
&gt;&gt;&gt; r_server.lrange(&quot;members&quot;, 0, -1)
['Bob']
</pre>
<ol>
<li>With the method rpop (right pop) we remove the element in the list on the right side (tail), which is &#8220;Carol&#8221;</li>
<li>Now when we ask for the list &#8220;members&#8221; from redis again (from the start of 0, and the end of -1 which returns everything) we see our list now doesn&#8217;t have &#8220;Carol&#8221;</li>
<li>We now lpop (left pop) an element from the list &#8220;members&#8221;. This will remove the far left element from the list, &#8220;Adam&#8221;</li>
<li>Now the entire list only contains &#8220;Bob&#8221;</li>
</ol>
<h3><strong>Data structure: Set</strong></h3>
<p>Again, sets perform identically to the <a href="http://docs.python.org/tutorial/datastructures.html#sets" target="_blank">built in Python set type</a>. Simply, sets are lists but, can only have unique values. In the above example if we added the value Adam (r_server.lpush(&#8220;members&#8221;, &#8220;Adam&#8221;) ) 20 times our list would contain 20 values all containing the value &#8220;Adam&#8221;. In a set, all elements are unique.</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; r_server.delete(&quot;members&quot;)
True
&gt;&gt;&gt; r_server.sadd(&quot;members&quot;, &quot;Adam&quot;)
True
&gt;&gt;&gt; r_server.sadd(&quot;members&quot;, &quot;Bob&quot;)
True
&gt;&gt;&gt; r_server.sadd(&quot;members&quot;, &quot;Carol&quot;)
True
&gt;&gt;&gt; r_server.sadd(&quot;members&quot;, &quot;Adam&quot;)
False
&gt;&gt;&gt; r_server.smembers(&quot;members&quot;)
set(['Bob', 'Adam', 'Carol'])
</pre>
<ol>
<li>First off we delete the old list in the key &#8220;members&#8221; so we can use it as a set</li>
<li>Then we sadd (set add) the value &#8220;Adam&#8221; to the key &#8220;members&#8221;</li>
<li>Do the same for the value &#8220;Bob&#8221;</li>
<li>Do the same for the value &#8220;Carol&#8221;</li>
<li>Now we try to add the value &#8220;Adam&#8221; to the key &#8220;members&#8221; again but, this time it returns &#8220;False&#8221; since we are working on a set, and a set only has unique values. There already is a value &#8220;Adam&#8221; present in this set</li>
<li>The method smembers returns all the members of the set in the Python type set</li>
</ol>
<p>An example of a use of sets in a web application would be for &#8220;upvotes&#8221; on a <a href="http://www.reddit.com/" target="_blank">reddit</a>, or <a href="http://news.ycombinator.com/" target="_blank">hacker news</a> type website. We want to keep track of who up votes a story but, you should only be able to up vote a story once.</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; r_server.sadd(&quot;story:5419:upvotes&quot;, &quot;userid:9102&quot;)
True
&gt;&gt;&gt; r_server.sadd(&quot;story:5419:upvotes&quot;, &quot;userid:12981&quot;)
True
&gt;&gt;&gt; r_server.sadd(&quot;story:5419:upvotes&quot;, &quot;userid:1233&quot;)
True
&gt;&gt;&gt; r_server.sadd(&quot;story:5419:upvotes&quot;, &quot;userid:9102&quot;)
False
&gt;&gt;&gt; r_server.scard(&quot;story:5419:upvotes&quot;)
3
&gt;&gt;&gt; r_server.smembers(&quot;story:5419:upvotes&quot;)
set(['userid:12981', 'userid:1233', 'userid:9102'])
</pre>
<p>I added a little twist in here with the name of the key: &#8220;story:5419:upvotes&#8221; but, it&#8217;s easy to explain. Redis is &#8220;flat&#8221; with it&#8217;s keyspace. So if we have many different stories we use a fixed key naming convention for easy reference in redis. For this example our key is broken down like this: &#8220;object type&#8221; : &#8220;id&#8221; : &#8220;attribute&#8221;. So, we have an object of type &#8220;story&#8221; with an ID of &#8220;5419&#8243; with an attribute &#8220;upvotes&#8217;. Redis has no idea what any of this means it just knows the key is &#8220;story:5419:upvotes&#8221; but, it doesn&#8217;t matter, we know what it means and we can divide up our objects into this name space to make it easier to work with and keep from &#8220;losing&#8221; things. The value being added to the key is divided up in the same way. &#8220;userid&#8221; is the type and &#8220;9102&#8243; is the value or the ID for that user voting on the story.</p>
<ol>
<li>Just like before we are adding the value &#8220;userid:9102&#8243; to the key &#8220;story:5419:upvotes&#8221;</li>
<li>Now we are adding the value &#8220;userid:12981&#8243;</li>
<li>Finally adding the valud &#8220;userid:1233&#8243;</li>
<li>Now, the user with the ID 9102 tries to up vote the story with the ID 5419 again, and redis returns False since that user has already up votes this story before and you can&#8217;t up vote a story twice!</li>
<li>The method &#8220;scard&#8221; is asking redis for the <a href="http://en.wikipedia.org/wiki/Cardinality" target="_blank">cardinality</a> of the set at key &#8220;story:5419:upvotes&#8221; or how many things are in this set, and redis returns 3.</li>
<li>Finally we return the list of userid&#8217;s that we have stored in the set.</li>
</ol>
<h3><strong>Data structure: Ordered sets</strong></h3>
<p>The last data structure we are going to talk about today is an ordered (or sorted) set. This operates just like a set but, has an extra attribute when we add something to a set called a &#8220;score&#8221;. This score determines the order of the elements in the set. We will stick with the concept for this final example</p>
<pre class="brush: python; title: ; notranslate">
&gt;&gt;&gt; r_server.zadd(&quot;stories:frontpage&quot;, &quot;storyid:3123&quot;, 34)
True
&gt;&gt;&gt; r_server.zadd(&quot;stories:frontpage&quot;, &quot;storyid:9001&quot;, 3)
True
&gt;&gt;&gt; r_server.zadd(&quot;stories:frontpage&quot;, &quot;storyid:2134&quot;, 127)
True
&gt;&gt;&gt; r_server.zadd(&quot;stories:frontpage&quot;, &quot;storyid:2134&quot;, 127)
False
&gt;&gt;&gt; r_server.zrange(&quot;stories:frontpage&quot;, 0, -1, withscores=True)
[('storyid:9001', 3.0), ('storyid:3123', 34.0), ('storyid:2134', 127.0)]
&gt;&gt;&gt; frontpage = r_server.zrange(&quot;stories:frontpage&quot;, 0, -1, withscores=True)
&gt;&gt;&gt; frontpage.reverse()
&gt;&gt;&gt; frontpage
[('storyid:2134', 127.0), ('storyid:3123', 34.0), ('storyid:9001', 3.0)]
</pre>
<p>Quick namespace explanation like before. For the key we are going to be referring to &#8220;stories:frontpage&#8221; which is going to be a set of stories slated for the front page of our website. We are storing in that key the value of &#8220;storyid:3123&#8243; which is the ID of some story on the site and then a score, which in our case is going to be the number of votes on a story.</p>
<ol>
<li>First we add the value &#8220;storyid:3123&#8243; to &#8220;stories:frontpage&#8221;, and &#8220;storyid:3123&#8243; in our example is going to have 34 votes.</li>
<li>Then add &#8220;storyid:9001&#8243; with 3 votes</li>
<li>Then add &#8220;storyid:2134&#8243; with 127 votes</li>
<li>We are going to try to add &#8220;story:2134&#8243; to the set again but, we can&#8217;t since it already exists.</li>
<li>Now we are going to ask redis for all the elements in &#8220;stories:frontpage&#8221; from index 0 to index -1 (the end of the list) with all associated scores (withscores=True)</li>
<li>We&#8217;ve got the scores but, they are in ascending order, we want them in descending order for our website, so we are going to store the results in the variable &#8220;frontpage&#8221;</li>
<li>Then reverse it (which is an in place operation in Python)</li>
<li>Now print out the front page!</li>
</ol>
<p>In conclusion let&#8217;s do a quick example of a &#8220;view&#8221; in an application in which a user will vote of a story using redis as a storage engine</p>
<pre class="brush: python; title: ; notranslate">
#given variables
#r_server   = our redis server
#user_id    = the user who voted on the story
#story_id   = the story which the user voted on
if r_server.sadd(&quot;story:%s&quot; % story_id, &quot;userid:%s&quot; % user_id):
    r_server.zincrby(&quot;stories:frontpage&quot;, &quot;storyid:%s&quot; % story_id, 1)
</pre>
<p>2 lines of code? This is might compact but, once we unravel it we can see how it makes sense and how powerful redis can be. Let&#8217;s start with the if statement.</p>
<pre class="brush: python; title: ; notranslate">
if r_server.sadd(&quot;story:%s&quot; % story_id, &quot;userid:%s&quot; % user_id):
</pre>
<p>We know the command &#8220;sadd&#8221; already. This will add an element to a set at a key. The key in this case is</p>
<pre class="brush: python; title: ; notranslate">
&quot;story:%s&quot; % story_id
</pre>
<p>If story_id is 3211, then the resulting string will be &#8220;story:3211&#8243;. This is the key in redis which contains the list of users that has voted on the story.</p>
<p>The value to be inserted at this key is</p>
<pre class="brush: python; title: ; notranslate">
&quot;userid:%s&quot; % user_id
</pre>
<p>Just like with story, if the user_id is 9481 then the string to be inserted into the set at &#8220;story:3211&#8243; will be &#8220;user_id:9481&#8243;</p>
<p>Now the redis command &#8220;sadd&#8221; will return False if that element is already present in the set. So if a user has already voted on this story before we don&#8217;t execute the statement under the if. But, if it is added, then we have a brand new vote and we have to increment the votes for the front page.</p>
<pre class="brush: python; title: ; notranslate">
r_server.zincrby(&quot;stories:frontpage&quot;, &quot;storyid:%s&quot; % story_id, 1)
</pre>
<p>We have an ordered set at the key &#8220;stories:frontpage&#8221; and we are going to increment the element &#8220;storyid:%s&#8221; % story_id (&#8220;story:3211&#8243;) by 1.</p>
<p>And now we&#8217;re done! We&#8217;ve made sure the user hasn&#8217;t voted on this story before and then we&#8217;ve incremented the number of votes for this story on the front page!</p>
<img src="http://feeds.feedburner.com/~r/degizmo_blog/~4/zdp9PW9HyBU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://degizmo.com/2010/03/22/getting-started-redis-and-python/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		<feedburner:origLink>http://degizmo.com/2010/03/22/getting-started-redis-and-python/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 0.908 seconds. --><!-- Cached page generated by WP Super-Cache on 2013-05-20 09:28:25 --><!-- super cache -->
