ohm-zset

Ohm Sorted Set (ZSET) support for Redis.

Basic Usage

class Big < Ohm::Model
  set :smalls, :Small
  zset :zsmalls, :Small, :size
end

class Small < Ohm::Model
  attribute :name 
  attribute :size
end

b = Big.create
s1 = Small.create(name: 'S1', size: 5)
s2 = Small.create(name: 'S2', size: 4)
s3 = Small.create(name: 'S3', size: 3)
s4 = Small.create(name: 'S4', size: 2)
s5 = Small.create(name: 'S5', size: 1)

b.zsmalls.add_list(s1, s2, s3, s4, s5)

b.zsmalls.size
# => 5

b.zsmalls.to_a.map(&:name)
# => ['S5', 'S4', 'S3', 'S2', 'S1']

b.zsmalls.to_a.map(&:size)
# => ['1', '2', '3', '4', '5']

Interacting with the elements of the set

Ohm-ZSET includes get, rank, revrank, score, range, revrange, rangebyscore, revrangebyscore


b.zsmalls.get(0).name
# => 'S5'

b.zsmalls.range(0, 3).to_a.map(&:name)
# => ['S5', 'S4', 'S3', 'S2']

b.zsmalls.revrange(0, 3).each do |small|
  puts "#{small.name} - #{small.size}"
end
# => S1 - 5
# => S2 - 4
# => S3 - 3
# => S4 - 2

s6 = Small.create(name:'S6', size:3.5)
b.zsmalls.add(s6)
b.zsmalls.to_a.map(&:name)
# => ['S5', 'S4', 'S3', 'S6', 'S2', 'S1']

You can also add an element with a custom score.

class Big < Ohm::Model
  include Ohm::ZScores

  zset :zcustom, :Bool, nil, ZScore::DateTime
end

class Bool < Ohm::Model
  attribute :name
  attribute :is_valid
end

b = Big.create
b1 = Bool.create(name: 'B1', is_valid: "false")
b2 = Bool.create(name: 'B2', is_valid: "true")
b3 = Bool.create(name: 'B3', is_valid: "false")
b4 = Bool.create(name: 'B4', is_valid: "true")

b.zcustom.add(b1, "2012-07-29 06:24:20 +0800")
b.zcustom.add(b2, "2012-07-25 06:24:20 +0800")
b.zcustom.add(b3, "2012-07-30 06:24:20 +0800")
b.zcustom.add(b4, "2012-07-27 06:24:20 +0800")

b.zcustom.to_a.map(&:name)
# => ['B2', 'B4', 'B1', 'B3']

You can update the score of an element by using update. There is also a count function that returns the number of elements with scores inside a specified range.

Deleting Elements

Ohm-ZSET includes delete for deleting a single element, clear for deleting all elements, and remrangebyrank and remrangebyscore for deleting selected elements.

b.zsmalls.delete(s6)
b.zsmalls.to_a.map(&:name)
# => ['S5', 'S4', 'S3', 'S2', 'S1']

b.zsmalls.include? s6
# => false

b.zsmalls.clear
b.zsmalls.to_a.map(&:name)
# => []

It also has destroy! to delete the key of the sorted set.

Set Intersection and Union

Set intersection between sorted sets and sets are allowed. You can use intersect, intersect_multiple, union, and union_multiple between sets and sorted sets.

b.smalls.add(s1)
b.smalls.add(s2)
b.smalls.add(s4)

# Intersect ['S5', 'S4', 'S3', 'S2', 'S1'] with ['S4', 'S2', 'S1']
b.zsmalls.intersect(b.smalls).to_a.map(&:name)
# => ['S4', 'S2', 'S1']

The sorted set allows union and intersection of multiple sets and sorted sets with weights. Result of intersection and union is another ZSET.

It also allows intersection and union to a new set with the specified name.

zunion = Ohm::ZSet.union_multiple('zunion', [zlittles, slittles, zlittles2, zlittles3])

zunion.key
# => 'zunion'

Scoring Functions

Ohm-ZSET also supports custom scoring functions. The default scoring function is ZScore::Integer. There are also available built-in scoring functions in the module.

class Bigger < Ohm::Model
  include Ohm::ZScores

  zset :zlittles, :Little, :score

  # Custom scoring function
  zset :zsmalls, :Small, :value, lambda{ |x| Integer(x) + 1 }

  # Built-in scoring functions
  zset :zlittles, :Little, :score, ZScore::Float
  zset :zbools, :Bool, :is_valid, ZScore::Boolean
  zset :zdts, :DT, :last_login, ZScore::DateTime

  # Built-in string sorting functions
  zset :zbools2, :Bool, :name, ZScore::String
  zset :zbools3, :Bool, :name, ZScore::StringInsensitive
  zset :zbools4, :Bool, :name, ZScore::StringInsensitiveHigh
end

class Bool < Ohm::Model
  attribute :name
  attribute :is_valid
end

class DT < Ohm::Model
  attribute :name
  attribute :last_login
end

class Small < Ohm::Model
  attribute :name 
  attribute :value
end

class Little < Ohm::Model
  attribute :name
  attribute :score
end

Redis allows only numerical scores so DateTime and strings objects are first converted to numbers and then stored as scores.

Note: The string scoring algorithm is limited only to the first 9 characters because of the floating point accuracy limit. You can use the starts_with function when dealing with string sorted sets. It returns all the elements of the set with a score field value that starts with the specified string.

Saving and Loading ZSet instances by name / key


sorted_set = b.zlittles
sorted_set.save_set

sorted_set_2 = Ohm::ZSet.load_set(sorted_set.key)
sorted_set_2.add(Little.create(name: 'X1',score: 29))

# sorted_set and sorted_set_2 are pointing to same ZSet instance

Updating gem


gem build ohm-zset.gemspec
gem push ohm-zset-0.X.gem

Copyright (c) 2012 Joshua Arvin Lat. See LICENSE for more details.