Friday, March 14, 2025

Elastic Cross-Cluster Ops - Replication + Search

Summary

This is the final post in a three-part series configuring Elasticsearch (ES) cross-cluster replication and search.  The first two posts set up two distinct ES clusters: one implemented in Kubernetes (ECK), and the other in Docker.

Cross-cluster Replication

Architecture


Configuration

Networking

The two clusters (West and East) are both implemented in Docker.  Although West is a K8s implementation, the underlying architecture of Kind is in fact, Docker.  Each cluster is in its own Docker network.  For cross-cluster operations to function, we need to configure the linkage between these two Docker networks.  The Docker commands below do just that.

Remote Cluster Configuration

The West Cluster needs to be added to the East as a remote cluster.  The commands below do that and then wait for the remote configuration to complete.




East Follower Index

In this scenario, we are setting up a leader index on the West cluster (named west_ccr) and its corresponding follower index on the East (named east_ccr).  This will allow one-way replication from West to East.





Demo

At this point, true replication of the West index (west_ccr), including mappings (schema) has been accomplished.  This can be verified with a simple Nodejs Elasticsearch client application that is located in the src/javascript directory.

Cross-cluster Search

Architecture



Configuration

Remote Cluster Configuration

Similar to the prior exercise of establishing the West cluster as a remote cluster on the East, the East cluster now needs to be configured as a remote cluster on the West.






Demo

At this point, everything is in place to execute queries that span the two clusters.  A Python Elasticsearch client script is included in the src/python directory.  That script executes a search against the West ES endpoint that spans both the west_ccs index on West and the east_ccs on East.

Source

Elastic Cross-Cluster Ops - East Cluster Build

Summary

This is Part 2 in the three-part series on Elasticsearch (ES) cross-cluster operations.  This ES cluster will be implemented in Docker.  Like the West Cluster, this configuration yields a single ES node and one Kibana node. 

Architecture



Configuration

Docker-compose

For the most part, I used the reference docker-compose.  I added a bind mount such that I could add the West Cluster's transport CA to the trusted CAs for the East Cluster.


Index

Below a minimal index is built via the REST API.  This index is used in a demonstration of cross-cluster search in the next post.

Source

Elastic Cross-Cluster Ops - West Cluster Build

Summary

This is Part 1 in a three-part series on a multi-cluster Elasticsearch (ES) build with cross-cluster replication and search enablement.  This post covers the build of the West cluster, which is implemented in Kubernetes.

Architecture

The West cluster is implemented as an Elastic Cloud on Kubernetes (ECK). I'm using Kind for the Kubernetes environment, which allows for a self-contained environment suitable for a capable laptop. Additionally, I use cloud-provider-kind to provide native load-balancer functionality.




Configuration

Kind/Cloud-Provider-Kind


ECK Operator


Elasticsearch + Kibana


Indices

Two minimal indices are created with the REST API. These indices will used in a later post on cross-cluster replication and search.

Source





Sunday, March 2, 2025

Geospatial Search with Redis and Apache Pinot

Summary

I'll discuss Redis Enterprise and Apache Pinot setup in Docker for this post. 
  • 3-node Redis environment
  • 4-node Pinot environment
  • 1M synthetic JSON records representing a user's geographic location
  • Equivalent geospatial search queries for both environments

Architecture


Data Generation

Synthetic records are created with a Python function that utilizes the Faker library. They are saved to a file called locations.json.  A snippet of the data generator is below.


Redis Deployment

Docker

Three Redis nodes are created.

Cluster Build, DB creation, Index Build, Data Load

Nodes are joined into a Redis cluster. A single-shard database is then created, along with an index. Finally, the database is populated from a JSON file with Riot.

Redis Insight




Pinot Deployment

Docker

A 4-node Pinot cluster is created in docker-compose.  Pinot Controller definition is below.

Schema/Table Build, Data Load


Pinot Console







Queries

The query below finds the count of users within a polygon defined as the boundaries of the State of Colorado.

Redis


Pinot


Source

Tuesday, December 31, 2024

Gloo Gateway on Kind

Summary

In this post, I'll cover a demo deployment of Gloo Gateway in a Kind K8s environment.
  • 3-worker node Kind K8s environment
  • 2 dummy REST microservices implemented in Nodejs via Express.js
  • OSS deployment of Gloo Gateway providing ingress to the two microservices

Architecture

Deployment

Kind



Gloo Gateway



Microservices



Source

Thursday, February 22, 2024

