Skip to content

@nate /redis-presentation.rb
Created

Embed URL

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
#!/usr/bin/env ruby
# My name is Nate Sutton
# I work for Sevenwire <http://sevenwire.com>
# Redis, yet another key-value store:
# * Dataset is non-volatile (unlike memcached)
# * Has four datatypes (unlike memcached, which just has string)
# * Fast. One benchmark put it at 110k SETs/s and 81k GETs/s. (lies, damned lies, and benchmarks, of course)
# http://code.google.com/p/redis/wiki/Benchmarks
# * Supports expiring keys
#
# Non-volatile:
# * In order to not be volatile but still be fast, it asynchronously saves
# to disk.
# * Save triggers are configurable (time and number of changes)
# * alternate Append-Only-File mode for complete persistence (much, much slower)
#
# Four data types:
# String
# List
# Set
# Sorted Set
# To use:
# gem install redis ohm json
# git clone http://github.com/ezmobius/redis-rb.git
# cd redis-rb
# rake redis:install # this is to get latest redis. use package manager for stable
# Start the redis server: redis-server
# Run this script: ruby redis-presentation.rb
# Used commands closest to the actual redis commands, but there is some
# syntactic sugar to be had with the ruby redis client library
# ex:
# this given code: r['foo'] = 'bar'
# is equivalent to: r.set 'foo', 'bar'
require 'rubygems'
require 'redis'
require 'json'
r = Redis.new
r.flushall
##############################################################################
### Some basic string commands
puts '-' * 80
# Setting and getting a value - O(1)
puts 'setting foo to "bar"'
r.set 'foo', 'bar'
puts 'value of foo'
puts r.get('foo')
puts '-' * 80
# Incrementing/Decrementing a key - O(1)
r.incr 'counter'
r.incr 'counter'
r.incr 'counter'
r.decr 'counter'
r.decr 'counter'
puts 'value of "counter"'
puts r.get('counter')
puts '-' * 80
##############################################################################
### Some basic list commands
# Push a value onto a list - lpush/rpush O(1), lrange O(n) (n is the length of the list)
r.rpush 'mylist', 'foo'
r.lpush 'mylist', 'bar'
r.lpush 'mylist', 'baz'
r.lpush 'mylist', 'bonk'
r.lpush 'mylist', 'bing'
r.lpush 'mylist', 'hi'
puts "value of mylist"
puts r.lrange('mylist', 0, -1).inspect
puts '-' * 80
# Pop a value off a list - lpop/rpush O(1)
r.lpop('mylist')
r.rpop('mylist')
puts 'value of mylist sans the beginning and end elements'
puts r.lrange('mylist', 0, -1).inspect
puts '-' * 80
# Trim values from a list - ltrim O(n) (with n being len of list - len of range)
r.ltrim('mylist', 0, 1)
puts 'value of mylist trimmed to the first two values'
puts r.lrange('mylist', 0, -1).inspect
puts '-' * 80
# Pop a value off one list onto another list atomically - rpoplpush O(1) (Redis >= 1.1)
(1..5).each do |i|
r.lpush 'ids_of_jobs_to_do', i
end
r.rpoplpush 'ids_of_jobs_to_do', 'worker1'
r.rpoplpush 'ids_of_jobs_to_do', 'worker2'
r.rpoplpush 'ids_of_jobs_to_do', 'worker3'
puts 'worker1: ' + r.lrange('worker1', 0, -1).inspect
puts 'worker2: ' + r.lrange('worker2', 0, -1).inspect
puts 'worker3: ' + r.lrange('worker3', 0, -1).inspect
puts 'ids_of_jobs_to_do: ' + r.lrange('ids_of_jobs_to_do', 0, -1).inspect
puts '-' * 80
##############################################################################
### Some basic set commands
# Adding members to the set - O(1)
%w(foo bar baz bonk).each do |value|
r.sadd 'myset1', value
r.sadd 'myset1', value
end
puts 'members of myset1'
puts r.smembers('myset1').inspect
puts '-' * 80
# Finding a random member of the set - O(1)
puts 'random members of the set'
puts r.srandmember('myset1')
puts r.srandmember('myset1')
puts r.srandmember('myset1')
puts '-' * 80
# Finding the union of sets - O(N) (N is the total number of elements of all the sets)
%w(baz bonk bing bang).each do |value|
r.sadd 'myset2', value
r.sadd 'myset2', value
end
puts 'union of myset1 and myset2'
puts r.sunion('myset1', 'myset2').inspect
puts '-' * 80
# Finding the intersection of sets - O(N*M) worst case where N is the cardinality of the smallest set and M the number of sets
puts 'intersection of myset1 and myset2'
puts r.sinter('myset1', 'myset2').inspect
puts '-' * 80
# Finding the diff of sets - O(N) with N being the total number of elements of all the sets
puts 'diff of myset1 and myset2'
puts r.sdiff('myset1', 'myset2').inspect
puts '-' * 80
##############################################################################
### Some basic sorted set commands
# Adding values to a sorted set or updates score
# O(log(N)) with N being the number of elements in the sorted set
# Expensive writes, cheap reads
r.zadd 'myzset', 3, 'third'
r.zadd 'myzset', 1, 'first'
r.zadd 'myzset', 2, 'second'
puts 'my sorted set, sorted'
puts r.zrange('myzset', 0, -1).inspect
puts '-' * 80
##############################################################################
### Using it to store larger data structures (both ways are naive)
# Way 1 (slow, key queries scan all the keys in the db)
id = r.incr 'Event:id'
puts "New event ID: #{id}"
r.set "Event:#{id}:name", "Nate's Lightning Talk"
r.sadd "Event:#{id}:participants", 'Participant:1'
r.sadd "Event:#{id}:participants", 'Participant:2'
r.sadd "Event:#{id}:participants", 'Participant:3'
r.lpush "Event:#{id}:comments", 'Wow that was awesome!'
r.lpush "Event:#{id}:comments", 'That was almost a spiritual experience!'
r.lpush "Event:#{id}:comments", 'I CANNOT CONTROL THE VOLUME OF MY TEXT!'
r.incr "Event:#{id}:votes"
r.keys("Event:#{id}:*").each do |key|
value = case r.type(key)
when "string"
r.get(key)
when "set"
r.smembers(key)
when "list"
r.lrange(key, 0, -1)
end
puts "#{key} - #{value.inspect}"
end
puts '-' * 80
# Way 2 (more like a document DB, strings can only be 1 GB though ;) )
id = r.incr 'Event:id'
puts "New event ID: #{id}"
attributes = { :name => "Nate's Lightning Talk",
:participants => ['Participant:1', 'Participant:2', 'Participant:3'],
:votes => 2,
:comments => ['Wow that was awesome!',
'That was almost a spiritual experience!',
'I CANNOT CONTROL THE VOLUME OF MY TEXT!'] }
r.set "Event:#{id}", attributes.to_json
puts JSON.parse(r.get("Event:#{id}")).inspect
puts '-' * 80
##############################################################################
### Ohm
# Comment out redis first
# require 'rubygems'
# require 'ohm'
#
# puts 'OHM'
# puts '==='
# puts
#
# Ohm.connect
# Ohm.redis.flushall
#
# class Person < Ohm::Model; end
# class Event < Ohm::Model; end
#
# class Person < Ohm::Model
# attribute :name
# set :events, Event
#
# index :name
#
# def validate
# assert_present :name
# end
# end
#
# class Event < Ohm::Model
# attribute :name
# set :participants, Person
# list :comments
# counter :votes
#
# index :name
#
# def validate
# assert_present :name
# end
# end
#
# puts "Creating a person"
# person = Person.create(:name => 'Bob Smith')
#
# puts "Creating an event"
# event = Event.create(:name => "Nate's Lightning Talk")
#
# puts "Associating records"
# event.participants.add(person)
# person.events.add(event)
#
# puts "Finding records"
# person = Person.find(:name => 'Bob Smith').first
# event = Event.find(:name => "Nate's Lightning Talk").first
#
# puts
# puts "Found object information:"
# puts "Person ID: #{person.id}"
# puts "Event ID: #{event.id}"
# puts "Person Name: #{person.name}"
# puts "Event Name: #{event.name}"
# puts "Person found through Event: #{event.participants.first.name}"
# puts "Event found through Person: #{person.events.first.name}"
# puts
# puts "Redis keys:"
# puts Ohm.redis.keys('*')
##############################################################################
### New Stuff Coming Soon
# BLPOP (and maybe BLPOPRPUSH?)
# Virtual Memory
# Redis Cluster
# Redis can be found at:
# http://code.google.com/p/redis/
# http://github.com/antirez/redis
#
# This talk can be found at:
# http://gist.github.com/265161
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.