Rotational Quantization (RQ)
Rotational quantization (RQ) is a fast vector compression technique that offers significant performance benefits. Three RQ variants are available in Weaviate:
- 8-bit RQ: Up to 4x compression while retaining almost perfect recall (98-99% on most datasets). Recommended for most use cases.
- 4-bit RQ: Up to 8x compression, roughly half the size of 8-bit RQ, and it depends on rescoring to reach comparable recall. Available for the
hnswindex only. - 1-bit RQ: Close to 32x compression as dimensionality increases with moderate recall across various datasets.
8-bit RQ
Section titled “8-bit RQ”8-bit RQ provides up-to 4x compression while maintaining 98-99% recall in internal testing. It is generally recommended for most use cases as the default quantization techniques.
Enable compression for new collection
Section titled “Enable compression for new collection”RQ can be enabled at collection creation time through the collection definition:
from weaviate.classes.config import Configure, Property, DataTypeclient.collections.create( name="MyCollection", vector_config=Configure.Vectors.text2vec_openai( quantizer=Configure.VectorIndex.Quantizer.rq() ), properties=[ Property(name="title", data_type=DataType.TEXT), ],)import weaviate, { configure } from 'weaviate-client';// Define the configuration for RQ. Setting 'enabled' to truerq_config := map[string]interface{}{ "enabled": true,}// Define the class schemaclass := &models.Class{ Class: className, Vectorizer: "text2vec-openai", // Assign the RQ configuration to the vector index config VectorIndexConfig: map[string]interface{}{ "rq": rq_config, },}// Create the collection in Weaviateerr = client.Schema().ClassCreator(). WithClass(class). Do(context.Background())client.collections.create("MyCollection", col -> col.vectorConfig(VectorConfig.text2vecTransformers(vc -> vc .quantization(Quantization.rq()) )).properties(Property.text("title")));await client.Collections.Create( new CollectionCreateParams { Name = "MyCollection", Properties = [Property.Text("title")], VectorConfig = Configure.Vector( "default", v => v.Text2VecTransformers(), index: new VectorIndex.HNSW { Quantizer = new VectorIndex.Quantizers.RQ(), } ), });Enable compression for existing collection
Section titled “Enable compression for existing collection”RQ can also be enabled for an existing collection by updating the collection definition:
from weaviate.classes.config import Reconfigure
collection = client.collections.use("MyCollection")
collection.config.update(
vector_config=Reconfigure.Vectors.update(
name="default",
vector_index_config=Reconfigure.VectorIndex.hnsw(
quantizer=Reconfigure.VectorIndex.Quantizer.rq(),
),
)
)import { reconfigure } from 'weaviate-client';
const collection = client.collections.use("MyCollection")CollectionHandle<Map<String, Object>> collection =
client.collections.use("MyCollection");
collection.config.update(c -> c.vectorConfig(VectorConfig
.text2vecTransformers(vc -> vc.quantization(Quantization.rq()))));await collection.Config.Update(c =>
{
var vectorConfig = c.VectorConfig["default"];
vectorConfig.VectorIndexConfig.UpdateHNSW(h =>
h.Quantizer = new VectorIndex.Quantizers.RQ()
);
});// Get the existing collection configuration
class, err := client.Schema().ClassGetter().
WithClassName(className).Do(context.Background())
if err != nil {
log.Fatalf("get class for vec idx cfg update: %v", err)
}
// Get the current vector index configuration
cfg := class.VectorIndexConfig.(map[string]interface{})
// Add RQ configuration to enable quantization
cfg["rq"] = map[string]interface{}{
"enabled": true,
}
// Update the class configuration
class.VectorIndexConfig = cfg
// Apply the updated configuration to the collection
err = client.Schema().ClassUpdater().
WithClass(class).Do(context.Background())
if err != nil {
log.Fatalf("update class to use rq: %v", err)
}4-bit RQ
Section titled “4-bit RQ”4-bit RQ stores each dimension in 4 bits instead of 8, so a compressed vector is about half the size of the 8-bit equivalent and roughly 8x smaller than the uncompressed vector. It sits between 8-bit RQ and 1-bit RQ: it trades some accuracy in the compressed distance calculation for a smaller index, and it depends more heavily on rescoring against the uncompressed vectors to recover that accuracy.
Enable compression for new collection
Section titled “Enable compression for new collection”4-bit RQ can be enabled at collection creation time through the collection definition:
from weaviate.classes.config import Configure, Property, DataTypeclient.collections.create( name="MyCollection", vector_config=Configure.Vectors.text2vec_openai( quantizer=Configure.VectorIndex.Quantizer.rq( bits=4, rescore_limit=20, # Optional: Number of candidates to fetch before rescoring ) ), properties=[ Property(name="title", data_type=DataType.TEXT), ],)import weaviate, { configure } from 'weaviate-client';// Define the configuration for RQ. 'bits' set to 4 requires an hnsw indexrq_config := map[string]interface{}{ "enabled": true, "bits": 4, "rescoreLimit": 20, // Optional: Number of candidates to fetch before rescoring}// Define the class schemaclass := &models.Class{ Class: className, Vectorizer: "text2vec-openai", // Assign the RQ configuration to the vector index config VectorIndexConfig: map[string]interface{}{ "rq": rq_config, },}// Create the collection in Weaviateerr = client.Schema().ClassCreator(). WithClass(class). Do(context.Background())client.collections.create("MyCollection", col -> col.vectorConfig(VectorConfig.text2vecTransformers(vc -> vc .quantization(Quantization.rq(q -> q.bits(4))) )).properties(Property.text("title")));await client.Collections.Create( new CollectionCreateParams { Name = "MyCollection", Properties = [Property.Text("title")], VectorConfig = Configure.Vector( "default", v => v.Text2VecTransformers(), index: new VectorIndex.HNSW { Quantizer = new VectorIndex.Quantizers.RQ { Bits = 4, RescoreLimit = 20, // Optional: Number of candidates to fetch before rescoring }, } ), });Enable compression for existing collection
Section titled “Enable compression for existing collection”4-bit RQ can also be enabled for an existing collection that is not yet compressed, by updating the collection definition. Weaviate re-encodes the existing vectors in the background.
from weaviate.classes.config import Reconfigure
collection = client.collections.use("MyCollection")
collection.config.update(
vector_config=Reconfigure.Vectors.update(
name="default",
vector_index_config=Reconfigure.VectorIndex.hnsw(
quantizer=Reconfigure.VectorIndex.Quantizer.rq(
bits=4,
rescore_limit=20,
),
),
)
)// Get the existing collection configuration
class, err := client.Schema().ClassGetter().
WithClassName(className).Do(context.Background())
if err != nil {
log.Fatalf("get class for vec idx cfg update: %v", err)
}
// Get the current vector index configuration
cfg := class.VectorIndexConfig.(map[string]interface{})
// Add RQ configuration to enable 4-bit quantization
cfg["rq"] = map[string]interface{}{
"enabled": true,
"bits": 4,
"rescoreLimit": 20, // Optional: Number of candidates to fetch before rescoring
}
// Update the class configuration
class.VectorIndexConfig = cfg
// Apply the updated configuration to the collection
err = client.Schema().ClassUpdater().
WithClass(class).Do(context.Background())
if err != nil {
log.Fatalf("update class to use rq: %v", err)
}CollectionHandle<Map<String, Object>> collection =
client.collections.use("MyCollection");
collection.config
.update(c -> c.vectorConfig(VectorConfig.text2vecTransformers(
vc -> vc.quantization(Quantization.rq(q -> q.bits(4))))));await collection.Config.Update(c =>
{
var vectorConfig = c.VectorConfig["default"];
vectorConfig.VectorIndexConfig.UpdateHNSW(h =>
h.Quantizer = new VectorIndex.Quantizers.RQ { Bits = 4, RescoreLimit = 20 }
);
});1-bit RQ
Section titled “1-bit RQ”1-bit RQ is an quantization technique that provides close to 32x compression as dimensionality increases. 1-bit RQ serves as a more robust and accurate alternative to BQ with only a slight performance trade-off. While more performant than PQ in terms of encoding time and distance calculations, 1-bit RQ typically offers slightly lower recall than well-tuned PQ.
Enable compression for new collection
Section titled “Enable compression for new collection”RQ can be enabled at collection creation time through the collection definition:
from weaviate.classes.config import Configure, Property, DataTypeclient.collections.create( name="MyCollection", vector_config=Configure.Vectors.text2vec_openai( quantizer=Configure.VectorIndex.Quantizer.rq(bits=1) ), properties=[ Property(name="title", data_type=DataType.TEXT), ],)import weaviate, { configure } from 'weaviate-client';// Define the configuration for RQ. Setting 'enabled' to truerq_config := map[string]interface{}{ "enabled": true, "bits": 1,}// Define the class schemaclass := &models.Class{ Class: className, Vectorizer: "text2vec-openai", // Assign the RQ configuration to the vector index config VectorIndexConfig: map[string]interface{}{ "rq": rq_config, },}// Create the collection in Weaviateerr = client.Schema().ClassCreator(). WithClass(class). Do(context.Background())client.collections.create("MyCollection", col -> col.vectorConfig(VectorConfig.text2vecTransformers(vc -> vc .quantization(Quantization.rq(q -> q.bits(1))) )).properties(Property.text("title")));await client.Collections.Create( new CollectionCreateParams { Name = "MyCollection", Properties = [Property.Text("title")], VectorConfig = Configure.Vector( "default", v => v.Text2VecTransformers(), index: new VectorIndex.HNSW { Quantizer = new VectorIndex.Quantizers.RQ { Bits = 1 }, } ), });Enable compression for existing collection
Section titled “Enable compression for existing collection”RQ can also be enabled for an existing collection by updating the collection definition:
from weaviate.classes.config import Reconfigure
collection = client.collections.use("MyCollection")
collection.config.update(
vector_config=Reconfigure.Vectors.update(
name="default",
vector_index_config=Reconfigure.VectorIndex.hnsw(
quantizer=Reconfigure.VectorIndex.Quantizer.rq(bits=1),
),
)
)import { reconfigure } from 'weaviate-client';
const collection = client.collections.use("MyCollection")// Get the existing collection configuration
class, err := client.Schema().ClassGetter().
WithClassName(className).Do(context.Background())
if err != nil {
log.Fatalf("get class for vec idx cfg update: %v", err)
}
// Get the current vector index configuration
cfg := class.VectorIndexConfig.(map[string]interface{})
// Add RQ configuration to enable scalar quantization
cfg["rq"] = map[string]interface{}{
"enabled": true,
"bits": 1,
}
// Update the class configuration
class.VectorIndexConfig = cfg
// Apply the updated configuration to the collection
err = client.Schema().ClassUpdater().
WithClass(class).Do(context.Background())
if err != nil {
log.Fatalf("update class to use rq: %v", err)
}CollectionHandle<Map<String, Object>> collection =
client.collections.use("MyCollection");
collection.config
.update(c -> c.vectorConfig(VectorConfig.text2vecTransformers(
vc -> vc.quantization(Quantization.rq(q -> q.bits(1))))));await collection.Config.Update(c =>
{
var vectorConfig = c.VectorConfig["default"];
vectorConfig.VectorIndexConfig.UpdateHNSW(h =>
h.Quantizer = new VectorIndex.Quantizers.RQ { Bits = 1 }
);
});RQ parameters
Section titled “RQ parameters”To tune RQ, use these quantization and vector index parameters:
| Parameter | Type | Default | Details |
|---|---|---|---|
rq: bits |
integer | 8 |
The number of bits used to quantize each data point. Value can be 8, 4 or 1, but not every index type accepts all three. The hnsw index type accepts 8, 4 and 1. The flat index type accepts only 8 and 1. The hfresh index type accepts only 1. This parameter is fixed once RQ is enabled and cannot be changed afterwards. Learn more about 8-bit, 4-bit and 1-bit RQ. |
rq: rescoreLimit |
integer | 20 (hnsw, 8-bit and 4-bit)512 (hnsw, 1-bit)-1 (flat) |
The minimum number of candidates to fetch before rescoring. Mutable at any time. The default depends on the vector index type, and under hnsw also on bits: 20 for 8-bit and 4-bit RQ, and 512 for 1-bit RQ. Under the flat index type the default is -1, which lets Weaviate pick the limit. The Java client sends this parameter under a field name that Weaviate does not read, so values set from that client are ignored and the server default applies. These defaults apply to the hnsw and flat index types. For the HFresh index, see HFresh index parameters. |
rq : cache |
boolean | false |
Whether to cache the vectors in memory. (only when using the flat vector index type) |
vectorCacheMaxObjects |
integer | 1e12 |
Maximum number of objects in the memory cache. By default, this limit is set to one trillion (1e12) objects when a new collection is created. For sizing recommendations, see Vector cache considerations. |
RQ supports the cosine, dot and l2-squared distance metrics. Other distance metrics are not supported.
from weaviate.classes.config import Configure, Property, DataTypeclient.collections.create( name="MyCollection", vector_config=Configure.Vectors.text2vec_openai( quantizer=Configure.VectorIndex.Quantizer.rq( bits=8, # Optional: Number of bits rescore_limit=20, # Optional: Number of candidates to fetch before rescoring cache=True, # Optional: Enable caching for flat index (enabled by default for for HNSW) ), vector_index_config=Configure.VectorIndex.flat( vector_cache_max_objects=100000, # Optional: Maximum number of objects in the memory cache ), ), properties=[ Property(name="title", data_type=DataType.TEXT), ],)import weaviate, { configure } from 'weaviate-client';// Define a custom configuration for RQrq_with_options_config := map[string]interface{}{ "enabled": true, "bits": 8, // Optional: Number of bits "rescoreLimit": 20, // Optional: Number of candidates to fetch before rescoring}// Define the class schema with the custom RQ config and other HNSW settingsclass_with_options := &models.Class{ Class: className, Vectorizer: "text2vec-openai", VectorIndexConfig: map[string]interface{}{ "rq": rq_with_options_config, },}// Create the collection in Weaviateerr = client.Schema().ClassCreator(). WithClass(class_with_options). Do(context.Background())client.collections.create("MyCollection", col -> col.vectorConfig(VectorConfig.text2vecTransformers(vc -> vc .quantization(Quantization.rq(q -> q.bits(8) // Optional: Number of bits .rescoreLimit(20) // Optional: Number of candidates to fetch before rescoring )) )).properties(Property.text("title")));await client.Collections.Create( new CollectionCreateParams { Name = "MyCollection", Properties = [Property.Text("title")], VectorConfig = Configure.Vector( "default", v => v.Text2VecTransformers(), index: new VectorIndex.HNSW { Quantizer = new VectorIndex.Quantizers.RQ { Bits = 8, // Optional: Number of bits RescoreLimit = 20, // Optional: Number of candidates to fetch before rescoring }, } ), });Additional considerations
Section titled “Additional considerations”Multiple vector embeddings (named vectors)
Section titled “Multiple vector embeddings (named vectors)”Collections can have multiple named vectors. The vectors in a collection can have their own configurations, and compression must be enabled independently for each vector. Every vector is independent and can use PQ, BQ, RQ, SQ, or no compression.
Multi-vector embeddings (ColBERT, ColPali, etc.)
Section titled “Multi-vector embeddings (ColBERT, ColPali, etc.)”Multi-vector embeddings (implemented through models like ColBERT, ColPali, or ColQwen) represent each object or query using multiple vectors instead of a single vector. Just like with single vectors, multi-vectors support PQ, BQ, RQ, SQ, or no compression.
During the initial search phase, compressed vectors are used for efficiency. However, when computing the MaxSim operation, uncompressed vectors are utilized to ensure more precise similarity calculations. This approach balances the benefits of compression for search efficiency with the accuracy of uncompressed vectors during final scoring.
Further resources
Section titled “Further resources”- Starter guides: Compression
- Reference: Vector index
- Concepts: Vector quantization
- Concepts: Vector index
Questions and feedback
Section titled “Questions and feedback”Have a question or feedback? Here's how to reach us.