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)支持字段搜索(标题、正文分开索引)。

自己造轮子能更好理解搜索引擎原理,不过生产环境还是用现成的方案更靠谱。

总结:核心就是倒排索引加集合操作。

回到顶部