在分层数据模型中使用Redis进行复合索引

man*_*nth 6 data-modeling redis

我有这样的数据模型:
字段:

  1. 柜台号码(例如00888,00777,00123等)
  2. 计数器代码(例如XA,XD,ZA,SI等)
  3. 开始日期(例如2017-12-31 ...)
  4. 结束日期(例如2017-12-31 ......)
  5. 其他柜台日期(例如xxxxx)

当前的数据结构组织是这样的(根和多子格式):

counter_num + counter_code
       ---> start_date + end_date --> xxxxxxxx
       ---> start_date + end_date --> xxxxxxxx
       ---> start_date + end_date --> xxxxxxxx
Run Code Online (Sandbox Code Playgroud)

例:

00888 + XA
       ---> Jan 10 + Jan 20 --> xxxxxxxx
       ---> Jan 21 + Jan 31 --> xxxxxxxx
       ---> Feb 01 + Dec 31 --> xxxxxxxx

00888 + ZI
       ---> Jan 09 + Feb 24 --> xxxxxxxx
       ---> Feb 25 + Dec 31 --> xxxxxxxx

00777 + XA
       ---> Jan 09 + Feb 24 --> xxxxxxxx
       ---> Feb 25 + Dec 31 --> xxxxxxxx
Run Code Online (Sandbox Code Playgroud)

今天,检索以两种方式进行:

//Fetch unique counter data using all the composite keys
counter_number + counter_code + date (start_date <= date <= end_date)

//Fetch all the counter codes and corresponding data matching the below conditions
counter_number + date (start_date <= date <= end_date)
Run Code Online (Sandbox Code Playgroud)

在redis中对此进行建模的最佳方法是什么,因为我需要缓存一些频繁访问的数据.我觉得排序集应该以某种方式做到这一点,但无法对其进行建模.

更新:

只是为了消除混淆,这里的问题不是针对SQL"BETWEEN"之类的查询.'因为我不知道start_date和end_date值是什么.认为它们只是列名.

我不想要的是

SELECT * FROM redis_db  
WHERE counter_num AND 
date_value BETWEEN start_date AND end_date
Run Code Online (Sandbox Code Playgroud)

我想要的是

SELECT * FROM redis_db
WHERE counter_num AND
start_date <= specifc_date AND end_date >= specific_date
Run Code Online (Sandbox Code Playgroud)

注意:该要求非常接近Redis多维索引文档中提出的2D索引

https://redis.io/topics/indexes#multi-dimensional-indexes

我理解了这个概念但却无法消化给出的实现细节.

Dav*_*ipe 5

我不太可能及时完成这件事以获得赏金,但那又怎么样......

这听起来像是地理哈希的工作。当您想要索引二维(或更高)的数据集时,您需要执行 Geohashing。例如,如果您有一个城市数据库,并且希望能够快速响应“查找 X 50 公里范围内的所有城市”之类的查询,则可以使用 geohashing。

出于此问题的目的,您可以将start_dateend_date视为xy坐标。通常,在地理哈希中,您要搜索数据集中靠近空间中特定点或某个有界空间区域的点。在这种情况下,您只有一个坐标的下限和另一个坐标的上限。但我想实际上整个数据集无论如何都是有界的,所以这不是问题。

如果 Redis 中有一个库可以执行此操作,那就太好了。如果你足够仔细的话,可能是有的。新版本的 Redis 具有内置的地理哈希功能。请参阅以 开头的命令GEO。但它并没有声称非常准确,而且它是为球体表面而不是平面而设计的。

据我所知,你有 3 个选择:

  • 将您的搜索空间映射到球体的一小部分,最好是在赤道附近。使用 Redis GEO 命令。要进行搜索,请使用GEOSPHERE覆盖您要搜索的三角形的圆,同时考虑到内置的不准确性以及通过映射到球体上获得的失真,然后过滤结果以获取实际位于三角形内的结果。
  • 找到一些适用于 Redis 的第三方 geohashing 客户端,它可以在平坦空间上运行,并且比 GEO 更准确。
  • 阅读本答案的其余部分,或其他一些有关 geohashing 的入门读物,然后在 Redis 上自行实现。这是最难(但最具教育意义)的选择。

如果您有一个使用数字排序对数据进行索引的数据库,以便您可以执行“查找介于z和 之间的a所有行/记录b”之类的查询,则可以在其之上构建 geohash 索引。假设坐标是(非负)整数xy。然后添加一个整数值列z和索引z。要计算z,请以二进制形式写出xy,然后从每个数字中取出交替的数字。例子:

x =     969 = 0 1 1 1 1 0 0 1 0 0 1 
y =    1130 =  1 0 0 0 1 1 0 1 0 1 0
z = 1750214 = 0110101011010011000110
Run Code Online (Sandbox Code Playgroud)

请注意,索引允许您查找例如z位于之间01011000000000000000000101101111111111111111包含位置的所有记录。换句话说,所有以z开头的记录010110。或者换句话说,您可以查找x001y开头的所有记录110。这组记录对应于我们要搜索的二维空间中的一个正方形。

并不是所有的方格都可以用这种方式搜索。我们将这些称为可搜索方块。(x,y)假设客户端发送对特定矩形内的所有记录的请求。(或圆形,或其他合理的几何形状。)然后您需要找到一组覆盖矩形的可搜索正方形。然后,对于您选择的每个方块,查询数据库以获取该方块内的记录并将结果发送给客户端。(但是您必须过滤结果,因为并非正方形中的所有记录实际上都在原始矩形中。)

有一个平衡点需要达成。如果您选择少量的大型特殊方块,您最终可能会覆盖比您需要的更大的地图区域;对数据库的查询将返回大量额外的结果,您必须将其过滤掉。或者,如果您使用大量的小特殊方块,您将对数据库进行大量查询,其中许多查询不会返回任何结果。

我上面说过,x并且y可以是start_timeend_time。但实际上,数据集的分布不会像大多数地理哈希的使用那样对称。x = end_time + start_time因此,如果您使用和 ,性能可能会更好(或更差)y = end_time - start_time