2

Redis Data Types: The Basics

 1 year ago
source link: https://thenewstack.io/redis-data-types-the-basics/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Redis Data Types: The Basics

Redis data types can be complex, structured and powerful. This introduction summarizes how and when to use some essential data types.

Dec 29th, 2022 6:49am by

Lee Atchison

Featued image for: Redis Data Types: The Basics

Image via Pixabay.

Redis is often called a key-value store because every value stored in the database is attached to a key, and that key is used to look up the value.

However, this definition doesn’t do Redis justice. The value stored in Redis isn’t necessarily a simple type. It can be a complex and structured data type.

In this article, we introduce you to the most commonly used data types that are available within Redis.

Redis Keys

Redis keys are the index to data stored in Redis. Redis keys are strings, with a unique string representing a single object in Redis. The strings are binary-safe, which means a key can be any binary data.

A good practice for naming keys is to create and stick to a particular schema. For example, a common scheme for identifying objects is to use an object-type:id schema. So an object representing user id#1000 would be attached to the key name user:1000. An object representing a purchase order with an order number of 1234 might be attached to a key named order:1234.

Additionally, keys related to the base object can use suffixes on the key. For example, while the user id#1000 can use the key user:1000, a queue associated with that user could use the key user:1000:queue.

Within a single Redis database, a key is attached to a single value. Each value is attached to a single key, and all key names must be unique.

While a key name can be very large (up to 512MB in length), for performance reasons you should keep them substantially smaller, generally less than 100 bytes. Simply avoid extremely long keys (many kilobytes or megabytes in length) to maintain reasonable performance. There is no reason to make keys as small as possible (for example, using u1000 instead of user:1000 or o1234 instead of order:1234), since the performance impact for a 5 byte key name versus a 10 byte key name is miniscule.

Redis provides a competitive edge to any business by delivering open source and enterprise-grade data platforms to power applications that drive real-time experiences at any scale. Developers rely on Redis to build performance, scalability, reliability, and security into their applications.
Learn More

A Few Redis Data Types

There are five data types in Redis that are commonly used. They constitute the basis of most data access within a basic Redis instance and include:

  • String: The most basic data type. In Redis, strings are multipurpose. They can store data as simple as an integer or as complex as a JPEG image file.
  • List: A simple list of strings. The position within the list is significant and maintained.
  • Set: A simple collection of strings. The collection of a string is unordered, and the position within the set is unimportant.
  • Sorted set: An ordered collection of strings. Sorted sets are just like regular sets, except that the position is deterministic and important. The position within a set is determined by a priority score assigned to each string within the set.
  • Hash: An object representing a mapping between fields and values. This is perhaps the most important data type to start with besides strings. Hashes can store relatively complex data, such as an object with named attributes.

The following is an overview of these core data types.

String

The string data type is the most basic type of data in Redis. Strings can be stored attached to a key using the SET command:

redis> SET mykey "This is a string"

Strings can be read back using the GET command:

redis> GET mykey
"This is a string"

Strings are stored attached to a key as a native Redis object. Figure 1 illustrates how strings are stored and assigned to keys. The user on the left manipulates the string assigned to the key mykey.

5fa1ba9f-image5-e1671807919754.png

Figure 1. Basic string data type

A string can hold any raw data value, including binary files, up to a size of 512 MB. This means you can use Redis’ string type to store binary data such as JPEG image files.

Using Strings as Numbers

Strings can also store numbers. Naturally, Redis provides commands for manipulating numbers.

For example, let’s assume you create the following key:

redis> SET numkey "0"

This stores a string representation of the number zero. Redis provides commands that can manipulate that string as a number:

redis> INCR numkey
redis> INCR numkey
redis> INCR numkey
redis> GET numkey

You can increment by any number:

redis> GET numkey
redis> INCRBY numkey 20
redis> INCRBY numkey 100
redis> GET numkey
"123"

Equivalently, there is a DECR and DECRBY command.

