Redis数据类型介绍——官网解读

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

Redis Strings


The Redis String type is the simplest type of value you can associate with a Redis key. It is the only data type in Memcached, so it is also very natural for newcomers to use it in Redis.

Redis String 类型是可以与 Redis 键关联的最简单的值类型。它是Memcached中唯一的数据类型,因此对于新手来说,在Redis中使用它也是很自然的。

Since Redis keys are strings, when we use the string type as a value too, we are mapping a string to another string. The string data type is useful for a number of use cases, like caching HTML fragments or pages.

因为 Redis 键是字符串,所以当我们使用字符串类型作为值时,也是将一个字符串映射到另一个字符串。字符串数据类型对于许多用例很有用,比如缓存 HTML 片段或页面。

Let’s play a bit with the string type, using redis-cli (all the examples will be performed via redis-cli in this tutorial).

让我们使用 redis-cli 对字符串类型进行一些操作(在本教程中,所有示例都将通过 redis-cli 执行)。

> set mykey somevalue OK > get mykey "somevalue"

As you can see using the SET and the GET commands are the way we set and retrieve a string value. Note that SET will replace any existing value already stored into the key, in the case that the key already exists, even if the key is associated with a non-string value. So SET performs an assignment.

正如您可以看到的,使用 SET 和 GET 命令是我们设置和检索字符串值的方式。注意,在键已经存在的情况下,SET 将替换已经存储在键中的任何现有值,即使键与非字符串值相关联。通过 SET 执行赋值操作。

Values can be strings (including binary data) of every kind, for instance you can store a jpeg image inside a value. A value can’t be bigger than 512 MB.

Values 值可以是各种类型的字符串(包括二进制数据) ,例如,您可以将 jpeg 图像存储在值中。这个值不能大于512mb。

The SET command has interesting options, that are provided as additional arguments. For example, I may ask SET to fail if the key already exists, or the opposite, that it only succeed if the key already exists:

SET 命令有一些有趣的选项,这些选项作为附加参数提供。例如,如果key已经存在,我可以要求 SET 失败,或者相反,如果key已经存在,SET 才能成功:

> set mykey newval nx (nil) > set mykey newval xx OK

Even if strings are the basic values of Redis, there are interesting operations you can perform with them. For instance, one is atomic increment:

即使字符串是Redis的基本值,您也可以使用它们执行一些有趣的操作。 例如,一个是原子增量:

> set counter 100 OK > incr counter (integer) 101 > incr counter (integer) 102 > incrby counter 50 (integer) 152

The INCR command parses the string value as an integer, increments it by one, and finally sets the obtained value as the new value. There are other similar commands like INCRBYDECR and DECRBY. Internally it’s always the same command, acting in a slightly different way.

INCR 命令将字符串值解析为整数,并将其增加一,最后将获得的值设置为新值。还有其他类似的命令,如 INCRBY、 DECR 和 DECRBY。在内部,它始终是相同的命令,以略有不同的方式行事。

What does it mean that INCR is atomic? That even multiple clients issuing INCR against the same key will never enter into a race condition. For instance, it will never happen that client 1 reads “10”, client 2 reads “10” at the same time, both increment to 11, and set the new value to 11. The final value will always be 12 and the read-increment-set operation is performed while all the other clients are not executing a command at the same time.

INCR 是原子的,这意味着什么?即使是针对同一个key发出 INCR 的多个客户机也永远不会进入竞争状态。例如,客户机1读取“10” ,客户机2同时读取“10” ,两者都增加到11,并将新值设置为11,这种情况永远不会发生。当所有其他客户端不同时执行命令时,最终值始终为12,并执行 read-increment-set 操作。

There are a number of commands for operating on strings. For example the GETSET command sets a key to a new value, returning the old value as the result. You can use this command, for example, if you have a system that increments a Redis key using INCR every time your web site receives a new visitor. You may want to collect this information once every hour, without losing a single increment. You can GETSET the key, assigning it the new value of “0” and reading the old value back.

有许多对字符串进行操作的命令。例如,GETSET 命令为新值设置一个键,并返回旧值作为结果。例如,如果您的系统在每次网站接收到新访问者时使用 INCR 递增一个 Redis key,则可以使用此命令。您可能希望每小时收集一次此信息,而不会丢失任何一个增量。您可以 GETSET 键,将其分配为新值“0” ,然后读回原来的值。

The ability to set or retrieve the value of multiple keys in a single command is also useful for reduced latency. For this reason there are the MSET and MGET commands:

在一个命令中设置或检索多个键值的能力对于减少延迟也很有用。出于这个原因,有 MSET 和 MGET 命令:

> mset a 10 b 20 c 30 OK > mget a b c 1) "10" 2) "20" 3) "30"

When MGET is used, Redis returns an array of values.

使用 MGET 时,Redis 将返回一个值数组。

Altering and querying the key space 改变和查询关键空间


There are commands that are not defined on particular types, but are useful in order to interact with the space of keys, and thus, can be used with keys of any type.

有些命令未在特定类型上定义,但是在与键的空间进行交互时很有用,因此可以与任何类型的键一起使用。

For example the EXISTS command returns 1 or 0 to signal if a given key exists or not in the database, while the DEL command deletes a key and associated value, whatever the value is.

