如何使用RediSearch与RedisJSON创建索引并按日期条件查询文档?
我通过RedisJSON存储了如下JSON格式数据,希望使用RediSearch根据输入条件查询特定记录。
示例数据:
{ "Ticker": "AAPL", "Name": "Apple Inc.", "returns": [ { "Range": { "Begin": "9/6/2014", "End": "4/5/2020"}, "Value": "0.0231"}, { "Range": { "Begin": "11/12/2011", "End": "14/9/2021"}, "Value": "1.455"}, { "Range": { "Begin": "1/2/2016", "End": "25/7/2022"}, "Value": "0.436"}, { "Range": { "Begin": "24/6/2012", "End": "18/5/2016"}, "Value": "2.756"}, { "Range": { "Begin": "14/8/2017", "End": "8/7/2020"}, "Value": "0.945"}, { "Range": { "Begin": "9/12/2019", "End": "22/10/2015"}, "Value": "4.256"} ] }
比如输入日期1/1/2015时,需要返回Range.Begin早于该日期的记录:
{ "Range": { "Begin": "9/6/2014", "End": "4/5/2020"}, "Value": "0.0231"}, { "Range": { "Begin": "11/12/2011", "End": "14/9/2021"}, "Value": "1.455"}, { "Range": { "Begin": "24/6/2012", "End": "18/5/2016"}, "Value": "2.756"}
请问如何创建满足该需求的RediSearch索引?另外,所有JSON值均为字符串,若将日期改为11122011这类数值形式,能否实现比较?
解决方案
1. 处理现有字符串格式日期(dd/mm/yyyy)
RedisSearch无法直接识别dd/mm/yyyy格式的字符串并做正确的日期比较——字符串排序逻辑和日期先后完全不匹配(比如1/2/2016字符串排序会比9/6/2014靠前,但实际日期更晚)。必须先把日期转换成可排序的格式,再创建索引:
步骤1:更新JSON数据
把每个Range.Begin和Range.End转换成Unix时间戳(数值型)或者yyyy-mm-dd格式的字符串(可排序),新增字段存到JSON里。比如给每个returns元素加个BeginTS字段存时间戳:
{ "Range": { "Begin": "9/6/2014", "BeginTS": 1407302400, "End": "4/5/2020"}, "Value": "0.0231"}
步骤2:创建RediSearch索引
针对数组里的BeginTS字段创建NUMERIC类型索引,同时可以按需添加其他字段的索引:
FT.CREATE stock_index ON JSON PREFIX 1 stock: SCHEMA $.returns[*].Range.BeginTS AS begin_ts NUMERIC $.returns[*].Value AS return_value NUMERIC $.Ticker AS ticker TAG
步骤3:执行查询
把目标日期1/1/2015转成Unix时间戳(比如1420070400),用FT.SEARCH筛选begin_ts小于该值的记录,指定返回需要的字段:
FT.SEARCH stock_index "*" FILTER "@begin_ts < 1420070400" RETURN 3 $.returns[*].Range $.returns[*].Value
2. 关于改为11122011这类数值格式的问题
如果只是改成ddmmyyyy的数值(比如11122011代表2011-12-11),不能实现正确的日期比较——因为数值大小和日期先后不对应:比如01012015(2015-01-01)的数值是1012015,而09062014(2014-06-09)是9062014,数值上前者更小,但实际日期更晚,筛选结果会完全错误。
但如果改成yyyymmdd的数值格式(比如20111211),数值大小就和日期先后完全一致了,这时候可以直接创建NUMERIC索引:
FT.CREATE stock_index ON JSON PREFIX 1 stock: SCHEMA $.returns[*].Range.Begin AS begin_date NUMERIC
查询时把目标日期转成yyyymmdd数值(比如20150101),执行:
FT.SEARCH stock_index "@begin_date:[0 20150101]" RETURN 0 $.returns[*]
这样就能正确筛选出Begin早于目标日期的记录。
总结
- 原
dd/mm/yyyy字符串日期必须转成可排序格式(Unix时间戳、yyyy-mm-dd字符串、yyyymmdd数值)才能用RediSearch做正确的日期筛选。 ddmmyyyy数值格式不适合日期比较,yyyymmdd数值格式可以直接用NUMERIC索引实现需求。
内容的提问来源于stack exchange,提问作者Gowthamss