Negative numbers work as expected:

redis> SET numkey "24"
redis> DECRBY numkey 100
redis> GET numkey
"-76"

Note that only integers are supported. Floating point numbers, fractions and other non-numbers can’t be manipulated in this manner.

redis> SET numkey "12 monkeys"
redis> INCR numkey
(error) ERR value is not an integer or out of range

The list data type allows you to store a collection of strings in an ordered way. One important concept: These strings are stored in the order they are inserted into the list.

Figure 2 shows a key that is assigned to a list of strings. In this case, the list of strings is a list of words, but the elements of the list can be anything of a string type, as specified above.

55fbb024-image1-e1671807869265.jpg

Figure 2. Basic list data type

Lists are typically implemented as simple linked lists. It is a fast, inexpensive operation to add, remove or read elements at the front or back of the list. However, it is substantially more expensive and slower to read an element at an arbitrary position within the list.

Smaller lists can be encoded using a more time-efficient ziplist encoding model that uses a bidirectional linked list, which reduces this cost. But, given that ziplist is only used with smaller lists, this efficiency doesn’t apply to larger lists, which are more prone to performance concerns. If performance is a significant factor, investigate options such as ziplist and listpack.

To add elements to the left end of a list, use the LPUSH command; add elements to the right end with the RPUSH command. You can read and delete strings from either end using the LPOP and RPOP commands.

So imagine we created a list using the following commands:

redis> LPUSH mylist "first"
redis> LPUSH mylist "second"
redis> LPUSH mylist "third"
redis> LPUSH mylist "fourth"

The list contains four elements (LLEN gives you the number of strings in a list):

redis> LLEN mylist

You can retrieve all the contents of the list at any time by using the LRANGE command:

redis> LRANGE mylist 0 -1
"fourth"
"third"
"second"
"first"

Finally, you can read and remove elements off the list from either end:

redis> LPOP mylist
"fourth"
redis> RPOP mylist
"first"
redis> LRANGE mylist 0 -1
"third"
"second"

That’s just a start. There are other ways to manipulate lists and many commands. Lists are great for implementing queues, particularly queues that operate on a first-in, first-out (FIFO) basis. FIFO queues are common, such as those to handle customer requests, print jobs and tech support queues.

The hash data type is incredibly powerful. On the surface, think of a hash data type as an enclosed set of key/value pairs inside the value of another key. The embedded keys are called fields. So a string is stored inside a key and inside a particular field within that key. The way they are built, they essentially allow for creating complex objects with named attributes assigned.

Figure 3 shows the basics of how a hash is stored. The key is associated with a hash object. That hash object can have multiple fields (i.e., subkeys) associated with individual strings. This allows you to store more complex data types.

09aa80cf-image4-e1671807906696.jpg

Figure 3. Basic hash data type

The use and importance of a hash is best illustrated with an example. Let’s assume we want to store an object that represents a User. Here is how you might store a User named lee as a hash:

redis> HMSET lee firstname Lee
redis> HMSET lee lastname Atchison
redis> HMSET lee twitter "@leeatchison"

These commands create a single object of type HASH, named with the key lee. That object has three attributes assigned to it, associated with three unique fields. The first is a first name (Lee) stored in the field firstname. The user’s last name (Atchison) is stored in the field lastname. Finally, the field twitter stores their Twitter handle (@leeatchison).

The HMGET command returns attributes for a given user. For example, to return the last name of the user lee, you would use:

redis> HMGET lee lastname
"Atchison"

If you had another user named beth, stored as a separate hash object, you could get their Twitter handle using:

redis> HMGET beth twitter
"@heartsdeesire"

Since hashes can store complex objects, hashes are one of the most important data types in Redis, beyond basic strings.

The set data type allows you to store unordered strings within a container. You can add instances of strings to a set or remove instances of strings from the set. Each string may be in the set, at most, once. You can query the set to see if a string is contained in it, or you can list its contents.

