Удаление нескольких ключей в redis-rb

#ruby #redis

#ruby #redis

Вопрос:

При использовании redis-rb в приложении Rails не работает следующее:

 irb> keys = $redis.keys("autocomplete*")
=> ["autocomplete_foo", "autocomplete_bar", "autocomplete_bat"]
irb> $redis.del(keys)
=> 0
  

Это работает нормально:

 irb> $redis.del("autocomplete_foo", "autocomplete_bar")
=> 2
  

Я упускаю что-то очевидное? Источник просто:

 # Delete a key.
def del(*keys)
  synchronize do
    @client.call [:del, *keys]
  end
end
  

мне кажется, что это должно сработать, чтобы передать ему массив …?

Ответ №1:

Небольшое кодирование, посвященное тому, как работает оператор splat:

 def foo(*keys)
  puts keys.inspect
end

>> foo("hi", "there")
["hi", "there"]

>> foo(["hi", "there"])
[["hi", "there"]]

>> foo(*["hi", "there"])
["hi", "there"]
  

Таким образом, передача обычного массива приведет к тому, что этот массив будет оцениваться как единый элемент, так что вы получите массив внутри массива в вашем методе. Если вы предваряете массив символом * при вызове метода:

 $redis.del(*keys)
  

Это позволяет методу знать, что его нужно распаковать / не принимать никаких дальнейших аргументов. Таким образом, это должно решить проблему, с которой вы столкнулись!

Просто ради дальнейшего разъяснения, это работает:

 >> foo("hello", *["hi", "there"])
  

Это приводит к синтаксической ошибке:

 >> foo("hello", *["hi", "there"], "world")
  

Комментарии:

1. причины удаления нескольких (тысяч) ключей: SystemStackError: слишком глубокий уровень стека, о котором сообщается в этом выпуске github.com/redis/redis-rb/issues/122 . Это решается прямым вызовом метода на клиенте: $redis.client.call [:del, *keys]

Ответ №2:

Для приложения Rails, над которым я работаю, мне нужно было протестировать результаты загрузки и выгрузки данных redis.

Пространство имен определяется средой, что позволяет избежать взаимодействия с разработкой. Это сработало хорошо.

 def clear_redis_cache
  keys = $redis.keys "#{namespace}*"
  $redis.del(*keys) unless keys.empty?
end
  

Комментарии:

1. Monkey-исправление пространства имен redis для этого gist.github.com/mahemoff/c3abf31d5eeda2b2ac751dccd5182cb9

2. -1 потому что команда KEYS не является готовой к работе командой. Это вызовет блокировку соединения и повлияет на другие команды. Подробнее redis.io/topics/latency

Ответ №3:

Этого лучше достичь с помощью перечислителя, возвращаемого scan_each .

 scan_each(match: 'autocomplete_*').each do |key|
  del key
end
  

Это не загружает все соответствующие ключи в память сразу, поэтому он не будет ограничен локальной памятью.

Комментарии:

1. ЭТО , так много всего этого! Я использовал оригинальный метод poster для сканирования всей базы данных на предмет совпадающих ключей, а затем пытался удалить массив, содержащий тысячи ключей. Это заняло больше часа. Этот scan_each метод сократил время до 10 минут!