def redis_cluster(): '''集群操作''' redis_nodes = [{ 'host': '10.12.28.222', 'port': 6380 }, { 'host': '10.12.28.222', 'port': 6381 }, { 'host': '10.12.28.224', 'port': 6380 }, { 'host': '10.12.28.224', 'port': 6381 }, { 'host': '10.12.28.227', 'port': 6380 }, { 'host': '10.12.28.227', 'port': 6381 }] try: r = StrictRedisCluster(startup_nodes=redis_nodes) except Exception as e: print("connect error %s" % e) # string 操作 r.set('thoth:thoth-ai:robot:1', 'kk') # r.delete('thoth:thoth-ai:robot:1') print("name is", r.get('thoth:thoth-ai:robot:1')) # list 操作 r.lpush('thoth:thoth-ai:robot:2', [[1, 2, 3], [2, 3, 4]]) print('list len:', r.llen("thoth:thoth-ai:robot:2")) # list size print("list ", r.lindex('thoth:thoth-ai:robot:2', 0)) # hash 操作 r.hset('thoth:thoth-ai:robot:3', 'private_vector', [[1, 2, 3], [2, 3, 4]]) r.hset('thoth:thoth-ai:robot:3', 'public_vector', [['4', 3, 2], [0, 1, 1]]) pv = r.hget( 'thoth:thoth-ai:robot:3', 'public_vector', ) print('hash.robot3.public_vector:', pv) aaa = pv.decode('utf-8') print(type(aaa), aaa) b = eval(aaa) # eval 函数妙用:将string‘[1,2,3]’--->list [1,2,3] print(type(b), b)
class selectclass: def __init__(self): self.rc = StrictRedisCluster(startup_nodes=config.startup_nodes) def _select(self, key_type, kwargs): partition = str(random.randint(1, kwargs['partition'])) _key_name = key_type + '_r_test_' + partition + ':00' + str( random.randint(1, kwargs['key_num'])) if key_type == 'string': self.rc.get(_key_name) elif key_type == 'hash': _filed = str(random.randint(1, int( kwargs['filed_num']))) + ':value_test' self.rc.hget(_key_name, _filed) elif key_type == 'list': _num_1 = random.randint(1, int(kwargs['filed_num'])) _num_2 = random.randint(1, int(kwargs['filed_num'])) if _num_1 < _num_2: self.rc.lrange(_key_name, _num_1, _num_2) else: self.rc.lrange(_key_name, _num_2, _num_1) elif key_type == 'set': self.rc.srandmember(_key_name) else: exit() def _update(self, key_type, kwargs): _value = ''.join( map(lambda xx: (hex(ord(xx))[2:]), os.urandom(random.randint(1, 200) / 2))) partition = str(random.randint(1, kwargs['partition'])) _key_name = key_type + '_r_test_' + partition + ':00' + str( random.randint(1, kwargs['key_num'])) if key_type == 'string': self.rc.set(_key_name, _value) elif key_type == 'hash': _filed_name = str(random.randint( 1, kwargs['filed_num'])) + ':_value_test' self.rc.hset(_key_name, _filed_name, _value) elif key_type == 'list': _filed_int = random.randint(0, kwargs['filed_num'] - 1) self.rc.lset(_key_name, _filed_int, _value) elif key_type == 'set': self.rc.spop(_key_name) self.rc.sadd(_key_name, _value) else: exit()
def redis_cluster(): redis_nodes = [{ 'host': '10.1.120.112', 'port': 8001, 'password': 123456 }, { 'host': '10.1.120.111', 'port': 8002, 'password': 123456 }, { 'host': '10.1.120.85', 'port': 8003, 'password': 123456 }, { 'host': '10.1.120.112', 'port': 9001, 'password': 123456 }, { 'host': '10.1.120.111', 'port': 9002, 'password': 123456 }, { 'host': '10.1.120.85', 'port': 9003, 'password': 123456 }, { 'host': '10.1.120.112', 'port': 9101, 'password': 123456 }, { 'host': '10.1.120.111', 'port': 9102, 'password': 123456 }, { 'host': '10.1.120.85', 'port': 9103, 'password': 123456 }] redisconn = StrictRedisCluster(startup_nodes=redis_nodes, password=123456) redisconn.hset("test1", "hello", '你好') print(redisconn.hget('test1', 'hello').decode('utf-8'))
def redis_cluster(): redis_nodes = [{ "host": "192.168.1.161", "port": 7000 }, { "host": "192.168.1.161", "port": 7001 }, { "host": "192.168.1.161", "port": 7002 }, { "host": "192.168.1.147", "port": 7000 }, { "host": "192.168.1.147", "port": 7001 }, { "host": "192.168.1.147", "port": 7002 }] try: redisconn = StrictRedisCluster(startup_nodes=redis_nodes) except Exception as e: print("connect error!!") sys.exit(1) redisconn.hset("info1", "name", "yiruiduan") redisconn.hset("info1", "age", 30) redisconn.hset("info1", "id", 2) # for key in redisconn.keys(): # redisconn.delete(key) print(redisconn.keys())
class RedisClusterNode(object): def __init__(self, node_list): self.node_list = node_list self.__connect() #析构函数,断开连接 def __del__(self): if self.connect: pass def __connect(self): try: self.connect = StrictRedisCluster(startup_nodes=self.node_list) except Exception as e: self.connect = None print("Connect redisCluster node error!", e) return #set方法 def set(self, key, value): try: self.connect.set(key, value) return True except Exception as e: print("RedisUtil excute set method failed!", e) return False #get方法 def get(self, key): try: return self.connect.get(key) except Exception as e: print("RedisUtil excute get method failed!", e) return None #del方法 def delete(self, key): try: self.connect.delete(key) return True except Exception as e: print("RedisUtil excute delete method failed!", e) return False #mset方法 def mset(self, map): try: self.connect.mset(map) return True except Exception as e: print("RedisUtil excute mset method failed!", e) return False #mget方法 def mget(self, array_keys): try: return self.connect.mget(array_keys) except Exception as e: print("RedisUtil excute mget method failed!", e) return None #hset方法 def hset(self, key, field, value): try: self.connect.hset(key, field, value) return True except Exception as e: print("RedisUtil excute hset method failed!", e) return False #hget方法 def hget(self, key, field): try: return self.connect.hget(key, field) except Exception as e: print("RedisUtil excute hget method failed!", e) return None
class TcRedis(): def __init__(self, *nodelist): self.redisinst = None if len(nodelist) == 0: self.redisinst = redis.StrictRedis(host='localhost', port=6379, db=0) elif len(nodelist) == 1: host, port = nodelist[0].split(':') self.redisinst = redis.StrictRedis(host=host, port=int(port)) elif len(nodelist) > 1: redis_nodes = [] for node in nodelist: host, port = node.split(':') redis_nodes.append({"host": host, "port": int(port)}) self.redisinst = StrictRedisCluster(startup_nodes=redis_nodes, decode_responses=True) def set(self, key, value): return self.redisinst.set(key, value) def get(self, key): return self.redisinst.get(key) def delete(self, key): return self.redisinst.delete(key) def ttl(self, key): return self.redisinst.ttl(key) def scan(self, cursor=0, match=None, count=2000): depth = 1000 cursor = 0 result = [] for i in range(depth): cursor, result0 = self.redisinst.scan(cursor, match=match) if len(result0) != 0: result = result + result0 if cursor == 0: break return result def hset(self, key, name, value): return self.redisinst.hset(key, name, value) def hget(self, key, name): return self.redisinst.hget(key, name) def lpush(self, key, *values): return self.redisinst.lpush(key, *values) def lpop(self, key): return self.redisinst.lpop(key) def sadd(self, key, *values): return self.redisinst.sadd(key, *values) def smembers(self, key): return self.redisinst.smembers(key) def zadd(self, key, *args, **kwargs): return self.redisinst.zadd(key, *args, **kwargs) def zrange(self, key, start, end): return self.redisinst.zrange(key, start, end)
class RedisDB: def __init__(self, ip_ports=None, db=None, user_pass=None, url=None, decode_responses=True, service_name=None, max_connections=32, **kwargs): """ redis的封装 Args: ip_ports: ip:port 多个可写为列表或者逗号隔开 如 ip1:port1,ip2:port2 或 ["ip1:port1", "ip2:port2"] db: user_pass: url: decode_responses: service_name: 适用于redis哨兵模式 """ # 可能会改setting中的值,所以此处不能直接赋值为默认值,需要后加载赋值 if ip_ports is None: ip_ports = setting.REDISDB_IP_PORTS if db is None: db = setting.REDISDB_DB if user_pass is None: user_pass = setting.REDISDB_USER_PASS if service_name is None: service_name = setting.REDISDB_SERVICE_NAME self._is_redis_cluster = False try: if not url: ip_ports = (ip_ports if isinstance(ip_ports, list) else ip_ports.split(",")) if len(ip_ports) > 1: startup_nodes = [] for ip_port in ip_ports: ip, port = ip_port.split(":") startup_nodes.append({"host": ip, "port": port}) if service_name: log.debug("使用redis哨兵模式") hosts = [(node["host"], node["port"]) for node in startup_nodes] sentinel = Sentinel(hosts, socket_timeout=3, **kwargs) self._redis = sentinel.master_for( service_name, password=user_pass, db=db, redis_class=redis.StrictRedis, decode_responses=decode_responses, max_connections=max_connections, **kwargs) else: log.debug("使用redis集群模式") self._redis = StrictRedisCluster( startup_nodes=startup_nodes, decode_responses=decode_responses, password=user_pass, max_connections=max_connections, **kwargs) self._is_redis_cluster = True else: ip, port = ip_ports[0].split(":") self._redis = redis.StrictRedis( host=ip, port=port, db=db, password=user_pass, decode_responses=decode_responses, max_connections=max_connections, **kwargs) else: self._redis = redis.StrictRedis.from_url( url, decode_responses=decode_responses) except Exception as e: raise else: if not url: log.debug("连接到redis数据库 %s db%s" % (ip_ports, db)) else: log.debug("连接到redis数据库 %s" % (url)) self._ip_ports = ip_ports self._db = db self._user_pass = user_pass self._url = url def __repr__(self): if self._url: return "<Redisdb url:{}>".format(self._url) return "<Redisdb ip_ports: {} db:{} user_pass:{}>".format( self._ip_ports, self._db, self._user_pass) @classmethod def from_url(cls, url): return cls(url=url) def sadd(self, table, values): """ @summary: 使用无序set集合存储数据, 去重 --------- @param table: @param values: 值; 支持list 或 单个值 --------- @result: 若库中存在 返回0,否则入库,返回1。 批量添加返回None """ if isinstance(values, list): pipe = self._redis.pipeline( transaction=True ) # redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 if not self._is_redis_cluster: pipe.multi() for value in values: pipe.sadd(table, value) pipe.execute() else: return self._redis.sadd(table, values) def sget(self, table, count=1, is_pop=True): """ 返回 list 如 ['1'] 或 [] @param table: @param count: @param is_pop: @return: """ datas = [] if is_pop: count = count if count <= self.sget_count( table) else self.sget_count(table) if count: if count > 1: pipe = self._redis.pipeline( transaction=True ) # redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 if not self._is_redis_cluster: pipe.multi() while count: pipe.spop(table) count -= 1 datas = pipe.execute() else: datas.append(self._redis.spop(table)) else: datas = self._redis.srandmember(table, count) return datas def srem(self, table, values): """ @summary: 移除集合中的指定元素 --------- @param table: @param values: 一个或者列表 --------- @result: """ if isinstance(values, list): pipe = self._redis.pipeline( transaction=True ) # redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 if not self._is_redis_cluster: pipe.multi() for value in values: pipe.srem(table, value) pipe.execute() else: self._redis.srem(table, values) def sget_count(self, table): return self._redis.scard(table) def sdelete(self, table): """ @summary: 删除set集合的大键(数据量大的表) 删除大set键,使用sscan命令,每次扫描集合中500个元素,再用srem命令每次删除一个键 若直接用delete命令,会导致Redis阻塞,出现故障切换和应用程序崩溃的故障。 --------- @param table: --------- @result: """ # 当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束 cursor = "0" while cursor != 0: cursor, data = self._redis.sscan(table, cursor=cursor, count=500) for item in data: # pipe.srem(table, item) self._redis.srem(table, item) # pipe.execute() def sismember(self, table, key): "Return a boolean indicating if ``value`` is a member of set ``name``" return self._redis.sismember(table, key) def zadd(self, table, values, prioritys=0): """ @summary: 使用有序set集合存储数据, 去重(值存在更新) --------- @param table: @param values: 值; 支持list 或 单个值 @param prioritys: 优先级; double类型,支持list 或 单个值。 根据此字段的值来排序, 值越小越优先。 可不传值,默认value的优先级为0 --------- @result:若库中存在 返回0,否则入库,返回1。 批量添加返回 [0, 1 ...] """ if isinstance(values, list): if not isinstance(prioritys, list): prioritys = [prioritys] * len(values) else: assert len(values) == len(prioritys), "values值要与prioritys值一一对应" pipe = self._redis.pipeline(transaction=True) if not self._is_redis_cluster: pipe.multi() for value, priority in zip(values, prioritys): pipe.zadd(table, priority, value) return pipe.execute() else: return self._redis.zadd(table, prioritys, values) def zget(self, table, count=1, is_pop=True): """ @summary: 从有序set集合中获取数据 优先返回分数小的(优先级高的) --------- @param table: @param count: 数量 -1 返回全部数据 @param is_pop:获取数据后,是否在原set集合中删除,默认是 --------- @result: 列表 """ start_pos = 0 # 包含 end_pos = count - 1 if count > 0 else count pipe = self._redis.pipeline( transaction=True ) # redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 if not self._is_redis_cluster: pipe.multi( ) # 标记事务的开始 参考 http://www.runoob.com/redis/redis-transactions.html pipe.zrange(table, start_pos, end_pos) # 取值 if is_pop: pipe.zremrangebyrank(table, start_pos, end_pos) # 删除 results, *count = pipe.execute() return results def zremrangebyscore(self, table, priority_min, priority_max): """ 根据分数移除成员 闭区间 @param table: @param priority_min: @param priority_max: @return: 被移除的成员个数 """ return self._redis.zremrangebyscore(table, priority_min, priority_max) def zrangebyscore(self, table, priority_min, priority_max, count=None, is_pop=True): """ @summary: 返回指定分数区间的数据 闭区间 --------- @param table: @param priority_min: 优先级越小越优先 @param priority_max: @param count: 获取的数量,为空则表示分数区间内的全部数据 @param is_pop: 是否删除 --------- @result: """ # 使用lua脚本, 保证操作的原子性 lua = """ local key = KEYS[1] local min_score = ARGV[2] local max_score = ARGV[3] local is_pop = ARGV[4] local count = ARGV[5] -- 取值 local datas = nil if count then datas = redis.call('zrangebyscore', key, min_score, max_score, 'limit', 0, count) else datas = redis.call('zrangebyscore', key, min_score, max_score) end -- 删除redis中刚取到的值 if (is_pop) then for i=1, #datas do redis.call('zrem', key, datas[i]) end end return datas """ cmd = self._redis.register_script(lua) if count: res = cmd(keys=[table], args=[table, priority_min, priority_max, is_pop, count]) else: res = cmd(keys=[table], args=[table, priority_min, priority_max, is_pop]) return res def zrangebyscore_increase_score(self, table, priority_min, priority_max, increase_score, count=None): """ @summary: 返回指定分数区间的数据 闭区间, 同时修改分数 --------- @param table: @param priority_min: 最小分数 @param priority_max: 最大分数 @param increase_score: 分数值增量 正数则在原有的分数上叠加,负数则相减 @param count: 获取的数量,为空则表示分数区间内的全部数据 --------- @result: """ # 使用lua脚本, 保证操作的原子性 lua = """ local key = KEYS[1] local min_score = ARGV[1] local max_score = ARGV[2] local increase_score = ARGV[3] local count = ARGV[4] -- 取值 local datas = nil if count then datas = redis.call('zrangebyscore', key, min_score, max_score, 'limit', 0, count) else datas = redis.call('zrangebyscore', key, min_score, max_score) end --修改优先级 for i=1, #datas do redis.call('zincrby', key, increase_score, datas[i]) end return datas """ cmd = self._redis.register_script(lua) if count: res = cmd(keys=[table], args=[priority_min, priority_max, increase_score, count]) else: res = cmd(keys=[table], args=[priority_min, priority_max, increase_score]) return res def zrangebyscore_set_score(self, table, priority_min, priority_max, score, count=None): """ @summary: 返回指定分数区间的数据 闭区间, 同时修改分数 --------- @param table: @param priority_min: 最小分数 @param priority_max: 最大分数 @param score: 分数值 @param count: 获取的数量,为空则表示分数区间内的全部数据 --------- @result: """ # 使用lua脚本, 保证操作的原子性 lua = """ local key = KEYS[1] local min_score = ARGV[1] local max_score = ARGV[2] local set_score = ARGV[3] local count = ARGV[4] -- 取值 local datas = nil if count then datas = redis.call('zrangebyscore', key, min_score, max_score, 'withscores','limit', 0, count) else datas = redis.call('zrangebyscore', key, min_score, max_score, 'withscores') end local real_datas = {} -- 数据 --修改优先级 for i=1, #datas, 2 do local data = datas[i] local score = datas[i+1] table.insert(real_datas, data) -- 添加数据 redis.call('zincrby', key, set_score - score, datas[i]) end return real_datas """ cmd = self._redis.register_script(lua) if count: res = cmd(keys=[table], args=[priority_min, priority_max, score, count]) else: res = cmd(keys=[table], args=[priority_min, priority_max, score]) return res def zget_count(self, table, priority_min=None, priority_max=None): """ @summary: 获取表数据的数量 --------- @param table: @param priority_min:优先级范围 最小值(包含) @param priority_max:优先级范围 最大值(包含) --------- @result: """ if priority_min != None and priority_max != None: return self._redis.zcount(table, priority_min, priority_max) else: return self._redis.zcard(table) def zrem(self, table, values): """ @summary: 移除集合中的指定元素 --------- @param table: @param values: 一个或者列表 --------- @result: """ if isinstance(values, list): pipe = self._redis.pipeline( transaction=True ) # redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 if not self._is_redis_cluster: pipe.multi() for value in values: pipe.zrem(table, value) pipe.execute() else: self._redis.zrem(table, values) def zexists(self, table, values): """ 利用zscore判断某元素是否存在 @param values: @return: """ is_exists = [] if isinstance(values, list): pipe = self._redis.pipeline( transaction=True ) # redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 pipe.multi() for value in values: pipe.zscore(table, value) is_exists_temp = pipe.execute() for is_exist in is_exists_temp: if is_exist != None: is_exists.append(1) else: is_exists.append(0) else: is_exists = self._redis.zscore(table, values) is_exists = 1 if is_exists != None else 0 return is_exists def lpush(self, table, values): if isinstance(values, list): pipe = self._redis.pipeline( transaction=True ) # redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 if not self._is_redis_cluster: pipe.multi() for value in values: pipe.rpush(table, value) pipe.execute() else: return self._redis.rpush(table, values) def lpop(self, table, count=1): """ @summary: --------- @param table: @param count: --------- @result: count>1时返回列表 """ datas = None count = count if count <= self.lget_count(table) else self.lget_count( table) if count: if count > 1: pipe = self._redis.pipeline( transaction=True ) # redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 if not self._is_redis_cluster: pipe.multi() while count: pipe.lpop(table) count -= 1 datas = pipe.execute() else: datas = self._redis.lpop(table) return datas def rpoplpush(self, from_table, to_table=None): """ 将列表 from_table 中的最后一个元素(尾元素)弹出,并返回给客户端。 将 from_table 弹出的元素插入到列表 to_table ,作为 to_table 列表的的头元素。 如果 from_table 和 to_table 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转(rotation)操作 @param from_table: @param to_table: @return: """ if not to_table: to_table = from_table return self._redis.rpoplpush(from_table, to_table) def lget_count(self, table): return self._redis.llen(table) def lrem(self, table, value, num=0): return self._redis.lrem(table, value, num) def hset(self, table, key, value): """ @summary: 如果 key 不存在,一个新的哈希表被创建并进行 HSET 操作。 如果域 field 已经存在于哈希表中,旧值将被覆盖 --------- @param table: @param key: @param value: --------- @result: 1 新插入; 0 覆盖 """ return self._redis.hset(table, key, value) def hset_batch(self, table, datas): """ 批量插入 Args: datas: [[key, value]] Returns: """ pipe = self._redis.pipeline(transaction=True) if not self._is_redis_cluster: pipe.multi() for key, value in datas: pipe.hset(table, key, value) return pipe.execute() def hincrby(self, table, key, increment): return self._redis.hincrby(table, key, increment) def hget(self, table, key, is_pop=False): if not is_pop: return self._redis.hget(table, key) else: lua = """ local key = KEYS[1] local field = ARGV[1] -- 取值 local datas = redis.call('hget', key, field) -- 删除值 redis.call('hdel', key, field) return datas """ cmd = self._redis.register_script(lua) res = cmd(keys=[table], args=[key]) return res def hgetall(self, table): return self._redis.hgetall(table) def hexists(self, table, key): return self._redis.hexists(table, key) def hdel(self, table, *keys): """ @summary: 删除对应的key 可传多个 --------- @param table: @param *keys: --------- @result: """ self._redis.hdel(table, *keys) def hget_count(self, table): return self._redis.hlen(table) def setbit(self, table, offsets, values): """ 设置字符串数组某一位的值, 返回之前的值 @param table: @param offsets: 支持列表或单个值 @param values: 支持列表或单个值 @return: list / 单个值 """ if isinstance(offsets, list): if not isinstance(values, list): values = [values] * len(offsets) else: assert len(offsets) == len(values), "offsets值要与values值一一对应" pipe = self._redis.pipeline( transaction=True ) # redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 pipe.multi() for offset, value in zip(offsets, values): pipe.setbit(table, offset, value) return pipe.execute() else: return self._redis.setbit(table, offsets, values) def getbit(self, table, offsets): """ 取字符串数组某一位的值 @param table: @param offsets: 支持列表 @return: list / 单个值 """ if isinstance(offsets, list): pipe = self._redis.pipeline( transaction=True ) # redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 pipe.multi() for offset in offsets: pipe.getbit(table, offset) return pipe.execute() else: return self._redis.getbit(table, offsets) def bitcount(self, table): return self._redis.bitcount(table) def strset(self, table, value, **kwargs): return self._redis.set(table, value, **kwargs) def str_incrby(self, table, value): return self._redis.incrby(table, value) def strget(self, table): return self._redis.get(table) def strlen(self, table): return self._redis.strlen(table) def getkeys(self, regex): return self._redis.keys(regex) def exists_key(self, key): return self._redis.exists(key) def set_expire(self, key, seconds): """ @summary: 设置过期时间 --------- @param key: @param seconds: 秒 --------- @result: """ self._redis.expire(key, seconds) def clear(self, table): try: self._redis.delete(table) except Exception as e: log.error(e) def get_redis_obj(self): return self._redis
class RedisClient(object): def __init__(self, key, startup_nodes): """ init cluster """ self.key = key self.conn = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True) def hdel(self, field): """ delete an item :param field: :return: """ self.conn.hdel(self.key, field) def hexists(self, field): """ 判断 key 中是否含有 field :param field: :return: """ return self.conn.hexists(self.key, field) def hget(self, field): """ 返回key中指定 field 中的 value :param field: :return: """ value = self.conn.hget(self.key, field) if isinstance(value, bytes): return value.decode('utf-8') else: return value if value else None def hgetall(self): """ 获取 {filed: value, field1: value1....} :return: """ all_dict = self.conn.hgetall(self.key) if not all_dict: return elif sys.version_info.major == 3: return { field.decode('utf-8'): value.decode('utf-8') for field, value in all_dict.items() } else: return all_dict def hkeys(self): """ 获取key中所有field :return: """ field = self.conn.hkeys(self.key) if isinstance(field, bytes): return field.decode('utf-8') else: return field if field else None def hlen(self): """ 获取所有 filed 数量 :return: """ return self.conn.hlen(self.key) def hset(self, field, value): """ 设置 field: value :param field: :param value: :return: """ self.conn.hset(self.key, field, value) def hvals(self): """ 获取所有values :return: """ values = self.conn.hvals(self.key) if not values: return elif sys.version_info.major == 3: return [value.decode('utf-8') for value in values] else: return values def change_key(self, key): """ 替换 key :param key: :return: """ self.key = key # =============================================== def blpop(self, timeout): self.conn.blpop(self.key, timeout=timeout) def brpop(self, timeout): self.conn.brpop(self.key, timeout=timeout) def brpoplpush(self, dst, timeout): self.conn.brpoplpush(self.key, dst=dst, timeout=timeout) def lindex(self, i): self.conn.lindex(self.key, index=i) def llen(self): self.conn.llen(self.key) def lpop(self): self.conn.lpop(self.key) def lpush(self): self.conn.lpush(self.key) def lrange(self, start, stop): self.conn.lrange(self.key, start, stop) def lset(self, i, value): self.conn.lset(self.key, index=i, value=value) def rpop(self): self.conn.rpop(self.key) def rpoplpush(self, dst): self.conn.rpoplpush(self.key, dst=dst) def rpush(self, value): self.conn.rpush(self.key, value)
class Leaderboard(object): VERSION = '3.5.0' DEFAULT_PAGE_SIZE = 25 DEFAULT_REDIS_HOST = 'localhost' DEFAULT_REDIS_PORT = 6379 DEFAULT_REDIS_DB = 0 DEFAULT_MEMBER_DATA_NAMESPACE = 'member_data' DEFAULT_GLOBAL_MEMBER_DATA = False DEFAULT_POOLS = {} ASC = 'asc' DESC = 'desc' MEMBER_KEY = 'member' MEMBER_DATA_KEY = 'member_data' SCORE_KEY = 'score' RANK_KEY = 'rank' DEFAULT_CLUSTER_MODE = False @classmethod def pool(self, host, port, db, pools={}, **options): ''' Fetch a redis conenction pool for the unique combination of host and port. Will create a new one if there isn't one already. ''' key = (host, port, db) rval = pools.get(key) if not isinstance(rval, ConnectionPool): rval = ConnectionPool(host=host, port=port, db=db, **options) pools[key] = rval return rval def __init__(self, leaderboard_name, **options): ''' Initialize a connection to a specific leaderboard. By default, will use a redis connection pool for any unique host:port:db pairing. The options and their default values (if any) are: host : the host to connect to if creating a new handle ('localhost') port : the port to connect to if creating a new handle (6379) db : the redis database to connect to if creating a new handle (0) page_size : the default number of items to return in each page (25) connection : an existing redis handle if re-using for this leaderboard connection_pool : redis connection pool to use if creating a new handle ''' self.leaderboard_name = leaderboard_name self.options = options self.page_size = self.options.pop('page_size', self.DEFAULT_PAGE_SIZE) if self.page_size < 1: self.page_size = self.DEFAULT_PAGE_SIZE self.member_data_namespace = self.options.pop( 'member_data_namespace', self.DEFAULT_MEMBER_DATA_NAMESPACE) self.global_member_data = self.options.pop( 'global_member_data', self.DEFAULT_GLOBAL_MEMBER_DATA) self.order = self.options.pop('order', self.DESC).lower() if not self.order in [self.ASC, self.DESC]: raise ValueError("%s is not one of [%s]" % (self.order, ",".join([self.ASC, self.DESC]))) redis_connection = self.options.pop('redis_connection', None) if redis_connection: # allow the developer to pass a raw redis connection and # we will use it directly instead of creating a new one self.redis_connection = redis_connection else: connection = self.options.pop('connection', None) if isinstance(connection, (StrictRedis, Redis)): self.options['connection_pool'] = connection.connection_pool host = self.options.pop('host', self.DEFAULT_REDIS_HOST) port = self.options.pop('port', self.DEFAULT_REDIS_PORT) if 'connection_pool' not in self.options: self.options['connection_pool'] = self.pool( host, port, self.options.pop('db', self.DEFAULT_REDIS_DB), self.options.pop('pools', self.DEFAULT_POOLS), **self.options) if not self.options.get("cluster_mode", self.DEFAULT_CLUSTER_MODE): self.redis_connection = Redis(**self.options) else: startup_nodes = [{"host": host, "port": port}] self.redis_connection = StrictRedisCluster( startup_nodes=startup_nodes, decode_responses=True, skip_full_coverage_check=True) def delete_leaderboard(self): ''' Delete the current leaderboard. ''' self.delete_leaderboard_named(self.leaderboard_name) def delete_leaderboard_named(self, leaderboard_name): ''' Delete the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. ''' pipeline = self.redis_connection.pipeline() pipeline.delete(leaderboard_name) pipeline.delete(self._member_data_key(leaderboard_name)) pipeline.execute() def rank_member(self, member, score, member_data=None): ''' Rank a member in the leaderboard. @param member [String] Member name. @param score [float] Member score. @param member_data [String] Optional member data. ''' self.rank_member_in(self.leaderboard_name, member, score, member_data) def rank_member_in(self, leaderboard_name, member, score, member_data=None): ''' Rank a member in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @param score [float] Member score. @param member_data [String] Optional member data. ''' pipeline = self.redis_connection.pipeline() if isinstance(self.redis_connection, Redis): pipeline.zadd(leaderboard_name, member, score) else: pipeline.zadd(leaderboard_name, score, member) if member_data: pipeline.hset(self._member_data_key(leaderboard_name), member, member_data) pipeline.execute() def rank_member_across(self, leaderboards, member, score, member_data=None): ''' Rank a member across multiple leaderboards. @param leaderboards [Array] Leaderboard names. @param member [String] Member name. @param score [float] Member score. @param member_data [String] Optional member data. ''' pipeline = self.redis_connection.pipeline() for leaderboard_name in leaderboards: if isinstance(self.redis_connection, Redis): pipeline.zadd(leaderboard_name, member, score) else: pipeline.zadd(leaderboard_name, score, member) if member_data: pipeline.hset(self._member_data_key(leaderboard_name), member, member_data) pipeline.execute() def rank_member_if(self, rank_conditional, member, score, member_data=None): ''' Rank a member in the leaderboard based on execution of the +rank_conditional+. The +rank_conditional+ is passed the following parameters: member: Member name. current_score: Current score for the member in the leaderboard. score: Member score. member_data: Optional member data. leaderboard_options: Leaderboard options, e.g. 'reverse': Value of reverse option @param rank_conditional [function] Function which must return +True+ or +False+ that controls whether or not the member is ranked in the leaderboard. @param member [String] Member name. @param score [float] Member score. @param member_data [String] Optional member_data. ''' self.rank_member_if_in(self.leaderboard_name, rank_conditional, member, score, member_data) def rank_member_if_in(self, leaderboard_name, rank_conditional, member, score, member_data=None): ''' Rank a member in the named leaderboard based on execution of the +rank_conditional+. The +rank_conditional+ is passed the following parameters: member: Member name. current_score: Current score for the member in the leaderboard. score: Member score. member_data: Optional member data. leaderboard_options: Leaderboard options, e.g. 'reverse': Value of reverse option @param leaderboard_name [String] Name of the leaderboard. @param rank_conditional [function] Function which must return +True+ or +False+ that controls whether or not the member is ranked in the leaderboard. @param member [String] Member name. @param score [float] Member score. @param member_data [String] Optional member_data. ''' current_score = self.redis_connection.zscore(leaderboard_name, member) if current_score is not None: current_score = float(current_score) if rank_conditional(self, member, current_score, score, member_data, {'reverse': self.order}): self.rank_member_in(leaderboard_name, member, score, member_data) def rank_members(self, members_and_scores): ''' Rank an array of members in the leaderboard. @param members_and_scores [Array] Variable list of members and scores. ''' self.rank_members_in(self.leaderboard_name, members_and_scores) def rank_members_in(self, leaderboard_name, members_and_scores): ''' Rank an array of members in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param members_and_scores [Array] Variable list of members and scores. ''' pipeline = self.redis_connection.pipeline() for member, score in grouper(2, members_and_scores): if isinstance(self.redis_connection, Redis): pipeline.zadd(leaderboard_name, member, score) else: pipeline.zadd(leaderboard_name, score, member) pipeline.execute() def member_data_for(self, member): ''' Retrieve the optional member data for a given member in the leaderboard. @param member [String] Member name. @return String of optional member data. ''' return self.member_data_for_in(self.leaderboard_name, member) def member_data_for_in(self, leaderboard_name, member): ''' Retrieve the optional member data for a given member in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @return String of optional member data. ''' return self.redis_connection.hget( self._member_data_key(leaderboard_name), member) def members_data_for(self, members): ''' Retrieve the optional member data for a given list of members in the leaderboard. @param members [Array] Member names. @return Array of strings of optional member data. ''' return self.members_data_for_in(self.leaderboard_name, members) def members_data_for_in(self, leaderboard_name, members): ''' Retrieve the optional member data for a given list of members in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param members [Array] Member names. @return Array of strings of optional member data. ''' return self.redis_connection.hmget( self._member_data_key(leaderboard_name), members) def update_member_data(self, member, member_data): ''' Update the optional member data for a given member in the leaderboard. @param member [String] Member name. @param member_data [String] Optional member data. ''' self.update_member_data_in(self.leaderboard_name, member, member_data) def update_member_data_in(self, leaderboard_name, member, member_data): ''' Update the optional member data for a given member in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @param member_data [String] Optional member data. ''' self.redis_connection.hset(self._member_data_key(leaderboard_name), member, member_data) def remove_member_data(self, member): ''' Remove the optional member data for a given member in the leaderboard. @param member [String] Member name. ''' self.remove_member_data_in(self.leaderboard_name, member) def remove_member_data_in(self, leaderboard_name, member): ''' Remove the optional member data for a given member in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. ''' self.redis_connection.hdel(self._member_data_key(leaderboard_name), member) def total_members(self): ''' Retrieve the total number of members in the leaderboard. @return total number of members in the leaderboard. ''' return self.total_members_in(self.leaderboard_name) def total_members_in(self, leaderboard_name): ''' Retrieve the total number of members in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @return the total number of members in the named leaderboard. ''' return self.redis_connection.zcard(leaderboard_name) def remove_member(self, member): ''' Remove a member from the leaderboard. @param member [String] Member name. ''' self.remove_member_from(self.leaderboard_name, member) def remove_member_from(self, leaderboard_name, member): ''' Remove the optional member data for a given member in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. ''' pipeline = self.redis_connection.pipeline() pipeline.zrem(leaderboard_name, member) pipeline.hdel(self._member_data_key(leaderboard_name), member) pipeline.execute() def total_pages(self, page_size=None): ''' Retrieve the total number of pages in the leaderboard. @param page_size [int, nil] Page size to be used when calculating the total number of pages. @return the total number of pages in the leaderboard. ''' return self.total_pages_in(self.leaderboard_name, page_size) def total_pages_in(self, leaderboard_name, page_size=None): ''' Retrieve the total number of pages in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param page_size [int, nil] Page size to be used when calculating the total number of pages. @return the total number of pages in the named leaderboard. ''' if page_size is None: page_size = self.page_size return int( math.ceil( self.total_members_in(leaderboard_name) / float(page_size))) def total_members_in_score_range(self, min_score, max_score): ''' Retrieve the total members in a given score range from the leaderboard. @param min_score [float] Minimum score. @param max_score [float] Maximum score. @return the total members in a given score range from the leaderboard. ''' return self.total_members_in_score_range_in(self.leaderboard_name, min_score, max_score) def total_members_in_score_range_in(self, leaderboard_name, min_score, max_score): ''' Retrieve the total members in a given score range from the named leaderboard. @param leaderboard_name Name of the leaderboard. @param min_score [float] Minimum score. @param max_score [float] Maximum score. @return the total members in a given score range from the named leaderboard. ''' return self.redis_connection.zcount(leaderboard_name, min_score, max_score) def total_scores(self): ''' Sum of scores for all members in the leaderboard. @return Sum of scores for all members in the leaderboard. ''' return self.total_scores_in(self.leaderboard_name) def total_scores_in(self, leaderboard_name): ''' Sum of scores for all members in the named leaderboard. @param leaderboard_name Name of the leaderboard. @return Sum of scores for all members in the named leaderboard. ''' return sum([ leader[self.SCORE_KEY] for leader in self.all_leaders_from(self.leaderboard_name) ]) def check_member(self, member): ''' Check to see if a member exists in the leaderboard. @param member [String] Member name. @return +true+ if the member exists in the leaderboard, +false+ otherwise. ''' return self.check_member_in(self.leaderboard_name, member) def check_member_in(self, leaderboard_name, member): ''' Check to see if a member exists in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @return +true+ if the member exists in the named leaderboard, +false+ otherwise. ''' return self.redis_connection.zscore(leaderboard_name, member) is not None def rank_for(self, member): ''' Retrieve the rank for a member in the leaderboard. @param member [String] Member name. @return the rank for a member in the leaderboard. ''' return self.rank_for_in(self.leaderboard_name, member) def rank_for_in(self, leaderboard_name, member): ''' Retrieve the rank for a member in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @return the rank for a member in the leaderboard. ''' if self.order == self.ASC: try: return self.redis_connection.zrank(leaderboard_name, member) + 1 except: return None else: try: return self.redis_connection.zrevrank(leaderboard_name, member) + 1 except: return None def score_for(self, member): ''' Retrieve the score for a member in the leaderboard. @param member Member name. @return the score for a member in the leaderboard or +None+ if the member is not in the leaderboard. ''' return self.score_for_in(self.leaderboard_name, member) def score_for_in(self, leaderboard_name, member): ''' Retrieve the score for a member in the named leaderboard. @param leaderboard_name Name of the leaderboard. @param member [String] Member name. @return the score for a member in the leaderboard or +None+ if the member is not in the leaderboard. ''' score = self.redis_connection.zscore(leaderboard_name, member) if score is not None: score = float(score) return score def score_and_rank_for(self, member): ''' Retrieve the score and rank for a member in the leaderboard. @param member [String] Member name. @return the score and rank for a member in the leaderboard as a Hash. ''' return self.score_and_rank_for_in(self.leaderboard_name, member) def score_and_rank_for_in(self, leaderboard_name, member): ''' Retrieve the score and rank for a member in the named leaderboard. @param leaderboard_name [String]Name of the leaderboard. @param member [String] Member name. @return the score and rank for a member in the named leaderboard as a Hash. ''' return { self.MEMBER_KEY: member, self.SCORE_KEY: self.score_for_in(leaderboard_name, member), self.RANK_KEY: self.rank_for_in(leaderboard_name, member) } def change_score_for(self, member, delta, member_data=None): ''' Change the score for a member in the leaderboard by a score delta which can be positive or negative. @param member [String] Member name. @param delta [float] Score change. @param member_data [String] Optional member data. ''' self.change_score_for_member_in(self.leaderboard_name, member, delta, member_data) def change_score_for_member_in(self, leaderboard_name, member, delta, member_data=None): ''' Change the score for a member in the named leaderboard by a delta which can be positive or negative. @param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @param delta [float] Score change. @param member_data [String] Optional member data. ''' pipeline = self.redis_connection.pipeline() pipeline.zincrby(leaderboard_name, member, delta) if member_data: pipeline.hset(self._member_data_key(leaderboard_name), member, member_data) pipeline.execute() def remove_members_in_score_range(self, min_score, max_score): ''' Remove members from the leaderboard in a given score range. @param min_score [float] Minimum score. @param max_score [float] Maximum score. ''' self.remove_members_in_score_range_in(self.leaderboard_name, min_score, max_score) def remove_members_in_score_range_in(self, leaderboard_name, min_score, max_score): ''' Remove members from the named leaderboard in a given score range. @param leaderboard_name [String] Name of the leaderboard. @param min_score [float] Minimum score. @param max_score [float] Maximum score. ''' self.redis_connection.zremrangebyscore(leaderboard_name, min_score, max_score) def remove_members_outside_rank(self, rank): ''' Remove members from the leaderboard in a given rank range. @param rank [int] the rank (inclusive) which we should keep. @return the total member count which was removed. ''' return self.remove_members_outside_rank_in(self.leaderboard_name, rank) def remove_members_outside_rank_in(self, leaderboard_name, rank): ''' Remove members from the named leaderboard in a given rank range. @param leaderboard_name [String] Name of the leaderboard. @param rank [int] the rank (inclusive) which we should keep. @return the total member count which was removed. ''' if self.order == self.DESC: rank = -(rank) - 1 return self.redis_connection.zremrangebyrank( leaderboard_name, 0, rank) else: return self.redis_connection.zremrangebyrank( leaderboard_name, rank, -1) def page_for(self, member, page_size=DEFAULT_PAGE_SIZE): ''' Determine the page where a member falls in the leaderboard. @param member [String] Member name. @param page_size [int] Page size to be used in determining page location. @return the page where a member falls in the leaderboard. ''' return self.page_for_in(self.leaderboard_name, member, page_size) def page_for_in(self, leaderboard_name, member, page_size=DEFAULT_PAGE_SIZE): ''' Determine the page where a member falls in the named leaderboard. @param leaderboard [String] Name of the leaderboard. @param member [String] Member name. @param page_size [int] Page size to be used in determining page location. @return the page where a member falls in the leaderboard. ''' rank_for_member = None if self.order == self.ASC: rank_for_member = self.redis_connection.zrank( leaderboard_name, member) else: rank_for_member = self.redis_connection.zrevrank( leaderboard_name, member) if rank_for_member is None: rank_for_member = 0 else: rank_for_member += 1 return int(math.ceil(float(rank_for_member) / float(page_size))) def percentile_for(self, member): ''' Retrieve the percentile for a member in the leaderboard. @param member [String] Member name. @return the percentile for a member in the leaderboard. Return +nil+ for a non-existent member. ''' return self.percentile_for_in(self.leaderboard_name, member) def percentile_for_in(self, leaderboard_name, member): ''' Retrieve the percentile for a member in the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @return the percentile for a member in the named leaderboard. ''' if not self.check_member_in(leaderboard_name, member): return None responses = self.redis_connection.pipeline().zcard( leaderboard_name).zrevrank(leaderboard_name, member).execute() percentile = math.ceil((float( (responses[0] - responses[1] - 1)) / float(responses[0]) * 100)) if self.order == self.ASC: return 100 - percentile else: return percentile def score_for_percentile(self, percentile): ''' Calculate the score for a given percentile value in the leaderboard. @param percentile [float] Percentile value (0.0 to 100.0 inclusive). @return the score corresponding to the percentile argument. Return +None+ for arguments outside 0-100 inclusive and for leaderboards with no members. ''' return self.score_for_percentile_in(self.leaderboard_name, percentile) def score_for_percentile_in(self, leaderboard_name, percentile): ''' Calculate the score for a given percentile value in the leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param percentile [float] Percentile value (0.0 to 100.0 inclusive). @return the score corresponding to the percentile argument. Return +None+ for arguments outside 0-100 inclusive and for leaderboards with no members. ''' if not 0 <= percentile <= 100: return None total_members = self.total_members_in(leaderboard_name) if total_members < 1: return None if self.order == self.ASC: percentile = 100 - percentile index = (total_members - 1) * (percentile / 100.0) scores = [ pair[1] for pair in self.redis_connection.zrange(leaderboard_name, int(math.floor(index)), int(math.ceil(index)), withscores=True) ] if index == math.floor(index): return scores[0] else: interpolate_fraction = index - math.floor(index) return scores[0] + interpolate_fraction * (scores[1] - scores[0]) def expire_leaderboard(self, seconds): ''' Expire the current leaderboard in a set number of seconds. Do not use this with leaderboards that utilize member data as there is no facility to cascade the expiration out to the keys for the member data. @param seconds [int] Number of seconds after which the leaderboard will be expired. ''' self.expire_leaderboard_for(self.leaderboard_name, seconds) def expire_leaderboard_for(self, leaderboard_name, seconds): ''' Expire the given leaderboard in a set number of seconds. Do not use this with leaderboards that utilize member data as there is no facility to cascade the expiration out to the keys for the member data. @param leaderboard_name [String] Name of the leaderboard. @param seconds [int] Number of seconds after which the leaderboard will be expired. ''' pipeline = self.redis_connection.pipeline() pipeline.expire(leaderboard_name, seconds) pipeline.expire(self._member_data_key(leaderboard_name), seconds) pipeline.execute() def expire_leaderboard_at(self, timestamp): ''' Expire the current leaderboard at a specific UNIX timestamp. Do not use this with leaderboards that utilize member data as there is no facility to cascade the expiration out to the keys for the member data. @param timestamp [int] UNIX timestamp at which the leaderboard will be expired. ''' self.expire_leaderboard_at_for(self.leaderboard_name, timestamp) def expire_leaderboard_at_for(self, leaderboard_name, timestamp): ''' Expire the given leaderboard at a specific UNIX timestamp. Do not use this with leaderboards that utilize member data as there is no facility to cascade the expiration out to the keys for the member data. @param leaderboard_name [String] Name of the leaderboard. @param timestamp [int] UNIX timestamp at which the leaderboard will be expired. ''' pipeline = self.redis_connection.pipeline() pipeline.expireat(leaderboard_name, timestamp) pipeline.expireat(self._member_data_key(leaderboard_name), timestamp) pipeline.execute() def leaders(self, current_page, **options): ''' Retrieve a page of leaders from the leaderboard. @param current_page [int] Page to retrieve from the leaderboard. @param options [Hash] Options to be used when retrieving the page from the leaderboard. @return a page of leaders from the leaderboard. ''' return self.leaders_in(self.leaderboard_name, current_page, **options) def leaders_in(self, leaderboard_name, current_page, **options): ''' Retrieve a page of leaders from the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param current_page [int] Page to retrieve from the named leaderboard. @param options [Hash] Options to be used when retrieving the page from the named leaderboard. @return a page of leaders from the named leaderboard. ''' if current_page < 1: current_page = 1 page_size = options.get('page_size', self.page_size) index_for_redis = current_page - 1 starting_offset = (index_for_redis * page_size) if starting_offset < 0: starting_offset = 0 ending_offset = (starting_offset + page_size) - 1 raw_leader_data = self._range_method(self.redis_connection, leaderboard_name, int(starting_offset), int(ending_offset), withscores=False) return self._parse_raw_members(leaderboard_name, raw_leader_data, **options) def all_leaders(self, **options): ''' Retrieve all leaders from the leaderboard. @param options [Hash] Options to be used when retrieving the leaders from the leaderboard. @return the leaders from the leaderboard. ''' return self.all_leaders_from(self.leaderboard_name, **options) def all_leaders_from(self, leaderboard_name, **options): ''' Retrieves all leaders from the named leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param options [Hash] Options to be used when retrieving the leaders from the named leaderboard. @return the named leaderboard. ''' raw_leader_data = self._range_method(self.redis_connection, leaderboard_name, 0, -1, withscores=False) return self._parse_raw_members(leaderboard_name, raw_leader_data, **options) def members_from_score_range(self, minimum_score, maximum_score, **options): ''' Retrieve members from the leaderboard within a given score range. @param minimum_score [float] Minimum score (inclusive). @param maximum_score [float] Maximum score (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard. @return members from the leaderboard that fall within the given score range. ''' return self.members_from_score_range_in(self.leaderboard_name, minimum_score, maximum_score, **options) def members_from_score_range_in(self, leaderboard_name, minimum_score, maximum_score, **options): ''' Retrieve members from the named leaderboard within a given score range. @param leaderboard_name [String] Name of the leaderboard. @param minimum_score [float] Minimum score (inclusive). @param maximum_score [float] Maximum score (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard. @return members from the leaderboard that fall within the given score range. ''' raw_leader_data = [] if self.order == self.DESC: raw_leader_data = self.redis_connection.zrevrangebyscore( leaderboard_name, maximum_score, minimum_score) else: raw_leader_data = self.redis_connection.zrangebyscore( leaderboard_name, minimum_score, maximum_score) return self._parse_raw_members(leaderboard_name, raw_leader_data, **options) def members_from_rank_range(self, starting_rank, ending_rank, **options): ''' Retrieve members from the leaderboard within a given rank range. @param starting_rank [int] Starting rank (inclusive). @param ending_rank [int] Ending rank (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard. @return members from the leaderboard that fall within the given rank range. ''' return self.members_from_rank_range_in(self.leaderboard_name, starting_rank, ending_rank, **options) def members_from_rank_range_in(self, leaderboard_name, starting_rank, ending_rank, **options): ''' Retrieve members from the named leaderboard within a given rank range. @param leaderboard_name [String] Name of the leaderboard. @param starting_rank [int] Starting rank (inclusive). @param ending_rank [int] Ending rank (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard. @return members from the leaderboard that fall within the given rank range. ''' starting_rank -= 1 if starting_rank < 0: starting_rank = 0 ending_rank -= 1 if ending_rank > self.total_members_in(leaderboard_name): ending_rank = self.total_members_in(leaderboard_name) - 1 raw_leader_data = [] if self.order == self.DESC: raw_leader_data = self.redis_connection.zrevrange(leaderboard_name, starting_rank, ending_rank, withscores=False) else: raw_leader_data = self.redis_connection.zrange(leaderboard_name, starting_rank, ending_rank, withscores=False) return self._parse_raw_members(leaderboard_name, raw_leader_data, **options) def top(self, number, **options): ''' Retrieve members from the leaderboard within a range from 1 to the number given. @param ending_rank [int] Ending rank (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard. @return number from the leaderboard that fall within the given rank range. ''' return self.top_in(self.leaderboard_name, number, **options) def top_in(self, leaderboard_name, number, **options): ''' Retrieve members from the named leaderboard within a range from 1 to the number given. @param leaderboard_name [String] Name of the leaderboard. @param starting_rank [int] Starting rank (inclusive). @param ending_rank [int] Ending rank (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard. @return members from the leaderboard that fall within the given rank range. ''' return self.members_from_rank_range_in(leaderboard_name, 1, number, **options) def member_at(self, position, **options): ''' Retrieve a member at the specified index from the leaderboard. @param position [int] Position in leaderboard. @param options [Hash] Options to be used when retrieving the member from the leaderboard. @return a member from the leaderboard. ''' return self.member_at_in(self.leaderboard_name, position, **options) def member_at_in(self, leaderboard_name, position, **options): ''' Retrieve a member at the specified index from the leaderboard. @param leaderboard_name [String] Name of the leaderboard. @param position [int] Position in named leaderboard. @param options [Hash] Options to be used when retrieving the member from the named leaderboard. @return a page of leaders from the named leaderboard. ''' if position > 0 and position <= self.total_members_in( leaderboard_name): page_size = options.get('page_size', self.page_size) current_page = math.ceil(float(position) / float(page_size)) offset = (position - 1) % page_size leaders = self.leaders_in(leaderboard_name, current_page, **options) if leaders: return leaders[offset] def around_me(self, member, **options): ''' Retrieve a page of leaders from the leaderboard around a given member. @param member [String] Member name. @param options [Hash] Options to be used when retrieving the page from the leaderboard. @return a page of leaders from the leaderboard around a given member. ''' return self.around_me_in(self.leaderboard_name, member, **options) def around_me_in(self, leaderboard_name, member, **options): ''' Retrieve a page of leaders from the named leaderboard around a given member. @param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @param options [Hash] Options to be used when retrieving the page from the named leaderboard. @return a page of leaders from the named leaderboard around a given member. Returns an empty array for a non-existent member. ''' reverse_rank_for_member = None if self.order == self.DESC: reverse_rank_for_member = self.redis_connection.zrevrank( leaderboard_name, member) else: reverse_rank_for_member = self.redis_connection.zrank( leaderboard_name, member) if reverse_rank_for_member is None: return [] page_size = options.get('page_size', self.page_size) starting_offset = reverse_rank_for_member - (page_size // 2) if starting_offset < 0: starting_offset = 0 ending_offset = (starting_offset + page_size) - 1 raw_leader_data = self._range_method(self.redis_connection, leaderboard_name, int(starting_offset), int(ending_offset), withscores=False) return self._parse_raw_members(leaderboard_name, raw_leader_data, **options) def ranked_in_list(self, members, **options): ''' Retrieve a page of leaders from the leaderboard for a given list of members. @param members [Array] Member names. @param options [Hash] Options to be used when retrieving the page from the leaderboard. @return a page of leaders from the leaderboard for a given list of members. ''' return self.ranked_in_list_in(self.leaderboard_name, members, **options) def ranked_in_list_in(self, leaderboard_name, members, **options): ''' Retrieve a page of leaders from the named leaderboard for a given list of members. @param leaderboard_name [String] Name of the leaderboard. @param members [Array] Member names. @param options [Hash] Options to be used when retrieving the page from the named leaderboard. @return a page of leaders from the named leaderboard for a given list of members. ''' ranks_for_members = [] pipeline = self.redis_connection.pipeline() for member in members: if self.order == self.ASC: pipeline.zrank(leaderboard_name, member) else: pipeline.zrevrank(leaderboard_name, member) pipeline.zscore(leaderboard_name, member) responses = pipeline.execute() for index, member in enumerate(members): data = {} data[self.MEMBER_KEY] = member rank = responses[index * 2] if rank is not None: rank += 1 else: if not options.get('include_missing', True): continue data[self.RANK_KEY] = rank score = responses[index * 2 + 1] if score is not None: score = float(score) data[self.SCORE_KEY] = score ranks_for_members.append(data) if ('with_member_data' in options) and (True == options['with_member_data']): for index, member_data in enumerate( self.members_data_for_in(leaderboard_name, members)): try: ranks_for_members[index][ self.MEMBER_DATA_KEY] = member_data except: pass if 'sort_by' in options: if self.RANK_KEY == options['sort_by']: ranks_for_members = sorted( ranks_for_members, key=lambda member: member[self.RANK_KEY]) elif self.SCORE_KEY == options['sort_by']: ranks_for_members = sorted( ranks_for_members, key=lambda member: member[self.SCORE_KEY]) return ranks_for_members def merge_leaderboards(self, destination, keys, aggregate='SUM'): ''' Merge leaderboards given by keys with this leaderboard into a named destination leaderboard. @param destination [String] Destination leaderboard name. @param keys [Array] Leaderboards to be merged with the current leaderboard. @param options [Hash] Options for merging the leaderboards. ''' keys.insert(0, self.leaderboard_name) self.redis_connection.zunionstore(destination, keys, aggregate) def intersect_leaderboards(self, destination, keys, aggregate='SUM'): ''' Intersect leaderboards given by keys with this leaderboard into a named destination leaderboard. @param destination [String] Destination leaderboard name. @param keys [Array] Leaderboards to be merged with the current leaderboard. @param options [Hash] Options for intersecting the leaderboards. ''' keys.insert(0, self.leaderboard_name) self.redis_connection.zinterstore(destination, keys, aggregate) def _range_method(self, connection, *args, **kwargs): if self.order == self.DESC: return connection.zrevrange(*args, **kwargs) else: return connection.zrange(*args, **kwargs) def _member_data_key(self, leaderboard_name): ''' Key for retrieving optional member data. @param leaderboard_name [String] Name of the leaderboard. @return a key in the form of +leaderboard_name:member_data+ ''' if self.global_member_data is False: return '%s:%s' % (leaderboard_name, self.member_data_namespace) else: return self.member_data_namespace def _parse_raw_members(self, leaderboard_name, members, members_only=False, **options): ''' Parse the raw leaders data as returned from a given leader board query. Do associative lookups with the member to rank, score and potentially sort the results. @param leaderboard_name [String] Name of the leaderboard. @param members [List] A list of members as returned from a sorted set range query @param members_only [bool] Set True to return the members as is, Default is False. @param options [Hash] Options to be used when retrieving the page from the named leaderboard. @return a list of members. ''' if members_only: return [{self.MEMBER_KEY: m} for m in members] if members: return self.ranked_in_list_in(leaderboard_name, members, **options) else: return []
#!/usr/bin/python3 # coding=utf-8 from rediscluster import StrictRedisCluster value = "<!--StartFragment--><p style=\"color:#333333;font-family:宋体;font-size:16px;background-color:#CCE8CF;text-align:center;\"><div id=\"barrierfree_container\"><div class=\"lanmu-main\"><div class=\"wenzhang\"><div class=\"zhengwen\"><div style=\"margin:0px auto;\"><div><table id=\"c\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" width=\"100%\" align=\"center\" class=\"ke-zeroborder\"><tbody><tr><td class=\"bt_content\" colspan=\"2\"><div style=\"font-size:15px;\" id=\"zoom\"><!--StartFragment--><p style=\"text-indent:43px;\"><span style=\"font-family:黑体;font-size:24px;\">一、<span style=\"font-family:楷体;\">党的建设持续优化</span></span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">一是思想建设不断强化</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">始终坚持正确政治方向,把坚持学习贯彻习近平新时代中国特色社会主义思想和党的十九大精神作为首要政治任务。</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">充分利用</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">主题党日</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">、“三会一课”、远程教育等传统形式,</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">运用</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">“学习强国”平台、</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">“回山视野”微信公众号、党建微信群等新型载体,深入推进“两学一做”学习教育常态化制度化</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">,组织召开党建工作专题会议3次,召开党支部书记例会2次,组织党员干部培训2次,开展集中座谈会3次,教育党员干部900余人次</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">,</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">全面提升镇村党员干部理论素养、服务意识及工作能力</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">,</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">切实增强</span>“<span style=\"font-family:仿宋_GB2312;\">四个自信</span>”<span style=\"font-family:仿宋_GB2312;\">。</span></span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">二是基层建设</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">融合</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">提升。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">迅速抓好乡镇合并各项工作,顺利完成镇人大代表换届工作,选举产生新一届镇人大代表61名。按期召开新一届镇人大代表会议,高票选出新的回山镇人大、政府领导班子</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">;</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">根据“三定方案”,优化整合设立“八办一中心”内设机构,各办岗位职责、领导干部人员分工得到明确,中层正职、副职机关干部已合理安排,工作人员办公室、宿舍已全部落实</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">;</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">扎实推进五星系列创建,彩建控股开展“五星双强”,</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">新天、</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">上市场等13个村开展“五星三A”创建</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">,推动“富裕、美丽、和谐、文明”协同发展</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">;</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">推进</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">8个</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">村级组织活动场所规范建设,其中</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">欧潭、新市场、袁家党群服务中心已开始动工建设,新天村已完成招投标建设,正在放样中</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">。</span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">三是作风建设</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">持续加强</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">。</span></strong><span style=\"font-family:仿宋;font-size:21px;\">以深化“三服务”为契机,把作风建设作为工作重点,</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">不断提升党员素质,</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">充分</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">发挥</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">党员在土地开发、垃圾分类等中心工作中</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">的</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">先锋引领作用。</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">全镇党组织</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">有效</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">发挥“回山红”党员志愿服务品牌作用,在疫情防控工作中,</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">做到</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">守小门、强防控、广宣传。进一步严明政治纪律,开展督查检查3次,对32个行政村的工作作风进行抽查,有效杜绝不作为、慢作为现象的发生。</span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">四是清廉建设深入推进。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">以红色党建为引领,积极推进清廉村居建设,2020年将着力把荷塘村、高湾村、雅里村、大安村和上贝村建设成清廉村居,新天村打造为清廉村居样板村。着重打造“红色回山 清风彩烟”廉政教育品牌,深入挖掘“清白家风”,学习回山本土清官、好官优秀特质,弘扬公正、和善、廉洁、担当等精神。以回山村“浙东西柏坡”、新天村“好官第一”、上下宅村“彩烟之廉”和大安村“民风淳朴”等清廉文化建设为重点,打造回山清风廉旅路线。</span></p><p style=\"text-indent:43px;\"><span style=\"font-family:楷体;font-size:24px;\">二、农村经济稳定发展</span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">一是特色农业持续向好。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">制定“回山镇农业强镇三年规划”,为系统打造回山高山农特产品交易市场、建立果蔬冷链配送体系,大力发展健康农业产业,把好发展方向;</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">新建茶叶市场,回山片新茶叶交易市场已完成建设,即将投入使用;以良好生态环境为基础,以打造健康农业基地为支撑,培育扶持官塘村无公害茭白基地建设;</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">红联、官元高标准农田项目已开始动工,涉及土地</span>1500<span style=\"font-family:仿宋_GB2312;\">亩</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">;</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">成功引进网易味央回山田园综合体项目,计划投资5亿元,涉及土地2000余亩,目前核心区块200亩的土地政策处理已完成85%</span><span style=\"font-family:Calibri;font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">。</span></span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">二是旅游</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">业态不断发展</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">2019年回山镇乡村旅游项目已竣工并完成现场初验,等待最终验收。2020年回山镇乡村旅游精品村项目涉及回山和上下宅2个村,已完成设计并通过设计评审,目前正在预算中。A级景区村项目涉及双溪、新市场2个村,AA级景区村项目涉及新天村,正在有序推进;2020年上半年新增民宿(溪客)1家,目前共有8家民宿投入经营,共计138个房间,268个床位。上半年接待游客8000余人次,民宿农家乐接待过夜游客人数800人次,旅游经营总收入达到184万元,其中住宿收入15万元,餐饮收入32万元,产品销售收入137万元;吸引9家企业现场踏看旅游项目,正在积极对接。</span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">三是土地开发加速攻坚</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">克服任务重、压力大、政策处理涉及量大面广等不利因素,早谋划、抓速度、拼进度,</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">全力攻坚</span></span><span style=\"font-family:Calibri;font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">土地开发、</span></span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">旱改水、土地复垦等工作</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">。</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">今年以来,</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">全镇已完成土地开发任务170亩,正在施工项目<span style=\"font-family:Times New Roman;\">2</span>个,土地面积<span style=\"font-family:Times New Roman;\">169</span>亩,已招标项目<span style=\"font-family:Times New Roman;\">4</span>个,涉及土地<span style=\"font-family:Times New Roman;\">315.7</span>亩,已立项<span style=\"font-family:Times New Roman;\">3</span>个,涉及土地<span style=\"font-family:Times New Roman;\">94.8</span>亩</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">;</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">完成回山镇雅里村等3村农村土地综合整治先行复垦项目的评审,共立项<span style=\"font-family:Times New Roman;\">8</span>亩。</span></p><p style=\"text-indent:43px;\"><span style=\"font-family:楷体;font-size:24px;\">三、项目建设加速推进</span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">一是交通</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">路网持续完善</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">杭绍台高速稳步推进,预计年底通车。杭绍台高铁、太下线基本完成政策处理工作。双溪口至新市场公路接点改造工程,路基已完成40%。官元至下山、雅里至渡河、后坂至下塘、下王畈至侯家等公路提升改造工程已全部开工。</span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">二是城镇建设有序开展。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">通过新建农贸市场招商,建成2000平方米农贸市场,引进规模1000平方米的大型超市,不断提升群众生活品质;</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">加快农村饮用水安全建设,完成西丁、官元等3个村饮用水改质提升工程,新市场和毛畈两座自来水厂建设进度达<span style=\"font-family:Times New Roman;\">60%</span>,完善大安、上贝等<span style=\"font-family:Times New Roman;\">13</span>个行政村管网建设,巩固提升<span style=\"font-family:Times New Roman;\">1.4</span>万农村人口供水保障水平。</span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">三是人居环境</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">不断改善</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">结合石碇水库、新市场后门山山塘等重点水利整治工程,加强淤泥源头管控,大力推进生态河网美化工程,目前已完成王家市山塘整治工程,完成蟠溪江、林里畈水库、后勤坂水库等排水沟、挡墙修复工程,完成养猪场污水纳管提升改造工程3个,新建沼气池<span style=\"font-family:Calibri;\">1</span>座</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">;美丽庭院创建任务数为924户,截止<span style=\"font-family:Calibri;\">5</span>月份,已创建成功<span style=\"font-family:Calibri;\">442</span>户,完成率为<span style=\"font-family:Calibri;\">47.8%</span>;</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">落实“一分二清三化”工作,抓好上贝、红联等<span style=\"font-family:Calibri;\">5</span>个垃圾分类准确村工作,启动旧里、官塘地埋式厌氧设备项目建设,邀请专家开展业务培训,指定第三方机构每月检查排名考核,确保农村人居环境切实提升。</span></p><p style=\"text-indent:43px;\"><span style=\"font-family:楷体;font-size:24px;\">四、以民生改善为重点,社会事业创造新业绩</span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">一是</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">疫情防控严格落实</span></strong><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">加强疫情重点地区人员排查与管控,摸排出武汉人员30人,湖北人员<span style=\"font-family:Calibri;\">70</span>人,重点地区<span style=\"font-family:Calibri;\">99</span>人,境外人员<span style=\"font-family:Calibri;\">159</span>人,设立备用隔离点<span style=\"font-family:Calibri;\">2</span>个,居家隔离<span style=\"font-family:Calibri;\">120</span>人,强制集中隔离<span style=\"font-family:Calibri;\">37</span>人,目前已全部解除隔离;全力落实人员进出管控,设立天台、磐安入新监测点<span style=\"font-family:Calibri;\">3</span>个,设立村级卡口<span style=\"font-family:Calibri;\">132</span>处。强化集聚场所管控,镇村二级联动,着力督查农贸市场经营情况,全面关闭域内文化礼堂、家宴中心、餐饮经营等集聚场所,取消集聚活动<span style=\"font-family:Calibri;\">9</span>场<span style=\"font-family:Calibri;\">140</span>桌<span style=\"font-family:Calibri;\">1390</span>人;推进复工复产,开展全程跟踪指导服务,督促企业严格落实复工疫情防控工作要求,指导企业做好防疫物资准备、员工健康监测、重点场所消杀、安全生产管理等工作,履行好主体责任。实时反馈发现的问题<span style=\"font-family:Calibri;\">28</span>个,针对性提出改进意见<span style=\"font-family:Calibri;\">37</span>条,把安全生产管理措施落到实处;线上通过“回山视野”微信公众号发布疫情推文<span style=\"font-family:Calibri;\">25</span>期,线下巧用移动小喇叭、广播、宣传车、红色大字报等方式高频次宣传,及时、准确传达疫情信息和防护知识,不断增强村民防疫意识,营造浓厚抗疫氛围。</span></p><p style=\"background-color:#FFFFFF;text-indent:32px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">二是民生事业协调发展。</span></strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">特开设回山-双彩环线镇级公交线路,促进群众出行、交流;生态公墓正在有序推进,目前涉及项目<span style=\"font-family:Calibri;\">3</span>个,其中已完场招标<span style=\"font-family:Calibri;\">1</span>个,即将施工,完成预算<span style=\"font-family:Calibri;\">1</span>个,完成设计<span style=\"font-family:Calibri;\">1</span>个;农村文化礼堂建设涉及樟花、西丁、上下西岭等<span style=\"font-family:Calibri;\">3</span>个村,樟花已基本完成建设,西</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">丁、上下西岭已完成设计初稿。</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">民</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">政救助体系不断完善,完成全镇低保户</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">656</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">户</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">、低保</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">边缘户年检工作</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">,</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">足额发放低保补助金、医疗补助款和救济救灾款;</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">加快3个农村家宴服务中心</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">项目</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">建设,已基本完成</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">项目1个</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">,等待验收</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">;去现金化目前已完成村务卡办理19村,剩余<span style=\"font-family:Times New Roman;\">13</span>个村村务卡银行正在办理中,<span style=\"font-family:Times New Roman;\">32</span>个村收款码已全部制作完成。</span></p><p style=\"text-indent:43px;\"><strong><span style=\"font-family:仿宋_GB2312;font-size:21px;\">三是平安建设全面加强。</span></strong><span style=\"font-family:'Times New Roman';font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">全力化解信访</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">重点督查</span><span style=\"font-family:'Times New Roman';font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">案件,成功化解</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">市级重点督查</span><span style=\"font-family:'Times New Roman';font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">案件</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">5</span><span style=\"font-family:'Times New Roman';font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">件中的</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">2</span><span style=\"font-family:'Times New Roman';font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">件,化解</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">县级</span><span style=\"font-family:'Times New Roman';font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">重点督察案件</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">7</span><span style=\"font-family:'Times New Roman';font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">中的</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">5</span><span style=\"font-family:'Times New Roman';font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">件;</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">推进品牌调解室建设,配备</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">“老娘舅”专职调解员2名,调解工作已正常开展;大力</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">开展扫黑除恶、消防、禁毒、防电信诈骗等平安</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">行动</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">,发放</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">宣传</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">资料</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">2000</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">0</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">余份</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">,</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">组织培训3次,开展安全隐患排查<span style=\"font-family:Times New Roman;\">4</span>次,整改隐患<span style=\"font-family:Times New Roman;\">35</span>处</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">;</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">优化调整网格设置,</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">加强网格员管理,网格长、专职网格员、兼职网格员、网格指导员“一长三员”配备率</span><span style=\"font-family:Calibri;font-size:21px;\">100%</span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">,</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">设置</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">村</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">级网格</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">60</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">个、专职网格员</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">60</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">人、网格员</span></span><span style=\"font-family:仿宋_GB2312;font-size:21px;\">180</span><span style=\"font-family:"font-size:21px;\"><span style=\"font-family:仿宋_GB2312;\">人。</span></span></p><!--EndFragment--></div></td></tr></tbody></table></div></div></div></div></div></div>http://www.zjxc.gov.cn/art/2020/7/27/art_1396905_53090595.html</p><!--EndFragment-->" redis_basis_conn = [{ 'host': '172.16.0.23', 'port': 7000 }, { 'host': '172.16.0.23', 'port': 7001 }, { 'host': '172.16.0.23', 'port': 7002 }, { 'host': '172.16.0.23', 'port': 7003 }, { 'host': '172.16.0.23', 'port': 7004 }, { 'host': '172.16.0.23', 'port': 7005 }] redisconn = StrictRedisCluster(startup_nodes=redis_basis_conn, password='') redisconn.hset("jgbtest", "111", value)
class Session(object): _uui = None _max_retry = 5 _retry_num = 0 def __init__(self, **options): self.options = { 'key_prefix': 'session', 'expire': 7200, } self.options.update(options) self.logger = Logger('session').get() self.connect() def connect(self): def func(): self.redis = StrictRedisCluster( startup_nodes=self.options['startup_nodes']) self._safe_way(func) def get(self, uui): self.logger.debug('Try to get session') def _get(): return self._get_session(uui) return self._safe_way(_get) def set(self, uui): self.logger.debug('Try to set new session: ' 'uuid {name}'.format(name=uui)) self._uui = uui def _set(): self._set_session(uui, str(datetime.datetime.now().time())) self._safe_way(_set) def _safe_way(self, func): try: return func() except: if self._max_retry == self._retry_num: self.logger.debug('Max try to reconnect. Closed') tornado.ioloop.IOLoop.instance().stop() else: self._retry_num += 1 self.logger.debug('Fail to connect.' 'Try to reconnect after 6 sec') time.sleep(6) self.connect() return func() def delete(self): self.logger.debug('Try to delete session') self.redis.delete(self._prefixed(self._uui)) def _prefixed(self, sid): return '%s:%s' % (self.options['key_prefix'], sid) def _get_session(self, uui): try_to_get = self._prefixed(uui) self.logger.debug('Get session data: {data}'.format(data=try_to_get)) data = self.redis.hget(try_to_get, 'user') session = pickle.loads(data) if data else None self.logger.debug('Got: %s' % session) return session def _set_session(self, uui, session_data): expiry = self.options['expire'] try_to_set = self._prefixed(uui) self.logger.debug('Set session data: {data}'.format(data=try_to_set)) self.redis.hset(try_to_set, 'user', pickle.dumps(session_data)) if expiry: self.redis.expire(self._prefixed(uui), expiry)
info = rc.info() # for key in info: # print "%s: %s" % (key, info[key]) # pprint.pprint(dir(rc)) print "-------------------" # pprint.pprint( rc.keys()) # zset rc.zadd("zset_", 9000, "zset.cc") # set rc.sadd("set_", "set.cc") # hash rc.hset("hash", "filed", "123456789") # string rc.set("foo", "xiaorui.cc") # list rc.lpush("list", "1") rc.lpush("list", "2") keysCount = len(rc.keys()) if keysCount < 1024: for key in rc.keys(): # 查询类型 pprint.pprint("type:" + rc.type(key) + "$key:" + key + "$value:" + getValue(rc, key)) # print rc.get(key) else: print "keysCount:" + str(keysCount) pass