Figure 4 shows a basic set with several strings contained in it.

d3381e40-image2-e1671807894538.jpg

Figure 4. Basic set data type

Let’s construct a set:

redis> SADD my_set "first"
redis> SADD my_set "second"
redis> SADD my_set "last"

We can query the set to see what’s in it:

redis> SISMEMBER my_set "first"
redis> SISMEMBER my_set "third"
redis> SISMEMBER my_set "last"

Using SISMEMBER, we confirm that “first” and “last” are in the set, but “third” is not.

We also can see what’s contained in the set using SMEMBERS:

redis> SMEMBERS my_set
"first"
"second"
"last"

We can add more members to the set:

redis> SADD my_set "third"
redis> SADD my_set "second"

Doing this adds the value “third” to the set. However, the value “second” was already in the set, so it is not re-added.

redis> SMEMBERS my_set
"first"
"second"
"last"
"third"

Many operations can be made on sets. For example, you can merge two or more sets:

redis> SADD set1 a
redis> SADD set1 b
redis> SADD set1 d
redis> SADD set2 c
redis> SADD set2 d
redis> SADD set2 e

Given these two sets, we can return a set containing the union of both sets:

redis> SMEMBERS set1
redis> SMEMBERS set2
redis> SUNION set1 set2

You can also store the results of this union operation:

redis> SUNION sets1_2 set1 set2
redis> SMEMBERS sets1_2

You can perform intersect operations as well as difference operations:

redis> SINTER set1 set2
redis> SDIFF set1 set2

Many other operations can be performed on the sets.

Sorted Set

A sorted set data type is like a regular set, except each string is also given a priority order number. That number specifies its ordered position within the set.

redis> ZADD thesset 1 "first"
redis> ZADD thesset 5 "second"
redis> ZADD thesset 3 "last"

You can now get the list of objects in the set, ordered by the priority number:

redis> ZRANGE thesset 0 -1
"first"
"last"
"second"

A lexicographical order is used if all elements within the sorted set have the same score.

This ZRANGE command says to return the values stored in thesset in priority order, starting with the first (0) and continuing for all strings in the set (-1).

You can add elements to the set, and insert them at the appropriate location:

redis> ZADD thesset 4 "third"
redis> ZRANGE thesset 0 -1
"first"
"last"
"third"
"second"

As with other set-related commands, there are commands that allow you to return parts of the sorted set, and to reverse the order. All the same intersect, union and difference operations are also available.

Sorted sets are extremely valuable for certain tasks such as creating leaderboards and high score lists.

Other Uses for Strings: Bitmaps

We already discussed the special case of using simple strings as numbers, and the commands (such as INCR and INCRBY), which can manipulate the strings as numbers. But there’s more.

You can also manipulate simple strings as if they were a binary bit array. In Redis, this is called a bitmap. Essentially, each bit in each byte of the string represents a binary value of 0 or 1 in an array. This is perfect for manipulating simple Yes/No, or On/Off, objects in very large arrays because it uses a small amount of memory.

For example, you can set or reset bits in the array using commands like this:

redis> SETBIT myarray 15 1
redis> SETBIT myarray 23 0
redis> SETBIT myarray 1203 1

Then, you can get any element in the array:

redis> GETBIT myarray 4
redis> GETBIT myarray 15
redis> GETBIT myarray 23
redis> GETBIT myarray 1000
redis> GETBIT myarray 1203

This basic array is stored efficiently in a string. In this example, this array has 1204 values (0-1203), and it can be stored in a simple string containing just 151 bytes of memory.

A bitmap is not a different data type, but rather a different way to manipulate string data types, much like INCR and DECR manipulate the string data type as an integer.

Structured Data with JSON

The body of this article focused on the data types that Redis developers use most often. But don’t assume that “the essentials” is the same as “everything Redis has to offer.” Once you are comfortable with these basics, you can extend Redis in genuinely powerful ways.