例如,EXISTS 命令返回1或0表示数据库中是否存在给定的键,而 DEL 命令则删除键和关联值,不管该值是什么。

> set mykey hello OK > exists mykey (integer) 1 > del mykey (integer) 1 > exists mykey (integer) 0

From the examples you can also see how DEL itself returns 1 or 0 depending on whether the key was removed (it existed) or not (there was no such key with that name).

从这些示例中,您还可以看到 DEL 本身如何返回1或0,具体取决于键是否被删除(它存在)(没有这样的键名)。

There are many key space related commands, but the above two are the essential ones together with the TYPE command, which returns the kind of value stored at the specified key:

有许多关键的空间相关的命令,但是上面两个命令和 TYPE 命令一起是必不可少的,它返回存储在指定键上的值类型:

> set mykey x OK > type mykey string > del mykey (integer) 1 > type mykey none


Redis expires: keys with limited time to live Redis expires: 存活时间有限的keys


Before continuing with more complex data structures, we need to discuss another feature which works regardless of the value type, and is called Redis expires. Basically you can set a timeout for a key, which is a limited time to live. When the time to live elapses, the key is automatically destroyed, exactly as if the user called the DEL command with the key.

在继续讨论更复杂的数据结构之前,我们需要讨论另一个不管值类型如何都能正常工作的特性,称为 Redis expires。基本上,您可以为一个键设置超时,这是一个有限的生存时间。当生存时间消逝时,key将被自动销毁,就像用户使用key调用 DEL 命令一样。

A few quick info about Redis expires:

一些关于 Redis 的快速信息过期了:

  • They can be set both using seconds or milliseconds precision. 可以使用秒或毫秒精度来设置它们

  • However the expire time resolution is always 1 millisecond. 但是过期时间分辨率始终是1毫秒

  • Information about expires are replicated and persisted on disk, the time virtually passes when your Redis server remains stopped (this means that Redis saves the date at which a key will expire). 有关过期的信息被复制并保留在磁盘上,实际上Redis服务器保持停止状态所经过的时间(这意味着Redis会保存key过期的日期)

Setting an expire is trivial:

设置一个过期是很简单的:

> set key some-value OK > expire key 5 (integer) 1 > get key (immediately) "some-value" > get key (after some time) (nil)

The key vanished between the two GET calls, since the second call was delayed more than 5 seconds. In the example above we used EXPIRE in order to set the expire (it can also be used in order to set a different expire to a key already having one, like PERSIST can be used in order to remove the expire and make the key persistent forever). However we can also create keys with expires using other Redis commands. For example using SET options:

key在两个 GET 调用之间消失,因为第二个调用被延迟了超过5秒。在上面的示例中,我们使用了 EXPIRE 来设置终止(也可以使用它来为已经拥有终止的key设置不同的终止,比如 PERSIST 可以用来移除终止并使key永久持久化)。但是,我们也可以使用其他 Redis 命令创建过期键。例如,使用 SET 选项:

> set key 100 ex 10 OK > ttl key (integer) 9

The example above sets a key with the string value 100, having an expire of ten seconds. Later the TTL command is called in order to check the remaining time to live for the key.

上面的示例设置了一个字符串值为100的键,其过期时间为10秒。稍后调用 TTL 命令以检查key的剩余存活时间。

In order to set and check expires in milliseconds, check the PEXPIRE and the PTTL commands, and the full list of SET options.

为了以毫秒为单位设置和检查过期,请检查 PEXPIRE 和 PTTL 命令,以及 SET 选项的完整列表。

Redis Lists Redis list


To explain the List data type it’s better to start with a little bit of theory, as the term List is often used in an improper way by information technology folks. For instance “Python Lists” are not what the name may suggest (Linked Lists), but rather Arrays (the same data type is called Array in Ruby actually).

为了解释 List 数据类型,最好从一点点理论开始,因为 List 这个术语经常被信息技术人员以不恰当的方式使用。例如,“ Python Lists”并不是名称所暗示的(Linked Lists) ,而是 Arrays (在 Ruby 中,相同的数据类型实际上被称为 Array)。

From a very general point of view a List is just a sequence of ordered elements: 10,20,1,2,3 is a list. But the properties of a List implemented using an Array are very different from the properties of a List implemented using a Linked List.

从非常普遍的观点来看,List 只是一个有序元素的序列: 10,20,1,2,3是一个 List。但是使用 Array 实现的 List 的属性与使用链表实现的 List 的属性非常不同。

Redis lists are implemented via Linked Lists. This means that even if you have millions of elements inside a list, the operation of adding a new element in the head or in the tail of the list is performed in constant time. The speed of adding a new element with the LPUSH command to the head of a list with ten elements is the same as adding an element to the head of list with 10 million elements.

**Redis 列表通过链接列表实现。**这意味着,即使在列表中有数百万个元素,在列表的头部或尾部添加新元素的操作也是在常量时间内执行的。使用 LPUSH 命令向包含10个元素的列表头部添加新元素的速度与向包含1000万个元素的列表头部添加元素的速度相同。

What’s the downside? Accessing an element by index is very fast in lists implemented with an Array (constant time indexed access) and not so fast in lists implemented by linked lists (where the operation requires an amount of work proportional to the index of the accessed element).