Redis RAG with Nvidia NeMoGuardrails

Summary


This post will cover the usage of guardrails in the context of an RAG application using Redis Stack as the vector store.  
  • Nvidia's guardrail package is used for the railed implementation.
  • Langchain LCEL is used for the non-railed implementation.
  • Content from the online Redis vector search documentation is used for the RAG content
  • GUI is implemented with Chainlit


Application Architecture


This bot is operating within a Chainlit app.  It has two modes of operation:  
  • 'chain' - no guardrails
  • 'rails' - NeMo guardrails in place for both user inputs and LLM outputs


Screenshots


Bot without rails

This first screenshot shows the bot operating with no guardrails.  It does just fine until an off-topic question is posed - then it cheerfully deviates from its purpose.



Bot with rails

Same series of questions here with guardrails enabled.  Note that it keeps the user on topic now.



Code Snippets

Non-railed chain (LCEL)



Railed with NeMO Guardrails



Source


Copyright  ©2024 Joey E Whelan, All rights reserved.

Monday, January 15, 2024

Change Data Capture w/Redis Enterprise

Summary

Redis Enterprise has the capability for continuous data integration with 3rd party data sources.  This capability is enabled via the Redis Data Integration (RDI) product.  With RDI, change data capture (CDC) can be achieved with all the major SQL databases for ingress.  Similarly, in the other direction, updates to Redis can be continuously written to 3rd party targets via the write-behind functionality of RDI.  

This post covers a demo-grade environment of Redis Enterprise + RDI with ingress and write-behind integrations with the following SQL databases:  Oracle, MS SQL, Postgres, and MySQL.  All components are containerized and run from a Docker environment.

Architecture


Ingress



Write-behind



Code Snippets

Docker Compose - Redis Enterprise Node



Docker Compose - Oracle Enterprise



Docker Compose - Debezium



RDI Ingress w/Prometheus Integration


Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Monday, January 8, 2024

Document AI with Apache Airflow

Summary

In this post, I cover an approach to a document AI problem using a task flow implemented in Apache Airflow.  The particular problem is around the de-duplication of invoices.  This comes up in payment provider space.  I use Azure AI Document Intelligence for OCR, Azure OpenAI for vector embeddings, and Redis Enterprise for vector search.

Architecture



Code Snippets


File Sensor DAG


OCR DAG


OCR Client (Azure AI Doc Intelligence)


Embedding DAG


Embedding Client (Azure OpenAI)


Vector Search DAG


Vector Search Client (Redis Enterprise)


Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Sunday, December 31, 2023

HAProxy with Redis Enterprise

Summary

This is Part 2 of a two-part series on the implementation of a contact center ACD using Redis data structures.  This part is focused on the network configuration.  In particular, I explain the configuration of HAProxy load balancing with VRRP redundancy in a Redis Enterprise environment.  To boot, I explain some of the complexities of doing this inside a Docker container environment.

Network Architecture


Load Balancing Configuration


HAProxy w/Keepalived

Docker Container

Dockerfile and associated Docker compose script below for two instances of HAProxy w/keepalived.  Note the default start-up for the HAProxy container is overridden with a CMD to start keepalived and haproxy.

Keepalived Config

VRRP redundancy of the two HAProxy instances is implemented with keepalived.  Below is the config for the Master instance.  The Backup instance is identical except for the priority.

Web Servers

I'll start with the simplest load-balancing scenario - web farm.


Docker Container

Below is the Dockerfile and associated Docker compose scripting for a 2-server deployment of Python FastAPI.  Note that no IP addresses are assigned and multiple instances are deployed via Docker compose 'replicas'.


HAProxy Config

Below are the front and backend configurations.  Note the use of Docker's DNS server to enable dynamic mapping of the web servers via a HAProxy server template.

Redis Enterprise Components

Redis Enterprise can provide its own load balancing via internal DNS servers.  For those that do not want to use DNS, external load balancing is also supported.  Official Redis documentation on the general configuration of external load balancing is here.  I'm going to go into detail on the specifics of setting this up with the HAProxy load balancer in a Docker environment.

Docker Containers

A three-node cluster is provisioned below.  Note the ports that are opened:
  • 8443 - Redis Enterprise Admin Console
  • 9443 - Redis Enterprise REST API
  • 12000 - The client port configured for the database.

RE Database Configuration

Below is a JSON config that can be used via the RE REST API to create a Redis database.  Note the proxy policy.  "all-nodes" enables a database client connection point on all the Redis nodes.

RE Cluster Configuration

