예제 #1
0
class RedisImageStorage(IOBase):
    def __init__(self, filename):
        self.filename = filename
        self._redis = StrictRedis(connection_pool=pool0)

    def write(self, data):
        self._redis.append('attendance:api:image:' + self.filename, data)
예제 #2
0
class LibRedis:

    # 默认所有key的前缀
    key_prefix = 'RAWE_'

    # redis 连接对象
    obj_redis = None

    # 默认的过期时间为3天
    DEFAULT_EXPIRE = 259200

    def __init__(self, host='127.0.0.1', port=6379, db=0, prefix=None, charset='utf-8'):
        """
        初始化
        """
        if not host or not port:
            return None

        if prefix:
            self.key_prefix = prefix.strip()
        # construct
        self.obj_redis = StrictRedis(
            host=host, port=port, db=db, charset='utf-8')

    def key_make(self, keyname=None):
        """
        处理所有key,增加前缀
        如果实例化时没有设置,则使用默认前缀
        """
        if not keyname:
            return None

        return self.key_prefix + str(keyname).strip()

    def set_expire(self, keyname=None):
        """
        设置key的过期时间,装饰器调用
        """
        if not keyname:
            return None

        return self.obj_redis.expire(self.key_make(keyname), self.DEFAULT_EXPIRE)

    # --------------------------------------------------------
    # String
    # --------------------------------------------------------

    @wraps_set_expire
    def set(self, keyname=None, value=None):
        """
        设置指定 key 的值。
        如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。
        return:
        设置操作成功完成时,才返回 OK
        """
        if not keyname or value is None:
            return None

        keyname = self.key_make(keyname.strip())
        if isinstance(value, str):
            value = value.strip()

        return self.obj_redis.set(keyname, value)

    def get(self, keyname=None):
        """
        获取指定 key 的值。
        return:
        key 的值
        如果 key 不存在,返回 nil。
        如果key 储存的值不是字符串类型,返回一个错误。
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.get(keyname)

        return None if not result else bytes.decode(result)

    def delete(self, keyname=None):
        """
        删除已存在的键。不存在的 key 会被忽略
        return:
        被删除 key 的数量
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.delete(keyname)

    @wraps_set_expire
    def append(self, keyname=None, value=None):
        """
        为指定的 keyname 追加值
        如果 keyname 已经存在并且是一个字符串,
        APPEND 命令将 value 追加到 keyname 原来的值的末尾。
        如果 keyname 不存在,
        APPEND 就简单地将给定 keyname 设为 value ,就像执行 SET keyname value 一样
        return:
        追加指定值之后, keyname 中字符串的长度
        """
        if not keyname or value is None:
            return None

        keyname = self.key_make(keyname.strip())
        if isinstance(value, str):
            value = value.strip()
        else:
            value = str(value)

        return self.obj_redis.append(keyname, value)

    @wraps_set_expire
    def incr(self, keyname=None, expire=None):
        """
        将 keyname 中储存的数字值增一。
        如果 keyname 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。
        如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
        本操作的值限制在 64 位(bit)有符号数字表示之内。
        return:
        执行 INCR 命令之后 key 的值
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.incr(keyname, 1)

    @wraps_set_expire
    def incrBy(self, keyname=None, amount=1):
        """
        将 keyname 中储存的数字加上指定的增量值。
        如果 keyname 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令
        如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
        本操作的值限制在 64 位(bit)有符号数字表示之内。
        return:
        加上指定的增量值之后, key 的值
        """
        if not keyname or not amount:
            return None

        keyname = self.key_make(keyname.strip())

        if isinstance(amount, int):
            amount = max(0, amount)
        else:
            amount = 1

        return self.obj_redis.incrby(keyname, amount)

    @wraps_set_expire
    def decr(self, keyname=None):
        """
        将 key 中储存的数字值减一。
        如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECR 操作。
        如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
        本操作的值限制在 64 位(bit)有符号数字表示之内。
        return:
        执行命令之后 key 的值
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.decr(keyname, 1)

    @wraps_set_expire
    def decrBy(self, keyname=None, amount=1):
        """
        将 keyname 所储存的值减去指定的减量值。
        如果 keyname 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 DECRBY 操作。
        如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。
        本操作的值限制在 64 位(bit)有符号数字表示之内
        """
        if not keyname or not amount:
            return None

        keyname = self.key_make(keyname.strip())
        amount = int(amount)
        return self.obj_redis.decr(keyname, amount)

    # --------------------------------------------------------
    # Hash 哈希
    # 一个string类型的field和value的映射表,hash特别适合用于存储对象
    # 每个 hash 可以存储 232 - 1 键值对(40多亿)
    # --------------------------------------------------------

    @wraps_set_expire
    def hSet(self, keyname=None, key=None, value=None):
        """
        从哈希名为keyname中添加key1->value1 将哈希表key中的域field的值设为value。-ok -ok
        如果key不存在,一个新的哈希表被创建并进行hset操作。
        如果域field已经存在于哈希表中,旧值将被覆盖。
        错误则 返回 FALSE
        如果字段是哈希表中的一个新建字段,并且值设置成功,返回 1 。 
        如果哈希表中域字段已经存在且旧值已被新值覆盖,返回 0 。
        """
        if not keyname or not key or value is None:
            return None

        keyname = self.key_make(keyname.strip())
        key = key.strip()
        return self.obj_redis.hset(keyname, key, value)

    @wraps_set_expire
    def hGet(self, keyname=None, key=None):
        """
        获取存储在哈希表中指定字段的值
        返回给定字段的值。如果给定的字段或 key 不存在时,返回 None 
        """
        if not keyname or not key:
            return None

        keyname = self.key_make(keyname.strip())
        key = key.strip()

        result = self.obj_redis.hget(keyname, key)
        if not result:
            return None

        # bytes to str
        return bytes.decode(result)

    @wraps_set_expire
    def hLen(self, keyname=None):
        """
        获取哈希表中字段的数量
        哈希表中字段的数量。 当 keyname 不存在时,返回 0 
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.hlen(keyname)

    @wraps_set_expire
    def hKeys(self, keyname=None):
        """
        获取哈希表中的所有域(field)
        包含哈希表中所有域(field)列表。 
        当 key 不存在时,返回一个空列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.hkeys(keyname)
        if not result:
            return None

        # bytes to str
        ret_list = list()
        for v in result:
            ret_list.append(bytes.decode(v))

        return ret_list

    @wraps_set_expire
    def hVals(self, keyname=None):
        """
        哈希表所有域(field)的值
        包含哈希表中所有域(field)值的列表。 
        当 key 不存在时,返回一个空表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.hvals(keyname)
        if not result:
            return None

        # bytes to str
        ret_list = list()
        for v in result:
            ret_list.append(bytes.decode(v))

        return ret_list

    @wraps_set_expire
    def hGetAll(self, keyname=None):
        """
        获取在哈希表中指定 keyname 的所有字段和值
        返回哈希表中,所有的字段和值
        在返回值里,紧跟每个字段名(field name)之后是字段的值(value),
        所以返回值的长度是哈希表大小的两倍。
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.hgetall(keyname)
        if not result:
            return None

        # bytes to str
        ret_dict = dict()
        for k, v in result.items():
            ret_dict[bytes.decode(k)] = bytes.decode(v)

        return ret_dict

    def hExists(self, keyname=None, key=None):
        """
        查看哈希表 keyname 中,是否存在键名为key的字段
        ashname含有给定字段key,返回 True。 
        keyname不存在 或 key 不存在,返回 False
        """
        if not keyname or key is None:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.hexists(keyname, key)

    def hDel(self, keyname=None, *keys):
        """
        删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略
        返回值
        被成功删除字段的数量,不包括被忽略的字段
        keyname 或 key 不存在则返回 0
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.hdel(keyname, *keys)

    # --------------------------------------------------------
    # List 列表, 左(Left)为头部,右(Right)为尾部
    # 一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)
    # --------------------------------------------------------

    @wraps_set_expire
    def lPush(self, keyname=None, *values):
        """
        将一个或多个值插入到列表头部, 返回操作后列表的长度。
        如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。 
        当 key 存在但不是列表类型时,返回一个错误。
        注意:在Redis 2.4版本以前的 LPUSH 命令,都只接受单个 value 值
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.lpush(keyname, *values)

    @wraps_set_expire
    def lPop(self, keyname=None):
        """
        弹出队列头部元素,移除并返回列表的第一个元素。
        返回列表的第一个元素。 当列表 key 不存在时,返回 None 
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.lpop(keyname)

    @wraps_set_expire
    def rPush(self, keyname=None, *values):
        """
        将一个或多个值插入到列表的尾部(最右边), 返回操作后列表的长度。
        如果列表不存在,一个空列表会被创建并执行 RPUSH 操作。 
        当列表存在但不是列表类型时,返回一个错误。
        注意:在 Redis 2.4 版本以前的 RPUSH 命令,都只接受单个 value 值。

        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.rpush(keyname, *values)

    @wraps_set_expire
    def rPop(self, keyname=None):
        """
        移除并获取列表最后一个元素
        返回列表的最后一个元素。 当列表不存在时,返回 None
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.rpop(keyname)
        if not result:
            return None
        # bytes to str
        return bytes.decode(result)

    @wraps_set_expire
    def lLen(self, keyname=None):
        """
        获取列表长度 
        如果列表 key 不存在,则 key 被解释为一个空列表,返回 0  
        如果 key 不是列表类型,返回一个错误
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.llen(keyname)

    @wraps_set_expire
    def lTrim(self, keyname=None, start=0, end=-1):
        """
        让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除
        下标 0 表示列表的第一个元素,1 表示列表的第二个元素
        -1 表示列表的最后一个元素,-2 表示列表的倒数第二个元素
        返回 True
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.ltrim(keyname, start, end)

    @wraps_set_expire
    def lGetRange(self, keyname=None, start=0, end=-1):
        """
        返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定
        下标 0 表示列表的第一个元素,以 1 表示列表的第二个元素
        -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素
        返回一个列表,包含指定区间内的元素
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.lrange(keyname, start, end)
        if not result:
            return None
        # bytes to str
        ret_list = list()
        for v in result:
            ret_list.append(bytes.decode(v))

        return ret_list

    @wraps_set_expire
    def lRemove(self, keyname=None, value=None, count=1):
        """
        根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。
        COUNT 的值可以是以下几种:
        count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。
        count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。
        count = 0 : 移除表中所有与 VALUE 相等的值。
        返回被移除元素的数量。 列表或元素不存在时返回 0
        """
        if not keyname or value is None:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.lrem(keyname, count, value)

    # --------------------------------------------------------
    # Set 无序集合
    # Set 是 String 类型的无序集合。集合成员是唯一的。
    # 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)
    # 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)
    # --------------------------------------------------------

    @wraps_set_expire
    def sAdd(self, keyname=None, *values):
        """
        将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略。
        假如集合 key 不存在,则创建一个只包含添加的元素作成员的集合。
        当集合 key 不是集合类型时,返回一个错误。
        注意:在Redis2.4版本以前, SADD 只接受单个成员值。
        """
        if not keyname:
            return None
        keyname = self.key_make(keyname.strip())
        return self.obj_redis.sadd(keyname, *values)

    @wraps_set_expire
    def sCard(self, keyname=None):
        """
        获取集合key中元素的数量
        集合的数量。 当集合 key 不存在时,返回 0
        """
        if not keyname:
            return None
        keyname = self.key_make(keyname.strip())
        return self.obj_redis.scard(keyname)

    def sDiff(self, keyname=None, *keys):
        """
        差集
        返回所给key列表想减后的集合,相当于求差集
        不存在的集合 key 将视为空集。
        请注意顺序是前面的集合,减去后面的集合,求差集
        返回包含差集成员的列表
        """
        if not keyname:
            return None

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        result = self.obj_redis.sdiff(keyname, *other_keys)
        if not result:
            return None

        # bytes to str
        ret_set = set()
        for v in result:
            ret_set.add(bytes.decode(v))

        return ret_set

    @wraps_set_expire
    def sDiffStore(self, store_key=None, key=None, *keys):
        """
        差集并存储
        给定所有集合的差集并存储在 store_key 中
        将给定集合之间的差集存储在指定的集合中。
        如果指定的集合 key 已存在,则会被覆盖
        返回store_key结果集中的元素数量
        """
        if not store_key or not key:
            return None

        store_key = self.key_make(store_key.strip())
        key = self.key_make(key.strip())

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        return self.obj_redis.sdiffstore(store_key, key, *other_keys)

    def sInter(self, keyname=None, *keys):
        """
        交集
        返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。 
        当给定集合当中有一个空集或key不存在时,结果也为空集(根据集合运算定律)。
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        result = self.obj_redis.sinter(keyname, *other_keys)
        if not result:
            return None

        # bytes to str
        ret_set = set()
        for v in result:
            ret_set.add(bytes.decode(v))

        return ret_set

    @wraps_set_expire
    def sInterStore(self, store_key=None, key=None, *keys):
        """
        交集并存储
        将给定集合之间的交集存储在指定的集合store_key中。
        如果指定的集合已经存在,则将其覆盖
        返回store_key存储交集的集合的元素数量
        """
        if not store_key or not key:
            return None

        store_key = self.key_make(store_key.strip())
        key = self.key_make(key.strip())

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        return self.obj_redis.sinterstore(store_key, key, *other_keys)

    def sUnion(self, keyname=None, *keys):
        """
        并集
        所给key列表所有的值,相当于求并集
        给定集合的并集。不存在的集合 key 被视为空集。
        返回并集成员的列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        result = self.obj_redis.sunion(keyname, *other_keys)
        if not result:
            return None

        # bytes to str
        ret_set = set()
        for v in result:
            ret_set.add(bytes.decode(v))

        return ret_set

    @wraps_set_expire
    def sUnionStore(self, store_key=None, key=None, *keys):
        """
        并集存储
        将给定集合的并集存储在指定的集合 store_key 中。
        如果 store_key 已经存在,则将其覆盖
        返回store_key存储并集的集合的元素数量
        """
        if not store_key or not key:
            return None

        store_key = self.key_make(store_key.strip())
        key = self.key_make(key.strip())

        other_keys = list()
        for k in keys:
            other_keys.append(self.key_make(k))

        return self.obj_redis.sunionstore(store_key, key, *other_keys)

    @wraps_set_expire
    def sIsMember(self, keyname=None, value=None):
        """
        判断成员元素是否是集合的成员
        如果成员元素是集合的成员,返回 True 
        如果成员元素不是集合的成员,或 key 不存在,返回 False
        """
        if not keyname or value is None:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.sismember(keyname, value)

    @wraps_set_expire
    def sMembers(self, keyname=None):
        """
        返回集合中的所有的成员。 
        不存在的集合 key 被视为空集合
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.smembers(keyname)

        if not result:
            return None
        # bytes to str
        ret_set = set()
        for v in result:
            ret_set.add(bytes.decode(v))

        return ret_set

    @wraps_set_expire
    def sRem(self, keyname=None, *values):
        """
        删除该数组中对应的值
        移除集合中的一个或多个成员元素,不存在的成员元素会被忽略。
        当 key 不是集合类型,返回一个错误。
        在 Redis 2.4 版本以前, SREM 只接受单个成员值。
        返回被成功移除的元素的数量,不包括被忽略的元素
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.srem(keyname, *values)

    @wraps_set_expire
    def sPop(self, keyname=None):
        """
        移除并返回集合中的一个随机元素
        将随机元素从集合中移除并返回
        移除的随机元素。 当集合不存在或是空集时,返回 None
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.spop(keyname)

        # bytes to str
        return None if not result else bytes.decode(result)

    @wraps_set_expire
    def sRandMember(self, keyname=None, count=1):
        """
        返回集合中的随机元素,而不对集合进行任何改动
        从 Redis 2.6 版本开始, Srandmember 命令接受可选的 count 参数:
        如果 count 为正数,且小于集合基数,
            返回一个包含 count 个元素的数组,数组中的元素各不相同。
        如果 count 大于等于集合基数,那么返回整个集合。
        如果 count 为负数,返回一个数组,
            数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值。
        返回:随机个数的元素列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())

        if isinstance(count, int):
            count = max(0, count)
        else:
            count = 1

        result = self.obj_redis.srandmember(keyname, count)

        if not result:
            return None

        # bytes to str
        ret_list = list()
        for v in result:
            ret_list.append(bytes.decode(v))

        return ret_list

    # --------------------------------------------------------
    # Zset( sorted set ) 有序集合
    # 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员
    # 有序集合的成员是唯一的,但分数(score)却可以重复
    # 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)
    # 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)
    # --------------------------------------------------------

    @wraps_set_expire
    def zAdd(self, keyname=None, **kwargs):
        """
        将一个或多个成员元素及其分数值加入到有序集当中。
        如果某个成员已经是有序集的成员,那么更新这个成员的分数值,
        并通过重新插入这个成员元素,来保证该成员在正确的位置上。
        如果有序集合 key 不存在,则创建一个空的有序集并执行 ZADD 操作。
        当 key 存在但不是有序集类型时,返回一个错误。
        返回:
            被成功添加的新成员的数量,不包括那些被更新的、已经存在的成员。
        注意: 在 Redis 2.4 版本以前, ZADD 每次只能添加一个元素
        **kwargs: name1=score1, name2=score2
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zadd(keyname, **kwargs)

    def zRangeByScore(self, keyname=None, min=None, max=None, withscores=False):
        """
        分数值正序
        返回有序集中指定分数区间内的所有的成员。
        有序集成员按分数值递减(从大到小)的次序排列。
        具有相同分数值的成员按字典序的逆序(reverse lexicographical order )排列
        返回;
        指定区间内,带有分数值(可选)的有序集成员的列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.zrangebyscore(
            keyname, min, max, withscores=withscores)

        if not result:
            return None

        # bytes to str
        if not withscores:
            # return list
            zret = list()
            for field in result:
                zret.append(bytes.decode(field))
        else:
            # return dict
            zret = list()
            for field, score in result:
                zret.append((bytes.decode(field), score))
            zret = dict(zret)

        return zret

    def zRevRangeByScore(self, keyname=None, max=None, min=None, withscores=False):
        """
        分数值逆序
        返回有序集中指定分数区间内的所有的成员。
        有序集成员按分数值递减(从大到小)的次序排列。
        具有相同分数值的成员按字典序的逆序(reverse lexicographical order )排列。
        返回;
        指定区间内,带有分数值(可选)的有序集成员的列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.zrevrangebyscore(
            keyname, max, min, withscores=withscores)

        if not result:
            return None

        # bytes to str
        if not withscores:
            # return list
            zret = list()
            for field in result:
                zret.append(bytes.decode(field))
        else:
            # return dict
            zret = list()
            for field, score in result:
                zret.append((bytes.decode(field), score))
            zret = dict(zret)

        return zret

    def zRank(self, keyname=None, member=None):
        """
        排名正序
        返回有序集中指定成员的排名。
        其中有序集成员按分数值递增(从小到大)顺序排列
        如果成员是有序集 key 的成员,返回 member 的排名。
        如果成员不是有序集 key 的成员,返回 None 。
        """
        if not keyname or member is None:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zrank(keyname, member)

    def zRevRank(self, keyname=None, member=None):
        """
        排名逆序
        返回有序集中指定成员的排名。
        其中有序集成员按分数值递减(从大到小)排序
        如果成员是有序集 key 的成员,返回 member 的排名。
        如果成员不是有序集 key 的成员,返回 None 。
        """
        if not keyname or member is None:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zrevrank(keyname, member)

    def zRange(self, keyname=None, start=None, end=None, withscores=False):
        """
        位置正序
        返回有序集中,指定区间内的成员。
        其中成员的位置按分数值递增(从小到大)来排序。
        具有相同分数值的成员按字典序(lexicographical order )来排列
        返回指定区间内,带有分数值(可选)的有序集成员的列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.zrange(
            keyname, start, end, withscores=withscores)

        if not result:
            return None

        # bytes to str
        if not withscores:
            # return list
            zret = list()
            for field in result:
                zret.append(bytes.decode(field))
        else:
            # return dict
            zret = list()
            for field, score in result:
                zret.append((bytes.decode(field), score))
            zret = dict(zret)

        return zret

    def zRevrange(self, keyname=None, start=None, end=None, withscores=False):
        """
        位置逆序
        返回有序集中,指定区间内的成员。
        其中成员的位置按分数值递减(从大到小)来排列。
        具有相同分数值的成员按字典序的逆序(reverse lexicographical order)排列
        返回指定区间内,带有分数值(可选)的有序集成员的列表
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        result = self.obj_redis.zrevrange(
            keyname, start, end, withscores=withscores)

        if not result:
            return None

        # bytes to str
        if not withscores:
            # return list
            zret = list()
            for field in result:
                zret.append(bytes.decode(field))
        else:
            # return dict
            zret = list()
            for field, score in result:
                zret.append((bytes.decode(field), score))
            zret = dict(zret)

        return zret

    def zRem(self, keyname, *member):
        """
        移除有序集中的一个或多个成员,不存在的成员将被忽略。
        当 key 存在但不是有序集类型时,返回一个错误。
        注意: 在 Redis 2.4 版本以前, ZREM 每次只能删除一个元素。
        返回被成功移除的成员的数量,不包括被忽略的成员0
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zrem(keyname, *member)

    def zRemRangeByRank(self, keyname=None, min=None, max=None):
        """
        删除正序
        移除有序集中,指定排名(rank)区间内的所有成员
        返回被移除成员的数量
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zremrangebyrank(keyname, min, max)

    def zRemrangebyscore(self, keyname=None, min=None, max=None):
        """
        删除正序
        移除有序集中,指定分数(score)区间内的所有成员
        返回被移除成员的数量
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zremrangebyscore(keyname, min, max)

    def zCard(self, keyname=None):
        """
        计算集合中元素的数量
        当 key 存在且是有序集类型时,返回有序集的基数。
        当 key 不存在时,返回 0
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zcard(keyname)

    def zCount(self, keyname=None, min=None, max=None):
        """
        计算有序集合中指定分数区间的成员数量
        返回分数值在 min 和 max 之间的成员的数量
        """
        if not keyname:
            return None

        keyname = self.key_make(keyname.strip())
        return self.obj_redis.zcount(keyname, min, max)
예제 #3
0
# 批量赋值
data = {'name1':'Durant', 'name2':'James'}
redis.mset(data)


# key 若存在 value 做加法, 如果 key 不存在则直接创建
redis.incr('age', 1)
redis.incr('age', 1)

# 与 incr 相反, 给 value 做减法, key 不存在则直接创建
redis.decr('age',1)


# 在 value 的后面追加内容
redis.append('name1', ' Hello')


# 返回 value 指定的 start index / end index 之间的内容. 只支持 string 类型
print(redis.substr('name1',2, -2))  # getrange() 也效果对于字符串  等同



#  -------  List 相关 --------

# 在指定的 key 的list 末尾增加元素. 如果 key 不存在则直接创建
redis.rpush('list', 1, 2, 3)


# 与 rpush 相反, 在表的开头插入元素
redis.lpush('list', -1, 0)
예제 #4
0
print()
print(redis.set('emotion', 'smile'))
redis.set('name', 'Leo')
redis.set('age', '19')
print(redis.get('emotion'))
print(redis.getset('emotion', 'humour'))
print(redis.mget(['emotion', 'name', 'age']))
print(redis.setnx('newname', 'James'))  # 不存在键才更新
print(redis.setex('country', 1, 'china'))
redis.setrange('name', 3, '2019')
print(redis.get('name'))
print(redis.mset({'name1': 'Modric', 'name2': 'Van Dik'}))
print(redis.msetnx({'name3': 'Salah', 'name4': 'Mane'}))  #键均不存在才批量更新
print(redis.incr('age', 1))
print(redis.decr('age', 1))
print(redis.append('name', 'ooo'))
print(redis.substr('name', 1, 4))
print(redis.getrange('name', 0, 3))

# 4.列表操作
print(redis.rpush('list', 1, 2, 3, 4, 5))
print(redis.lpush('list', 0))
print(redis.llen('list'))
print(redis.lrange('list', 1, 3))
print(redis.ltrim('list', 1, 3))
print(redis.lindex('list', 1))
print(redis.lset('list', 1, 666))
print(redis.lrem('list', 1, 1))
print(redis.lpop('list'))
print(redis.rpop('list'))
#print(redis.blpop('list'))
unix://[:password]@/path/to/socket.sock?db=db    # Redis Unix Socket 连接

\String操作
    方法	                            作用	                                    示例	                                  示例结果
set(name, value)	            给name赋值为value	                       redis.set('name', 'Bob')	                           True
get(name)	                    返回数据库中key为name的string的value	     redis.get('name')	                                 b'Bob'
getset(name, value)	            给数据库中key为name的string赋予值value并返回上次的value	redis.getset('name', 'Mike')	           b'Bob'
mget(keys, *args)	            返回多个key对应的value	                    redis.mget(['name', 'nickname'])	                [b'Mike', b'Miker']
setnx(name, value)	            如果key不存在才设置value	                 redis.setnx('newname', 'James')	                 第一次运行True,第二次False
setex(name, time, value)	    设置可以对应的值为string类型的value,并指定此键值对应的有效期	redis.setex('name', 1, 'James')	       True
setrange(name, offset, value)	设置指定key的value值的子字符串	             redis.set('name', 'Hello') redis.setrange('name', 6, 'World')	11,修改后的字符串长度
mset(mapping)	                批量赋值	                               redis.mset({'name1': 'Durant', 'name2': 'James'})	True
msetnx(mapping)	                key均不存在时才批量赋值	                     redis.msetnx({'name3': 'Smith', 'name4': 'Curry'})	  True
incr(name, amount=1)	        key为name的value增值操作,默认1,key不存在则被创建并设为amount	redis.incr('age', 1)	              1,即修改后的值
decr(name, amount=1)	        key为name的value减值操作,默认1,key不存在则被创建并设置为-amount	redis.decr('age', 1)	          -1,即修改后的值
append(key, value)	            key为name的string的值附加value	            redis.append('nickname', 'OK')	                     13,即修改后的字符串长度
substr(name, start, end=-1)	    返回key为name的string的value的子串	         redis.substr('name', 1, 4)	                          b'ello'
getrange(key, start, end)	    获取key的value值从start到end的子字符串	      redis.getrange('name', 1, 4)	                       b'ello'

# 源码
def set(self, name, value, ex=None, px=None, nx=False, xx=False):
        """
        Set the value at key ``name`` to ``value``
        ``ex`` sets an expire flag on key ``name`` for ``ex`` seconds.
        ``px`` sets an expire flag on key ``name`` for ``px`` milliseconds.
        ``nx`` if set to True, set the value at key ``name`` to ``value`` only
            if it does not exist.
        ``xx`` if set to True, set the value at key ``name`` to ``value`` only
            if it already exists.
        """
예제 #6
0
# print(redis.flushdb())
# 删除所有数据库所有键
# print(redis.flushall())
# 给赋值 并且返回原来的值
print(redis.getset('nickname', 'newname'))
# 返回多个键值对应的value
print(redis.mget(['nickname', 'name2']))
# 批量赋值
print(redis.mset({'n': 1, 'x': 2}))
# 如果键不存在就设置值 否则不设置值  (只新增 不更新)第二条不起作用
print(redis.setnx('ni', 'wo'))
print(redis.setnx('ni', '2'))
# 如果键不存在就设置值 否则不设置值  (只新增 不更新)第二条不起作用 批量
print(redis.msetnx({'nix': 1, 'wox': 2}))
print(redis.msetnx({'nix': 3, 'wox': 4}))
# 设置键的值以及过期时间  可以新增以及更新
print(redis.setex('wo', 120, 'Lucy'))
# 往value插入字符串 如果字符不存在会新建 如果位置不存在 会为空类型变成binary 如果是0就可以
print(redis.setrange('ni', 2, 'hao'))
print(redis.setrange('nini', 2, 'hao'))
# 增长 默认1
print(redis.incr('nix', 10))
# 减少 默认1
print(redis.decr('nix', 10))
# 值的最后位置追加
print(redis.append('nickname', 'nickname'))
# 获取子串 开始 以及结束 不传就是 -1
print(redis.substr('nickname', 3))
# 获取子串 开始 以及结束 不传就是 报错 也可以是-1
print(redis.getrange('nickname', 4, 5))
예제 #7
0
redis.setnx('newname', 'heihei')
# 设值饼设值有效期
redis.setex('name', 1, 'James')
# 设值指定键的value 的子字符串
redis.set('name', 'Hello')
redis.setrange('name', 6, 'World')
# 批量赋值
redis.mset({'name1': 'Smith', 'name2': 'Curry'})
# 键都不存在时才批量赋值
redis.msetnx({'name3': 'Smith', 'name4': 'Curry'})
# 增操作
redis.incr('age', 1)
# 减操作 不存在 则设置为-1
redis.decr('age', 1)
# 追加 返回长度
redis.append('name', 'OK')
# 截取子串 默认截取到末尾
redis.substr('name', 1, end=-1)
redis.getrange('name', 1, 4)
"""列表操作"""
# name-list 尾部添加
redis.rpush('list', 1, 2, 3)
# name-list 头部添加
redis.lpush('list', 0)
# 返回长度 以上三个都是返回列表大小
redis.llen('list')
# 取范围 返回列表
redis.lrange('list', 1, 3)
# 截取,保留范围内容 返回bool
redis.ltrim('list', 1, 3)
# 取索引元素 返回元素
예제 #8
0
파일: analyzer.py 프로젝트: cuiods/Skyline
class Analyzer(Thread):
    def __init__(self, parent_pid):
        """
        Initialize the Analyzer
        """
        super(Analyzer, self).__init__()
        self.redis_conn = StrictRedis(
            unix_socket_path=settings.REDIS_SOCKET_PATH)
        self.daemon = True
        self.parent_pid = parent_pid
        self.current_pid = getpid()
        self.anomalous_metrics = Manager().list()
        self.exceptions_q = Queue()
        self.anomaly_breakdown_q = Queue()

    def check_if_parent_is_alive(self):
        """
        Self explanatory
        """
        try:
            kill(self.current_pid, 0)
            kill(self.parent_pid, 0)
        except:
            exit(0)

    def send_graphite_metric(self, name, value):
        if settings.GRAPHITE_HOST != '':
            sock = socket.socket()
            sock.connect((settings.GRAPHITE_HOST, settings.CARBON_PORT))
            sock.sendall('%s %s %i\n' % (name, value, time()))
            sock.close()
            return True

        return False

    def spin_process(self, i, unique_metrics):
        """
        Assign a bunch of metrics for a process to analyze.
        """
        # Discover assigned metrics
        keys_per_processor = int(
            ceil(
                float(len(unique_metrics)) /
                float(settings.ANALYZER_PROCESSES)))
        if i == settings.ANALYZER_PROCESSES:
            assigned_max = len(unique_metrics)
        else:
            assigned_max = i * keys_per_processor
        assigned_min = assigned_max - keys_per_processor
        assigned_keys = range(assigned_min, assigned_max)

        # Compile assigned metrics
        assigned_metrics = [unique_metrics[index] for index in assigned_keys]

        # Check if this process is unnecessary
        if len(assigned_metrics) == 0:
            return

        # Multi get series
        raw_assigned = self.redis_conn.mget(assigned_metrics)

        # Make process-specific dicts
        exceptions = defaultdict(int)
        anomaly_breakdown = defaultdict(int)

        # Distill timeseries strings into lists
        for i, metric_name in enumerate(assigned_metrics):
            self.check_if_parent_is_alive()

            try:
                raw_series = raw_assigned[i]
                unpacker = Unpacker(use_list=False)
                unpacker.feed(raw_series)
                timeseries = list(unpacker)

                anomalous, ensemble, datapoint = run_selected_algorithm(
                    timeseries, metric_name)

                # If it's anomalous, add it to list
                if anomalous:
                    base_name = metric_name.replace(settings.FULL_NAMESPACE,
                                                    '', 1)
                    metric = [datapoint, base_name]
                    self.anomalous_metrics.append(metric)

                    # Get the anomaly breakdown - who returned True?
                    for index, value in enumerate(ensemble):
                        if value:
                            algorithm = settings.ALGORITHMS[index]
                            anomaly_breakdown[algorithm] += 1

                    # Add anomaly datapoint to redis
                    key = ''.join((settings.ANOMALY_NAMESPACE, base_name))
                    anomaly_full_uniques = settings.ANOMALY_NAMESPACE + 'unique_metrics'
                    self.redis_conn.append(key, packb(datapoint))
                    self.redis_conn.sadd(anomaly_full_uniques, key)

            # It could have been deleted by the Roomba
            except TypeError:
                exceptions['DeletedByRoomba'] += 1
            except TooShort:
                exceptions['TooShort'] += 1
            except Stale:
                exceptions['Stale'] += 1
            except Boring:
                exceptions['Boring'] += 1
            except:
                exceptions['Other'] += 1
                logger.info(traceback.format_exc())

        # Add values to the queue so the parent process can collate
        for key, value in anomaly_breakdown.items():
            self.anomaly_breakdown_q.put((key, value))

        for key, value in exceptions.items():
            self.exceptions_q.put((key, value))

    def run(self):
        """
        Called when the process intializes.
        """
        while 1:
            now = time()

            # Make sure Redis is up
            try:
                self.redis_conn.ping()
            except:
                logger.error(
                    'skyline can\'t connect to redis at socket path %s' %
                    settings.REDIS_SOCKET_PATH)
                sleep(10)
                self.redis_conn = StrictRedis(
                    unix_socket_path=settings.REDIS_SOCKET_PATH)
                continue

            # Discover unique metrics
            unique_metrics = list(
                self.redis_conn.smembers(settings.FULL_NAMESPACE +
                                         'unique_metrics'))

            if len(unique_metrics) == 0:
                logger.info(
                    'no metrics in redis. try adding some - see README')
                sleep(10)
                continue

            # Spawn processes
            pids = []
            for i in range(1, settings.ANALYZER_PROCESSES + 1):
                if i > len(unique_metrics):
                    logger.info(
                        'WARNING: skyline is set for more cores than needed.')
                    break

                p = Process(target=self.spin_process, args=(i, unique_metrics))
                pids.append(p)
                p.start()

            # Send wait signal to zombie processes
            for p in pids:
                p.join()

            # Grab data from the queue and populate dictionaries
            exceptions = dict()
            anomaly_breakdown = dict()
            while 1:
                try:
                    key, value = self.anomaly_breakdown_q.get_nowait()
                    if key not in anomaly_breakdown.keys():
                        anomaly_breakdown[key] = value
                    else:
                        anomaly_breakdown[key] += value
                except Empty:
                    break

            while 1:
                try:
                    key, value = self.exceptions_q.get_nowait()
                    if key not in exceptions.keys():
                        exceptions[key] = value
                    else:
                        exceptions[key] += value
                except Empty:
                    break

            # Send alerts
            if settings.ENABLE_ALERTS:
                for alert in settings.ALERTS:
                    for metric in self.anomalous_metrics:
                        if alert[0] in metric[1]:
                            cache_key = 'last_alert.%s.%s' % (alert[1],
                                                              metric[1])
                            try:
                                last_alert = self.redis_conn.get(cache_key)
                                if not last_alert:
                                    self.redis_conn.setex(
                                        cache_key, alert[2], packb(metric[0]))
                                    trigger_alert(alert, metric)

                            except Exception as e:
                                logger.error("couldn't send alert: %s" % e)

            # Write anomalous_metrics to static webapp directory
            filename = path.abspath(
                path.join(path.dirname(__file__), '..', settings.ANOMALY_DUMP))
            with open(filename, 'w') as fh:
                # Make it JSONP with a handle_data() function
                anomalous_metrics = list(self.anomalous_metrics)
                anomalous_metrics.sort(key=operator.itemgetter(1))
                fh.write('handle_data(%s)' % anomalous_metrics)

            # Log progress
            logger.info('seconds to run    :: %.2f' % (time() - now))
            logger.info('total metrics     :: %d' % len(unique_metrics))
            logger.info('total analyzed    :: %d' %
                        (len(unique_metrics) - sum(exceptions.values())))
            logger.info('total anomalies   :: %d' %
                        len(self.anomalous_metrics))
            logger.info('exception stats   :: %s' % exceptions)
            logger.info('anomaly breakdown :: %s' % anomaly_breakdown)

            # Log to Graphite
            # self.send_graphite_metric('skyline.analyzer.run_time', '%.2f' % (time() - now))
            # self.send_graphite_metric('skyline.analyzer.total_analyzed', '%.2f' % (len(unique_metrics) - sum(exceptions.values())))

            # Check canary metric
            raw_series = self.redis_conn.get(settings.FULL_NAMESPACE +
                                             settings.CANARY_METRIC)
            if raw_series is not None:
                unpacker = Unpacker(use_list=False)
                unpacker.feed(raw_series)
                timeseries = list(unpacker)
                time_human = (timeseries[-1][0] - timeseries[0][0]) / 3600
                projected = 24 * (time() - now) / time_human

                logger.info('canary duration   :: %.2f' % time_human)
                self.send_graphite_metric('skyline.analyzer.duration',
                                          '%.2f' % time_human)
                self.send_graphite_metric('skyline.analyzer.projected',
                                          '%.2f' % projected)

            # Reset counters
            self.anomalous_metrics[:] = []

            # Sleep if it went too fast
            if time() - now < 5:
                logger.info('sleeping due to low run time...')
                sleep(10)