public
Last active

  • Download Gist
redis-presentation.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
#!/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

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.