批量重命名键

时间:2014-02-26 20:21:09

标签: redis

我有一个相当大的数据库(每个大约有一百万个密钥的5个dbs),每个密钥都有一个环境命名空间。例如:"datamine::production::crosswalk==foobar"

我需要将开发环境与从生产RDB快照复制的数据同步。

所以我要做的是批量重命名每个键,将命名空间从datamine::production更改为datamine::development。有没有一种好的方法来实现这个目标?

到目前为止我尝试了什么

  • keys "datamine::production*"的redis-cli命令,管道输入sed,然后返回redis-cli。这需要永远,并且由于某种原因在许多键上进行炸弹(偶尔将几个键合在同一行中)。我更喜欢更好的选择。

  • 在.rdb文件上进行Perl搜索/替换。我的本地redis-server flat拒绝加载修改后的RDB。

2 个答案:

答案 0 :(得分:3)

解决方案:

好的,这是我为解决这个问题而编写的脚本。它需要“Redis”宝石。希望其他人觉得这很有用......

#!/usr/bin/env ruby

# A script to translate the current redis database into a namespace for another environment
# GWI's Redis keys are namespaced as "datamine::production", "datamine::development", etc.
# This script connects to redis and translates these key names in-place.
#
# This script does not use Rails, but needs the "redis" gem available
require 'Benchmark'
require 'Redis'

FROM_NAMESPACE = "production"
TO_NAMESPACE = "development"
NAMESPACE_PREFIX = "datamine::"
REDIS_SERVER = "localhost"
REDIS_PORT   = "6379"
REDIS_DBS = [0,1,2,3,4,5]

redis = Redis.new(host: REDIS_SERVER, port: REDIS_PORT, timeout: 30)

REDIS_DBS.each do |redis_db|
  redis.select(redis_db)
  puts "Translating db ##{redis_db}..."
  seconds = Benchmark.realtime do
    dbsize = redis.dbsize.to_f
    inc_threshold = (dbsize/100.0).round
    i = 0
    old_keys = redis.keys("#{NAMESPACE_PREFIX}#{FROM_NAMESPACE}*")
    old_keys.each do |old_key|
      new_key = old_key.gsub(FROM_NAMESPACE, TO_NAMESPACE)
      redis.rename(old_key, new_key)
      print "#{((i/dbsize)*100.0).round}% complete\r" if (i % inc_threshold == 0) # on whole # % only
      i += 1
    end
  end
  puts "\nDone. It took #{seconds} seconds"
end

答案 1 :(得分:1)

我有一个有效的解决方案:

#!/usr/bin/env python3

import tkinter as tk

# --- constants --- (UPPER_CASE names)

DISPLAY_WIDHT = 800
DISPLAY_HEIGHT = 600

# --- classes --- (CamelCase names)

#class Player():
#    pass

#class BlueEnemy():
#    pass

# --- functions --- (lower_case names)

def move_a(event):
    # don't move if gama paused
    if not game_paused:
        canvas.coords(a, event.x-50, event.y-50, event.x+50, event.y+50)

def move_b():
    # inform function to use external/global variable
    # because we use `=` to change its value
    global b_speed_x
    global b_speed_y
    global b_direction

    # don't move if gama paused
    if not game_paused:
        canvas.move(b, b_speed_x, b_speed_y)

        # get current position
        x1, y1, x2, y2 = canvas.coords(b)

        if b_direction == 'down':
            if y2 >= DISPLAY_HEIGHT:
                b_direction = 'right'
                b_speed_x = 5
                b_speed_y = 0
        elif b_direction == 'up':
            if y1 <= 0:
                b_direction = 'left'
                b_speed_x = -5
                b_speed_y = 0
        elif b_direction == 'right':
            if x2 >= DISPLAY_WIDHT:
                b_direction = 'up'
                b_speed_x = 0
                b_speed_y = -5
        elif b_direction == 'left':
            if x1 <= 0:
                b_direction = 'down'
                b_speed_x = 0
                b_speed_y = 5

    # move again after 25 ms (0.025s)
    root.after(25, move_b)

def pause(event):
    global game_paused

    # change True/False
    game_paused = not game_paused

    if game_paused:
        # center text on canvas
        canvas.coords(text_pause, DISPLAY_WIDHT//2, DISPLAY_HEIGHT//2)
    else:
        # move text somewhere outside canvas
        canvas.coords(text_pause, -1000, -1000)

# --- main --- (lower_case names)

# init
root = tk.Tk()

# key `p` pause game
game_paused = False
root.bind('p', pause)

# create canvas
canvas = tk.Canvas(root, width=DISPLAY_WIDHT, height=DISPLAY_HEIGHT)
canvas.pack()

# create objects
a = canvas.create_rectangle(0, 0, 100, 100, fill='red')
b = canvas.create_rectangle(0, 0, 100, 100, fill='blue')
# create global variables
b_direction = 'down'
b_speed_x = 0
b_speed_y = 5

# start moving `a` with mouse
canvas.bind("<Motion>", move_a)

# start moving `b` automatically
move_b()

# create text somewhere outside canvas - so it will be "invisible"
text_pause = canvas.create_text(-1000, -1000, text="PAUSED", font=(50,))

# start program
root.mainloop()

最后两个参数分别是旧前缀和新前缀。