查看: 63|回复: 0

[Redis] Redis 数值范围查询(Numeric Range Queries)的实现

[复制链接]

0

主题

0

回帖

0

积分

积极分子

金币
0
阅读权限
220
精华
0
威望
0
贡献
0
在线时间
0 小时
注册时间
2008-10-8
发表于 2025-11-13 09:33:19 | 显示全部楼层 |阅读模式

一、基本语法

1. 普通范围查询

使用查询字符串语法,将字段名及上下界写在一对方括号内:

FT.SEARCH idx "@field:[start end]"
  • startend 默认均包含(inclusive)。
  • 例如,检索价格在 500 到 1000 区间的商品:
FT.SEARCH idx:bicycle "@price:[500 1000]"

2. 排除边界

若要排除上(或下)界,在该值前加左括号 (

FT.SEARCH idx "@price:[(1000 +inf]"
  • 上例匹配 price > 1000
  • -inf / +inf 可用于定义“下不封顶”或“上不封顶”的开/闭区间。

二、FILTER 与执行计划差异

除了在查询字符串中直接指定范围,还可借助 FILTER 子句:

FT.SEARCH idx "*" FILTER price 500 1000
  • FILTER 会在查询解析(如全文 *)完成后再执行数值过滤。
  • 当索引包含数值字段且仅依赖数值过滤时,若直接在查询字符串中指定范围,RediSearch 能利用索引跳过不匹配文档,性能通常更佳;
  • 若查询中包含复杂子句或聚合,FILTER 提供了灵活的后置过滤方案。

三、排序与分页

1. SORTBY

默认情况下,结果按文档出现顺序返回。可用 SORTBY 按数值字段排序:

FT.SEARCH idx:bicycle "@price:[-inf 2000]" 
  SORTBY price ASC
  LIMIT 0 5
  • ASC / DESC 指定升序或降序。
  • 未显式排序时,可视为按文档 ID 或添加顺序返回。

2. LIMIT

  • LIMIT offset count 控制返回窗口,实现分页或“滚动”访问大结果集;
  • Redis 默认只返回前 10 条,若需完整结果,务必配合 LIMIT

四、典型示例

假设已创建如下索引:

FT.CREATE idx:bicycle ON JSON PREFIX 1 bicycle:
  SCHEMA $.price AS price NUMERIC SORTABLE
         $.brand AS brand TEXT SORTABLE
         $.model AS model TEXT SORTABLE

并已插入若干文档。

示例1:500 ≤ price ≤ 1000

FT.SEARCH idx:bicycle "@price:[500 1000]"

示例2:price > 1000

FT.SEARCH idx:bicycle "@price:[(1000 +inf]"

示例3:price ≤ 2000,返回最便宜的 5 辆

FT.SEARCH idx:bicycle "@price:[-inf 2000]"
  SORTBY price ASC
  LIMIT 0 5

示例4:使用 FILTER(等价于示例1)

FT.SEARCH idx:bicycle "*" FILTER price 500 1000

五、多语言客户端示例

以下以 Python 和 Go 为例,展示如何在客户端执行数值范围查询。

Python(redis-py + redisearch-py)

from redis import Redis
from redis.commands.search.field import NumericField, TextField
from redis.commands.search.query import Query

r = Redis()
# 假设已创建索引

q = Query("@price:[500 1000]").sort_by("price", asc=True).paging(0, 10)
res = r.ft("idx:bicycle").search(q)
print(res.total, res.docs)

Go(go-redis + redisearch)

import (
    "fmt"
    "github.com/RediSearch/redisearch-go/redisearch"
)

client := redisearch.NewClient("localhost:6379", "idx:bicycle")

// 构造查询:500 <= price <= 1000,按 price 升序,返回前 10 条
q := redisearch.NewQuery("@price:[500 1000]").
    SortBy("price", true).
    Limit(0, 10)

docs, total, err := client.Search(q)
if err != nil {
    panic(err)
}
fmt.Printf("匹配 %d 条,结果:%v\n", total, docs)

六、最佳实践

  1. 字段声明时加 SORTABLE
    使 SORTBY 与范围过滤都能利用压缩索引,高效跳过不匹配文档。

  2. 尽量在查询字符串中指定范围
    直接使用 @field:[a b],避免 FILTER 的后置过滤带来的额外扫描。

  3. 分页与并发拉取
    对于百万级以上结果集,避免一次性拉取所有结果,用 LIMIT 分页,并发执行多次查询或使用游标。

  4. 监控查询性能
    通过 FT.INFO idx 查看索引 cardinality、统计信息;用 LATENCY 命令监控查询延迟分布。

  5. 结合其他索引类型
    可将数值过滤与全文(TEXT)、标签(TAG)、地理(GEO)等条件组合,使用布尔子句优化多维度查询。

七、常见误区

  • 误用通配符 * 加 FILTER
    FT.SEARCH idx "*" FILTER price x y 等价于全表扫描再过滤,性能逊于直接 @price:[x y]
  • 忽略 SORTABLE
    未加 SORTABLE 的数值字段无法在查询时高效排序或范围扫描。
  • 忘记 LIMIT
    默认只返回前 10 条,若需遍历后续结果,务必使用 LIMIT offset count

八、总结

Redis 数值范围查询提供了简洁灵活的语法和高效的执行性能。通过在索引设计阶段添加 NUMERIC SORTABLE,在查询时优先使用 @field:[a b],并结合 SORTBYLIMIT,即可在大规模数据集上快速完成价格区间、阈值筛选等场景下的检索需求。配合监控与索引优化,你将获得更稳定、更低延迟的数值范围查询体验。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

相关侵权、举报、投诉及建议等,请发 E-mail:qiongdian@foxmail.com

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部