Table of contents
1.
Introduction
2.
What is a Redis stack?
3.
Why should you use Redis Stack?
3.1.
License for Redis Stack
4.
Redis Stack clients
4.1.
Supporting Redis Stack client libraries
4.2.
Core client libraries 
4.3.
Libraries for high-level clients
5.
NODE-REDIS
5.1.
Installation
5.2.
Usage
5.3.
Redis Command
5.3.1.
 
5.3.2.
Unsupported Redis command: Use this if you wish to run commands or use arguments that Node Redis isn't aware of .sendCommand():
5.3.3.
 
5.3.4.
Blocking Commands: Any command can be executed on a new connection using the isolated option. When the Promise command is fulfilled, the newly established relationship is closed.
5.3.5.
This approach is convenient for blocking instructions like BLPOP and BLMOVE:
5.4.
Programmability
5.4.1.
Functions
5.4.2.
 
5.4.3.
Events
6.
Redis-py
6.1.
Installation
6.2.
ZADD, MSET, and MSETNX
6.3.
Encoding of user input
6.4.
Locks
6.5.
API Reference
7.
Jedis
7.1.
Accessing a Redis cluster
7.2.
Using Redis modules
8.
Redis OM .NET
8.1.
Installation
8.2.
Indexing embedded documents
8.3.
Querying
9.
Redis OM for node.js
9.1.
Defining an entity:
9.2.
Connect to Redis with a client
9.3.
Redis connection strings
10.
Redis OM Python
10.1.
Modeling your data
10.2.
Validating Data With Your Model
11.
Redis OM Spring
11.1.
The Springboot app
11.2.
The Mapped Model
12.
FAQs
12.1.
What are applications of Redis stacks clients?
12.2.
Why to use Redis?
12.3.
What are some Redis clients that we use often?
13.
Conclusion
Last Updated: Mar 27, 2024
Medium

Redis Stack clients

Introduction

In this competitive world, every one of us is trying to get our work done asap. We don’t mind using some assistance while doing any work. In this article, we will be discuss some add-ons that will assist you in your work. We will see how to add modern data models and processing engines to Redis. Before going into the details, we first start by knowing what a Redis stack is?

What is a Redis stack?

 Redis Stack is a Redis add-on that integrates current data models and processing engines to give developers a whole developer experience. Following are some add-ons that are integrated into data models,

  • Redis stack supports: in addition to all of the features of OSS Redis
  • JSON documents with query ability
  • Searchable full-text
  • Data collected throughout time (ingestion & querying)
  • Modeling graph data using the Cypher query language
  • Structures of probabilistic data

Why should you use Redis Stack?

The Redis Stack was intended to assist developers in creating real-time applications with a backend data platform that can consistently handle requests in less than a millisecond. Redis Stack integrates current data models and processing tools into Redis (Document, Graph, Search, and Time Series).

Redis Stack brings together and streamlines the developer experience of the most popular Redis modules and their features. Redis Stack is a collection of five Redis modules, including RedisJSON, RedisSearch, RedisGraph, RedisTimeSeries, and RedisBloom.

Clients

Several Redis client libraries support Redis Stack. Redis-py, node Redis, and Jedis are a few examples. Redis Stack is supported by four higher-level object mapping libraries: Redis OM.NET, Redis OM Node, Redis OM Python, and Redis OM Spring.

RedisInsight

Redis Stack also comes with RedisInsight, a visualization tool for analyzing and improving Redis data.

License for Redis Stack

The Redis Stack is made up of various components, each of which is licensed differently:

  • Redis Stack Server is released under the Redis Source Available License and includes open source Redis, RediSearch, RedisJSON RedisGraph, RedisTimeSeries, and RedisBloom (RSAL).
  • The Server Side Public License applies to RedisInsight (SSPL).

Redis Stack clients

Supporting Redis Stack client libraries

