我有这样的数据模型:
字段:
当前的数据结构组织是这样的(根和多子格式):
counter_num + counter_code
---> start_date + end_date --> xxxxxxxx
---> start_date + end_date --> xxxxxxxx
---> start_date + end_date --> xxxxxxxx
示例:
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
今天,检索以两种方式进行:
//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)
在redis中建模的最佳方式是什么,因为我需要缓存一些频繁访问的数据。我觉得排序集应该以某种方式做到这一点,但无法对其进行建模。
更新
为了消除这种混淆,这里的问题不适用于SQL&#34; BETWEEN&#34;喜欢查询。 &#39;因为我不知道start_date和end_date值是什么。认为它们只是列名。
我不想要的是
SELECT * FROM redis_db
WHERE counter_num AND
date_value BETWEEN start_date AND end_date
我想要的是
SELECT * FROM redis_db
WHERE counter_num AND
start_date <= specifc_date AND end_date >= specific_date
注意:该要求非常接近Redis多维索引文档中提议的二维索引
https://redis.io/topics/indexes#multi-dimensional-indexes
我理解了这个概念但无法消化给出的实现细节。
答案 0 :(得分:3)
由于您的问题对于查询数据的方式仍然有点模糊,因此仍然不清楚如何解决您的问题。但是,考虑到这一点,以下是我对如何建模数据的想法:
我编辑了这个答案,以便能够以动态日期范围查询的方式存储您的值。此编辑假定您的数据库值是时间戳,因为值是一次,而不是2,就像在当前设置中一样。
是的,你是正确的,使用排序集将能够实现这一点。我建议你总是在这些有序集合中为得分组件使用Unix时间戳值。
如果您还不熟悉redis,请解释索引限制。 Redis是一个简单的键值,旨在通过键快速检索值。由于这种设计,它不包含传统DBMS的许多功能,例如索引列。
在redis中,您可以使用键完成索引,并且HASH和SORTED SET中可以使用嵌套最多的类似键的结构,但是您只能获得2个类似键的结构。在HASH中,您拥有密钥(与任何数据类型相同)和内部哈希密钥,它可以采用任何字符串的形式。
在SORTED SET中,您拥有密钥(与任何数据类型相同)和数值。
使用HASH很好地保持分组数据的组织。
如果您想通过一系列值进行查询,那么SORTED SET很不错。这可能非常适合您的数据。
您的SORTED SET
将如下所示:
key
00888:XA =>
score (date value) value
1452427200 (2016-01-10) xxxxxxxx
1452859200 (2016-01-10) yyyyxxxx
1453291200 (2016-01-10) zzzzxxxx
让我们使用一个更直观的例子,2017年尤文图斯名单:
要在下表中生成SORTED SET,请在redis客户端中发出以下命令:
ZADD JUVENTUS 32 "Emil Audero" 1 "Gianluigi Buffon" 42 "Mattia Del Favero" 36 "Leonardo Loria" 25 "Neto" 15 "Andrea Barzagli" 4 "Medhi Benatia" 19 "Leonardo Bonucci" 3 "Giorgio Chiellini" 40 "Luca Coccolo" 29 "Paolo De Ceglie" 26 "Stephan Lichtsteiner" 12 "Alex Sandro" 24 "Daniele Rugani" 43 "Alessandro Semprini" 23 "Dani Alves" 22 "Kwadwo Asamoah" 7 "Juan Cuadrado" 6 "Sami Khedira" 18 "Mario Lemina" 46 "Mehdi Leris" 38 "Rolando Mandragora" 8 "Claudio Marchisio" 14 "Federico Mattiello" 45 "Simone Muratore" 20 "Marko Pjaca" 5 "Miralem Pjanic" 28 "Tomás Rincón" 27 "Stefano Sturaro" 21 "Paulo Dybala" 9 "Gonzalo Higuaín" 34 "Moise Kean" 17 "Mario Mandzukic"
Jersey Name Jersey Name
32 Emil Audero 23 Dani Alves
1 Gianluigi Buffon 42 Mattia Del Favero
36 Leonardo Loria 25 Neto
15 Andrea Barzagli 4 Medhi Benatia
19 Leonardo Bonucci 3 Giorgio Chiellini
40 Luca Coccolo 29 Paolo De Ceglie
26 Stephan Lichtsteiner 12 Alex Sandro
24 Daniele Rugani 43 Alessandro Semprini
22 Kwadwo Asamoah 7 Juan Cuadrado
6 Sami Khedira 18 Mario Lemina
46 Mehdi Leris 38 Rolando Mandragora
8 Claudio Marchisio 14 Federico Mattiello
45 Simone Muratore 20 Marko Pjaca
5 Miralem Pjanic 28 Tomás Rincón
27 Stefano Sturaro 21 Paulo Dybala
9 Gonzalo Higuaín 34 Moise Kean
17 Mario Mandzukic
通过一系列球衣号码查询名单:
ZRANGEBYSCORE JUVENTUS 1 5
Output:
1) "Gianluigi Buffon"
2) "Giorgio Chiellini"
3) "Medhi Benatia"
4) "Miralem Pjanic"
请注意,不会返回分数,但ZRANGEBYSCORE
命令会按分数按ASC顺序排序结果。
要添加分数,请附加&#34; WITHSCORES&#34;命令如下:ZRANGEBYSCORE JUVENTUS 1 5 WITHSCORES
通过使用ZRANGEBYSCORE,您应该能够查询具有日期范围的任何密钥(计数器编号+计数器代码), 产生该范围内的值。
根据您的示例,我建议您使用HASH
。
使用哈希,您将有一个主键来查找哈希值(例如00888:XA
)。然后在哈希中,你有密钥 - &gt;价值对(例如2017-01-10:2017-01-20
- &gt; xxxxxxxx
)。我更喜欢划分或标记我的密钥&#39;具有冒号char :
的组件,但您可以使用任何分隔符。
HASH
非常符合您的示例数据结构:
key
00888:XA =>
hashkey value
2017-01-10:2017-01-20 xxxxxxxx
2017-01-21:2017-01-31 yyyyxxxx
2016-02-01:2016-12-31 zzzzxxxx
key
00888:ZI =>
hashkey value
2017-01-10:2017-01-20 xxxxxxxx
2017-01-21:2017-01-31 xxxxyyyy
2016-02-01:2016-12-31 xxxxzzzz
在查询数据时,您将使用GET key
进行查询,而不是HGET key hashkey
。设置值相同,而不是SET key value
,请使用HSET key hashkey value
。
示例命令
HSET 00777:XA 2017-01-10:2017-01-20 xxxxxxxx
HSET 00777:XA 2017-01-21:2017-01-31 yyyyyyyy
HSET 00777:XA 2016-02-01:2016-12-31 zzzzzzzz
(注意:还有HMSET
将其简化为单个命令)
然后:
HGET 00777:XA 2017-01-21:2017-01-31
会返回yyyyyyyy
除非您的数据有某些特定的性能考虑因素或其他目标,否则我认为Hashes将非常适合您的系统。
如果您想使用HKEYS
,HVALS
或HGETALL
等命令获取给定哈希的所有哈希密钥或所有值,这也非常方便。
答案 1 :(得分:3)
我不太可能及时为赏金做到这一点,但到底是什么......
这听起来像是一个地理位置的工作。当您想要索引二维(或更高)数据集时,您将执行Geohashing。例如,如果您有城市数据库,并且希望能够快速响应诸如“查找距离X 50公里范围内的所有城市”之类的查询,则可以使用地理位置。
出于此问题的目的,您可以将start_date
和end_date
视为x
和y
坐标。通常在地理分析中,您在数据集中搜索空间中特定点附近或某个有界空间区域中的点。在这种情况下,您只需在其中一个坐标上设置下限,在另一个坐标上设置上限。但我认为实际上整个数据集都是有界限的,所以这不是问题。
如果在Redis中有一个用于执行此操作的库,那将会很好。如果你足够努力,可能会有。较新版本的Redis具有内置的geohashing功能。请参阅以GEO
开头的命令。但它并没有声称是非常准确的,它是专为球体表面而不是平面设计的。
据我所知,你有3个选择:
GEOSPHERE
,同时考虑内置的不准确性以及通过映射到球体上获得的失真,然后过滤结果以获得实际的结果在三角形里面。如果您有一个使用数字排序索引数据的数据库,那么您可以执行查询,例如“查找z
介于a
和b
之间的所有行/记录“,你可以在它上面构建一个geohash索引。假设坐标是(非负)整数x
和y
。然后添加整数值列z
,并按z
索引。要计算z
,请以二进制形式写入x
和y
,然后从每个中取出备用数字。例如:
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
请注意,索引允许您查找位于z
和0101100000000000000000
之间0101101111111111111111
的所有记录。换句话说,z
以010110
开头的所有记录。或者换句话说,您可以找到x
以001
开头,y
以110
开头的所有记录。这组记录对应于我们试图搜索的二维空间中的一个正方形。
并非所有方格都能以这种方式搜索。我们将这些可搜索的方块称为。假设客户端发送了对(x,y)
在特定矩形内的所有记录的请求。 (或圆形,或其他合理的几何形状。)然后,您需要找到一组覆盖矩形的可搜索方块。然后,对于您选择的每个方块,在数据库中查询该方块内的记录并将结果发送给客户端。 (但你必须过滤结果,因为并非广场上的所有记录都在原始矩形中。)
要取得平衡。如果你选择少量的大型特殊方块,你最终可能会覆盖比你需要的更大的地图区域;对数据库的查询将返回许多您必须过滤掉的额外结果。或者,如果你使用许多小的特殊方块,你将对数据库进行大量的查询,其中许多都不会返回任何结果。
我在上面说x
和y
可能是start_time
和end_time
。但实际上,数据集的分布与大多数geohashing的使用不一样。因此,如果您使用x = end_time + start_time
和y = end_time - start_time
,性能可能会更好(或更糟)。