Class: Redis::SortedSet

Inherits:
EnumerableObject show all
Defined in:
lib/redis/sorted_set.rb

Overview

Class representing a sorted set.

Instance Attribute Summary

Attributes inherited from BaseObject

#key, #options

Instance Method Summary collapse

Methods inherited from EnumerableObject

#as_json, #each, #sort

Methods inherited from BaseObject

#allow_expiration, #as_json, #initialize, #redis, #set_expiration, #to_hash, #to_json

Methods included from Helpers::CoreCommands

#exists, #exists?, #expire, #expireat, #marshal, #move, #persist, #rename, #renamenx, #serializer, #ttl, #type, #unmarshal

Constructor Details

This class inherits a constructor from Redis::BaseObject

Instance Method Details

#==(x) ⇒ Object



270
271
272
# File 'lib/redis/sorted_set.rb', line 270

def ==(x)
  members == x
end

#[](index, length = nil) ⇒ Object Also known as: slice

Same functionality as Ruby arrays. If a single number is given, return just the element at that index using Redis: ZRANGE. Otherwise, return a range of values using Redis: ZRANGE.



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/redis/sorted_set.rb', line 39

def [](index, length=nil)
  if index.is_a? Range
    range(index.first, index.max)
  elsif length
    case length <=> 0
    when 1  then range(index, index + length - 1)
    when 0  then []
    when -1 then nil  # Ruby does this (a bit weird)
    end
  else
    result = score(index) || 0 # handles a nil score
  end
end

#[]=(member, score) ⇒ Object

How to add values using a sorted set. The key is the member, eg, “Peter”, and the value is the score, eg, 163. So:

num_posts['Peter'] = 163


11
12
13
# File 'lib/redis/sorted_set.rb', line 11

def []=(member, score)
  add(member, score)
end

#add(member, score) ⇒ Object

Add a member and its corresponding value to Redis. Note that the arguments to this are flipped; the member comes first rather than the score, since the member is the unique item (not the score).



18
19
20
21
22
# File 'lib/redis/sorted_set.rb', line 18

def add(member, score)
  allow_expiration do
    redis.zadd(key, score, marshal(member))
  end
end

#at(index) ⇒ Object

Return the value at the given index. Can also use familiar list syntax. Redis: ZRANGE



280
281
282
# File 'lib/redis/sorted_set.rb', line 280

def at(index)
  range(index, index).first
end

#decrement(member, by = 1) ⇒ Object Also known as: decr, decrby

Convenience to calling increment() with a negative number.



184
185
186
187
188
# File 'lib/redis/sorted_set.rb', line 184

def decrement(member, by=1)
  allow_expiration do
    zincrby(member, -by)
  end
end

#delete(value) ⇒ Object

Delete the value from the set. Redis: ZREM



155
156
157
158
159
# File 'lib/redis/sorted_set.rb', line 155

def delete(value)
  allow_expiration do
    redis.zrem(key, marshal(value))
  end
end

#delete_if(&block) ⇒ Object

Delete element if it matches block

Raises:

  • (ArgumentError)


162
163
164
165
166
167
168
169
170
171
# File 'lib/redis/sorted_set.rb', line 162

def delete_if(&block)
  raise ArgumentError, "Missing block to SortedSet#delete_if" unless block_given?
  res = false
  redis.zrange(key, 0, -1).each do |m|
    if block.call(unmarshal(m))
      res = redis.zrem(key, m)
    end
  end
  res
end

#empty?Boolean

Returns true if the set has no members. Redis: SCARD == 0

Returns:

  • (Boolean)


266
267
268
# File 'lib/redis/sorted_set.rb', line 266

def empty?
  length == 0
end

#firstObject

Return the first element in the list. Redis: ZRANGE(0)



285
286
287
# File 'lib/redis/sorted_set.rb', line 285

def first
  at(0)
end

#increment(member, by = 1) ⇒ Object Also known as: incr, incrby

Increment the rank of that member atomically and return the new value. This method is aliased as incr() for brevity. Redis: ZINCRBY



175
176
177
178
179
# File 'lib/redis/sorted_set.rb', line 175

def increment(member, by=1)
  allow_expiration do
    zincrby(member, by)
  end
end

#intersection(*sets) ⇒ Object Also known as: intersect, inter, &

Return the intersection with another set. Can pass it either another set object or set name. Also available as & which is a bit cleaner:

members_in_both = set1 & set2

If you want to specify multiple sets, you must use intersection:

members_in_all = set1.intersection(set2, set3, set4)
members_in_all = set1.inter(set2, set3, set4)  # alias

Redis: SINTER



203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'lib/redis/sorted_set.rb', line 203

def intersection(*sets)
  result = nil
  temp_key = :"#{key}:intersection:#{Time.current.to_i + rand}"

  redis.multi do
    interstore(temp_key, *sets)
    redis.expire(temp_key, 1)

    result = redis.zrange(temp_key, 0, -1)
  end

  result.value
end

#interstore(name, *sets) ⇒ Object

Calculate the intersection and store it in Redis as name. Returns the number of elements in the stored intersection. Redis: SUNIONSTORE



222
223
224
225
226
227
# File 'lib/redis/sorted_set.rb', line 222

def interstore(name, *sets)
  allow_expiration do
    opts = sets.last.is_a?(Hash) ? sets.pop : {}
    redis.zinterstore(key_from_object(name), keys_from_objects([self] + sets), **opts)
  end
end

#lastObject

Return the last element in the list. Redis: ZRANGE(-1)



290
291
292
# File 'lib/redis/sorted_set.rb', line 290

def last
  at(-1)
end

#lengthObject Also known as: size, count

The number of members in the set. Aliased as size or count. Redis: ZCARD



295
296
297
# File 'lib/redis/sorted_set.rb', line 295

def length
  redis.zcard(key)
end

#member?(value) ⇒ Boolean

Return a boolean indicating whether value is a member.

Returns:

  • (Boolean)


307
308
309
# File 'lib/redis/sorted_set.rb', line 307

def member?(value)
  !redis.zscore(key, marshal(value)).nil?
end

#members(options = {}) ⇒ Object Also known as: value

Return all members of the sorted set with their scores. Extremely CPU-intensive. Better to use a range instead.



85
86
87
# File 'lib/redis/sorted_set.rb', line 85

def members(options={})
  range(0, -1, options) || []
end

#merge(values) ⇒ Object Also known as: add_all

Add a list of members and their corresponding value (or a hash mapping values to scores) to Redis. Note that the arguments to this are flipped; the member comes first rather than the score, since the member is the unique item (not the score).



28
29
30
31
32
33
# File 'lib/redis/sorted_set.rb', line 28

def merge(values)
  allow_expiration do
    vals = values.map{|v,s| [s, marshal(v)] }
    redis.zadd(key, vals)
  end
end

#range(start_index, end_index, options = {}) ⇒ Object

Return a range of values from start_index to end_index. Can also use the familiar list Ruby syntax. Redis: ZRANGE



92
93
94
95
96
97
98
# File 'lib/redis/sorted_set.rb', line 92

def range(start_index, end_index, options={})
  if options[:withscores] || options[:with_scores]
    redis.zrange(key, start_index, end_index, :with_scores => true).map{|v,s| [unmarshal(v), s] }
  else
    redis.zrange(key, start_index, end_index).map{|v| unmarshal(v) }
  end
end

#range_size(min, max) ⇒ Object

The number of members within a range of scores. Redis: ZCOUNT



302
303
304
# File 'lib/redis/sorted_set.rb', line 302

def range_size(min, max)
  redis.zcount(key, min, max)
end

#rangebyscore(min, max, options = {}) ⇒ Object

Return the all the elements in the sorted set at key with a score between min and max (including elements with score equal to min or max). Options:

:count, :offset - passed to LIMIT
:withscores     - if true, scores are returned as well

Redis: ZRANGEBYSCORE



114
115
116
117
118
119
120
121
# File 'lib/redis/sorted_set.rb', line 114

def rangebyscore(min, max, options={})
  args = {}
  args[:limit] = [options[:offset] || 0, options[:limit] || options[:count]] if
            options[:offset] || options[:limit] || options[:count]
  args[:with_scores] = true if options[:withscores] || options[:with_scores]

  redis.zrangebyscore(key, min, max, **args).map{|v| unmarshal(v) }
end

#rank(member) ⇒ Object

Return the rank of the member in the sorted set, with scores ordered from low to high. revrank returns the rank with scores ordered from high to low. When the given member does not exist in the sorted set, nil is returned. The returned rank (or index) of the member is 0-based for both commands



67
68
69
70
71
72
73
# File 'lib/redis/sorted_set.rb', line 67

