8

Redis 在概念上与我使用的传统 SQL 数据库不同,我试图弄清楚它是否适合我的项目......我一直在环顾四周,但似乎找不到我的问题的答案。

我有一组需要存储的用户,每个用户都有一个唯一的 ID 和几个与之关联的值(例如他们的名字)。似乎我可以简单地将它们存储为哈希:

user:fef982dcfe1a7bcba4849b4c281bba95
"username" "andrewm" "name" "Andrew"

我还有一堆要存储的消息,每条消息都有一些属性,例如发件人和收件人:

message:1a7bcba4849b4c281bfef98a952dcfeb
"sender" "fef982dcfe1a7bcba4849b4c281bba95" "recipient" "82dcfe1a7bcba4849b4c281bba95fef9" "message" "Hi!"

我的问题是,我将如何检索特定用户(由他们的哈希指定)发送的所有消息。我应该改用传统的关系数据库,还是像 MongoDB 这样的 NoSQL 数据库(我以前用过)?如果是这样,有人对高性能商店有什么建议吗?我不会进行任何真正的搜索(即 MySQLLIKE查询)——实际上只是键值查找。

4

2 回答 2

11

当然可以使用 Redis 对这些数据进行建模,但您需要考虑数据结构和访问路径。使用 Redis,访问路径不是隐式管理的(就像 RDBMS/MongoDB 中的索引一样)。

对于提供的示例,您可以:

user:<user hash> -> hash of user properties
user:<user hash>:sent -> set of <msg hash>
user:<user hash>:received -> set of <msg hash>
message:<msg hash> -> hash of message properties

添加/删除消息意味着在添加/删除消息对象本身的基础上维护与发送者和接收者相对应的 *:sent 和 *:received 集。

检索给定用户发送或接收的消息只是一个 SMEMBERS 命令,或者如果您还想同时检索消息的属性,则需要一个 SORT:

# Get a list of message hash codes only in one roundtrip
smembers user:<user hash>:received

# Get a list of message contents in one roundtrip
sort user:<user hash>:received by nosort get message:*->sender get message:*->message

有关使用排序的基本原理,请参见:

注意 1:对于 Redis,最好使用整数作为键而不是 UUID 或哈希码(尤其是在集合中),因为它们以更有效的方式存储。

注意 2:如果您需要对消息进行排序,则必须使用列表而不是集合。结果是只能删除最旧的消息,并且只能以有效的方式添加新消息。您可能还会为所有消息添加一个全局列表。

于 2012-07-01T09:32:37.003 回答
1

Redis的基本数据类型不支持多条件查询、全文搜索等,因此我们对Redis源码进行了修改,通过辅助索引将Redis转化为可以像SQL数据一样使用的数据库。

这个项目主页是https://oncedb.com

OnceDB 不会改变 Redis 的数据存储结构。Redis数据库文件可以直接在OnceDB中操作,然后返回Redis使用。

索引搜索

创建索引

全文搜索的性能很差。您可以通过创建索引来提高性能。方法是为索引字段创建有序列表,然后在进行条件查询时对这些有序列表进行交集查询操作。

# Create hash data
hmset article:001 poster dota visit 21 key js
hmset article:002 poster dota visit 11 key c
hmset article:003 poster like visit 34 key js
hmset article:004 poster like visit 44 key c

然后我们为上述字段创建索引,权重分数设置为:202000201,一个关于时间的整数,值为文章的ID值

# Create indexed
zadd *article.poster:dota 20200201 001 20200201 002
zadd *article.poster:like 20200201 003 20200201 004
zadd *article.key:js 20200201 001 20200201 003
zadd *article.key:c 20200201 002 20200201 004
# "visit" using its value as the weight score
zadd *article.visit 21 001 11 002 34 003 44 004

按索引查询

找到 *article.key:js 和 *article.poster:dota 两个索引的交集,并将它们存储在 *tmp1 有序列表中:

zinterstore *tmp1 2 *article.key:js *article.poster:dota
> 1

然后*tmp1存储满足key=js和poster=dota条件的ID集合:

zrange *tmp1 0 -1
> 001

可以使用 zrangehmget 命令打印对应的 HASH 值:

zrangehmget *tmp1 0 -1 article: key poster
1) 001
2) 40400402
3) js
4) dota
5) 
6) 

结果与直接全文搜索key = js 和poster = dota 一样

hsearch article:* key = js poster = dota
1) article:001
2) js
3) dota

搜索范围

比如要搜索访问次数在20到30之间的数据,key=js,可以通过控制权重来实现

创建临时索引,只取*article.visit的权重和key=js的数据

zinterstore *tmp2 2 *article.key:js *article.visit weights 0 1
> 2

获取 20 到 30 之间的数据

zrangebyscore *tmp2 20 30
> 001

您可以使用 zrangehmgetbyscore 打印相应的哈希数据:

zrangehmgetbyscore *tmp2 20 30 article: key visit
1) 001
2) 21
3) js
4) 21
5) 
6) 

结果与使用全文搜索的结果一致:

hsearch article:* visit >= 20 visit <= 30 key = js
1) article:001
2) 21
3) 
4) js

因为有两个相同的字段,visit> = 20 visit <= 30,所以搜索结果只会输出一个,第三行重复的字段会输出空。

更多OnceDB扩展指令可查看:OnceDB中的搜索、查询、计算、求和指令

自动索引

Redis索引的创建和维护不是很方便。OnceDB 可以选择在数据修改时自动创建辅助索引。

创建索引:upsert schema field operator value ...

使用 upsert / insert / update 指令和特殊运算符自动创建索引:

上面的例子可以写成:

upsert article id @ 001 poster ? dota visit / 21 key ? js
upsert article id @ 002 poster ? dota visit / 11 key ? c
upsert article id @ 003 poster ? like visit / 34 key ? js
upsert article id @ 004 poster ? like visit / 44 key ? c

操作员:

@:主键 ?:组索引 /:排序索引

操作后自动创建索引: *article *article.poster:dota *article.poster:like *article.visit *article.key:js *article.key:c

多条件索引查询:查找schema from to field operator value ...

对于有索引的字段,可以使用 find 命令通过索引字段进行查询。例如查询:key = js 和poster = dota 的数据。您可以使用 ”?” 表示这两个字段是分组索引:

find article 0 -1 key ? js poster ? dota
1) 1
2) article:001
3) js
4) dota

1代表数据总量。如果为-1,则表示使用全文搜索,性能较差。

索引范围查询

您可以添加 @ 来指定索引范围,并使用 + 来指定将哪个索引字段用于分数权重范围。

find article 0@20 -1@30 key ? js visit /+ *
1) 1
2) article:001
3) js
4) 21

删除索引

OnceDB 不存储索引定义。删除时需要手动指明哪些字段包含索引。您需要指定字段名称和索引运算符。

remove article @ 001 key ? poster ? visit /

您还可以自定义索引名称和权重分数。更多说明请参见:OnceDB数据修改和查询帮助文档

于 2020-02-01T10:08:36.780 回答