RediSearch
RediSearch
选方案 A 很对:RediSearch(RedisStack)= 产品化搜索体验,10 万本书不需要下拉框,直接“输入即搜索 + 结果列表”,而且还能做排序、分页、权重、模糊匹配。
下面我给你一套可直接落地的方案:Redis 部署/建索引 → 后端 API → 前端交互。你照着做就能跑。
0)你需要的前提:你的 Redis 必须支持 RediSearch
两条路:
方案 A1:自建 RedisStack(最简单)
用 Docker(推荐):
1 | |
- 6379:应用连接
- 8001:RedisInsight(可视化管理)
方案 A2:用支持 Search 的托管 Redis
比如 Redis Cloud 的某些套餐支持 RediSearch(看产品功能是否含 Search/Query)。
如果你的托管 Redis 不支持模块,那就没法用 FT.* 命令。
你可以在服务器上验证:
1 | |
看到 search/ft 相关模块才算支持。
1)你的数据存储要符合索引规则
你已经在用:
vault:book:meta:<bookAddr>(HASH)
只要你确保这个 HASH 里存在这些字段(并保持一致):
name(书名)author(作者)symbol(书籍代码)serial(序列号)publisher(出版社地址,小写)createdAt(时间戳,可排序)txHash(可选)
并且 key 前缀统一是:
vault:book:meta:✅
那 RediSearch 就能自动索引。
2)创建 RediSearch 索引(一次性执行)
用 redis-cli 跑:
1 | |
解释一下(很关键):
publisher TAG:你可以按 publisher 精确过滤(必须)symbol/serial TAG:代码/序列号精确匹配非常快name/author TEXT:模糊/分词搜索体验好(name 权重更高)createdAt SORTABLE:可以按最新排序
你可以验证索引是否创建成功:
1 | |
3)后端新增 API:GET /api/v1/publisher/books/search
你要的交互是:输入书名/作者/代码 → 搜索 → 返回候选 → 选中 → 生成二维码。
推荐接口
GET /api/v1/publisher/books/search?publisher=0x...&q=xxx&limit=20&offset=0
RediSearch 查询语句(核心)
必须过滤 publisher:
@publisher:{0xabc...}(TAG 过滤)
同时对 name/author/symbol/serial 搜索:
(@name:(xxx*)|@author:(xxx*)|@symbol:{xxx}|@serial:{xxx})
拼成完整 query:
1 | |
Go(go-redis)实现要点
go-redis 没有强类型 FT 接口,但可以用 Do():
1 | |
返回解析会稍麻烦(RediSearch 返回的是数组结构),但这是标准做法。
4)部署成功时:写入 meta(让搜索立刻可用)
你现在部署成功后一定要写:
Key:vault:book:meta:<bookAddrLower>
Fields:至少包含上面索引字段
这样 RediSearch 才能搜到。
这一步是产品化关键:不扫链、不读事件,部署即入库可检索。
5)前端怎么改:下拉框 → 搜索框 + 候选列表
UI 逻辑:
- 一个输入框(至少 2 个字符才触发)
- debounce 300ms
- 请求
/api/v1/publisher/books/search - 返回 items(最多 20 条)
- 渲染列表(书名/作者/symbol/serial)
- 点击某条 →
selectedBookAddr = item.bookAddr - 生成二维码时用
contract = selectedBookAddr
交互体验建议
输入框 placeholder:
输入书名 / 作者 / 代码 / serial列表每条显示:
《name》 - author (symbol / serial)
选中后显示一个 “已选择:xxx” 的 badge
再点“批量生成二维码”
6)10 万本是否扛得住?
扛得住,而且是 RediSearch 的典型场景:
- 过滤 publisher 后再搜:规模立刻缩小
- 返回 limit=20:传输很小
- 支持排序(createdAt DESC)体验很好
你未来要做“全站搜索/多出版社搜索”,也可以加权限/租户隔离,方案不变。
7)你现在需要我给你“可运行的后端文件 + 前端文件”吗?
我可以直接给你两份可下载、可运行的补丁文件:
publisher.go:新增GetPublisherBooksSearch(/api/v1/publisher/books/search)- 部署成功写入
vault:book:meta:<bookAddr>
Publisher.tsx:把下拉框换成搜索选择
但有个现实限制:你之前有些上传文件在会话里会过期(你也见到过这种提示)。为了我能把代码“精准地插进你现有项目结构”并保证一次编译通过,你把下面两个文件再上传一下(就这两个):
- 你当前后端在用的
internal/handlers/publisher.go(最新版) - 你当前前端在用的
src/pages/Publisher.tsx(最新版)
我拿到后会直接输出:
[Download publisher.go][Download Publisher.tsx]
并告诉你main.go要加哪两行路由。
你现在就可以先做的事情(不等我改文件也能推进)
- 在 Redis 上跑
FT.CREATE idx:books ... - 用
redis-cli试一下搜索是否返回结果:
举例:
1 | |
如果能返回,说明 Redis 侧 OK,接下来就是接 API + 前端。
你把两份文件上传后,我就把“完整可运行版本”直接给你。
如果我自建这个服务,那本地的redis数据库是不是用不了了?
docker run -d –name redisstack
-p 6379:6379 -p 8001:8001
redis/redis-stack:latest 如果我自建这个服务,那本地的redis数据库是不是用不了了?
不会“用不了”,但会冲突:你现在机器上如果已经有一个 Redis 在占用 6379,你再 docker run -p 6379:6379 会出现 端口占用,新容器起不来(或你得先停掉旧 Redis)。
你有三种常用做法,按产品化推荐顺序给你:
方案 1(推荐):RedisStack 用不同端口,不影响你现有 Redis
把容器的 6379 映射到主机的 6380(或任意空闲端口):
1 | |
这时:
- 你原来的 Redis:还是
localhost:6379(完全不动) - RedisStack(带 Search):
localhost:6380 - RedisInsight:
http://<服务器IP>:8001
你的后端要用 Search 就把 Redis 地址改成 localhost:6380(或只把需要 Search 的服务指向它)。
方案 2:直接替换掉本机 Redis(如果你不需要保留原 Redis)
如果你愿意让 RedisStack 成为“唯一 Redis”,可以:
- 停掉旧 Redis(systemd 示例):
1 | |
- 再用 RedisStack 占用 6379:
1 | |
⚠️ 注意:旧 Redis 的数据如果你没迁移/没备份,会“看不到”(因为你换了一个实例)。
方案 3:RedisStack 和旧 Redis 各用一个实例,做“数据迁移/双写”
适合你创业产品演进:
- 先让 RedisStack 跑在
6380 - 你的业务逐步迁移到
6380 - 迁完再切换到
6379
迁移方式:
redis-cli --rdb导出/导入- 或者
redis-shake/redis-migrate-tool(更专业)
你真正关心的点:数据会不会丢?
端口不冲突时(方案 1),不会影响你现有 Redis 数据。
RedisStack 是另一个实例,数据是独立的。
你现在该怎么选?
如果你现在已经在用 localhost:6379 跑业务(读者码/绑定/领奖等都在里面),我强烈建议你:
✅ 先用方案 1(RedisStack 用 6380)
等你验证 Search OK,再决定是否替换到 6379。
两个快速自检命令
1) 看 6379 是否已被占用
1 | |
2) 测试 RedisStack 是否带 RediSearch
(假设你按方案 1 用 6380)
1 | |
看到 search / ft 相关模块,就说明可以用 FT.CREATE / FT.SEARCH。
如果你把你现在后端的 REDIS_ADDR 环境变量值贴一下(例如 localhost:6379 还是别的),我可以告诉你:你应该用方案 1 还是方案 2,以及改哪些配置最省事。
docker环境搭好了
环境搭好啦 ✅(redis-stack 跑在 6380,RedisInsight 在 8001)。
接下来确实需要改 publisher.go,但更准确地说是:你需要两步:
- 让后端连接到 redis-stack(6380)(至少 publisher 相关服务要连这个)
- 在 RedisStack 里创建 RediSearch 索引 + 在部署成功时写 meta 数据,然后新增搜索 API 给前端用
我按你现在的架构给你一个最稳的落地方案(不会影响你原本 6379 的 Redis)。
第一步:后端连到 RedisStack(6380)
你现在后端默认读的是 REDIS_ADDR(你 main.go 里就是这么写的)。
所以你只要把运行服务的环境变量改成:
1 | |
如果你用 systemd/supervisor/docker-compose,就在对应配置里改。
✅ 验证方式:后端启动日志应该还能显示 “Redis 连接成功”,并且你用:
1 | |
应该返回 PONG。
注意:如果你希望“旧业务继续用 6379、只有 publisher 搜索用 6380”,那就要做“双 Redis 客户端”(稍复杂)。创业产品化我建议你逐步迁移到 RedisStack 作为主 Redis。
第二步:创建 RediSearch 索引(只做一次)
在服务器上执行(连接 6380):
1 | |
如果提示 “Index already exists”,说明已经建过,忽略即可。
✅ 检查索引:
1 | |
第三步:修改 publisher.go(你问的重点)
需要改的点有 3 个:
A) 部署成功后,必须写入 meta(让搜索有数据)
部署成功拿到 bookAddr 后写:
HSET vault:book:meta:<bookAddrLower> name author symbol serial publisher createdAt txHash- (可选)你原来的 ZSET 索引也可保留:
ZADD vault:publisher:books:z:<publisher> createdAt bookAddr
这一步做好后,FT.SEARCH 才能搜到书。
B) 新增搜索接口:GET /api/v1/publisher/books/search
后端用:
FT.SEARCH idx:books "<query>" LIMIT offset limit SORTBY createdAt DESC RETURN ...
并且必须带 publisher 过滤:
@publisher:{publisherLower} ...
C) main.go 注册路由
加一行:
1 | |
我现在可以直接给你“可运行 publisher.go”
但要说明一下:你之前一些文件在会话里会过期(工具提示我有过期情况),我这边不能可靠地读取你本机的现有代码状态。
你现在只要把你项目里正在使用的这个文件内容再发我一次(任选一种方式):
backend/internal/handlers/publisher.go(你现在正在用的最新版,直接粘贴或上传)
我就能给你:
- ✅ 完整可运行的
publisher.go(包含SearchPublisherBooks+ 部署写 meta) - ✅ 告诉你 main.go 要加的路由行
- ✅ 给你一个“前端搜索选择书籍 → 再生成 zip”的 Publisher.tsx 改法(可下载)
你可以先自己做一个“是否需要改代码”的快速判断
在 RedisStack 上跑:
1 | |
- 如果返回 0 条:说明你还没有把
vault:book:meta:*写到 6380(或字段不对) - 如果能返回书:说明 meta 数据已经写对了,你只需要加搜索 API 即可
最关键的一句
是的,你现在需要修改 publisher.go ——因为:
- 你要产品级搜索(FT.SEARCH)
- 你要从“下拉框加载 10 万本”变成“输入联想搜索”
把 publisher.go 上传给我(最新版),我马上给你一个最终可下载、可运行的版本(包含 search API 和 deploy 写索引)。
写入redis数据库的脚本
你这个报错是我上次插入 argparse 代码时缩进没整体缩进进 main(),导致第 64 行的 print(...) 变成“突然缩进”,Python 就直接 IndentationError 了。
我已经把缩进修好了,并重新生成了一个能直接运行的脚本:
✅ 下载修复版:
下载 generate_vault_data.redisstack.fixed.py
你怎么用(写入 redis-stack 6380)
在你的服务器上执行:
1 | |
默认会连:
- host:
127.0.0.1 - port:
6380 - db:
0
如果你想显式指定(可选):
1 | |
验证是否写进 redis-stack
1 | |
只要数量 > 0 就说明写入成功了。

