基于redis的sorted set实现排名(Ranking)和等级玩家搜索功能。
testcase1()有方法的调用样例:
#-*- coding: utf-8 -* import redis import random # 调试开关 _DEBUG = False # 删除缓冲 BUF_SIZE = 128 def _import_func(func_name): components = func_name.split('.') if len(components) == 1: return globals()[func_name] mod = __import__(components[0]) for comp in components[1:]: mod = getattr(mod, comp) return mod class Ranking: _instances = {} def __init__(self, id, redis_inst, conf, eval_rank_cb): self.label = id self.redis = redis_inst self.conf = conf self.eval_rank_cb = eval_rank_cb @classmethod def instance(cls, label): return cls._instances[label] @classmethod def init(cls, configs, callback=None): label = configs['label'] instance = None if cls._instances.has_key(label): instance = cls._instances[label] if instance is None: conf = cls.parse_config(configs) if conf is not None: instance = cls(conf['label'], \ conf['redis'], \ conf, \ conf['eval_rank_cb']) cls._instances[label] = instance return instance def add(self, uid, **attrs): name, value = self.eval_rank_cb(**attrs) if name is not None: self.do_add(name, uid, value) else: pass def do_add(self, rank, id, value): if _DEBUG: print "[DEBUG] Ranking.do_add: rank:", rank, " id:", id, " value", value rank_len = self.conf['rank_len'] rc = self.redis.zadd(rank, value, id) len = self.redis.zcount(rank, '-inf', '+inf') if (len - BUF_SIZE) > rank_len: self.redis.zremrangebyrank(rank, 0, (len - rank_len)) if _DEBUG: len = self.redis.zcount(rank, '-inf', '+inf') print "[DEBUG] Ranking.do_add: do remove due to too long, now len =", len def get(self, rank, len, end=-1): start = end - len return self.redis.zrange(rank, start, end, withscores=True) @classmethod def parse_config(cls, configs): conf = {} conf['label'] = '' conf['redis_server'] = '' conf['redis_port'] = -1 conf['redis_db'] = '' conf['rank_len'] = 1000 if configs.has_key('redis_server'): conf['label'] = configs['label'] if configs.has_key('redis_server'): conf['redis_server'] = configs['redis_server'] if configs.has_key('redis_port'): conf['redis_port'] = int(configs['redis_port']) if configs.has_key('redis_db'): conf['redis_db'] = configs['redis_db'] if configs.has_key('rank_size'): conf['rank_len'] = int(configs['rank_size']) if configs.has_key('eval_rank_func'): conf['eval_rank_cb'] = _import_func(configs['eval_rank_func']) try: conf['redis'] = redis.StrictRedis(host=conf['redis_server'], \ port=conf['redis_port'], \ db=conf['redis_db'], \ socket_timeout=3) except Exception,e: print "Ranking.parse_config.Error:", e return None return conf # 回调接口 # 返回值格式 (rank_name, score) def testcase1_eval(**kwargs): # 为每个等级建立一个rank,rank的依据是当前时间 # 实现:搜索指定顶级的玩家列表功能 import time lv = kwargs['level'] return ('Lv%03d'%lv, time.time()) def testcase1_eval2(**kwargs): # 建立等级的rank,玩家根据级别大小排列。 lv = kwargs['level'] return ('Level', lv) def testcase1(): fifo_configs = { 'label' : 'Fifo', 'redis_server': '127.0.0.1', 'redis_port': 6379, 'redis_db': 0, 'rank_len': 20, 'eval_rank_func': 'testcase1_eval', } level_configs = { 'label' : 'Level', 'redis_server': '127.0.0.1', 'redis_port': 6379, 'redis_db': 0, 'rank_len': 20, 'eval_rank_func': 'testcase1_eval2', } Ranking.init(fifo_configs) Ranking.init(level_configs) level_instance = Ranking.instance('Level') fifo_instance = Ranking.instance('Fifo') for i in xrange(10000): uid = "uid%d" % i level = random.randint(1, 40) fifo_instance.add(uid, level=level) # 添加rank数据 level_instance.add(uid, level=level) # 添加rank数据 data = level_instance.get("Level", 20) # 获取等级最高的玩家列表(20条) print "Level:", data data = fifo_instance.get("Lv007", 20) # 获取等级为7级的玩家列表(20条) print "Level:", data if __name__ == '__main__': testcase1()