缺点是什么?在使用 Array (常量时间索引访问)实现的列表中,按索引访问元素的速度非常快,而在使用链表实现的列表中(其中的操作需要的工作量与被访问元素的索引成比例)则不那么快。

Redis Lists are implemented with linked lists because for a database system it is crucial to be able to add elements to a very long list in a very fast way. Another strong advantage, as you’ll see in a moment, is that Redis Lists can be taken at constant length in constant time.

Redis list 是用链表实现的,因为对于数据库系统来说,能够以非常快的速度将元素添加到一个非常长的列表中是至关重要的。另一个强大的优势,正如你马上就会看到的,是 Redis list 可以在固定时间内获得固定长度。

When fast access to the middle of a large collection of elements is important, there is a different data structure that can be used, called sorted sets. Sorted sets will be covered later in this tutorial.

当快速访问大量元素集合的中间部分很重要时,可以使用一种不同的数据结构,称为排序集。排序集将在本教程后面介绍。

First steps with Redis Lists 使用 Redis list 的第一步


The LPUSH command adds a new element into a list, on the left (at the head), while the RPUSH command adds a new element into a list, on the right (at the tail). Finally the LRANGE command extracts ranges of elements from lists:

LPUSH 命令将新元素添加到左侧的列表中(在头部) ,而 RPUSH 命令将新元素添加到右侧的列表中(在尾部)。最后,LRANGE 命令从 list 中提取元素的范围:

> rpush mylist A (integer) 1 > rpush mylist B (integer) 2 > lpush mylist first (integer) 3 > lrange mylist 0 -1 1) "first" 2) "A" 3) "B"

Note that LRANGE takes two indexes, the first and the last element of the range to return. Both the indexes can be negative, telling Redis to start counting from the end: so -1 is the last element, -2 is the penultimate element of the list, and so forth.

注意,LRANGE 接受两个索引,即要返回的范围的第一个元素和最后一个元素。两个索引都可以是负的,告诉 Redis 从结尾开始计数: -1是最后一个元素,-2是列表的倒数第二个元素,等等。

As you can see RPUSH appended the elements on the right of the list, while the final LPUSH appended the element on the left.

正如您可以看到的,RPUSH 将元素追加到列表的右侧,而最终的 LPUSH 将元素追加到左侧。

Both commands are variadic commands, meaning that you are free to push multiple elements into a list in a single call:

这两个命令都是可变的命令,这意味着您可以在一个调用中将多个元素推入一个列表:

> rpush mylist 1 2 3 4 5 "foo bar" (integer) 9 > lrange mylist 0 -1 1) "first" 2) "A" 3) "B" 4) "1" 5) "2" 6) "3" 7) "4" 8) "5" 9) "foo bar"

An important operation defined on Redis lists is the ability to pop elements. Popping elements is the operation of both retrieving the element from the list, and eliminating it from the list, at the same time. You can pop elements from left and right, similarly to how you can push elements in both sides of the list:

在 Redis 列表中定义的一个重要操作是弹出元素的能力。弹出元素是同时从列表中检索元素和从列表中消除元素的操作。你可以从左边和右边弹出元素,类似于你可以在列表的两边都弹出元素:

> rpush mylist a b c (integer) 3 > rpop mylist "c" > rpop mylist "b" > rpop mylist "a"

We added three elements and popped three elements, so at the end of this sequence of commands the list is empty and there are no more elements to pop. If we try to pop yet another element, this is the result we get:

我们添加了三个元素并弹出了三个元素,因此在这个命令序列的末尾,列表是空的,如果我们尝试弹出另一个元素,没有更多的元素可以弹出。结果如下:

> rpop mylist (nil)

Redis returned a NULL value to signal that there are no elements in the list.

Redis 返回一个 NULL 值,表示列表中没有元素。

Common use cases for lists 列表的常见用例


Lists are useful for a number of tasks, two very representative use cases are the following:

列表对于许多任务是有用的,两个非常具有代表性的用例如下:

  • Remember the latest updates posted by users into a social network. 记住用户发布到社交网络上的最新更新

  • Communication between processes, using a consumer-producer pattern where the producer pushes items into a list, and a consumer (usually a worker) consumes those items and executed actions. Redis has special list commands to make this use case both more reliable and efficient.

  • 使用消费者-生产者模式进行流程之间的通信,其中生产者将项目推送到列表中,而消费者(通常是工人)消耗这些项目和执行的动作。 Redis具有特殊的列表命令,以使此用例更加可靠和高效

For example both the popular Ruby libraries resque and sidekiq use Redis lists under the hood in order to implement background jobs.

例如,流行的 Ruby 库 reque 和 sidekiq 都在引擎盖下使用 Redis 列表来实现后台作业。

The popular Twitter social network takes the latest tweets posted by users into Redis lists.

流行的 Twitter 社交网络把用户发布的最新推文放到 Redis 列表中。

To describe a common use case step by step, imagine your home page shows the latest photos published in a photo sharing social network and you want to speedup access.

为了一步一步地描述一个常见的用例,假设你的主页显示了在照片分享社交网络上发布的最新照片,你想加速访问。

  • Every time a user posts a new photo, we add its ID into a list with 每次用户发布新照片时,我们将其 ID 添加到一个列表中LPUSH.

  • When users visit the home page, we use 当用户访问主页时,我们使用LRANGE 0 9 in order to get the latest 10 posted items. 为了得到最新的10个邮寄项目