The Redis Stack is based on Redis and employs the Redis client protocol. As a result, Redis Stack is supported by most Redis client libraries. On the other hand, some client libraries provide a more comprehensive developer experience.

A client library must provide an API for the commands exposed by Redis Stack to support it meaningfully. Each Redis Stack command is usually represented by one method in core client libraries. High-level libraries are abstractions that can employ a variety of instructions.

Core client libraries 

Redis Stack is supported by the following core client libraries:

  • node-redis >= 4.0 
  • redis-py >= 4.0 
  • Jedis >= 4.0

Libraries for high-level clients

The Redis OM client libraries allow you to use Redis Stack's document modeling, indexing, and querying features the same way an ORM would. Redis OM supports the following Redis Stack libraries:

  • Redis OM Node
  • Redis OM .NET
  • Redis OM Python
  • Redis OM Spring

NODE-REDIS

Node-Redis is a modern Redis client with good performance node.js.

Installation

Node-Redis can be installed similar to other node packages.

Code

npm install redis

Usage

Basic Example

import { createClient } from 'redis';

const client = createClient();

client.on('error', (err) => console.log('Redis Client Error', err));

await client.connect();

await client.set('key', 'value');
const value = await client.get('key');

 

The code above uses port 6379 to connect to localhost. Use a connection string in this format to connect to a different host or port: 

 redis[s]://[[username][:password]@][host][:port][/db-number]

Redis Command

All of the Redis commands that come out of the box are supported. The raw Redis command names (HSET, HGETALL, etc.) and a friendlier camel-cased version are used to expose them (hSet, hGetAll, etc.):

// raw Redis commands
await client.HSET('key', 'field', 'value');
await client.HGETALL('key');

// friendly JavaScript commands
await client.hSet('key', 'field', 'value');
await client.hGetAll('key');

 

Unsupported Redis command: Use this if you wish to run commands or use arguments that Node Redis isn't aware of .sendCommand():

await client.sendCommand(['SET', 'key', 'value', 'NX']); // 'OK'

await client.sendCommand(['HGETALL', 'key']); // ['key1', 'field1', 'key2', 'field2']

 

Blocking Commands: Any command can be executed on a new connection using the isolated option. When the Promise command is fulfilled, the newly established relationship is closed.

This approach is convenient for blocking instructions like BLPOP and BLMOVE:

import { commandOptions } from 'redis';

const blPopPromise = client.blPop(
  commandOptions({ isolated: true }),
  'key',
  0
);

await client.lPush('key', ['1', '2']);

await blPopPromise; // '2'

Programmability

Redis has a programming interface that allows you to run code on the server.

Functions

The example below fetches a key in Redis and returns the key's value, incremented by an integer. For example, if the value of your key foo is 17 and we run add('foo', 25), the answer to Life, the Universe, and Everything is returned.

#!lua name=library


redis.register_function {
  function_name = 'add',
  callback = function(keys, args) return redis.call('GET', keys[1]) + args[1] end,
  flags = { 'no-writes' }
}

 

Events

The Node Redis client class is an EventEmitter in Nodejs, and it emits an event whenever the network status changes:

Event Name Scenes Arguments to be passed to the listener
connect The client is establishing a connection to the server. No argument
ready The client established a successful connection with the server. No argument
end The client used .quit() or .disconnect to terminate the server connection (). No argument
error When a network error occurs, such as being unable to connect to the server or having the connection abruptly terminated. 1 Argument: The error object will be SocketClosedUnexpectedlyError: Socket closed unexpectedly or Error: connect ECONNREFUSED [IP]:[PORT].
reconnecting The client is trying to reconnect a connection with the server. No argument

Redis-py

The Redis key-value store's Python interface.

Installation

Redis-py requires a functioning Redis server. Installation instructions can be found in Redis' quickstart.

Redis-py, like other Python packages, can be installed via pip. With pip, do not use Sudo. To avoid problems with other package managers and Python projects, it's best to operate in a virtualenv or venv.

$ pip install redis