For example, one of the most powerful data constructs possible with Redis is the JSON module. Redis can store arbitrary JSON documents in a single Redis key, as illustrated in Figure 5. You store these JSON documents in Redis using a special JSON version of the Redis SET/GET commands. Once the JSON is stored in a key, however, the data can be manipulated in interesting and potentially powerful ways.

59d2b136-image3-e1671807881500.jpg

Figure 5. Structured JSON in Redis assigned to a key

All of this is made possible by loading the RedisJSON module. This module lets you store any type of data in Redis, including custom data types, in a format that can be easily reconstituted into usable data.

Once the module is loaded, creating a JSON document in Redis is easy. Here is a sample creation and manipulation of a JSON document within a single Redis key named testkey:

redis> JSON.SET testkey . '[ 123, { "life": 42, "fish":"please"} ]'
redis> JSON.GET testkey
"[123,{\"life\":42},{\"fish\":\"please\"}]"

Once created, you can manipulate individual elements of a JSON document:

redis> JSON.SET testkey . '[ 123, { "life":42, "fish":"please"} ]'
redis> JSON.GET testkey [1].life
redis> JSON.GET testkey [1].fish
"please"

You can return parts of the JSON tree:

redis> JSON.SET testkey . '[ 123, { "life":42, "fish":"please", "universe":{ "and":"everything" } } ]'
redis> JSON.GET testkey [1].universe
"{\"and\":\"everything\"}"

Or you can traverse deeper into the tree:

redis> JSON.SET testkey . '[ 123, { "life":42, "fish":"please", "universe":{ "and":"everything" } } ]'
redis> JSON.GET testkey [1].universe.and
"everything"

Complex Operations

Besides storing and retrieving all or part of a JSON document, you can manipulate a JSON document in interesting and advanced ways. For example, if we create a JSON document like this:

redis> JSON.SET testkey . '[123,{"life":42,"fish":1}]'

We can read it in any of these ways:

redis> JSON.GET testkey
"[123,{\"life\":42,\"fish\":1}]"
redis> JSON.GET testkey [1].life

Now let’s try changing the JSON document’s contents:

redis> JSON.NUMINCRBY testkey [1].life 1
redis> JSON.GET testkey
"[123,{\"life\":43,\"fish\":1}]"
redis> JSON.NUMINCRBY testkey [1].fish 123
redis> JSON.GET testkey
"[123,{\"life\":43,\"fish\":124}]"
redis JSON.GET testkey [1].life
redis JSON.GET testkey [1].fish

There are many other ways to manipulate the JSON document, including the ability to add information to the document (SET, STRAPPEND, ARRAPPEND, ARRINSERT), remove information from the document (DEL, ARRPOP, ARRTRIM), manipulate objects within the document (NUMINCRBY, STRAPPEND) and inspect individual objects (GET, MGET, TYPE).

Redis also enables you to index, query and perform full-text searches on data stored in JSON documents.

Advanced Data Types

The data types described here are the basics to get started building with Redis. Redis enables many other data types, and you can create your own, too.

Some of the advanced data models and engines available from Redis include:

  • Search: Enables querying, secondary indexing and full-text search of Redis. Dive deep into Redis databases to retrieve information super-fast, with support for exact phrase matches, geo filtering and vector similarity. It’s a no-brainer if you have a customer or product database where you need near-instant responses.
  • Bloom: Allows storing probabilistic data structures, including bloom filters.
  • Graph: Allows storing complex related data. It’s useful for social graph operations, fraud detection and real-time recommendation algorithms.
  • Time-series: Allows storing data that changes over time and analysis of the data. Typical examples are stock prices, temperature probe measurements and telemetry.

Redis has a wide variety of data types, models and engines that allow storing and manipulating data in interesting and useful ways. Used properly, they can be used to store complex data constructs and make that data accessible fast and efficiently.

Ready to explore? You can start building with Redis Stack or take advantage of Redis’ developer resources.

GroupCreated with Sketch.

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK