《Redis应用实例》书摘(16):紧凑字符串

一般来说,当需要在Redis里面存储大量字符串的时候,常见的做法就是为每个字符串分别创建一个字符串键。 为了减少存储大量字符串时的内存占用,我们可以选择另一种变通的存储方式:

  • 使用APPEND命令,将大量字符串以追加的形式存储在同一个字符串键里面,这样就避免了使用多个字符串键或多个列表项带来的内存消耗。

  • 在每次向字符串键执行追加操作之前,向被追加的新字符串末尾添加一个特殊的分隔符作为标识,比如换行符\n

  • 当有需要的时候,从字符串键里面取出指定大小的数据块,然后基于分隔符将它们逐一还原为字符串。

代码清单 CODE_COMPACT_LOG 展示了基于上一节介绍的原理实现的紧凑字符串程序。


代码清单 CODE_COMPACT_LOG 紧凑字符串程序compact_string.py

DEFAULT_SEPARATOR = "\n"

class CompactString:

    def __init__(self, client, key, separator=DEFAULT_SEPARATOR):
        """
        可选的separator参数用于指定分隔各个字符串的分隔符,默认为\n。
        """
        self.client = client
        self.key = key
        self.separator = separator

    def append(self, string):
        """
        将给定的字符串添加至已有字符串值的末尾。
        """
        content = string + self.separator
        return self.client.append(self.key, content)

    def get_bytes(self, start=0, end=-1):
        """
        可选的索引参数用于指定想要获取的字符串数据的范围。
        如果没有给定索引范围则默认返回所有字符串。
        这个方法将返回一个列表,其中可以包含零个或任意多个字符串。
        (在指定索引范围的情况下,位于索引两端的字符串可能是不完整的。)
        """
        # 根据索引范围获取字符串数据
        content = self.client.getrange(self.key, start, end)
        # 基于字符串数据的内容对其进行处理
        if content == "":
            # 内容为空
            return []
        elif self.separator not in content:
            # 内容只包含单个不完整的字符串
            return [content]
        else:
            # 内容包含至少一个完整的字符串,基于分隔符对其进行分割
            list_of_strings = content.split(self.separator)
            # 移除split()方法可能在列表中包含的空字符串值
            if "" in list_of_strings:
                list_of_strings.remove("")
            return list_of_strings

作为例子,以下代码演示了这个紧凑字符串程序的使用方法:

>>> from redis import Redis
>>> from compact_string import CompactString
>>> client = Redis(decode_responses=True)
>>> logs = CompactString(client, "CompactLogs")
>>> logs.append("HTTP/1.1 200 OK")  # 添加字符串
16
>>> logs.append("Server: nginx/1.16.1")
37
>>> logs.append("Date: Fri, 05 Jun 2024 14:40:07 GMT")
73
>>> logs.get_bytes()  # 获取所有字符串
['HTTP/1.1 200 OK', 'Server: nginx/1.16.1', 'Date: Fri, 05 Jun 2024 14:40:07 GMT']
>>> logs.get_bytes(0, 20)  # 获取前20字节的字符串内容
['HTTP/1.1 200 OK', 'Serve']

Tip

本文摘录自《Redis应用实例》一书。
欢迎访问书本主页以了解更多Redis使用案例:huangz.works/rediscookbook/
../_images/rediscookbook-banner.png