ZADD, MSET, and MSETNX

These commands all require a key/value pair mapping. This mapping could be given as *args or **kwargs in redis-py 2.X. When Redis added optional flags to ZADD, these techniques presented problems. In Python 2.7, relying on *args caused the optional argument order complications. Using **kwargs resulted in the possibility of user keys colliding with argument names in the method signature.

To address this, in redis-py 3.0, these three commands now accept a single positional parameter named mapping, which is assumed to be a dict. The dict in MSET and MSETNX is mapping key names to values. The dict in ZADD is a mapping of element names to scores.

def mset(self, mapping):
def msetnx(self, mapping):
def zadd(self, name, mapping, nx=False, xx=False, ch=False, incr=False):

Encoding of user input

Redis-py 3.0 only accepts user data in bytes, characters, or numbers (ints, longs, and floats). A DataError exception will be thrown if you try to provide a key or value as any other type.

Any type of input was attempted to be converted into a string by redis-py 2.X. When users submitted boolean values (which were coerced to 'True' or 'False'), a None value (which was coerced to 'None'), or other values, such as user defined kinds, this produced all sorts of hidden issues.

All redis-py 2.X users should ensure that the keys and values they pass in are either bytes, strings, or integers.

Locks

The pipeline-based Lock is no longer supported in redis-py 3.0, and only the Lua-based Lock is supported. LuaLock has been renamed to Lock as a result of this. Redis server 2.6 or higher is also required for redis-py Lock objects.

2.X users who were referring to LuaLock explicitly will now have to refer to Lock instead.

API Reference

  • SELECT: This option is not available. See the Thread Safety section for further information.
  • DEL: In Python syntax, del is a reserved keyword. As a result, redis-py employs delete instead.
  • MULTI/EXEC: As part of the Pipeline class, these are implemented. When the pipeline is executed, it is wrapped by default with the MULTI and EXEC statements, which can be disabled by specifying transaction=False. Pipelines are discussed more below.
  • SUBSCRIBE/LISTEN: PubSub is built as a separate class, similar to pipelines, because it puts the underlying connection in a condition where it can't execute non-pubsub commands. The pubsub method in the Redis client returns a PubSub object, which may be used to subscribe to channels and listen for messages. Only the Redis client can use the PUBLISH command.
  • SCAN/SSCAN/HSCAN/ZSCAN: The Redis documentation's *SCAN commands are implemented. Furthermore, each command has a corresponding iterator method. These are entirely for the user's convenience so that they don't have to worry about keeping track of the cursor when iterating. For this behaviour, use the scan iter/sscan iter/hscan iter/zscan iter functions.

Jedis

Jedis is a Redis client written in Java that focuses on performance and usability.

Accessing a Redis cluster

Jedis supports the Redis Cluster Specification by allowing you to connect to Redis Clusters. You'll need to use JedisCluster to accomplish this. Consider the following example:

Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7380));
JedisCluster jedis = new JedisCluster(jedisClusterNodes);

You can now send instructions to the JedisCluster instance as if it were a typical pooled connection:

jedis.sadd("planets", "Mars");

Using Redis modules

Some Redis modules, like RedisJSON and RediSearch, are supported by Jedis.

Redis OM .NET

Redis OM is a high-level abstraction for using Redis in.NET that makes modeling and querying Redis domain objects simple.

Installation

To use the dotnet cli, type:

dotnet add package Redis.OM

Indexing embedded documents

With Redis, there are two ways to index embedded documents. A complex object is an embedded document, for example, if our Customer model has an Address property with the following model:

[Document(IndexName = "address-idx", StorageType = StorageType.Json)]
public partial class Address
{
    public string StreetName { get; set; }
    public string ZipCode { get; set; }
    [Indexed] public string City { get; set; }
    [Indexed] public string State { get; set; }
    [Indexed(CascadeDepth = 1)] public Address ForwardingAddress { get; set; }
    [Indexed] public GeoLoc Location { get; set; }
    [Indexed] public int HouseNumber { get; set; }
}