In the start.sh script, this command below is added to configure redirects in the Cluster (per the Redis documentation).

HAProxy Config - RE Admin Console

Redis Enterprise has a web interface for configuration and monitoring (TLS, port 8443).  I configure back-to-back TLS sessions below with a local SSL cert for the front end.  Additionally, I configure 'sticky' sessions via cookies.

HAProxy Config - RE REST API

Redis Enterprise provides a REST API for programmatic configuration and provisioning (TLS, port 9443).  For this scenario, I simply pass the TLS sessions through HAProxy via TCP.

HAProxy Config - RE Database

A Redis Enterprise database can have a configurable client connection port.  In this case, I've configured it to 12000 (TCP).  Note in the backend configuration I've set up a Layer 7 health check that will attempt to create an authenticated Redis client connection, send a Redis PING, and then close that connection.

Source


https://github.com/redis-developer/basic-acd

Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Basic ACD with Redis Enterprise

Summary

This post covers a contact ACD implementation I've done utilizing Redis data structures.  The applications are written in Python.  The client interface is implemented as REST API via FastAPI.  An internal Python app (Dispatcher) is used to monitor and administer the ACD data structures in Redis.  Docker containers are used for architectural components.


Application Architecture



Data Structures


Contact, Queue


Contacts are implemented as Redis JSON objects.  Each contact has an associated array of skills necessary to service that contact.  Example:  English language proficiency.

A single queue for all contacts is implemented as a Redis Sorted Set.  The members of the set are the Redis key names of the contacts.  The associated scores are millisecond timestamps of the time the contact entered the queue.  This allows for FIFO queue management  


Agent


Agents are implemented as Redis JSON objects.  Agent meta-data is stored as simple properties.  Agent skills are maintained as arrays.  The redis-py implementation of Redlock is used to ensure mutual exclusion to agent objects.


Agent Availability


Redis Sorted Sets are also used to track Agent availability.  A sorted set is created per skill.  The members of that set are the Redis keys for the agents that are available with the associated skill.  The associated scores are millisecond timestamps of the time the agent became available.  This use of sorted sets allows for multi-skill routing to the longest available agent (LAA).


Operations


Agent Targeting 


Routing of contacts to agents is performed by multiple Dispatcher processes.  Each Dispatcher is running an infinite loop that does the following:
  • Pop the oldest contact from the queue
  • Perform an intersection of the availability sets for the skills necessary for that contact
  • If there are agent(s) available, assign that agent to this contact and set the agent to unavailable.
  • If there are no agents available with the necessary skills, put the contact back in the queue

Source


Sunday, November 19, 2023

DICOM Image Caching with Redis

 Summary

This post covers a demonstration of the usage of Redis for caching DICOM imagery.  I use a Jupyter Notebook to step through loading and searching DICOM images in a Redis Enterprise environment.

Architecture




Redis Enterprise Environment

Screen-shot below of the resulting environment in Docker.



Sample DICOM Image

I use a portion of sample images included with the Pydicom lib.  Below is an example:


Code Snippets

Data Load

The code below loops through the Pydicom-included DICOM files.  Those that contain the meta-data that is going to be subsequently used for some search scenarios are broken up into 5 KB chunks and stored as Redis Strings.  Those chunks and the meta-data are then saved to a Redis JSON object.  The chunks' Redis key names are stored as an array in that JSON object.

Search Scenario 1

This code retrieves all the byte chunks for a DICOM image where the Redis key is known.  Strictly, speaking this isn't a 'search'.  I'm simply performing a JSON GET for a key name.

Search Scenario 2

The code below demonstrates how to put together a Redis Search on the image meta-data.  In this case, we're looking for a DICOM image with a protocolName of 194 and studyDate in 2019.

Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Sunday, November 5, 2023

Redis Vector Database Sizing Tool

Summary

In this post, I cover a utility I wrote for observing Redis vector data and index sizes with varying data types and index parameters.  The tool creates a single-node, single-shard Redis Enterprise database with the Search and JSON modules enabled.

Code Snippets

Constants and Enums



Redis Index Build and Data Load


Sample Results


Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Redis Search - Rental Availability

Summary

This post covers a very specific use case of Redis in the short-term rental domain.  Specifically, Redis is used to find property availability in a given geographic area and date/time slot.

Architecture


Code Snippets

Data Load

The code below loads rental properties as Redis JSON objects and US Postal ZIP codes with their associated lat/longs as Redis strings.


Property Search