查询hash
可以的,这个很简单,本质就是:把 tell_me_valid_hash.py 里连 Redis 的地方改成连 6380(redis-stack)。
我已经帮你改好了一个版本,默认直接连:
- host:
127.0.0.1 - port:
6380 - db:
0
并且支持命令行参数/环境变量(和刚才那个脚本一致风格)。
📦 下载修复版:
下载 tell_me_valid_hash.redisstack.py
这个脚本现在做了什么改动
核心就三点:
1. Redis 连接改成可配置(默认 6380)
1 | |
2. main 里用这个 client
1 | |
使用方式
最简单(直接用 redis-stack):
1 | |
如果你想显式指定:
1 | |
或者:
1 | |
如何确认它真的在查 redis-stack?
你可以故意停掉旧 redis(6379),只留 redis-stack:
1 | |
然后跑脚本,如果还能正常输出结果,说明:
这个脚本 100% 在查 6380 的 redis-stack,而不是旧 redis。
工程上非常重要的一点(你现在已经走对路了)
你现在的状态是:
- 旧 redis(6379):历史遗留
- 新 redis-stack(6380):产品级主库 + 搜索引擎
正确做法就是你现在这样:
所有 新脚本、新索引、新业务查询 → 全部指向 6380
旧 6379 慢慢淘汰
这是非常标准的 “生产系统迁移姿势”,不是 hack,是正统工程做法。
python tell_me_valid_hash.redisstack.py