Capped lists 有上限的名单


In many use cases we just want to use lists to store the latest items, whatever they are: social network updates, logs, or anything else.

在许多用例中,我们只想使用列表来存储最新的条目,不管它们是什么: 社交网络更新、日志或其他任何东西。

Redis allows us to use lists as a capped collection, only remembering the latest N items and discarding all the oldest items using the LTRIM command.

Redis允许我们将列表用作上限集合,只记住最新的 n 个项目,并使用 LTRIM 命令丢弃所有最旧的项目。

The LTRIM command is similar to LRANGE, but instead of displaying the specified range of elements it sets this range as the new list value. All the elements outside the given range are removed.

LTRIM 命令类似于 LRANGE,但是它没有显示指定的元素范围,而是将这个范围设置为新的列表值。超出给定范围的所有元素都被删除

An example will make it more clear:

举个例子就能更清楚地说明这一点:

> rpush mylist 1 2 3 4 5 (integer) 5 > ltrim mylist 0 2 OK > lrange mylist 0 -1 1) "1" 2) "2" 3) "3"

The above LTRIM command tells Redis to take just list elements from index 0 to 2, everything else will be discarded. This allows for a very simple but useful pattern: doing a List push operation + a List trim operation together in order to add a new element and discard elements exceeding a limit:

上面的 LTRIM 命令告诉 Redis 只从索引0到2获取列表元素,其他所有内容都将被丢弃。这允许一个非常简单但有用的模式: 执行一个 List push 操作 + 一个 List trim 操作,以添加一个新元素并丢弃超过限制的元素:

LPUSH mylist <some element> LTRIM mylist 0 999

The above combination adds a new element and takes only the 1000 newest elements into the list. With LRANGE you can access the top items without any need to remember very old data.

上面的组合添加了一个新元素,并且只将1000个最新元素添加到列表中。使用 LRANGE,您可以访问顶级项目,而不需要记住任何非常旧的数据。

Note: while LRANGE is technically an O(N) command, accessing small ranges towards the head or the tail of the list is a constant time operation.

注意: 虽然 LRANGE 在技术上是一个 o (n)命令,访问列表头部或尾部的小范围是一个常量时间操作。

Blocking operations on lists 对列表进行阻塞操作


Lists have a special feature that make them suitable to implement queues, and in general as a building block for inter process communication systems: blocking operations.

列表有一个特殊的特性,使它们适合于实现队列,并且通常作为进程间通信系统的构建块: 阻塞操作。

Imagine you want to push items into a list with one process, and use a different process in order to actually do some kind of work with those items. This is the usual producer / consumer setup, and can be implemented in the following simple way:

假设您想用一个进程将项目推送到一个列表中,并使用不同的进程来实际处理这些项目。这是通常的生产者/消费者设置,可以用以下简单的方式实现:

  • To push items into the list, producers call 要将项目推入列表,生产者调用LPUSH.

  • To extract / process items from the list, consumers call 要从列表中提取/处理项,使用者调用RPOP.

However it is possible that sometimes the list is empty and there is nothing to process, so RPOP just returns NULL. In this case a consumer is forced to wait some time and retry again with RPOP. This is called polling, and is not a good idea in this context because it has several drawbacks:

然而,有时候列表可能是空的,没有什么需要处理的,所以 RPOP 只返回 NULL。在这种情况下,使用者被迫等待一段时间并使用 RPOP 重试。这就是所谓的轮询,在这种情况下不是一个好主意,因为它有几个缺点:

  1. Forces Redis and clients to process useless commands (all the requests when the list is empty will get no actual work done, they’ll just return NULL). 强制 Redis 和客户端处理无用的命令(当列表为空时,所有的请求都不会完成任何实际的工作,它们只会返回 NULL)

  2. Adds a delay to the processing of items, since after a worker receives a NULL, it waits some time. To make the delay smaller, we could wait less between calls to RPOP, with the effect of amplifying problem number 1, i.e. more useless calls to Redis.

  3. 由于工作人员在收到NULL之后会等待一段时间,因此会增加项目处理的延迟。 为了减小延迟,我们可以在两次调用RPOP之间等待更少的时间,从而扩大了问题编号1,即对Redis的更多无用的调用。

So Redis implements commands called BRPOP and BLPOP which are versions of RPOP and LPOP able to block if the list is empty: they’ll return to the caller only when a new element is added to the list, or when a user-specified timeout is reached.

所以 Redis 实现了命令 BRPOP 和 BLPOP,它们是 RPOP 和 LPOP 的版本,如果列表是空的,它们就可以阻塞: 只有当一个新元素添加到列表中,或者达到用户指定的超时时,它们才会返回给调用者。

This is an example of a BRPOP call we could use in the worker:

这是一个 BRPOP 调用的例子,我们可以在 worker 中使用:

> brpop tasks 5 1) "tasks" 2) "do_something"

It means: “wait for elements in the list tasks, but return if after 5 seconds no element is available”.

它的意思是: “等待列表任务中的元素,但如果5秒后没有元素可用,则返回”。

Note that you can use 0 as timeout to wait for elements forever, and you can also specify multiple lists and not just one, in order to wait on multiple lists at the same time, and get notified when the first list receives an element.

