《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']