Databases 11 min read

Using Redis as a Vector Database with Go: Index Creation, Data Insertion, and Vector Search

This article explains how to leverage Redis Stack modules such as RedisJSON, RediSearch, and RedisTimeSeries to store, index, and query high‑dimensional vectors for image‑search services, providing Go code examples for index creation, bulk insertion, memory inspection, and K‑Nearest‑Neighbour vector searches with optional filtering.

System Architect Go
System Architect Go
System Architect Go
Using Redis as a Vector Database with Go: Index Creation, Data Insertion, and Vector Search

Preface

Beyond its well‑known caching capabilities, Redis offers modules like RedisJSON, RediSearch, RedisTimeSeries, and RedisBloom that add JSON handling, full‑text and vector search, time‑series data, and probabilistic structures. All of these can be imported on demand or bundled in Redis Stack for immediate use.

This article briefly describes how Redis can be used as a vector database.

Redis as a Vector Database

Assume we want to build an image‑search service. The core data model includes: photoID: unique identifier for each image userID: identifier of the image owner, usable as a filter vector: the feature vector representing the image

Creating the Index & Inserting Vectors

We store the data in JSON format and use the FT.CREATE command to create an index (required for vector search):

FT.CREATE photos ON JSON
PREFIX 1 photoID: SCORE 1.0
SCHEMA
    $.userID as userID NUMERIC
    $.vector AS vector VECTOR FLAT 6 TYPE FLOAT32 DIM 512 DISTANCE_METRIC L2

The command creates a JSON‑based index named photos that applies to keys prefixed with photoID:. Two fields are indexed: userID (numeric) and vector (a 512‑dimensional FLOAT32 vector using the FLAT similarity algorithm with L2 distance).

Below is a Go implementation that creates the index and inserts 1,000 random 512‑dimensional vectors:

package redis_test

import (
    "bytes"
    "context"
    "encoding/binary"
    "encoding/json"
    "fmt"
    "math/rand"
    "strconv"

    "github.com/redis/go-redis/v9"
)

func GenVectorArr(dim int) []float32 {
    vectors := make([]float32, dim)
    for i := 0; i < dim; i++ {
        vectors[i] = rand.Float32()
    }
    return vectors
}

type Photos struct {
    ID     int      `json:"-"`
    UserID int      `json:"userID"`
    Vector []float32 `json:"vector"`
}

var rds *redis.Client

func getRedisClient() *redis.Client {
    if rds == nil {
        rds = redis.NewClient(&redis.Options{Addr: "your-redis-host", Username: "xxxx", Password: "xxxx"})
    }
    return rds
}

func CreateVector() {
    rdb := getRedisClient()
    ctx := context.Background()
    rdb.FlushAll(ctx)

    // Create index (FT.CREATE ...)
    val, err := rdb.Do(ctx, "FT.CREATE", "photos", "ON", "JSON", "PREFIX", "1", "photoID:", "SCORE", "1.0", "SCHEMA", "$.userID", "as", "userID", "NUMERIC", "$.vector", "as", "vector", "VECTOR", "FLAT", "6", "TYPE", "FLOAT32", "DIM", "512", "DISTANCE_METRIC", "L2").Result()
    if err != nil { panic(err) }
    fmt.Println("FT.CREATE:", val.(string))

    // Insert 1000 vectors
    for i := 0; i < 1000; i++ {
        photo := Photos{ID: 100000 + i, UserID: 200000 + (i / 100), Vector: GenVectorArr(512)}
        photobytes, _ := json.Marshal(photo)
        if r := rdb.JSONSet(ctx, "photoID:"+strconv.Itoa(photo.ID), "$", photobytes); r.Err() != nil { panic(r.Err()) }
    }
}

The example uses JSON.SET to store each generated vector.

Memory usage per record can be inspected with JSON.DEBUG MEMORY:

> JSON.DEBUG memory photoID:100000
(integer) 16552

Thus a single record occupies roughly 16 KB; 1,000 records need about 16 MB, and one million would require ~16 GB.

Index information can be retrieved with FT.INFO.

Vector Search

Vector search is performed with the FT.SEARCH command.

Example 1 – basic K‑NN search returning the top 10 closest vectors and the associated userID:

FT.SEARCH photos "*=>[KNN 10 @vector $BLOB AS my_scores]" 
    RETURN 1 $.userID 
    PARAMS 2 
    BLOB "query vector" 
    SORTBY my_scores 
    DIALECT 2

Explanation:

Searches the photos index using K‑NN on the vector field.

Returns only the userID field to avoid transferring large vectors.

Two parameters are passed: the binary blob of the query vector.

Results are sorted by the computed similarity score.

Example 2 – adds a pre‑filter on userID range:

FT.SEARCH photos "(@userID:[200000,200000])=>[KNN $K @vector $BLOB AS my_scores]" 
    RETURN 1 $.userID 
    PARAMS 4 
    BLOB "query vector" 
    K 3 
    SORTBY my_scores 
    DIALECT 2

Go code for the filtered search:

func Float32SliceToBytes(data []float32) ([]byte, error) {
    buf := new(bytes.Buffer)
    if err := binary.Write(buf, binary.LittleEndian, data); err != nil { return nil, err }
    return buf.Bytes(), nil
}

func SearchVector() {
    rdb := getRedisClient()
    ctx := context.Background()
    searchVector := GenVectorArr(512)
    searchBlob, _ := Float32SliceToBytes(searchVector)

    // Basic KNN search
    val, err := rdb.Do(ctx, "FT.SEARCH", "photos", "*=>[KNN 10 @vector $BLOB AS my_scores]", "RETURN", "1", "$.userID", "PARAMS", "2", "BLOB", searchBlob, "SORTBY", "my_scores", "DIALECT", "2").Result()
    if err != nil { panic(err) }
    fmt.Println("FT.SEARCH:", val)

    // KNN with userID filter
    r2, err := rdb.Do(ctx, "FT.SEARCH", "photos", "(@userID:[200000,200000])=>[KNN $K @vector $BLOB AS my_scores]", "RETURN", "1", "$.userID", "PARAMS", "4", "BLOB", searchBlob, "K", "3", "SORTBY", "my_scores", "DIALECT", "2").Result()
    if err != nil { panic(err) }
    fmt.Println("FT.SEARCH with filter total results:", r2)
}

Performance

Redis published a benchmark article titled “Benchmarking results for vector databases”, concluding that Redis delivers the highest throughput and lowest latency among tested vector stores.

Because vector calculations are CPU‑intensive, Redis employs multi‑threading for search operations to avoid blocking the main event loop.

For modest data volumes, using Redis as a vector database is a practical and high‑performance choice.

References:

https://redis.io/blog/benchmarking-results-for-vector-databases/

https://cookbook.openai.com/examples/vector_databases/redis/getting-started-with-redis-and-openai

https://redis.io/docs/latest/develop/get-started/vector-database/

https://redis.io/docs/latest/develop/interact/search-and-query/advanced-concepts/vectors/

https://redis.io/docs/latest/develop/interact/search-and-query/indexing/

https://redis.io/docs/latest/develop/interact/search-and-query/query/vector-search/

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

IndexingGoJSONft-searchvector-database
System Architect Go
Written by

System Architect Go

Programming, architecture, application development, message queues, middleware, databases, containerization, big data, image processing, machine learning, AI, personal growth.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.