请注意,您可以使用0作为超时来永久等待元素,您还可以指定多个列表,而不是一个,以便在同一时间等待多个列表,并在第一个列表接收到元素时得到通知。

A few things to note about BRPOP:

关于 BRPOP 需要注意的一些事情:

  1. Clients are served in an ordered way: the first client that blocked waiting for a list, is served first when an element is pushed by some other client, and so forth. 以一种有序的方式服务客户端: 阻止等待列表的第一个客户端,当一个元素被其他客户端推送时首先服务,以此类推

  2. The return value is different compared to RPOP: it is a two-element array since it also includes the name of the key, because BRPOP and BLPOP are able to block waiting for elements from multiple lists.

  3. 返回值与RPOP相比有所不同:它是一个包含两个元素的数组,因为它还包含key的名称,因为BRPOP和BLPOP能够阻止等待来自多个列表的元素。

  4. If the timeout is reached, NULL is returned. 如果超时达到,则返回 NULL

There are more things you should know about lists and blocking ops. We suggest that you read more on the following:

关于列表和阻塞操作,还有更多的事情你应该知道。我们建议你更多地阅读以下内容:

  • It is possible to build safer queues or rotating queues using 可以使用以下方法构建更安全的队列或旋转队列LMOVE.

  • There is also a blocking variant of the command, called 还有一个命令的阻塞变体,称为BLMOVE.

Automatic creation and removal of keys 自动创建和删除键


So far in our examples we never had to create empty lists before pushing elements, or removing empty lists when they no longer have elements inside. It is Redis’ responsibility to delete keys when lists are left empty, or to create an empty list if the key does not exist and we are trying to add elements to it, for example, with LPUSH.

到目前为止,在我们的示例中,我们从未在推入元素之前创建空列表,或者在空列表中不再有元素时移除空列表。当列表为空时,Redis 有责任删除键; 如果键不存在,Redis 有责任创建一个空列表,并且我们正在尝试向其中添加元素,例如,使用 LPUSH。

This is not specific to lists, it applies to all the Redis data types composed of multiple elements – Streams, Sets, Sorted Sets and Hashes.

这并不特定于列表,它适用于由多个元素组成的所有 Redis 数据类型—— Streams、 Sets、 Sorted Sets 和 hash。

Basically we can summarize the behavior with three rules:

基本上,我们可以用三条规则来总结这种行为:

  1. When we add an element to an aggregate data type, if the target key does not exist, an empty aggregate data type is created before adding the element. 当我们向聚合数据类型添加元素时,如果目标键不存在,则在添加元素之前创建一个空的聚合数据类型

  2. When we remove elements from an aggregate data type, if the value remains empty, the key is automatically destroyed. The Stream data type is the only exception to this rule. 当我们从聚合数据类型中删除元素时,如果值仍然为空,则键将自动销毁。Stream 数据类型是此规则的唯一例外

  3. Calling a read-only command such as LLEN (which returns the length of the list), or a write command removing elements, with an empty key, always produces the same result as if the key is holding an empty aggregate type of the type the command expects to find.

  4. 调用带有空键的只读命令(例如LLEN(返回列表的长度))或写命令删除元素,命令希望找到 总是产生与键保持空的聚合类型相同的结果。

Examples of rule 1:

规则1的例子:

> del mylist (integer) 1 > lpush mylist 1 2 3 (integer) 3

However we can’t perform operations against the wrong type if the key exists:

但是,如果键存在,我们不能对错误的类型执行操作:

> set foo bar OK > lpush foo 1 2 3 (error) WRONGTYPE Operation against a key holding the wrong kind of value > type foo string

Example of rule 2:

规则2的例子:

> lpush mylist 1 2 3 (integer) 3 > exists mylist (integer) 1 > lpop mylist "3" > lpop mylist "2" > lpop mylist "1" > exists mylist (integer) 0

The key no longer exists after all the elements are popped.

在弹出所有元素后,键不再存在。

Example of rule 3:

规则3的例子:

> del mylist (integer) 0 > llen mylist (integer) 0 > lpop mylist (nil)

Redis Hashes Redis hash


Redis hashes look exactly how one might expect a “hash” to look, with field-value pairs:

通过字段值对,Redis 散列看起来就像是一个“散列” :

> hmset user:1000 username antirez birthyear 1977 verified 1 OK > hget user:1000 username "antirez" > hget user:1000 birthyear "1977" > hgetall user:1000 1) "username" 2) "antirez" 3) "birthyear" 4) "1977" 5) "verified" 6) "1"

While hashes are handy to represent objects, actually the number of fields you can put inside a hash has no practical limits (other than available memory), so you can use hashes in many different ways inside your application.

虽然哈希表示对象很方便,但实际上可以放在哈希中的字段数没有实际限制(除了可用内存) ,因此可以在应用程序中以多种方式使用哈希。

The command HMSET sets multiple fields of the hash, while HGET retrieves a single field. HMGET is similar to HGET but returns an array of values:

命令 HMSET 设置哈希的多个字段,而 HGET 检索单个字段。与 HGET 类似,但返回一个值数组:

> hmget user:1000 username birthyear no-such-field 1) "antirez" 2) "1977" 3) (nil)

There are commands that are able to perform operations on individual fields as well, like HINCRBY:

还有一些命令也可以对单个字段执行操作,比如 HINCRBY:

