Memory optimization
Learn how to optimize memory consumption in Redis vector sets
Vector set is a new data type that is currently in preview and may be subject to change.
Overview
Redis vector sets are efficient, but vector similarity indexing and graph traversal require memory tradeoffs. This guide helps you manage memory use through quantization, graph tuning, and attribute choices.
Quantization modes
Vector sets support three quantization levels:
Mode | Memory usage | Recall | Notes |
---|---|---|---|
Q8 |
4x smaller | High | Default, fast and accurate |
BIN |
32x smaller | Lower | Fastest, best for coarse search |
NOQUANT |
Full size | Highest | Best precision, slowest |
Use Q8
unless your use case demands either ultra-precision (use NOQUANT
) or ultra-efficiency (use BIN
).
Graph structure memory
HNSW graphs store multiple connections per node. Each node:
- Has an average of
M * 2 + M * 0.33
pointers (default M = 16). - Stores pointers using 8 bytes each.
- Allocates ~1.33 layers per node.
A single node with M = 64 may consume ~1 KB in links alone.
To reduce memory:
- Lower
M
to shrink per-node connections. - Avoid unnecessarily large values for
M
unless recall needs to be improved.
Attribute and label size
Each node stores:
- A string label (element name)
- Optional JSON attribute string
Tips:
- Use short, fixed-length strings for labels.
- Keep attribute JSON minimal and flat. For example, use
{"year":2020}
instead of nested data.
Vector dimension
High-dimensional vectors increase storage:
- 300 components at
FP32
= 1200 bytes/vector - 300 components at
Q8
= 300 bytes/vector
You can reduce this using the REDUCE
option during VADD
, which applies random projection:
>VADD setNotReduced VALUES 300 ... element
(integer) 1
> VDIM setNotReduced
(integer) 300
>VADD setReduced REDUCE 100 VALUES 300 ... element
(integer) 1
> VDIM setReduced
(integer) 100
"""
Code samples for Vector set doc pages:
https://redis.io/docs/latest/develop/data-types/vector-sets/
"""
import redis
from redis.commands.vectorset.commands import (
QuantizationOptions
)
r = redis.Redis(decode_responses=True)
res1 = r.vset().vadd("points", [1.0, 1.0], "pt:A")
print(res1) # >>> 1
res2 = r.vset().vadd("points", [-1.0, -1.0], "pt:B")
print(res2) # >>> 1
res3 = r.vset().vadd("points", [-1.0, 1.0], "pt:C")
print(res3) # >>> 1
res4 = r.vset().vadd("points", [1.0, -1.0], "pt:D")
print(res4) # >>> 1
res5 = r.vset().vadd("points", [1.0, 0], "pt:E")
print(res5) # >>> 1
res6 = r.type("points")
print(res6) # >>> vectorset
res7 = r.vset().vcard("points")
print(res7) # >>> 5
res8 = r.vset().vdim("points")
print(res8) # >>> 2
res9 = r.vset().vemb("points", "pt:A")
print(res9) # >>> [0.9999999403953552, 0.9999999403953552]
res10 = r.vset().vemb("points", "pt:B")
print(res10) # >>> [-0.9999999403953552, -0.9999999403953552]
res11 = r.vset().vemb("points", "pt:C")
print(res11) # >>> [-0.9999999403953552, 0.9999999403953552]
res12 = r.vset().vemb("points", "pt:D")
print(res12) # >>> [0.9999999403953552, -0.9999999403953552]
res13 = r.vset().vemb("points", "pt:E")
print(res13) # >>> [1, 0]
res14 = r.vset().vsetattr("points", "pt:A", {
"name": "Point A",
"description": "First point added"
})
print(res14) # >>> 1
res15 = r.vset().vgetattr("points", "pt:A")
print(res15)
# >>> {'name': 'Point A', 'description': 'First point added'}
res16 = r.vset().vsetattr("points", "pt:A", "")
print(res16) # >>> 1
res17 = r.vset().vgetattr("points", "pt:A")
print(res17) # >>> None
res18 = r.vset().vadd("points", [0, 0], "pt:F")
print(res18) # >>> 1
res19 = r.vset().vcard("points")
print(res19) # >>> 6
res20 = r.vset().vrem("points", "pt:F")
print(res20) # >>> 1
res21 = r.vset().vcard("points")
print(res21) # >>> 5
res22 = r.vset().vsim("points", [0.9, 0.1])
print(res22)
# >>> ['pt:E', 'pt:A', 'pt:D', 'pt:C', 'pt:B']
res23 = r.vset().vsim(
"points", "pt:A",
with_scores=True,
count=4
)
print(res23)
# >>> {'pt:A': 1.0, 'pt:E': 0.8535534143447876, 'pt:D': 0.5, 'pt:C': 0.5}
res24 = r.vset().vsetattr("points", "pt:A", {
"size": "large",
"price": 18.99
})
print(res24) # >>> 1
res25 = r.vset().vsetattr("points", "pt:B", {
"size": "large",
"price": 35.99
})
print(res25) # >>> 1
res26 = r.vset().vsetattr("points", "pt:C", {
"size": "large",
"price": 25.99
})
print(res26) # >>> 1
res27 = r.vset().vsetattr("points", "pt:D", {
"size": "small",
"price": 21.00
})
print(res27) # >>> 1
res28 = r.vset().vsetattr("points", "pt:E", {
"size": "small",
"price": 17.75
})
print(res28) # >>> 1
# Return elements in order of distance from point A whose
# `size` attribute is `large`.
res29 = r.vset().vsim(
"points", "pt:A",
filter='.size == "large"'
)
print(res29) # >>> ['pt:A', 'pt:C', 'pt:B']
# Return elements in order of distance from point A whose size is
# `large` and whose price is greater than 20.00.
res30 = r.vset().vsim(
"points", "pt:A",
filter='.size == "large" && .price > 20.00'
)
print(res30) # >>> ['pt:C', 'pt:B']
# Import `QuantizationOptions` enum using:
#
# from redis.commands.vectorset.commands import (
# QuantizationOptions
# )
res31 = r.vset().vadd(
"quantSetQ8", [1.262185, 1.958231],
"quantElement",
quantization=QuantizationOptions.Q8
)
print(res31) # >>> 1
res32 = r.vset().vemb("quantSetQ8", "quantElement")
print(f"Q8: {res32}")
# >>> Q8: [1.2643694877624512, 1.958230972290039]
res33 = r.vset().vadd(
"quantSetNoQ", [1.262185, 1.958231],
"quantElement",
quantization=QuantizationOptions.NOQUANT
)
print(res33) # >>> 1
res34 = r.vset().vemb("quantSetNoQ", "quantElement")
print(f"NOQUANT: {res34}")
# >>> NOQUANT: [1.262184977531433, 1.958230972290039]
res35 = r.vset().vadd(
"quantSetBin", [1.262185, 1.958231],
"quantElement",
quantization=QuantizationOptions.BIN
)
print(res35) # >>> 1
res36 = r.vset().vemb("quantSetBin", "quantElement")
print(f"BIN: {res36}")
# >>> BIN: [1, 1]
# Create a list of 300 arbitrary values.
values = [x / 299 for x in range(300)]
res37 = r.vset().vadd(
"setNotReduced",
values,
"element"
)
print(res37) # >>> 1
res38 = r.vset().vdim("setNotReduced")
print(res38) # >>> 300
res39 = r.vset().vadd(
"setReduced",
values,
"element",
reduce_dim=100
)
print(res39) # >>> 1
res40 = r.vset().vdim("setReduced") # >>> 100
print(res40)
import { createClient } from 'redis';
const client = createClient({
RESP: 3 // Required for vector set commands
});
await client.connect();
const res1 = await client.vAdd("points", [1.0, 1.0], "pt:A");
console.log(res1); // >>> true
const res2 = await client.vAdd("points", [-1.0, -1.0], "pt:B");
console.log(res2); // >>> true
const res3 = await client.vAdd("points", [-1.0, 1.0], "pt:C");
console.log(res3); // >>> true
const res4 = await client.vAdd("points", [1.0, -1.0], "pt:D");
console.log(res4); // >>> true
const res5 = await client.vAdd("points", [1.0, 0], "pt:E");
console.log(res5); // >>> true
const res6 = await client.type("points");
console.log(res6); // >>> vectorset
const res7 = await client.vCard("points");
console.log(res7); // >>> 5
const res8 = await client.vDim("points");
console.log(res8); // >>> 2
const res9 = await client.vEmb("points", "pt:A");
console.log(res9); // >>> [0.9999999403953552, 0.9999999403953552]
const res10 = await client.vEmb("points", "pt:B");
console.log(res10); // >>> [-0.9999999403953552, -0.9999999403953552]
const res11 = await client.vEmb("points", "pt:C");
console.log(res11); // >>> [-0.9999999403953552, 0.9999999403953552]
const res12 = await client.vEmb("points", "pt:D");
console.log(res12); // >>> [0.9999999403953552, -0.9999999403953552]
const res13 = await client.vEmb("points", "pt:E");
console.log(res13); // >>> [1, 0]
const res14 = await client.vSetAttr("points", "pt:A", {
name: "Point A",
description: "First point added"
});
console.log(res14); // >>> true
const res15 = await client.vGetAttr("points", "pt:A");
console.log(res15);
// >>> {name: 'Point A', description: 'First point added'}
const res16 = await client.vSetAttr("points", "pt:A", "");
console.log(res16); // >>> true
const res17 = await client.vGetAttr("points", "pt:A");
console.log(res17); // >>> null
const res18 = await client.vAdd("points", [0, 0], "pt:F");
console.log(res18); // >>> true
const res19 = await client.vCard("points");
console.log(res19); // >>> 6
const res20 = await client.vRem("points", "pt:F");
console.log(res20); // >>> true
const res21 = await client.vCard("points");
console.log(res21); // >>> 5
const res22 = await client.vSim("points", [0.9, 0.1]);
console.log(res22);
// >>> ['pt:E', 'pt:A', 'pt:D', 'pt:C', 'pt:B']
const res23 = await client.vSimWithScores("points", "pt:A", { COUNT: 4 });
console.log(res23);
// >>> {pt:A: 1.0, pt:E: 0.8535534143447876, pt:D: 0.5, pt:C: 0.5}
const res24 = await client.vSetAttr("points", "pt:A", {
size: "large",
price: 18.99
});
console.log(res24); // >>> true
const res25 = await client.vSetAttr("points", "pt:B", {
size: "large",
price: 35.99
});
console.log(res25); // >>> true
const res26 = await client.vSetAttr("points", "pt:C", {
size: "large",
price: 25.99
});
console.log(res26); // >>> true
const res27 = await client.vSetAttr("points", "pt:D", {
size: "small",
price: 21.00
});
console.log(res27); // >>> true
const res28 = await client.vSetAttr("points", "pt:E", {
size: "small",
price: 17.75
});
console.log(res28); // >>> true
// Return elements in order of distance from point A whose
// `size` attribute is `large`.
const res29 = await client.vSim("points", "pt:A", {
FILTER: '.size == "large"'
});
console.log(res29); // >>> ['pt:A', 'pt:C', 'pt:B']
// Return elements in order of distance from point A whose size is
// `large` and whose price is greater than 20.00.
const res30 = await client.vSim("points", "pt:A", {
FILTER: '.size == "large" && .price > 20.00'
});
console.log(res30); // >>> ['pt:C', 'pt:B']
const res31 = await client.vAdd("quantSetQ8", [1.262185, 1.958231], "quantElement", {
QUANT: 'Q8'
});
console.log(res31); // >>> true
const res32 = await client.vEmb("quantSetQ8", "quantElement");
console.log(`Q8: ${res32}`);
// >>> Q8: [1.2643694877624512, 1.958230972290039]
const res33 = await client.vAdd("quantSetNoQ", [1.262185, 1.958231], "quantElement", {
QUANT: 'NOQUANT'
});
console.log(res33); // >>> true
const res34 = await client.vEmb("quantSetNoQ", "quantElement");
console.log(`NOQUANT: ${res34}`);
// >>> NOQUANT: [1.262184977531433, 1.958230972290039]
const res35 = await client.vAdd("quantSetBin", [1.262185, 1.958231], "quantElement", {
QUANT: 'BIN'
});
console.log(res35); // >>> true
const res36 = await client.vEmb("quantSetBin", "quantElement");
console.log(`BIN: ${res36}`);
// >>> BIN: [1, 1]
// Create a list of 300 arbitrary values.
const values = Array.from({length: 300}, (_, x) => x / 299);
const res37 = await client.vAdd("setNotReduced", values, "element");
console.log(res37); // >>> true
const res38 = await client.vDim("setNotReduced");
console.log(res38); // >>> 300
const res39 = await client.vAdd("setReduced", values, "element", {
REDUCE: 100
});
console.log(res39); // >>> true
const res40 = await client.vDim("setReduced");
console.log(res40); // >>> 100
await client.quit();
package io.redis.examples.async;
import io.lettuce.core.*;
import io.lettuce.core.api.async.RedisAsyncCommands;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.vector.QuantizationType;
import java.util.concurrent.CompletableFuture;
public class VectorSetExample {
public void run() {
RedisClient redisClient = RedisClient.create("redis://localhost:6379");
try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {
RedisAsyncCommands<String, String> asyncCommands = connection.async();
CompletableFuture<Boolean> addPointA = asyncCommands.vadd("points", "pt:A", 1.0, 1.0).thenApply(result -> {
System.out.println(result); // >>> true
return result;
}).toCompletableFuture();
CompletableFuture<Boolean> addPointB = asyncCommands.vadd("points", "pt:B", -1.0, -1.0).thenApply(result -> {
System.out.println(result); // >>> true
return result;
}).toCompletableFuture();
CompletableFuture<Boolean> addPointC = asyncCommands.vadd("points", "pt:C", -1.0, 1.0).thenApply(result -> {
System.out.println(result); // >>> true
return result;
}).toCompletableFuture();
CompletableFuture<Boolean> addPointD = asyncCommands.vadd("points", "pt:D", 1.0, -1.0).thenApply(result -> {
System.out.println(result); // >>> true
return result;
}).toCompletableFuture();
CompletableFuture<Boolean> addPointE = asyncCommands.vadd("points", "pt:E", 1.0, 0.0).thenApply(result -> {
System.out.println(result); // >>> true
return result;
}).toCompletableFuture();
// Chain checkDataType after all vadd operations complete
CompletableFuture<Void> vaddOperations = CompletableFuture
.allOf(addPointA, addPointB, addPointC, addPointD, addPointE)
.thenCompose(ignored -> asyncCommands.type("points")).thenAccept(result -> {
System.out.println(result); // >>> vectorset
}).toCompletableFuture();
CompletableFuture<Void> getCardinality = asyncCommands.vcard("points").thenAccept(result -> {
System.out.println(result); // >>> 5
}).toCompletableFuture();
CompletableFuture<Void> getDimensions = asyncCommands.vdim("points").thenAccept(result -> {
System.out.println(result); // >>> 2
}).toCompletableFuture();
CompletableFuture<Void> getEmbeddingA = asyncCommands.vemb("points", "pt:A").thenAccept(result -> {
System.out.println(result); // >>> [0.9999999403953552, 0.9999999403953552]
}).toCompletableFuture();
CompletableFuture<Void> getEmbeddingB = asyncCommands.vemb("points", "pt:B").thenAccept(result -> {
System.out.println(result); // >>> [-0.9999999403953552, -0.9999999403953552]
}).toCompletableFuture();
CompletableFuture<Void> getEmbeddingC = asyncCommands.vemb("points", "pt:C").thenAccept(result -> {
System.out.println(result); // >>> [-0.9999999403953552, 0.9999999403953552]
}).toCompletableFuture();
CompletableFuture<Void> getEmbeddingD = asyncCommands.vemb("points", "pt:D").thenAccept(result -> {
System.out.println(result); // >>> [0.9999999403953552, -0.9999999403953552]
}).toCompletableFuture();
CompletableFuture<Void> getEmbeddingE = asyncCommands.vemb("points", "pt:E").thenAccept(result -> {
System.out.println(result); // >>> [1.0, 0.0]
}).toCompletableFuture();
CompletableFuture<Void> setAttributeA = asyncCommands
.vsetattr("points", "pt:A", "{\"name\": \"Point A\", \"description\": \"First point added\"}")
.thenAccept(result -> {
System.out.println(result); // >>> true
}).toCompletableFuture();
CompletableFuture<Void> getAttributeA = asyncCommands.vgetattr("points", "pt:A").thenAccept(result -> {
System.out.println(result); // >>> {"name": "Point A", "description": "First point added"}
}).toCompletableFuture();
CompletableFuture<Void> clearAttributeA = asyncCommands.vsetattr("points", "pt:A", "").thenAccept(result -> {
System.out.println(result); // >>> true
}).toCompletableFuture();
CompletableFuture<Void> verifyAttributeCleared = asyncCommands.vgetattr("points", "pt:A").thenAccept(result -> {
System.out.println(result); // >>> null
}).toCompletableFuture();
CompletableFuture<Void> addTempPointF = asyncCommands.vadd("points", "pt:F", 0.0, 0.0).thenAccept(result -> {
System.out.println(result); // >>> true
}).toCompletableFuture();
CompletableFuture<Void> checkCardinalityBefore = asyncCommands.vcard("points").thenAccept(result -> {
System.out.println(result); // >>> 6
}).toCompletableFuture();
CompletableFuture<Void> removePointF = asyncCommands.vrem("points", "pt:F").thenAccept(result -> {
System.out.println(result); // >>> true
}).toCompletableFuture();
CompletableFuture<Void> checkCardinalityAfter = asyncCommands.vcard("points").thenAccept(result -> {
System.out.println(result); // >>> 5
}).toCompletableFuture();
CompletableFuture<Void> basicSimilaritySearch = asyncCommands.vsim("points", 0.9, 0.1).thenAccept(result -> {
System.out.println(result); // >>> [pt:E, pt:A, pt:D, pt:C, pt:B]
}).toCompletableFuture();
VSimArgs vsimArgs = new VSimArgs();
vsimArgs.count(4L);
CompletableFuture<Void> similaritySearchWithScore = asyncCommands.vsimWithScore("points", vsimArgs, "pt:A")
.thenAccept(result -> {
System.out.println(result); // >>> {pt:A=1.0, pt:E=0.8535534143447876, pt:D=0.5, pt:C=0.5}
}).toCompletableFuture();
CompletableFuture<Void> filteredSimilaritySearch = asyncCommands
.vsetattr("points", "pt:A", "{\"size\": \"large\", \"price\": 18.99}").thenCompose(result -> {
System.out.println(result); // >>> true
return asyncCommands.vsetattr("points", "pt:B", "{\"size\": \"large\", \"price\": 35.99}");
}).thenCompose(result -> {
System.out.println(result); // >>> true
return asyncCommands.vsetattr("points", "pt:C", "{\"size\": \"large\", \"price\": 25.99}");
}).thenCompose(result -> {
System.out.println(result); // >>> true
return asyncCommands.vsetattr("points", "pt:D", "{\"size\": \"small\", \"price\": 21.00}");
}).thenCompose(result -> {
System.out.println(result); // >>> true
return asyncCommands.vsetattr("points", "pt:E", "{\"size\": \"small\", \"price\": 17.75}");
}).thenCompose(result -> {
System.out.println(result); // >>> true
// Return elements in order of distance from point A whose size attribute is large.
VSimArgs filterArgs = new VSimArgs();
filterArgs.filter(".size == \"large\"");
return asyncCommands.vsim("points", filterArgs, "pt:A");
}).thenCompose(result -> {
System.out.println(result); // >>> [pt:A, pt:C, pt:B]
// Return elements in order of distance from point A whose size is large and price > 20.00.
VSimArgs filterArgs2 = new VSimArgs();
filterArgs2.filter(".size == \"large\" && .price > 20.00");
return asyncCommands.vsim("points", filterArgs2, "pt:A");
}).thenAccept(result -> {
System.out.println(result); // >>> [pt:C, pt:B]
}).toCompletableFuture();
VAddArgs q8Args = VAddArgs.Builder.quantizationType(QuantizationType.Q8);
CompletableFuture<Void> quantizationOperations = asyncCommands
.vadd("quantSetQ8", "quantElement", q8Args, 1.262185, 1.958231).thenCompose(result -> {
System.out.println(result); // >>> true
return asyncCommands.vemb("quantSetQ8", "quantElement");
}).thenCompose(result -> {
System.out.println("Q8: " + result); // >>> Q8: [1.2643694877624512, 1.958230972290039]
VAddArgs noQuantArgs = VAddArgs.Builder.quantizationType(QuantizationType.NO_QUANTIZATION);
return asyncCommands.vadd("quantSetNoQ", "quantElement", noQuantArgs, 1.262185, 1.958231);
}).thenCompose(result -> {
System.out.println(result); // >>> true
return asyncCommands.vemb("quantSetNoQ", "quantElement");
}).thenCompose(result -> {
System.out.println("NOQUANT: " + result); // >>> NOQUANT: [1.262184977531433, 1.958230972290039]
VAddArgs binArgs = VAddArgs.Builder.quantizationType(QuantizationType.BINARY);
return asyncCommands.vadd("quantSetBin", "quantElement", binArgs, 1.262185, 1.958231);
}).thenCompose(result -> {
System.out.println(result); // >>> true
return asyncCommands.vemb("quantSetBin", "quantElement");
}).thenAccept(result -> {
System.out.println("BIN: " + result); // >>> BIN: [1.0, 1.0]
}).toCompletableFuture();
// Create a list of 300 arbitrary values.
Double[] values = new Double[300];
for (int i = 0; i < 300; i++) {
values[i] = (double) i / 299;
}
CompletableFuture<Void> dimensionalityReductionOperations = asyncCommands.vadd("setNotReduced", "element", values)
.thenCompose(result -> {
System.out.println(result); // >>> true
return asyncCommands.vdim("setNotReduced");
}).thenCompose(result -> {
System.out.println(result); // >>> 300
return asyncCommands.vadd("setReduced", 100, "element", values);
}).thenCompose(result -> {
System.out.println(result); // >>> true
return asyncCommands.vdim("setReduced");
}).thenAccept(result -> {
System.out.println(result); // >>> 100
}).toCompletableFuture();
// Wait for all async operations to complete
CompletableFuture.allOf(
// Vector addition operations (chained: parallel vadd + sequential checkDataType)
vaddOperations,
// Cardinality and dimension operations
getCardinality, getDimensions,
// Vector embedding retrieval operations
getEmbeddingA, getEmbeddingB, getEmbeddingC, getEmbeddingD, getEmbeddingE,
// Attribute operations
setAttributeA, getAttributeA, clearAttributeA, verifyAttributeCleared,
// Vector removal operations
addTempPointF, checkCardinalityBefore, removePointF, checkCardinalityAfter,
// Similarity search operations
basicSimilaritySearch, similaritySearchWithScore, filteredSimilaritySearch,
// Advanced operations
quantizationOperations, dimensionalityReductionOperations).join();
} finally {
redisClient.shutdown();
}
}
}
package io.redis.examples.reactive;
import io.lettuce.core.*;
import io.lettuce.core.api.reactive.RedisReactiveCommands;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.vector.QuantizationType;
import reactor.core.publisher.Mono;
public class VectorSetExample {
public void run() {
RedisClient redisClient = RedisClient.create("redis://localhost:6379");
try (StatefulRedisConnection<String, String> connection = redisClient.connect()) {
RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();
Mono<Boolean> addPointA = reactiveCommands.vadd("points", "pt:A", 1.0, 1.0).doOnNext(result -> {
System.out.println(result); // >>> true
});
Mono<Boolean> addPointB = reactiveCommands.vadd("points", "pt:B", -1.0, -1.0).doOnNext(result -> {
System.out.println(result); // >>> true
});
Mono<Boolean> addPointC = reactiveCommands.vadd("points", "pt:C", -1.0, 1.0).doOnNext(result -> {
System.out.println(result); // >>> true
});
Mono<Boolean> addPointD = reactiveCommands.vadd("points", "pt:D", 1.0, -1.0).doOnNext(result -> {
System.out.println(result); // >>> true
});
Mono<Boolean> addPointE = reactiveCommands.vadd("points", "pt:E", 1.0, 0.0).doOnNext(result -> {
System.out.println(result); // >>> true
});
Mono<Void> vaddOperations = Mono.when(addPointA, addPointB, addPointC, addPointD, addPointE)
.then(reactiveCommands.type("points")).doOnNext(result -> {
System.out.println(result); // >>> vectorset
}).then();
Mono<Long> getCardinality = reactiveCommands.vcard("points").doOnNext(result -> {
System.out.println(result); // >>> 5
});
Mono<Long> getDimensions = reactiveCommands.vdim("points").doOnNext(result -> {
System.out.println(result); // >>> 2
});
Mono<java.util.List<Double>> getEmbeddingA = reactiveCommands.vemb("points", "pt:A").collectList()
.doOnNext(result -> {
System.out.println(result); // >>> [0.9999999403953552, 0.9999999403953552]
});
Mono<java.util.List<Double>> getEmbeddingB = reactiveCommands.vemb("points", "pt:B").collectList()
.doOnNext(result -> {
System.out.println(result); // >>> [-0.9999999403953552, -0.9999999403953552]
});
Mono<java.util.List<Double>> getEmbeddingC = reactiveCommands.vemb("points", "pt:C").collectList()
.doOnNext(result -> {
System.out.println(result); // >>> [-0.9999999403953552, 0.9999999403953552]
});
Mono<java.util.List<Double>> getEmbeddingD = reactiveCommands.vemb("points", "pt:D").collectList()
.doOnNext(result -> {
System.out.println(result); // >>> [0.9999999403953552, -0.9999999403953552]
});
Mono<java.util.List<Double>> getEmbeddingE = reactiveCommands.vemb("points", "pt:E").collectList()
.doOnNext(result -> {
System.out.println(result); // >>> [1.0, 0.0]
});
Mono<Boolean> setAttributeA = reactiveCommands
.vsetattr("points", "pt:A", "{\"name\": \"Point A\", \"description\": \"First point added\"}")
.doOnNext(result -> {
System.out.println(result); // >>> true
});
Mono<String> getAttributeA = reactiveCommands.vgetattr("points", "pt:A").doOnNext(result -> {
System.out.println(result); // >>> {"name": "Point A", "description": "First point added"}
});
Mono<Boolean> clearAttributeA = reactiveCommands.vsetattr("points", "pt:A", "").doOnNext(result -> {
System.out.println(result); // >>> true
});
Mono<String> verifyAttributeCleared = reactiveCommands.vgetattr("points", "pt:A").doOnNext(result -> {
System.out.println(result); // >>> null
});
Mono<Boolean> addTempPointF = reactiveCommands.vadd("points", "pt:F", 0.0, 0.0).doOnNext(result -> {
System.out.println(result); // >>> true
});
Mono<Long> checkCardinalityBefore = reactiveCommands.vcard("points").doOnNext(result -> {
System.out.println(result); // >>> 6
});
Mono<Boolean> removePointF = reactiveCommands.vrem("points", "pt:F").doOnNext(result -> {
System.out.println(result); // >>> true
});
Mono<Long> checkCardinalityAfter = reactiveCommands.vcard("points").doOnNext(result -> {
System.out.println(result); // >>> 5
});
Mono<java.util.List<String>> basicSimilaritySearch = reactiveCommands.vsim("points", 0.9, 0.1).collectList()
.doOnNext(result -> {
System.out.println(result); // >>> [pt:E, pt:A, pt:D, pt:C, pt:B]
});
VSimArgs vsimArgs = new VSimArgs();
vsimArgs.count(4L);
Mono<java.util.Map<String, Double>> similaritySearchWithScore = reactiveCommands
.vsimWithScore("points", vsimArgs, "pt:A").doOnNext(result -> {
System.out.println(result); // >>> {pt:A=1.0, pt:E=0.8535534143447876, pt:D=0.5, pt:C=0.5}
});
Mono<Void> filteredSimilaritySearch = reactiveCommands
.vsetattr("points", "pt:A", "{\"size\": \"large\", \"price\": 18.99}").doOnNext(result -> {
System.out.println(result); // >>> true
}).flatMap(result -> reactiveCommands.vsetattr("points", "pt:B", "{\"size\": \"large\", \"price\": 35.99}"))
.doOnNext(result -> {
System.out.println(result); // >>> true
}).flatMap(result -> reactiveCommands.vsetattr("points", "pt:C", "{\"size\": \"large\", \"price\": 25.99}"))
.doOnNext(result -> {
System.out.println(result); // >>> true
}).flatMap(result -> reactiveCommands.vsetattr("points", "pt:D", "{\"size\": \"small\", \"price\": 21.00}"))
.doOnNext(result -> {
System.out.println(result); // >>> true
}).flatMap(result -> reactiveCommands.vsetattr("points", "pt:E", "{\"size\": \"small\", \"price\": 17.75}"))
.doOnNext(result -> {
System.out.println(result); // >>> true
}).flatMap(result -> {
// Return elements in order of distance from point A whose size attribute is large.
VSimArgs filterArgs = new VSimArgs();
filterArgs.filter(".size == \"large\"");
return reactiveCommands.vsim("points", filterArgs, "pt:A").collectList();
}).doOnNext(result -> {
System.out.println(result); // >>> [pt:A, pt:C, pt:B]
}).flatMap(result -> {
// Return elements in order of distance from point A whose size is large and price > 20.00.
VSimArgs filterArgs2 = new VSimArgs();
filterArgs2.filter(".size == \"large\" && .price > 20.00");
return reactiveCommands.vsim("points", filterArgs2, "pt:A").collectList();
}).doOnNext(result -> {
System.out.println(result); // >>> [pt:C, pt:B]
}).then();
VAddArgs q8Args = VAddArgs.Builder.quantizationType(QuantizationType.Q8);
Mono<Void> quantizationOperations = reactiveCommands.vadd("quantSetQ8", "quantElement", q8Args, 1.262185, 1.958231)
.doOnNext(result -> {
System.out.println(result); // >>> true
}).flatMap(result -> reactiveCommands.vemb("quantSetQ8", "quantElement").collectList()).doOnNext(result -> {
System.out.println("Q8: " + result); // >>> Q8: [1.2643694877624512, 1.958230972290039]
}).flatMap(result -> {
VAddArgs noQuantArgs = VAddArgs.Builder.quantizationType(QuantizationType.NO_QUANTIZATION);
return reactiveCommands.vadd("quantSetNoQ", "quantElement", noQuantArgs, 1.262185, 1.958231);
}).doOnNext(result -> {
System.out.println(result); // >>> true
}).flatMap(result -> reactiveCommands.vemb("quantSetNoQ", "quantElement").collectList())
.doOnNext(result -> {
System.out.println("NOQUANT: " + result); // >>> NOQUANT: [1.262184977531433, 1.958230972290039]
}).flatMap(result -> {
VAddArgs binArgs = VAddArgs.Builder.quantizationType(QuantizationType.BINARY);
return reactiveCommands.vadd("quantSetBin", "quantElement", binArgs, 1.262185, 1.958231);
}).doOnNext(result -> {
System.out.println(result); // >>> true
}).flatMap(result -> reactiveCommands.vemb("quantSetBin", "quantElement").collectList())
.doOnNext(result -> {
System.out.println("BIN: " + result); // >>> BIN: [1.0, 1.0]
}).then();
// Create a list of 300 arbitrary values.
Double[] values = new Double[300];
for (int i = 0; i < 300; i++) {
values[i] = (double) i / 299;
}
Mono<Void> dimensionalityReductionOperations = reactiveCommands.vadd("setNotReduced", "element", values)
.doOnNext(result -> {
System.out.println(result); // >>> true
}).flatMap(result -> reactiveCommands.vdim("setNotReduced")).doOnNext(result -> {
System.out.println(result); // >>> 300
}).flatMap(result -> reactiveCommands.vadd("setReduced", 100, "element", values)).doOnNext(result -> {
System.out.println(result); // >>> true
}).flatMap(result -> reactiveCommands.vdim("setReduced")).doOnNext(result -> {
System.out.println(result); // >>> 100
}).then();
// Wait for all reactive operations to complete
Mono.when(
// Vector addition operations (chained sequentially)
vaddOperations,
// Cardinality and dimension operations
getCardinality, getDimensions,
// Vector embedding retrieval operations
getEmbeddingA, getEmbeddingB, getEmbeddingC, getEmbeddingD, getEmbeddingE,
// Attribute operations
setAttributeA, getAttributeA, clearAttributeA, verifyAttributeCleared,
// Vector removal operations
addTempPointF, checkCardinalityBefore, removePointF, checkCardinalityAfter,
// Similarity search operations
basicSimilaritySearch, similaritySearchWithScore, filteredSimilaritySearch,
// Advanced operations
quantizationOperations, dimensionalityReductionOperations).block();
} finally {
redisClient.shutdown();
}
}
}
package example_commands_test
import (
"context"
"fmt"
"sort"
"github.com/redis/go-redis/v9"
)
func ExampleClient_vectorset() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
defer rdb.Close()
res1, err := rdb.VAdd(ctx, "points", "pt:A",
&redis.VectorValues{Val: []float64{1.0, 1.0}},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res1) // >>> true
res2, err := rdb.VAdd(ctx, "points", "pt:B",
&redis.VectorValues{Val: []float64{-1.0, -1.0}},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res2) // >>> true
res3, err := rdb.VAdd(ctx, "points", "pt:C",
&redis.VectorValues{Val: []float64{-1.0, 1.0}},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res3) // >>> true
res4, err := rdb.VAdd(ctx, "points", "pt:D",
&redis.VectorValues{Val: []float64{1.0, -1.0}},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res4) // >>> true
res5, err := rdb.VAdd(ctx, "points", "pt:E",
&redis.VectorValues{Val: []float64{1.0, 0.0}},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res5) // >>> true
res6, err := rdb.Type(ctx, "points").Result()
if err != nil {
panic(err)
}
fmt.Println(res6) // >>> vectorset
res7, err := rdb.VCard(ctx, "points").Result()
if err != nil {
panic(err)
}
fmt.Println(res7) // >>> 5
res8, err := rdb.VDim(ctx, "points").Result()
if err != nil {
panic(err)
}
fmt.Println(res8) // >>> 2
res9, err := rdb.VEmb(ctx, "points", "pt:A", false).Result()
if err != nil {
panic(err)
}
fmt.Println(res9) // >>> [0.9999999403953552 0.9999999403953552]
res10, err := rdb.VEmb(ctx, "points", "pt:B", false).Result()
if err != nil {
panic(err)
}
fmt.Println(res10) // >>> [-0.9999999403953552 -0.9999999403953552]
res11, err := rdb.VEmb(ctx, "points", "pt:C", false).Result()
if err != nil {
panic(err)
}
fmt.Println(res11) // >>> [-0.9999999403953552 0.9999999403953552]
res12, err := rdb.VEmb(ctx, "points", "pt:D", false).Result()
if err != nil {
panic(err)
}
fmt.Println(res12) // >>> [0.9999999403953552 -0.9999999403953552]
res13, err := rdb.VEmb(ctx, "points", "pt:E", false).Result()
if err != nil {
panic(err)
}
fmt.Println(res13) // >>> [1 0]
attrs := map[string]interface{}{
"name": "Point A",
"description": "First point added",
}
res14, err := rdb.VSetAttr(ctx, "points", "pt:A", attrs).Result()
if err != nil {
panic(err)
}
fmt.Println(res14) // >>> true
res15, err := rdb.VGetAttr(ctx, "points", "pt:A").Result()
if err != nil {
panic(err)
}
fmt.Println(res15)
// >>> {"description":"First point added","name":"Point A"}
res16, err := rdb.VClearAttributes(ctx, "points", "pt:A").Result()
if err != nil {
panic(err)
}
fmt.Println(res16) // >>> true
// `VGetAttr()` returns an error if the attribute doesn't exist.
_, err = rdb.VGetAttr(ctx, "points", "pt:A").Result()
if err != nil {
fmt.Println(err)
}
res18, err := rdb.VAdd(ctx, "points", "pt:F",
&redis.VectorValues{Val: []float64{0.0, 0.0}},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res18) // >>> true
res19, err := rdb.VCard(ctx, "points").Result()
if err != nil {
panic(err)
}
fmt.Println(res19) // >>> 6
res20, err := rdb.VRem(ctx, "points", "pt:F").Result()
if err != nil {
panic(err)
}
fmt.Println(res20) // >>> true
res21, err := rdb.VCard(ctx, "points").Result()
if err != nil {
panic(err)
}
fmt.Println(res21) // >>> 5
res22, err := rdb.VSim(ctx, "points",
&redis.VectorValues{Val: []float64{0.9, 0.1}},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res22) // >>> [pt:E pt:A pt:D pt:C pt:B]
res23, err := rdb.VSimWithArgsWithScores(
ctx,
"points",
&redis.VectorRef{Name: "pt:A"},
&redis.VSimArgs{Count: 4},
).Result()
if err != nil {
panic(err)
}
sort.Slice(res23, func(i, j int) bool {
return res23[i].Name < res23[j].Name
})
fmt.Println(res23)
// >>> [{pt:A 1} {pt:C 0.5} {pt:D 0.5} {pt:E 0.8535534143447876}]
// Set attributes for filtering
res24, err := rdb.VSetAttr(ctx, "points", "pt:A",
map[string]interface{}{
"size": "large",
"price": 18.99,
},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res24) // >>> true
res25, err := rdb.VSetAttr(ctx, "points", "pt:B",
map[string]interface{}{
"size": "large",
"price": 35.99,
},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res25) // >>> true
res26, err := rdb.VSetAttr(ctx, "points", "pt:C",
map[string]interface{}{
"size": "large",
"price": 25.99,
},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res26) // >>> true
res27, err := rdb.VSetAttr(ctx, "points", "pt:D",
map[string]interface{}{
"size": "small",
"price": 21.00,
},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res27) // >>> true
res28, err := rdb.VSetAttr(ctx, "points", "pt:E",
map[string]interface{}{
"size": "small",
"price": 17.75,
},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res28) // >>> true
// Return elements in order of distance from point A whose
// `size` attribute is `large`.
res29, err := rdb.VSimWithArgs(ctx, "points",
&redis.VectorRef{Name: "pt:A"},
&redis.VSimArgs{Filter: `.size == "large"`},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res29) // >>> [pt:A pt:C pt:B]
// Return elements in order of distance from point A whose size is
// `large` and whose price is greater than 20.00.
res30, err := rdb.VSimWithArgs(ctx, "points",
&redis.VectorRef{Name: "pt:A"},
&redis.VSimArgs{Filter: `.size == "large" && .price > 20.00`},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res30) // >>> [pt:C pt:B]
}
func ExampleClient_vectorset_quantization() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
defer rdb.Close()
// Add with Q8 quantization
vecQ := &redis.VectorValues{Val: []float64{1.262185, 1.958231}}
res1, err := rdb.VAddWithArgs(ctx, "quantSetQ8", "quantElement", vecQ,
&redis.VAddArgs{
Q8: true,
},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res1) // >>> true
embQ8, err := rdb.VEmb(ctx, "quantSetQ8", "quantElement", false).Result()
if err != nil {
panic(err)
}
fmt.Printf("Q8 embedding: %v\n", embQ8)
// >>> Q8 embedding: [1.2621850967407227 1.9582309722900391]
// Add with NOQUANT option
res2, err := rdb.VAddWithArgs(ctx, "quantSetNoQ", "quantElement", vecQ,
&redis.VAddArgs{
NoQuant: true,
},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res2) // >>> true
embNoQ, err := rdb.VEmb(ctx, "quantSetNoQ", "quantElement", false).Result()
if err != nil {
panic(err)
}
fmt.Printf("NOQUANT embedding: %v\n", embNoQ)
// >>> NOQUANT embedding: [1.262185 1.958231]
// Add with BIN quantization
res3, err := rdb.VAddWithArgs(ctx, "quantSetBin", "quantElement", vecQ,
&redis.VAddArgs{
Bin: true,
},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res3) // >>> true
embBin, err := rdb.VEmb(ctx, "quantSetBin", "quantElement", false).Result()
if err != nil {
panic(err)
}
fmt.Printf("BIN embedding: %v\n", embBin)
// >>> BIN embedding: [1 1]
}
func ExampleClient_vectorset_dimension_reduction() {
ctx := context.Background()
rdb := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
defer rdb.Close()
// Create a vector with 300 dimensions
values := make([]float64, 300)
for i := 0; i < 300; i++ {
values[i] = float64(i) / 299
}
vecLarge := &redis.VectorValues{Val: values}
// Add without reduction
res1, err := rdb.VAdd(ctx, "setNotReduced", "element", vecLarge).Result()
if err != nil {
panic(err)
}
fmt.Println(res1) // >>> true
dim1, err := rdb.VDim(ctx, "setNotReduced").Result()
if err != nil {
panic(err)
}
fmt.Printf("Dimension without reduction: %d\n", dim1)
// >>> Dimension without reduction: 300
// Add with reduction to 100 dimensions
res2, err := rdb.VAddWithArgs(ctx, "setReduced", "element", vecLarge,
&redis.VAddArgs{
Reduce: 100,
},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res2) // >>> true
dim2, err := rdb.VDim(ctx, "setReduced").Result()
if err != nil {
panic(err)
}
fmt.Printf("Dimension after reduction: %d\n", dim2)
// >>> Dimension after reduction: 100
}
This projects a 300-dimensional vector into 100 dimensions, reducing size and improving speed at the cost of some recall.
Summary
Strategy | Effect |
---|---|
Use Q8 |
Best tradeoff for most use cases |
Use BIN |
Minimal memory, fastest search |
Lower M |
Shrinks HNSW link graph size |
Reduce dimensions | Cuts memory per vector |
Minimize JSON | Smaller attributes, less memory per node |