Python练手写了一个简单的Redis全文搜索模块
有一个 Node.js 的小网站使用到了 github.com/tj/reds 来做 Redis 文本搜索功能,稍微研究了下源码
然后一直想学点 python,尝试着写了一个 pyreds
https://github.com/7anshuai/pyreds
欢迎使用并反馈问题。
Python练手写了一个简单的Redis全文搜索模块
1 回复
这个想法挺有意思的,自己实现Redis的全文搜索确实是个不错的练手项目。核心思路一般是用Redis的Sorted Set来存储文档ID和分数,用Set来存储倒排索引(词条到文档ID的映射)。
下面是一个最基础的实现框架,包含了索引创建和简单搜索:
import redis
import jieba # 用于中文分词,如果是英文可以用str.split()
class SimpleRedisSearch:
def __init__(self, host='localhost', port=6379, db=0):
self.client = redis.Redis(host=host, port=port, db=db, decode_responses=True)
self.doc_prefix = "doc:"
self.index_prefix = "idx:"
def add_document(self, doc_id, content):
"""添加文档到索引"""
# 存储原始文档
self.client.set(f"{self.doc_prefix}{doc_id}", content)
# 分词并创建倒排索引
words = jieba.lcut_for_search(content) # 搜索引擎模式分词
for word in words:
if len(word.strip()) < 2: # 过滤短词
continue
# 将文档ID添加到该词条的集合中
self.client.sadd(f"{self.index_prefix}{word}", doc_id)
def search(self, query, limit=10):
"""搜索文档"""
words = jieba.lcut_for_search(query)
if not words:
return []
# 获取包含所有搜索词的文档ID交集
keys = [f"{self.index_prefix}{word}" for word in words]
if len(keys) == 1:
doc_ids = self.client.smembers(keys[0])
else:
# 求所有词条对应的文档ID交集
self.client.sinterstore("temp_result", *keys)
doc_ids = self.client.smembers("temp_result")
self.client.delete("temp_result")
# 返回文档内容
results = []
for doc_id in list(doc_ids)[:limit]:
content = self.client.get(f"{self.doc_prefix}{doc_id}")
if content:
results.append({"id": doc_id, "content": content})
return results
# 使用示例
if __name__ == "__main__":
search_engine = SimpleRedisSearch()
# 添加文档
search_engine.add_document("1", "Python是一种流行的编程语言")
search_engine.add_document("2", "Redis是高性能的键值数据库")
search_engine.add_document("3", "用Python操作Redis很简单")
# 搜索
results = search_engine.search("Python Redis")
for r in results:
print(f"文档ID: {r['id']}, 内容: {r['content']}")
这个实现用了集合求交集的方式做AND查询,是最基础的版本。如果要做得更实用,可以考虑这些方向:1)用Sorted Set存储词频做相关性排序;2)支持OR查询和NOT查询;3)添加停用词过滤;4)支持字段搜索(标题、正文分开索引)。
自己造轮子能更好理解搜索引擎原理,不过生产环境还是用现成的方案更靠谱。
总结:核心就是倒排索引加集合操作。