def rank(member)
  if n = redis.zrank(key, marshal(member))
    n.to_i
  else
    nil
  end
end

#remrangebyrank(min, max) ⇒ Object

Remove all elements in the sorted set at key with rank between start and end. Start and end are 0-based with rank 0 being the element with the lowest score. Both start and end can be negative numbers, where they indicate offsets starting at the element with the highest rank. For example: -1 is the element with the highest score, -2 the element with the second highest score and so forth. Redis: ZREMRANGEBYRANK



144
145
146
# File 'lib/redis/sorted_set.rb', line 144

def remrangebyrank(min, max)
  redis.zremrangebyrank(key, min, max)
end

#remrangebyscore(min, max) ⇒ Object

Remove all the elements in the sorted set at key with a score between min and max (including elements with score equal to min or max). Redis: ZREMRANGEBYSCORE



150
151
152
# File 'lib/redis/sorted_set.rb', line 150

def remrangebyscore(min, max)
  redis.zremrangebyscore(key, min, max)
end

#revrange(start_index, end_index, options = {}) ⇒ Object

Return a range of values from start_index to end_index in reverse order. Redis: ZREVRANGE



101
102
103
104
105
106
107
# File 'lib/redis/sorted_set.rb', line 101

def revrange(start_index, end_index, options={})
  if options[:withscores] || options[:with_scores]
    redis.zrevrange(key, start_index, end_index, :with_scores => true).map{|v,s| [unmarshal(v), s] }
  else
    redis.zrevrange(key, start_index, end_index).map{|v| unmarshal(v) }
  end
end

#revrangebyscore(max, min, options = {}) ⇒ Object

Returns all the elements in the sorted set at key with a score between max and min (including elements with score equal to max or min). In contrary to the default ordering of sorted sets, for this command the elements are considered to be ordered from high to low scores. Options:

:count, :offset - passed to LIMIT
:withscores     - if true, scores are returned as well

Redis: ZREVRANGEBYSCORE



130
131
132
133
134
135
136
137
# File 'lib/redis/sorted_set.rb', line 130

def revrangebyscore(max, min, options={})
  args = {}
  args[:limit] = [options[:offset] || 0, options[:limit] || options[:count]] if
            options[:offset] || options[:limit] || options[:count]
  args[:with_scores] = true if options[:withscores] || options[:with_scores]

  redis.zrevrangebyscore(key, max, min, **args).map{|v| unmarshal(v) }
end

#revrank(member) ⇒ Object



75
76
77
78
79
80
81
# File 'lib/redis/sorted_set.rb', line 75

def revrank(member)
  if n = redis.zrevrank(key, marshal(member))
    n.to_i
  else
    nil
  end
end

#score(member) ⇒ Object

Return the score of the specified element of the sorted set at key. If the specified element does not exist in the sorted set, or the key does not exist at all, nil is returned. Redis: ZSCORE.



57
58
59
60
61
# File 'lib/redis/sorted_set.rb', line 57

def score(member)
  result = redis.zscore(key, marshal(member))

  result.to_f unless result.nil?
end

#to_sObject



274
275
276
# File 'lib/redis/sorted_set.rb', line 274

def to_s
  members.join(', ')
end

#union(*sets) ⇒ Object Also known as: |, +

Return the union with another set. Can pass it either another set object or set name. Also available as | and + which are a bit cleaner:

members_in_either = set1 | set2
members_in_either = set1 + set2

If you want to specify multiple sets, you must use union:

members_in_all = set1.union(set2, set3, set4)

Redis: SUNION



240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/redis/sorted_set.rb', line 240

def union(*sets)
  result = nil
  temp_key = :"#{key}:union:#{Time.current.to_i + rand}"

  redis.multi do
    unionstore(temp_key, *sets)
    redis.expire(temp_key, 1)

    result = redis.zrange(temp_key, 0, -1)
  end

  result.value
end

#unionstore(name, *sets) ⇒ Object

Calculate the union and store it in Redis as name. Returns the number of elements in the stored union. Redis: SUNIONSTORE



258
259
260
261
262
263
# File 'lib/redis/sorted_set.rb', line 258

def unionstore(name, *sets)
  allow_expiration do
    opts = sets.last.is_a?(Hash) ? sets.pop : {}
    redis.zunionstore(key_from_object(name), keys_from_objects([self] + sets), **opts)
  end
end