Go-Redis × RediSearch 全流程实践

1. 连接 Redis

go 复制代码
ctx := context.Background()

rdb := redis.NewClient(&redis.Options{
	Addr:     "localhost:6379",
	Password: "",
	DB:       0,
	Protocol: 2,           // 推荐 RESP2
	// UnstableResp3: true, // 若要体验 RESP3 + Raw*
})

2. 准备示例数据

go 复制代码
user1 := map[string]interface{}{
	"name":  "Paul John",
	"email": "paul.john@example.com",
	"age":   42,
	"city":  "London",
}
user2 := map[string]interface{}{
	"name":  "Eden Zamir",
	"email": "eden.zamir@example.com",
	"age":   29,
	"city":  "Tel Aviv",
}
user3 := map[string]interface{}{
	"name":  "Paul Zamir",
	"email": "paul.zamir@example.com",
	"age":   35,
	"city":  "Tel Aviv",
}

3. 为 JSON 数据建索引

go 复制代码
_, err := rdb.FTCreate(
	ctx, "idx:users",
	&redis.FTCreateOptions{
		OnJSON: true,                   // 针对 JSON
		Prefix: []interface{}{"user:"},// 仅索引 user:* 键
	},
	// schema
	&redis.FieldSchema{              // 全文本字段
		FieldName: "$.name",
		As:        "name",
		FieldType: redis.SearchFieldTypeText,
	},
	&redis.FieldSchema{              // TAG 用于精确匹配/聚合
		FieldName: "$.city",
		As:        "city",
		FieldType: redis.SearchFieldTypeTag,
	},
	&redis.FieldSchema{              // 数值范围查询
		FieldName: "$.age",
		As:        "age",
		FieldType: redis.SearchFieldTypeNumeric,
	},
).Result()
if err != nil { panic(err) }

写入 JSON 文档

go 复制代码
_, _ = rdb.JSONSet(ctx, "user:1", "$", user1)
_, _ = rdb.JSONSet(ctx, "user:2", "$", user2)
_, _ = rdb.JSONSet(ctx, "user:3", "$", user3)

RediSearch 监听 user: 前缀,写入即自动索引。

4. 查询示例

4.1 复合搜索

go 复制代码
res, _ := rdb.FTSearch(ctx,
	"idx:users",
	"Paul @age:[30 40]",
).Result()

fmt.Printf("匹配总数:%d\n", res.Total)

4.2 指定返回字段(RETURN

go 复制代码
cities, _ := rdb.FTSearchWithArgs(
	ctx, "idx:users", "Paul",
	&redis.FTSearchOptions{
		Return: []redis.FTSearchReturn{
			{FieldName: "$.city", As: "city"},
		},
	},
).Result()

for _, d := range cities.Docs {
	fmt.Println(d.Fields["city"])
}
// London / Tel Aviv

4.3 仅计数不取文档

go 复制代码
cnt, _ := rdb.FTSearchWithArgs(
	ctx, "idx:users", "Paul",
	&redis.FTSearchOptions{CountOnly: true},
).Result()
fmt.Println(cnt.Total) // 输出 2

4.4 聚合:统计每个城市的用户数

go 复制代码
agg, _ := rdb.FTAggregateWithArgs(
	ctx, "idx:users", "*",
	&redis.FTAggregateOptions{
		GroupBy: []redis.FTAggregateGroupBy{
			{
				Fields: []interface{}{"@city"},
				Reduce: []redis.FTAggregateReducer{
					{Reducer: redis.SearchCount, As: "count"},
				},
			},
		},
	},
).Result()

for _, row := range agg.Rows {
	fmt.Printf("%s - %v\n", row.Fields["city"], row.Fields["count"])
}
// London - 1
// Tel Aviv - 2

5. 切换到 Hash 模式的差异

  1. 建索引
go 复制代码
_, err := rdb.FTCreate(
	ctx, "hash-idx:users",
	&redis.FTCreateOptions{
		OnHash: true,
		Prefix: []interface{}{"huser:"},
	},
	&redis.FieldSchema{FieldName: "name", FieldType: redis.SearchFieldTypeText},
	&redis.FieldSchema{FieldName: "city", FieldType: redis.SearchFieldTypeTag},
	&redis.FieldSchema{FieldName: "age",  FieldType: redis.SearchFieldTypeNumeric},
).Result()

OnHash:true不需要 As 别名------字段名即 Hash 的 key。

  1. 写入数据
go 复制代码
rdb.HSet(ctx, "huser:1", user1)
rdb.HSet(ctx, "huser:2", user2)
rdb.HSet(ctx, "huser:3", user3)
  1. 查询语法相同,但结果字段直接展开:
go 复制代码
docs, _ := rdb.FTSearch(ctx,
	"hash-idx:users",
	"Paul @age:[30 40]",
).Result()
fmt.Println(docs.Docs[0].Fields["city"]) // 直接获取 city

6. 常见坑位

问题 解决方案
返回 "dialect version not supported" 显式升级 RediSearch ≥ 2.4,或在服务器 FT.CONFIG SET DEFAULT_DIALECT 2
Cannot create index while write traffic is on 在生产写高峰创建索引时加 FT.CREATE ... ON JSON ... STOPWORDS 0 或使用 FT.ALTER 增量添加字段
RESP3 报 unsupported 使用 Protocol:2,或启用 UnstableResp3 并用 RawResult() 解析
查询结果字段在 $ 键下 这是 JSON 模式的设计:所有字段存入 Fields["$"] 字符串里,需要二次解析或用 RETURN $.field

7. 结语

通过 FTCreate → FTSearch → FTAggregate 等指令,Redis 在单节点即可完成近实时全文搜索与 OLAP 式聚合。

配合 go-redis,你可以:

  • 统一接口同时操作 JSON 与 Hash;
  • 利用 RETURN / CountOnly / GROUPBY 精确控制返回量;
  • 轻松在 Go 服务中嵌入"搜索引擎 + KV 存储"二合一的能力。

赶快复制示例代码试一把,让你的业务查询飞起来 🚀

相关推荐
秦禹辰15 分钟前
开源多场景问答社区论坛Apache Answer本地部署并发布至公网使用
开发语言·后端·golang
数据知道2 小时前
Go基础:常用数学函数处理(主要是math包rand包的处理)
开发语言·后端·golang·go语言
学习同学2 小时前
从0到1制作一个go语言服务器 (一) 配置
服务器·开发语言·golang
数据知道3 小时前
Go基础:文件与文件夹操作详解
开发语言·后端·golang·go语言
gopyer3 小时前
180课时吃透Go语言游戏后端开发2:Go语言中的变量
开发语言·游戏·golang·游戏后端开发
麦兜*5 小时前
Redis 7.0 新特性深度解读:迈向生产级的新纪元
java·数据库·spring boot·redis·spring·spring cloud·缓存
AAA修煤气灶刘哥5 小时前
Redis为什么快??3 个底层逻辑拆明白,性能优化不用瞎折腾
redis·后端·架构
坐吃山猪6 小时前
Redis03-缓存知识点
redis·缓存
学历真的很重要6 小时前
Claude Code 万字斜杠命令指南
后端·语言模型·面试·职场和发展·golang·ai编程
会跑的葫芦怪9 小时前
Go语言net/http库使用详解
http·golang·iphone