The code below represents an Expressjs route for performing searches on the Redis properties.  The search is performed on rental property type and geographic distance from a given location.

Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Monday, May 29, 2023

OpenAI Q&A using Redis VSS for Context

Summary

I'll be covering the use case of providing supplemental context to OpenAI in a question/answer scenario (ChatGPT).  Various news articles will be vectorized and stored in Redis.  For a given question that lies outside of ChatGPT's knowledge, additional context will be fetched from Redis via Vector Similarity Search (VSS).   That context will aid ChatGPT in providing a more accurate answer.

Architecture


Code Snippets

OpenAI Prompt/Collect Helper Function


The code below is a simple function for sending a prompt into ChatGPT and then extracting the resulting response.

OpenAI QnA Example 1


The prompt below is on a topic (FTX meltdown) that is outside of ChatGPT's training cut-off date. As a result, the response is of poor quality (wrong).

Redis Context Index Build


The code below uses Redis-py client lib to build an index for business article content in Redis. The index has two fields in its schema: the text content itself and a vector representing the embedding of that text content.

Context Storage as Redis JSON


The code below loads up a dozen different business articles into Redis as JSON objects.

RedisInsight



Redis Vector Search (KNN)


A vector search in Redis is depicted below. This particular query picks the #1 article as far as vector distance to a given question (prompt).

Reprompt ChatGPT with Redis-fetched Context


The context fetched in the previous step is now added as supplemental info to ChatGPT for the same FTX-related question. The response is now in line with expectations.

Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

OpenAI + Redis VSS w/JSON

Summary

This post will cover an example of how to use Redis Vector Similarity Search (VSS) capabilities with OpenAI as the embedding engine.  Documents will be stored as JSON objects within Redis and then searched via VSS via KNN and Hybrid queries.

Architecture

Code Snippets

OpenAI Embedding


Redis Index Creation


Redis JSON Document Insertion


RedisInsight



Redis Semantic Search (KNN)


Redis Hybrid Search (Full-text + KNN)


Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Saturday, May 27, 2023

Redis Polygon Search

Summary

This post will demonstrate the usage of a new search feature within Redis - geospatial search with polygons.  This search feature is part of the 7.2.0-M01 Redis Stack release.  This initial release supports the WITHIN and CONTAINS query types for polygons, only.  Additional geospatial search types will be forthcoming in future releases.  

Architecture


Code Snippets

Point Generation

I use the Shapely module to generate the geometries for this demo.  The code snippet below will generate a random point, optionally within a bounding box.

Polygon Generation

Random polygons can be generated using the random point function above.  By passing a polygon as an input parameter, the generated polygon can be placed inside that input polygon.

Redis Polygon Search Index

The command below creates an index on the polygons with the new keyword 'GEOMETRY' for their associated WKT-formatted points.  Note this code is sending a raw CLI command to Redis.  The redis-py lib does not support the new geospatial command sets at the time of this writing.

Redis Polygon Load as JSON

The code below inserts 4 polygons into Redis as JSON objects.  Those objects are indexed within Redis by the code above.
  

Redis Polygon Search

Redis Polygon search (contains or within) code below. Again, this is the raw CLI command.

Results

Plot






Results


Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Sunday, April 23, 2023

Redis Document/Search - Java Examples

Summary

This post will provide some snippets from Redis Query Workshop available on GitHub.  That workshop covers parallel examples in CLI, Python, Nodejs, Java, and C#.  This post will focus on Java examples.



Basic JSON


Basic Search


Advanced JSON


Advanced Search


Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Redis Document/Search - C# Examples

Summary

This post will provide some snippets from Redis Query Workshop available on GitHub.  That workshop covers parallel examples in CLI, Python, Nodejs, Java, and C#.  This post will focus on C# examples.



Basic JSON


Basic Search


Advanced JSON


Advanced Search


Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Redis Document/Search - Nodejs Examples

Summary

This post will provide some snippets from Redis Query Workshop available on GitHub.  That workshop covers parallel examples in CLI, Python, Nodejs, Java, and C#.  This post will focus on Nodejs examples.



Basic JSON


Basic Search


Advanced JSON


Advanced Search


Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.

Redis Document/Search - Python Examples

Summary

This post will provide some snippets from Redis Query Workshop available on GitHub.  That workshop covers parallel examples in CLI, Python, Nodejs, Java, and C#.  This post will focus on Python examples.



Basic JSON


Basic Search


Advanced JSON


Advanced Search


Source


Copyright ©1993-2024 Joey E Whelan, All rights reserved.