> hincrby user:1000 birthyear 10 (integer) 1987 > hincrby user:1000 birthyear 10 (integer) 1997

You can find the full list of hash commands in the documentation.

您可以在文档中找到散列命令的完整列表。

It is worth noting that small hashes (i.e., a few elements with small values) are encoded in special way in memory that make them very memory efficient.

值得注意的是,小散列(即少数具有小值的元素)在内存中以特殊方式编码,这使它们非常有效地提高了内存效率。

Redis Sets


Redis Sets are unordered collections of strings. The SADD command adds new elements to a set. It’s also possible to do a number of other operations against sets like testing if a given element already exists, performing the intersection, union or difference between multiple sets, and so forth.

Redis 集是字符串的无序集合。SADD 命令向集合中添加新元素。还可以对集合执行一些其他操作,比如测试给定的元素是否已经存在,执行多个集合之间的交集、并集或差集,等等。

> sadd myset 1 2 3 (integer) 3 > smembers myset 1. 3 2. 1 3. 2

Here I’ve added three elements to my set and told Redis to return all the elements. As you can see they are not sorted – Redis is free to return the elements in any order at every call, since there is no contract with the user about element ordering.

这里我给我的集合添加了三个元素,并告诉 Redis 返回所有的元素。正如您所看到的,它们没有排序—— Redis 可以在每次调用时以任何顺序返回元素,因为没有与用户关于元素排序的约定。

Redis has commands to test for membership. For example, checking if an element exists:

Redis 有测试成员资格的命令。例如,检查一个元素是否存在:

> sismember myset 3 (integer) 1 > sismember myset 30 (integer) 0

“3” is a member of the set, while “30” is not.

“3”是集合中的一员,而“30”不是。

Sets are good for expressing relations between objects. For instance we can easily use sets in order to implement tags.

集合适于表达对象之间的关系。例如,我们可以很容易地使用集合来实现标记。

A simple way to model this problem is to have a set for every object we want to tag. The set contains the IDs of the tags associated with the object.

为这个问题建模的一个简单方法是为我们想要标记的每个对象都设置一个集合。该集合包含与对象关联的标记的 id。

One illustration is tagging news articles. If article ID 1000 is tagged with tags 1, 2, 5 and 77, a set can associate these tag IDs with the news item:

其中一个例子是给新闻文章加标签。如果文章 ID 1000用标签1、2、5和77标记,那么集合可以将这些标签 ID 与新闻项关联起来:

> sadd news:1000:tags 1 2 5 77 (integer) 4

We may also want to have the inverse relation as well: the list of all the news tagged with a given tag:

我们可能还需要一个反向关系: 所有新闻的列表都用给定的标签标记:

> sadd tag:1:news 1000 (integer) 1 > sadd tag:2:news 1000 (integer) 1 > sadd tag:5:news 1000 (integer) 1 > sadd tag:77:news 1000 (integer) 1

To get all the tags for a given object is trivial:

获取给定对象的所有标记是很简单的:

> smembers news:1000:tags 1. 5 2. 1 3. 77 4. 2

Note: in the example we assume you have another data structure, for example a Redis hash, which maps tag IDs to tag names.

注意: 在本例中,我们假设您有另一个数据结构,例如 Redis 散列,它将标记 id 映射到标记名。

There are other non trivial operations that are still easy to implement using the right Redis commands. For instance we may want a list of all the objects with the tags 1, 2, 10, and 27 together. We can do this using the SINTER command, which performs the intersection between different sets. We can use:

使用正确的 Redis 命令仍然可以很容易地实现其他非平凡的操作。例如,我们可能需要一个包含所有标记1、2、10和27的对象的列表。我们可以使用 semater 命令来完成这一操作,该命令执行不同集之间的交集。我们可以使用:

> sinter tag:1:news tag:2:news tag:10:news tag:27:news ... results here ...

In addition to intersection you can also perform unions, difference, extract a random element, and so forth.

除了交集之外,还可以执行联合、差分、提取随机元素等操作。

The command to extract an element is called SPOP, and is handy to model certain problems. For example in order to implement a web-based poker game, you may want to represent your deck with a set. Imagine we use a one-char prefix for ©lubs, (D)iamonds, (H)earts, (S)pades:

提取元素的命令称为 SPOP,可以方便地对某些问题进行建模。例如,为了实现一个基于网络的扑克游戏,您可能希望用一个集合来表示您的牌。假设我们用一个字符前缀表示© lubs,(d) iamonds,(h) earts,(s) pades:

> sadd deck C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 CJ CQ CK D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 DJ DQ DK H1 H2 H3 H4 H5 H6 H7 H8 H9 H10 HJ HQ HK S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 SJ SQ SK (integer) 52

Now we want to provide each player with 5 cards. The SPOP command removes a random element, returning it to the client, so it is the perfect operation in this case.

现在我们要给每个玩家5张牌。SPOP 命令删除一个随机元素,并将其返回给客户机,因此在这种情况下,这是一个完美的操作。

However if we call it against our deck directly, in the next play of the game we’ll need to populate the deck of cards again, which may not be ideal. So to start, we can make a copy of the set stored in the deck key into the game:1:deck key.