Querying

var customers = provider.RedisCollection<Customer>();

// Insert customer
customers.Insert(new Customer()
{
    FirstName = "James",
    LastName = "Bond",
    Age = 68,
    Email = "bondjamesbond@email.com"
});

// Find all customers whose last name is "Bond"
customers.Where(x => x.LastName == "Bond");

// Find all customers whose last name is Bond OR whose age is greater than 65
customers.Where(x => x.LastName == "Bond" || x.Age > 65);

// Find all customers whose last name is Bond AND whose first name is James
customers.Where(x => x.LastName == "Bond" && x.FirstName == "James");

// Find all customers with the nickname of Jim
customer.Where(x=>x.NickNames.Contains("Jim"));

Redis OM for node.js

Redis OM makes it simple to integrate Redis into your Node.js application by mapping Redis data structures to classes you specify. No more inconvenient low-level instructions; just pure code with a natural user interface.

Defining an entity:

class Album extends Entity {}

const schema = new Schema(Album, {
  artist: { type: 'string' },
  title: { type: 'text' },
  year: { type: 'number' }
});

Connect to Redis with a client

The Client class has methods for opening, closing, and running raw Redis commands.

import { Client } from 'redis-om'

const client = new Client()
await client.open('redis://localhost:6379')

const aString = await client.execute(['PING'])
// 'PONG'

const aNumber = await client.execute(['HSET', 'foo', 'bar', 'baz', 'qux', 42])
// 2

const anArray = await client.execute(['HGETALL', 'foo'])
// [ 'bar', 'baz', 'qux', '42' ]

await client.close()

Redis connection strings

You give a URL to a Redis client when you start it up. This URL's basic format is as follows:

redis://username:password@host:port

Redis OM Python

Redis OM Python makes modelling Redis data in Python applications simple.

Modeling your data

Redis OM includes sophisticated declarative models that provide Redis with data validation, serialisation, and persistence.

import datetime
from typing import Optional
from pydantic import EmailStr
from redis_om import HashModel

class Customer(HashModel):
    first_name: str
    last_name: str
    email: EmailStr
    join_date: datetime.date
    age: int
    bio: Optional[str]

Validating Data With Your Model

Redis OM validates data using Pydantic based on the type annotations you supply to model class fields.

This check guarantees that fields defined as str in the Customer model, such as first name, are always strings. However, because every Redis OM object is also a Pydantic model, you can utilise Pydantic validators like as EmailStr, Pattern, and many more to perform complicated validations!

If we try to create a Customer with an invalid email address, for example, we'll get a validation error because we used the EmailStr type for the email field:

import datetime
from typing import Optional
from pydantic import EmailStr, ValidationError
from redis_om import HashModel

class Customer(HashModel):
    first_name: str
    last_name: str
    email: EmailStr
    join_date: datetime.date
    age: int
    bio: Optional[str]

try:
    Customer(
        first_name="Andrew",
        last_name="Brookins",
        email="Not an email address!",
        join_date=datetime.date.today(),
        age=38,
        bio="Python developer, works at Redis, Inc."
    )
except ValidationError as e:
    print(e)
    """
    pydantic.error_wrappers.ValidationError: 1 validation error for Customer
     email
       value is not a valid email address (type=value_error.email)
    """

Redis OM Spring

The Redis OM Built on top of the robust Spring Data Redis (SDR) architecture, Spring provides a powerful repository and custom object-mapping abstractions.

This sample version includes all of SDR's features, as well as the following:

  • Spring Data models are mapped to Redis JSON documents using the @Document annotation.
  • @EnableRedisEnhancedRepositories extends SDR's @RedisHash to: uses Redis' native search engine (RediSearch) for secondary indexing uses ULID for @Id annotated fields
  • Using @EnableRedisDocumentRepositories, RedisDocumentRepository automatically implements Repository interfaces for advanced querying capabilities.
  • @Indexable Declarative Search Indices
  • @Searchable Entity Full-text Search Indices
  • @Bloom annotation for Streams-based Query Builder to identify whether a value is in a collection very quickly and with a high degree of assurance.

