Add TurboQuant quantization documentation (v1.18.0) (#2313)

* Add TurboQuant quantization documentation (v1.18.0)

Adds a new TurboQuant section to the quantization guide covering the
four encoding options (bits1/bits1_5/bits2/bits4), automatic asymmetric
quantization, distance metric support, and the automatic TQ+ precision
enhancement for sealed segments. Updates the comparison table and
method-selection guidance to recommend TurboQuant over Binary and
Scalar Quantization for new collections. Adds HTTP-only snippets for
basic setup and explicit bit-depth selection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Consistently use title case for headers

* Restructure doc to lead with TurboQuant

* Clarify rescoring

* Edits

* Soften TQ advice

* Updates

* Fix

* Apply suggestions from code review

Co-authored-by: Jojii <15957865+JojiiOfficial@users.noreply.github.com>

* Review feedback

* Add Go/Java/C# code snippets

* Add list of 4 quantization methods to introduction

* Review feedback

* Stronger advice for TQ4

* Add Python snippets

* Add Rust snippets

* Add TS snippets

* Update recommendation table

* Update production checklist

* Remove link to article

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Jojii <15957865+JojiiOfficial@users.noreply.github.com>
This commit is contained in:
Abdon Pijpelink
2026-05-11 08:13:03 +02:00
committed by GitHub
co-authored by Claude Sonnet 4.6 Jojii
parent 2746db8762
commit 46e81449a8
30 changed files with 647 additions and 59 deletions
@@ -0,0 +1 @@
This code creates a collection with TurboQuant using 2-bit encoding. Specify `bits` to select the compression level. Available values are `bits4` (default, 8× compression), `bits2` (16× compression), `bits1_5` (24× compression), and `bits1` (32× compression).
@@ -0,0 +1,21 @@
using Qdrant.Client;
using Qdrant.Client.Grpc;
public class Snippet
{
public static async Task Run()
{
// @hide-start
var client = new QdrantClient("localhost", 6334);
// @hide-end
await client.CreateCollectionAsync(
collectionName: "{collection_name}",
vectorsConfig: new VectorParams { Size = 1536, Distance = Distance.Cosine },
quantizationConfig: new QuantizationConfig
{
Turboquant = new TurboQuantization { AlwaysRam = true, Bits = TurboQuantBitSize.Bits2 }
}
);
}
}
@@ -0,0 +1,13 @@
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
await client.CreateCollectionAsync(
collectionName: "{collection_name}",
vectorsConfig: new VectorParams { Size = 1536, Distance = Distance.Cosine },
quantizationConfig: new QuantizationConfig
{
Turboquant = new TurboQuantization { AlwaysRam = true, Bits = TurboQuantBitSize.Bits2 }
}
);
```
@@ -0,0 +1,21 @@
```go
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client.CreateCollection(context.Background(), &qdrant.CreateCollection{
CollectionName: "{collection_name}",
VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
Size: 1536,
Distance: qdrant.Distance_Cosine,
}),
QuantizationConfig: qdrant.NewQuantizationTurbo(
&qdrant.TurboQuantization{
AlwaysRam: qdrant.PtrOf(true),
Bits: qdrant.TurboQuantBitSize_Bits2.Enum(),
},
),
})
```
@@ -0,0 +1,34 @@
```java
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.CreateCollection;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.QuantizationConfig;
import io.qdrant.client.grpc.Collections.TurboQuantBitSize;
import io.qdrant.client.grpc.Collections.TurboQuantization;
import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.grpc.Collections.VectorsConfig;
client
.createCollectionAsync(
CreateCollection.newBuilder()
.setCollectionName("{collection_name}")
.setVectorsConfig(
VectorsConfig.newBuilder()
.setParams(
VectorParams.newBuilder()
.setSize(1536)
.setDistance(Distance.Cosine)
.build())
.build())
.setQuantizationConfig(
QuantizationConfig.newBuilder()
.setTurboquant(
TurboQuantization.newBuilder()
.setAlwaysRam(true)
.setBits(TurboQuantBitSize.Bits2)
.build())
.build())
.build())
.get();
```
@@ -0,0 +1,14 @@
```python
from qdrant_client import QdrantClient, models
client.create_collection(
collection_name="{collection_name}",
vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
quantization_config=models.TurboQuantization(
turbo=models.TurboQuantQuantizationConfig(
always_ram=True,
bits=models.TurboQuantBitSize.BITS2,
),
),
)
```
@@ -0,0 +1,19 @@
```rust
use qdrant_client::qdrant::{
CreateCollectionBuilder, Distance, TurboQuantBitSize, TurboQuantizationBuilder,
VectorParamsBuilder,
};
use qdrant_client::Qdrant;
client
.create_collection(
CreateCollectionBuilder::new("{collection_name}")
.vectors_config(VectorParamsBuilder::new(1536, Distance::Cosine))
.quantization_config(
TurboQuantizationBuilder::new()
.always_ram(true)
.bits(TurboQuantBitSize::Bits2),
),
)
.await?;
```
@@ -0,0 +1,16 @@
```typescript
import { QdrantClient } from "@qdrant/js-client-rest";
client.createCollection("{collection_name}", {
vectors: {
size: 1536,
distance: "Cosine",
},
quantization_config: {
turbo: {
always_ram: true,
bits: "bits2",
},
},
});
```
@@ -0,0 +1,32 @@
package snippet
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
func Main() {
// @hide-start
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
if err != nil { panic(err) }
// @hide-end
client.CreateCollection(context.Background(), &qdrant.CreateCollection{
CollectionName: "{collection_name}",
VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
Size: 1536,
Distance: qdrant.Distance_Cosine,
}),
QuantizationConfig: qdrant.NewQuantizationTurbo(
&qdrant.TurboQuantization{
AlwaysRam: qdrant.PtrOf(true),
Bits: qdrant.TurboQuantBitSize_Bits2.Enum(),
},
),
})
}
@@ -0,0 +1,15 @@
```http
PUT /collections/{collection_name}
{
"vectors": {
"size": 1536,
"distance": "Cosine"
},
"quantization_config": {
"turbo": {
"bits": "bits2",
"always_ram": true
}
}
}
```
@@ -0,0 +1,43 @@
package com.example.snippets_amalgamation;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.CreateCollection;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.QuantizationConfig;
import io.qdrant.client.grpc.Collections.TurboQuantBitSize;
import io.qdrant.client.grpc.Collections.TurboQuantization;
import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.grpc.Collections.VectorsConfig;
public class Snippet {
public static void run() throws Exception {
// @hide-start
QdrantClient client =
new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
// @hide-end
client
.createCollectionAsync(
CreateCollection.newBuilder()
.setCollectionName("{collection_name}")
.setVectorsConfig(
VectorsConfig.newBuilder()
.setParams(
VectorParams.newBuilder()
.setSize(1536)
.setDistance(Distance.Cosine)
.build())
.build())
.setQuantizationConfig(
QuantizationConfig.newBuilder()
.setTurboquant(
TurboQuantization.newBuilder()
.setAlwaysRam(true)
.setBits(TurboQuantBitSize.Bits2)
.build())
.build())
.build())
.get();
}
}
@@ -0,0 +1,16 @@
from qdrant_client import QdrantClient, models
# @hide-start
client = QdrantClient(url="http://localhost:6333")
# @hide-end
client.create_collection(
collection_name="{collection_name}",
vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
quantization_config=models.TurboQuantization(
turbo=models.TurboQuantQuantizationConfig(
always_ram=True,
bits=models.TurboQuantBitSize.BITS2,
),
),
)
@@ -0,0 +1,25 @@
use qdrant_client::qdrant::{
CreateCollectionBuilder, Distance, TurboQuantBitSize, TurboQuantizationBuilder,
VectorParamsBuilder,
};
use qdrant_client::Qdrant;
pub async fn main() -> anyhow::Result<()> {
// @hide-start
let client = Qdrant::from_url("http://localhost:6334").build()?;
// @hide-end
client
.create_collection(
CreateCollectionBuilder::new("{collection_name}")
.vectors_config(VectorParamsBuilder::new(1536, Distance::Cosine))
.quantization_config(
TurboQuantizationBuilder::new()
.always_ram(true)
.bits(TurboQuantBitSize::Bits2),
),
)
.await?;
Ok(())
}
@@ -0,0 +1,18 @@
import { QdrantClient } from "@qdrant/js-client-rest";
// @hide-start
const client = new QdrantClient({ host: "localhost", port: 6333 });
// @hide-end
client.createCollection("{collection_name}", {
vectors: {
size: 1536,
distance: "Cosine",
},
quantization_config: {
turbo: {
always_ram: true,
bits: "bits2",
},
},
});
@@ -0,0 +1 @@
This code creates a collection with TurboQuant enabled using the default 4-bit encoding. To enable TurboQuant on an existing collection, use a PATCH request or the `update_collection` method and omit the vector configuration.
@@ -0,0 +1,21 @@
using Qdrant.Client;
using Qdrant.Client.Grpc;
public class Snippet
{
public static async Task Run()
{
// @hide-start
var client = new QdrantClient("localhost", 6334);
// @hide-end
await client.CreateCollectionAsync(
collectionName: "{collection_name}",
vectorsConfig: new VectorParams { Size = 1536, Distance = Distance.Cosine },
quantizationConfig: new QuantizationConfig
{
Turboquant = new TurboQuantization { AlwaysRam = true }
}
);
}
}
@@ -0,0 +1,13 @@
```csharp
using Qdrant.Client;
using Qdrant.Client.Grpc;
await client.CreateCollectionAsync(
collectionName: "{collection_name}",
vectorsConfig: new VectorParams { Size = 1536, Distance = Distance.Cosine },
quantizationConfig: new QuantizationConfig
{
Turboquant = new TurboQuantization { AlwaysRam = true }
}
);
```
@@ -0,0 +1,20 @@
```go
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client.CreateCollection(context.Background(), &qdrant.CreateCollection{
CollectionName: "{collection_name}",
VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
Size: 1536,
Distance: qdrant.Distance_Cosine,
}),
QuantizationConfig: qdrant.NewQuantizationTurbo(
&qdrant.TurboQuantization{
AlwaysRam: qdrant.PtrOf(true),
},
),
})
```
@@ -0,0 +1,29 @@
```java
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.CreateCollection;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.QuantizationConfig;
import io.qdrant.client.grpc.Collections.TurboQuantization;
import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.grpc.Collections.VectorsConfig;
client
.createCollectionAsync(
CreateCollection.newBuilder()
.setCollectionName("{collection_name}")
.setVectorsConfig(
VectorsConfig.newBuilder()
.setParams(
VectorParams.newBuilder()
.setSize(1536)
.setDistance(Distance.Cosine)
.build())
.build())
.setQuantizationConfig(
QuantizationConfig.newBuilder()
.setTurboquant(TurboQuantization.newBuilder().setAlwaysRam(true).build())
.build())
.build())
.get();
```
@@ -0,0 +1,13 @@
```python
from qdrant_client import QdrantClient, models
client.create_collection(
collection_name="{collection_name}",
vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
quantization_config=models.TurboQuantization(
turbo=models.TurboQuantQuantizationConfig(
always_ram=True,
),
),
)
```
@@ -0,0 +1,14 @@
```rust
use qdrant_client::qdrant::{
CreateCollectionBuilder, Distance, TurboQuantizationBuilder, VectorParamsBuilder,
};
use qdrant_client::Qdrant;
client
.create_collection(
CreateCollectionBuilder::new("{collection_name}")
.vectors_config(VectorParamsBuilder::new(1536, Distance::Cosine))
.quantization_config(TurboQuantizationBuilder::new().always_ram(true)),
)
.await?;
```
@@ -0,0 +1,15 @@
```typescript
import { QdrantClient } from "@qdrant/js-client-rest";
client.createCollection("{collection_name}", {
vectors: {
size: 1536,
distance: "Cosine",
},
quantization_config: {
turbo: {
always_ram: true,
},
},
});
```
@@ -0,0 +1,31 @@
package snippet
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
func Main() {
// @hide-start
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
if err != nil { panic(err) }
// @hide-end
client.CreateCollection(context.Background(), &qdrant.CreateCollection{
CollectionName: "{collection_name}",
VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
Size: 1536,
Distance: qdrant.Distance_Cosine,
}),
QuantizationConfig: qdrant.NewQuantizationTurbo(
&qdrant.TurboQuantization{
AlwaysRam: qdrant.PtrOf(true),
},
),
})
}
@@ -0,0 +1,14 @@
```http
PUT /collections/{collection_name}
{
"vectors": {
"size": 1536,
"distance": "Cosine"
},
"quantization_config": {
"turbo": {
"always_ram": true
}
}
}
```
@@ -0,0 +1,38 @@
package com.example.snippets_amalgamation;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.CreateCollection;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.QuantizationConfig;
import io.qdrant.client.grpc.Collections.TurboQuantization;
import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.grpc.Collections.VectorsConfig;
public class Snippet {
public static void run() throws Exception {
// @hide-start
QdrantClient client =
new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
// @hide-end
client
.createCollectionAsync(
CreateCollection.newBuilder()
.setCollectionName("{collection_name}")
.setVectorsConfig(
VectorsConfig.newBuilder()
.setParams(
VectorParams.newBuilder()
.setSize(1536)
.setDistance(Distance.Cosine)
.build())
.build())
.setQuantizationConfig(
QuantizationConfig.newBuilder()
.setTurboquant(TurboQuantization.newBuilder().setAlwaysRam(true).build())
.build())
.build())
.get();
}
}
@@ -0,0 +1,15 @@
from qdrant_client import QdrantClient, models
# @hide-start
client = QdrantClient(url="http://localhost:6333")
# @hide-end
client.create_collection(
collection_name="{collection_name}",
vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
quantization_config=models.TurboQuantization(
turbo=models.TurboQuantQuantizationConfig(
always_ram=True,
),
),
)
@@ -0,0 +1,20 @@
use qdrant_client::qdrant::{
CreateCollectionBuilder, Distance, TurboQuantizationBuilder, VectorParamsBuilder,
};
use qdrant_client::Qdrant;
pub async fn main() -> anyhow::Result<()> {
// @hide-start
let client = Qdrant::from_url("http://localhost:6334").build()?;
// @hide-end
client
.create_collection(
CreateCollectionBuilder::new("{collection_name}")
.vectors_config(VectorParamsBuilder::new(1536, Distance::Cosine))
.quantization_config(TurboQuantizationBuilder::new().always_ram(true)),
)
.await?;
Ok(())
}
@@ -0,0 +1,17 @@
import { QdrantClient } from "@qdrant/js-client-rest";
// @hide-start
const client = new QdrantClient({ host: "localhost", port: 6333 });
// @hide-end
client.createCollection("{collection_name}", {
vectors: {
size: 1536,
distance: "Cosine",
},
quantization_config: {
turbo: {
always_ram: true,
},
},
});
@@ -14,7 +14,7 @@ By transforming original vectors into a new representations, quantization compre
Different quantization methods have different mechanics and tradeoffs. We will cover them in this section.
Quantization is primarily used to reduce the memory footprint and accelerate the search process in high-dimensional vector spaces.
In the context of the Qdrant, quantization allows you to optimize the search engine for specific use cases, striking a balance between accuracy, storage efficiency, and search speed.
In the context of Qdrant, quantization allows you to optimize the search engine for specific use cases, striking a balance between accuracy, storage efficiency, and search speed.
There are tradeoffs associated with quantization.
On the one hand, quantization allows for significant reductions in storage requirements and faster search times.
@@ -22,6 +22,63 @@ This can be particularly beneficial in large-scale applications where minimizing
On the other hand, quantization introduces an approximation error, which can lead to a slight decrease in search quality.
The level of this tradeoff depends on the quantization method and its parameters, as well as the characteristics of the data.
Qdrant supports four quantization methods:
- **[TurboQuant](#turboquant-quantization)** supports up to 32x compression, with strong recall across most embedding models.
- **[Scalar Quantization](#scalar-quantization)** compresses each vector component from a 32-bit float to an 8-bit integer, achieving 4x compression with minimal accuracy loss.
- **[Binary Quantization](#binary-quantization)** reduces each vector component to one to two bits for up to 32x compression. Best suited for high-dimensional, centered vector distributions.
- **[Product Quantization](#product-quantization)** enables up to 64x compression when minimizing memory is the top priority.
To help you choose the right quantization method for your use case, refer to the [next section](#how-to-choose-the-right-quantization-method).
## How to Choose the Right Quantization Method
Depending on your requirements for recall, compression, and distance metrics, consult this table for guidance:
| Compression | Method |
|-------------|-------------|
| 4 | Use **Scalar Quantization**. It is a well-established quantization method with a good balance between recall and compression. <br/><br/>However, unless you need to use the Manhattan (L1) distance metric, consider using 4-bit **TurboQuant** instead of scalar quantization, as it offers comparable recall at double the compression. |
| 8 | Use 4-bit **TurboQuant**. It offers a good balance between recall and compression. <br/><br/>When using the Manhattan (L1) distance metric, consider using another quantization method. |
| 16 | **2-bit TurboQuant** and **2-bit binary quantization** offer similar results at this compression level. Binary quantization is faster, but TurboQuant provides better recall. |
| 24 | **1.5-bit TurboQuant** and **1.5-bit binary quantization** offer similar results at this compression level. Binary quantization is faster, but TurboQuant provides better recall. |
| 32 | **1-bit TurboQuant** and **1-bit binary quantization** offer similar results at this compression level. Binary quantization is faster, but TurboQuant provides better recall. |
| Up to 64 | Use **Product Quantization** if the memory footprint is the top priority and accuracy and speed are not critical. |
## TurboQuant Quantization
*Available as of v1.18.0*
<aside role="status">Test TurboQuant on your data before committing. We encourage you to try it on new collections.</aside>
TurboQuant is [a quantization method developed by Google](https://research.google/blog/turboquant-redefining-ai-efficiency-with-extreme-compression/). It operates by applying a fast random rotation to vectors before compression, which evenly redistributes data across coordinates. This allows applying a single pre-computed, globally optimized quantization mapping across the dataset, enabling TurboQuant to work effectively with any vector distribution and overcoming a key limitation found in binary quantization.
Qdrant's implementation of TurboQuant extends the original algorithm to close the gap between the algorithm's theoretical assumptions and real-world embeddings.
TurboQuant uses asymmetric quantization automatically: only stored vectors are compressed, while queries are scored in full precision. This improves accuracy and requires no additional configuration.
### Encoding Options
TurboQuant supports four bit depths:
| Encoding | Bit Depth | Compression |
|----------|-----------|-------------|
| `bits4` (default) | 4 bits | 8× |
| `bits2` | 2 bits | 16× |
| `bits1_5` | 1.5 bits | 24× |
| `bits1` | 1 bit | 32× |
In our benchmarks, 4-bit TurboQuant, at twice the compression ratio of scalar quantization, delivers similar recall and speed. Results vary by dataset and embedding model: it may outperform or slightly underperform scalar quantization. This makes 4-bit TurboQuant a good default choice for many use cases.
Compared to binary quantization, TurboQuant offers better recall at lower speed and equivalent storage budgets.
The default encoding is `bits4`, which offers the best accuracy.
### Distance Metric Support
TurboQuant fully supports Cosine, Dot, and Euclidean (L2) distance with SIMD-accelerated scoring.
Manhattan (L1) distance is supported but requires full vector reconstruction per comparison, making it significantly slower than the other metrics. Use Cosine, Dot, or Euclidean distance for best performance with TurboQuant.
## Scalar Quantization
*Available as of v1.1.0*
@@ -48,11 +105,7 @@ Please refer to the [Quantization Tips](#quantization-tips) section for more inf
*Available as of v1.5.0*
Binary quantization is an extreme case of scalar quantization.
This feature lets you represent each vector component as a single bit, effectively reducing the memory footprint by a **factor of 32**.
This is the fastest quantization method, since it lets you perform a vector comparison with a few CPU instructions.
Binary quantization can achieve up to a **40x** speedup compared to the original vectors.
This feature lets you represent each vector component as a single bit, effectively reducing the memory footprint by a factor of 32. This is the fastest quantization method, since it lets you perform a vector comparison with a few CPU instructions. Binary quantization can achieve up to a 40x speedup compared to the original vectors.
However, binary quantization is only efficient for high-dimensional vectors and require a centered distribution of vector components.
@@ -63,9 +116,9 @@ At the moment, binary quantization shows good accuracy results with the followin
Models with a lower dimensionality or a different distribution of vector components may require additional experiments to find the optimal quantization parameters.
We recommend using binary quantization only with rescoring enabled, as it can significantly improve the search quality
with just a minor performance impact.
Additionally, oversampling can be used to tune the tradeoff between search speed and search quality in the query time.
We recommend using binary quantization only with rescoring enabled, as this can significantly improve search quality. However, keep in mind that if the original vectors are stored on disk, rescoring can significantly decrease search speed.
Additionally, oversampling can be used to tune the tradeoff between search speed and search quality at query time.
### Binary Quantization as Hamming Distance
@@ -148,29 +201,7 @@ Also, product quantization has a loss of accuracy, so it is recommended to use i
Please refer to the [Quantization Tips](#quantization-tips) section for more information on how to optimize the quantization parameters for your use case.
## How to choose the right quantization method
Here is a brief table of the pros and cons of each quantization method:
| Quantization method | Accuracy | Speed | Compression |
|---------------------|----------|--------------|-------------|
| Scalar | 0.99 | up to x2 | 4 |
| Product | 0.7 | 0.5 | up to 64 |
| Binary (1 bit) | 0.95* | up to x40 | 32 |
| Binary (1.5 bit) | 0.95** | up to x30 | 24 |
| Binary (2 bit) | 0.95*** | up to x20 | 16 |
- `*` - for compatible models with high-dimensional vectors (approx. 1536+ dimensions)
- `**` - for compatible models with medium-dimensional vectors (approx. 1024-1536 dimensions)
- `***` - for compatible models with low-dimensional vectors (approx. 768-1024 dimensions)
- **Binary Quantization** is the fastest method and the most memory-efficient, but it requires a centered distribution of vector components. It is recommended to use with tested models only.
- If you are planning to use binary quantization with low or medium-dimensional vectors (approx. 512-1024 dimensions), it is recommended to use 1.5-bit or 2-bit quantization as well as asymmetric quantization feature.
- **Scalar Quantization** is the most universal method, as it provides a good balance between accuracy, speed, and compression. It is recommended as default quantization if binary quantization is not applicable.
- **Product Quantization** may provide a better compression ratio, but it has a significant loss of accuracy and is slower than scalar quantization. It is recommended if the memory footprint is the top priority and the search speed is not critical.
## Setting up Quantization in Qdrant
## Setting Up Quantization in Qdrant
You can configure quantization for a collection by specifying the quantization parameters in the `quantization_config` section of the collection configuration.
@@ -181,7 +212,25 @@ Quantized vectors are stored alongside the original vectors in the collection, s
The `quantization_config` can also be set on a per vector basis by specifying it in a named vector.
### Setting up Scalar Quantization
### Setting Up TurboQuant
To enable TurboQuant, specify it in the `quantization_config` section of the collection configuration.
When enabling TurboQuant on an existing collection, use a PATCH request or the corresponding `update_collection` method and omit the vector configuration, as it's already defined.
{{< code-snippet path="/documentation/headless/snippets/create-collection/with-turbo-quant/" >}}
`bits` - the encoding bit depth. Defaults to `bits4`. Available values: `bits4`, `bits2`, `bits1_5`, and `bits1`. Lower bit depths offer higher compression at the cost of accuracy.
`always_ram` - whether to keep quantized vectors always cached in RAM or not. By default, quantized vectors are loaded in the same way as the original vectors. Set `always_ram` to `true` to store quantized vectors in RAM.
#### Select a Bit Depth
To use a specific compression level, set the `bits` parameter:
{{< code-snippet path="/documentation/headless/snippets/create-collection/with-turbo-quant-bits/" >}}
### Setting Up Scalar Quantization
To enable scalar quantization, you need to specify the quantization parameters in the `quantization_config` section of the collection configuration.
@@ -206,7 +255,7 @@ However, in some setups you might want to keep quantized vectors in RAM to speed
In this case, you can set `always_ram` to `true` to store quantized vectors in RAM.
### Setting up Binary Quantization
### Setting Up Binary Quantization
To enable binary quantization, you need to specify the quantization parameters in the `quantization_config` section of the collection configuration.
@@ -219,14 +268,14 @@ However, in some setups you might want to keep quantized vectors in RAM to speed
In this case, you can set `always_ram` to `true` to store quantized vectors in RAM.
#### Set up bit depth
#### Set Up Bit Depth
To enable 2bit or 1.5bit quantization, you need to specify `encoding` parameter in the `quantization_config` section of the collection configuration. Available values are `two_bits` and `one_and_half_bits`.
{{< code-snippet path="/documentation/headless/snippets/create-collection/with-binary-quantization-and-encoding/" >}}
#### Set up asymmetric quantization
#### Set Up Asymmetric Quantization
To enable asymmetric quantization, you need to specify `query_encoding` parameter in the `quantization_config` section of the collection configuration. Available values are:
- `default` and `binary` - use regular binary quantization for the query.
@@ -235,7 +284,7 @@ To enable asymmetric quantization, you need to specify `query_encoding` paramete
{{< code-snippet path="/documentation/headless/snippets/create-collection/with-binary-quantization-and-query-encoding/" >}}
### Setting up Product Quantization
### Setting Up Product Quantization
To enable product quantization, you need to specify the quantization parameters in the `quantization_config` section of the collection configuration.
@@ -270,10 +319,7 @@ However, there are a few options that you can use to control the search process:
`ignore` - Toggle whether to ignore quantized vectors during the search process. By default, Qdrant will use quantized vectors if they are available.
`rescore` - Having the original vectors available, Qdrant can re-evaluate top-k search results using the original vectors.
This can improve the search quality, but may slightly decrease the search speed, compared to the search without rescore.
It is recommended to disable rescore only if the original vectors are stored on a slow storage (e.g. HDD or network storage).
By default, rescore is enabled.
`rescore` - Qdrant can re-evaluate top-k search results using the original vectors. While this can improve search quality, it may decrease search speed, especially if the original vectors are stored on disk. In such cases, it is recommended to disable rescoring. By default, rescoring is only enabled for binary quantization. Other quantization methods do not rescore by default.
**Available as of v1.3.0**
@@ -281,9 +327,9 @@ By default, rescore is enabled.
For example, if oversampling is 2.4 and limit is 100, then 240 vectors will be pre-selected using quantized index, and then top-100 will be returned after re-scoring.
Oversampling is useful if you want to tune the tradeoff between search speed and search quality in the query time.
## Quantization tips
## Quantization Tips
#### Accuracy tuning
### Accuracy Tuning
In this section, we will discuss how to tune the search precision.
The fastest way to understand the impact of quantization on the search quality is to compare the search results with and without quantization.
@@ -297,9 +343,9 @@ By setting it to a value lower than 1.0, you can exclude extreme values (outlier
For example, if you set the quantile to 0.99, 1% of the extreme values will be excluded.
By adjusting the quantile, you find an optimal value that will provide the best search quality for your collection.
- **Enable rescore**: Having the original vectors available, Qdrant can re-evaluate top-k search results using the original vectors. On large collections, this can improve the search quality, with just minor performance impact.
- **Enable rescoring**: Qdrant can re-evaluate top-k search results using the original vectors. While this can improve search quality, it may decrease search speed, especially if the original vectors are stored on disk. In such cases, it is recommended to disable rescoring. By default, rescoring is only enabled for binary quantization. Other quantization methods do not rescore by default.
#### Memory and speed tuning
### Memory and Speed Tuning
In this section, we will discuss how to tune the memory and speed of the search process with quantization.
@@ -309,21 +355,18 @@ There are 3 possible modes to place storage of vectors within the qdrant collect
- **Original on Disk, quantized in RAM** - this is a hybrid mode, allows to obtain a good balance between speed and memory usage. Recommended scenario if you are aiming to shrink the memory footprint while keeping the search speed.
This mode is enabled by setting `always_ram` to `true` in the quantization config while using memmap storage:
This mode is enabled by setting `always_ram` to `true` in the quantization config while using memmap storage:\
{{< code-snippet path="/documentation/headless/snippets/create-collection/scalar-quantization-in-ram/" >}}
In this scenario, the number of disk reads may play a significant role in the search speed.
In a system with high disk latency, the re-scoring step may become a bottleneck.
Consider disabling `rescore` to improve the search speed:
In this scenario, the number of disk reads may play a significant role in the search speed.
In a system with high disk latency, the re-scoring step may become a bottleneck.
Consider disabling `rescore` to improve the search speed:\
{{< code-snippet path="/documentation/headless/snippets/query-points/with-disabled-rescoring/" >}}
- **All on Disk** - all vectors, original and quantized, are stored on disk. This mode allows to achieve the smallest memory footprint, but at the cost of the search speed.
It is recommended to use this mode if you have a large collection and fast storage (e.g. SSD or NVMe).
This mode is enabled by setting `always_ram` to `false` in the quantization config while using mmap storage:
It is recommended to use this mode if you have a large collection and fast storage (e.g. SSD or NVMe).
This mode is enabled by setting `always_ram` to `false` in the quantization config while using mmap storage:\
{{< code-snippet path="/documentation/headless/snippets/create-collection/quantization-on-disk/" >}}
@@ -31,11 +31,7 @@ Distribute incoming requests evenly across cluster nodes to ensure consistent pe
Compress vectors to reduce memory footprint. [Quantization](/documentation/manage-data/quantization/) is one of the most impactful changes you can make before going to production.
- **Evaluate whether [Scalar Quantization](/documentation/manage-data/quantization/#scalar-quantization) fits your use case.**
Scalar quantization converts `float32` to `uint8`, reducing memory by a factor of 4. The right default for most production workloads, especially with high-dimensional vectors.
- **Consider [Binary Quantization](/documentation/manage-data/quantization/#binary-quantization) for maximum compression.**
Binary quantization reduces memory by a factor of 32 and can significantly speed up searches. Best suited for compatible high-dimensional embedding models (for example, OpenAI `text-embedding-ada-002` or Cohere `embed-english-v2.0`).
- **Quantization** reduces the memory footprint of vectors, by compressing them to fewer bits. This enables you to store more vectors in memory and on disk, which can improve query performance and reduce costs. Qdrant supports multiple quantization methods, each with different trade-offs between recall, speed, and compression. [Choose the right method](/documentation/manage-data/quantization/#how-to-choose-the-right-quantization-method) based on your requirements for recall, compression, and distance metrics.
- **Benchmark retrieval quality after applying quantization.**
Some models produce embeddings that can't be quantized efficiently. [Verify](/documentation/manage-data/quantization/#accuracy-tuning) that error rates stay within your acceptable threshold for your specific dataset and query patterns. Rescoring adds latency. [Tune](/documentation/manage-data/quantization/#memory-and-speed-tuning) quantization settings to ensure it meets your performance targets.