然而,如果我们直接对着我们的牌组调用它,在下一次游戏中,我们将需要再次填充牌组,这可能不是理想的。因此,开始时,我们可以复制一个集存储在甲板键到游戏: 1: 甲板键。

This is accomplished using SUNIONSTORE, which normally performs the union between multiple sets, and stores the result into another set. However, since the union of a single set is itself, I can copy my deck with:

这是通过使用 SUNIONSTORE 实现的,它通常执行多个集合之间的并集,并将结果存储到另一个集合中。然而,由于一个集合本身就是一个集合,我可以用以下命令来复制我的集合:

> sunionstore game:1:deck deck (integer) 52

Now I’m ready to provide the first player with five cards:

现在我已经准备好向第一个玩家提供五张牌:

> spop game:1:deck "C6" > spop game:1:deck "CQ" > spop game:1:deck "D1" > spop game:1:deck "CJ" > spop game:1:deck "SJ"

One pair of jacks, not great…

一对 j,不是很好…。

This is a good time to introduce the set command that provides the number of elements inside a set. This is often called the cardinality of a set in the context of set theory, so the Redis command is called SCARD.

现在正是介绍 set 命令的好时机,该命令提供集合中元素的数量。在集合论的上下文中,这通常称为集合的基数,因此 Redis 命令称为 SCARD。

> scard game:1:deck (integer) 47

The math works: 52 - 5 = 47.

这个数学公式是: 52-5 = 47。

When you need to just get random elements without removing them from the set, there is the SRANDMEMBER command suitable for the task. It also features the ability to return both repeating and non-repeating elements.

当您只需要获取随机元素而不需要将它们从集合中移除时,可以使用适合该任务的 SRANDMEMBER 命令。它还具有返回重复和非重复元素的能力。

Redis Sorted sets Redis 排序集


Sorted sets are a data type which is similar to a mix between a Set and a Hash. Like sets, sorted sets are composed of unique, non-repeating string elements, so in some sense a sorted set is a set as well.

排序集是一种类似于 Set 和 Hash 的混合的数据类型。与集合类似,排序集合由唯一的、不重复的字符串元素组成,因此在某种意义上,排序集合也是一个集合。

However while elements inside sets are not ordered, every element in a sorted set is associated with a floating point value, called the score (this is why the type is also similar to a hash, since every element is mapped to a value).

然而,当集合中的元素没有排序时,排序集合中的每个元素都与一个浮点值(称为得分)关联(这就是为什么该类型也类似于散列,因为每个元素都映射到一个值)。

Moreover, elements in a sorted sets are taken in order (so they are not ordered on request, order is a peculiarity of the data structure used to represent sorted sets). They are ordered according to the following rule:

此外,有序集合中的元素是按顺序排列的(所以它们不是按请求排序的,顺序是用于表示有序集合的数据结构的一个特点)。它们是根据以下规则订购的:

  • If A and B are two elements with a different score, then A > B if A.score is > B.score. 如果 a 和 b 是两个得分不同的元素,那么 a > b 如果 a > b

  • If A and B have exactly the same score, then A > B if the A string is lexicographically greater than the B string. A and B strings can’t be equal since sorted sets only have unique elements. 如果 a 和 b 的得分完全相同,那么如果 a 字符串在字母顺序上大于 b 字符串,则 a > b。A 和 b 字符串不能相等,因为排序集只有唯一的元素

Let’s start with a simple example, adding a few selected hackers names as sorted set elements, with their year of birth as “score”.

让我们从一个简单的示例开始,添加一些选定的黑客名称作为排序集元素,其出生年份作为“ score”。

> zadd hackers 1940 "Alan Kay" (integer) 1 > zadd hackers 1957 "Sophie Wilson" (integer) 1 > zadd hackers 1953 "Richard Stallman" (integer) 1 > zadd hackers 1949 "Anita Borg" (integer) 1 > zadd hackers 1965 "Yukihiro Matsumoto" (integer) 1 > zadd hackers 1914 "Hedy Lamarr" (integer) 1 > zadd hackers 1916 "Claude Shannon" (integer) 1 > zadd hackers 1969 "Linus Torvalds" (integer) 1 > zadd hackers 1912 "Alan Turing" (integer) 1

As you can see ZADD is similar to SADD, but takes one additional argument (placed before the element to be added) which is the score. ZADD is also variadic, so you are free to specify multiple score-value pairs, even if this is not used in the example above.

正如您所看到的,ZADD 类似于 SADD,但是它接受一个额外的参数(放在要添加的元素之前) ,这个参数就是分数。ZADD 也是可变的,因此您可以自由地指定多个分值对,即使上面的示例中没有使用这个值。

With sorted sets it is trivial to return a list of hackers sorted by their birth year because actually they are already sorted.

对于排序集,返回按出生年份排序的黑客列表是很简单的,因为实际上它们已经被排序了。

Implementation note: Sorted sets are implemented via a dual-ported data structure containing both a skip list and a hash table, so every time we add an element Redis performs an O(log(N)) operation. That’s good, but when we ask for sorted elements Redis does not have to do any work at all, it’s already all sorted:

实现注意: 排序集是通过包含跳跃列表和哈希表的双端口数据结构实现的,因此每次添加元素 Redis 时执行一个 o (log (n))操作。这很好,但是当我们获取 Redis 排序元素时,它根本不需要做任何工作,它已经被排序了:

> zrange hackers 0 -1 1) "Alan Turing" 2) "Hedy Lamarr" 3) "Claude Shannon" 4) "Alan Kay" 5) "Anita Borg" 6) "Richard Stallman" 7) "Sophie Wilson" 8) "Yukihiro Matsumoto" 9) "Linus Torvalds"

最后

分享一套我整理的面试干货,这份文档结合了我多年的面试官经验,站在面试官的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。

面试经验技巧篇
  • 经验技巧1 如何巧妙地回答面试官的问题
  • 经验技巧2 如何回答技术性的问题
  • 经验技巧3 如何回答非技术性问题
  • 经验技巧4 如何回答快速估算类问题
  • 经验技巧5 如何回答算法设计问题
  • 经验技巧6 如何回答系统设计题
  • 经验技巧7 如何解决求职中的时间冲突问题
  • 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
  • 经验技巧9 在被企业拒绝后是否可以再申请
  • 经验技巧10 如何应对自己不会回答的问题
  • 经验技巧11 如何应对面试官的“激将法”语言
  • 经验技巧12 如何处理与面试官持不同观点这个问题
  • 经验技巧13 什么是职场暗语

面试真题篇
  • 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
  • 真题详解2 某知名社交平台软件工程师笔试题
  • 真题详解3 某知名安全软件服务提供商软件工程师笔试题
  • 真题详解4 某知名互联网金融企业软件工程师笔试题
  • 真题详解5 某知名搜索引擎提供商软件工程师笔试题
  • 真题详解6 某初创公司软件工程师笔试题
  • 真题详解7 某知名游戏软件开发公司软件工程师笔试题
  • 真题详解8 某知名电子商务公司软件工程师笔试题
  • 真题详解9 某顶级生活消费类网站软件工程师笔试题
  • 真题详解10 某知名门户网站软件工程师笔试题
  • 真题详解11 某知名互联网金融企业软件工程师笔试题
  • 真题详解12 国内某知名网络设备提供商软件工程师笔试题
  • 真题详解13 国内某顶级手机制造商软件工程师笔试题
  • 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
  • 真题详解15 某著名社交类上市公司软件工程师笔试题
  • 真题详解16 某知名互联网公司软件工程师笔试题
  • 真题详解17 某知名网络安全公司校园招聘技术类笔试题
  • 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题

资料整理不易,点个关注再走吧
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
zrange hackers 0 -1 1) “Alan Turing” 2) “Hedy Lamarr” 3) “Claude Shannon” 4) “Alan Kay” 5) “Anita Borg” 6) “Richard Stallman” 7) “Sophie Wilson” 8) “Yukihiro Matsumoto” 9) “Linus Torvalds”`

最后

分享一套我整理的面试干货,这份文档结合了我多年的面试官经验,站在面试官的角度来告诉你,面试官提的那些问题他最想听到你给他的回答是什么,分享出来帮助那些对前途感到迷茫的朋友。

面试经验技巧篇
  • 经验技巧1 如何巧妙地回答面试官的问题
  • 经验技巧2 如何回答技术性的问题
  • 经验技巧3 如何回答非技术性问题
  • 经验技巧4 如何回答快速估算类问题
  • 经验技巧5 如何回答算法设计问题
  • 经验技巧6 如何回答系统设计题
  • 经验技巧7 如何解决求职中的时间冲突问题
  • 经验技巧8 如果面试问题曾经遇见过,是否要告知面试官
  • 经验技巧9 在被企业拒绝后是否可以再申请
  • 经验技巧10 如何应对自己不会回答的问题
  • 经验技巧11 如何应对面试官的“激将法”语言
  • 经验技巧12 如何处理与面试官持不同观点这个问题
  • 经验技巧13 什么是职场暗语

[外链图片转存中…(img-wb3AQk4Q-1714741692799)]

面试真题篇
  • 真题详解1 某知名互联网下载服务提供商软件工程师笔试题
  • 真题详解2 某知名社交平台软件工程师笔试题
  • 真题详解3 某知名安全软件服务提供商软件工程师笔试题
  • 真题详解4 某知名互联网金融企业软件工程师笔试题
  • 真题详解5 某知名搜索引擎提供商软件工程师笔试题
  • 真题详解6 某初创公司软件工程师笔试题
  • 真题详解7 某知名游戏软件开发公司软件工程师笔试题
  • 真题详解8 某知名电子商务公司软件工程师笔试题
  • 真题详解9 某顶级生活消费类网站软件工程师笔试题
  • 真题详解10 某知名门户网站软件工程师笔试题
  • 真题详解11 某知名互联网金融企业软件工程师笔试题
  • 真题详解12 国内某知名网络设备提供商软件工程师笔试题
  • 真题详解13 国内某顶级手机制造商软件工程师笔试题
  • 真题详解14 某顶级大数据综合服务提供商软件工程师笔试题
  • 真题详解15 某著名社交类上市公司软件工程师笔试题
  • 真题详解16 某知名互联网公司软件工程师笔试题
  • 真题详解17 某知名网络安全公司校园招聘技术类笔试题
  • 真题详解18 某知名互联网游戏公司校园招聘运维开发岗笔试题

[外链图片转存中…(img-JMB1vWmk-1714741692799)]

资料整理不易,点个关注再走吧
《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

  • 17
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值