The Springboot app

Inject repositories beans implementing RedisDocumentRepository which you can use for CRUD operations and custom queries (all by declaring Spring Data Query Interfaces) using the @EnableRedisDocumentRepositories annotation:
 

package com.redis.om.documents;

import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.geo.Point;

import com.redis.om.documents.domain.Company;
import com.redis.om.documents.repositories.CompanyRepository;

@SpringBootApplication
@Configuration
@EnableRedisDocumentRepositories(basePackages = "com.redis.om.documents.*")
public class RomsDocumentsApplication {

  @Autowired
  CompanyRepository companyRepo;

  @Bean
  CommandLineRunner loadTestData() {
    return args -> {
      // remove all companies
      companyRepo.deleteAll();

      // Create a couple of `Company` domain entities
      Company redis = Company.of(
        "Redis", "https://redis.com", new Point(-122.066540, 37.377690), 526, 2011 //
      );
      redis.setTags(Set.of("fast", "scalable", "reliable"));

      Company microsoft = Company.of(
        "Microsoft", "https://microsoft.com", new Point(-122.124500, 47.640160), 182268, 1975 //
      );
      microsoft.setTags(Set.of("innovative", "reliable"));

      // save companies to the database
      companyRepo.save(redis);
      companyRepo.save(microsoft);
    };
  }

  public static void main(String[] args) {
    SpringApplication.run(RomsDocumentsApplication.class, args);
  }
}

The Mapped Model

An annotation at the class level, like many other Spring Data projects, controls how instances of the class are persisted. The @Document annotation in Redis OM Spring allows you to persist models as JSON documents using RedisJSON:

package com.redis.om.documents.domain;

import java.util.HashSet;
import java.util.Set;
import org.springframework.data.annotation.Id;
import org.springframework.data.geo.Point;
import com.redis.om.spring.annotations.Document;
import com.redis.om.spring.annotations.Searchable;
import lombok.*;

@Data
@NoArgsConstructor
@RequiredArgsConstructor(staticName = "of")
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@Document
public class Company {
  @Id private String id;
  @Searchable private String name;
  @Indexed private Point location;
  @Indexed private Set<String> tags = new HashSet<String>();
  @Indexed private Integer numberOfEmployees;
  @Indexed private Integer yearFounded;
  private String url;
  private boolean publiclyListed;


  // ...
}

FAQs

What are applications of Redis stacks clients?

Applications of redis stack clients are as follows:

  • Redis stack supports: in addition to all of the features of OSS Redis
  • JSON documents with queryability
  • Searchable full-text
  • Data collected throughout time (ingestion & querying)
  • Modeling graph data using the Cypher query language
  • Structures of probabilistic data

Why to use Redis?

The Redis Stack was intended to assist developers to create real-time applications with a backend data platform that can consistently handle requests in less than a millisecond.

What are some Redis clients that we use often?

Jedis, node-redis, redis-py, Redis OM .NET, Redis OM Node, Redis OM Python, and Redis OM Spring are some clients that we use generally.

Conclusion

In this article, we have extensively discussed the Redis stack clients.  We hope that this blog has helped you enhance your knowledge and aspects that you should keep in mind while dealing with Redis stack clients. If you would like to learn more, check out our articles here. Do upvote our blog to help other ninjas grow. 

Refer to our guided paths on Coding Ninjas Studio to learn more about DSA, Competitive Programming, JavaScript, System Design, etc. Enroll in our courses and refer to the mock test and problems available, interview puzzles. Also, look at the interview experiences and interview bundle for placement preparations. Please look at this YouTube tutorial if you want to explore the preparation strategy for SDE placements.

Happy Learning!

Live masterclass