量化

量化是 Qdrant 中的一项可选功能,能够实现对高维向量的高效存储和搜索。通过将原始向量转换为新的表示形式,量化在压缩数据的同时,保留了向量之间近乎原始的相对距离。不同的量化方法具有不同的机制和权衡,我们将在本节中进行介绍。

量化主要用于减少内存占用并加速高维向量空间的搜索过程。在 Qdrant 的上下文中,量化允许您针对特定用例优化搜索引擎,在精度、存储效率和搜索速度之间取得平衡。

量化伴随着一定的权衡。一方面,量化可以显著降低存储需求并加快搜索速度。这对于大规模应用尤其有利,因为在这些应用中,最小化资源使用是首要任务。另一方面,量化引入了近似误差,这可能导致搜索质量略有下降。这种权衡的程度取决于量化方法及其参数,以及数据的特征。

Qdrant 支持四种量化方法

若要为您的用例选择合适的量化方法,请参考下一节

如何选择合适的量化方法

根据您对召回率、压缩比和距离度量的要求,请参考下表进行选择

压缩率方法
4使用标量量化。这是一种成熟的量化方法,在召回率和压缩比之间取得了良好的平衡。

但是,除非您需要使用曼哈顿 (L1) 距离度量,否则请考虑使用 4 位 TurboQuant 代替标量量化,因为它能以双倍的压缩比提供相当的召回率。
8使用 4 位 TurboQuant。它在召回率和压缩比之间提供了良好的平衡。

当使用曼哈顿 (L1) 距离度量时,请考虑使用其他量化方法。
162 位 TurboQuant2 位二值量化在此压缩级别下提供相似的结果。二值量化速度更快,但 TurboQuant 的召回率更高。
241.5 位 TurboQuant1.5 位二值量化在此压缩级别下提供相似的结果。二值量化速度更快,但 TurboQuant 的召回率更高。
321 位 TurboQuant1 位二值量化在此压缩级别下提供相似的结果。二值量化速度更快,但 TurboQuant 的召回率更高。
最高 64 倍如果内存占用是首要任务,且精度和速度并非关键,请使用乘积量化

TurboQuant 量化

自 v1.18.0 版本起可用

TurboQuant 是由 Google 开发的一种量化方法。它通过在压缩前对向量应用快速随机旋转来工作,从而将数据均匀地重新分布到各个坐标上。这使得可以在整个数据集上应用单一的、预计算且全局优化的量化映射,从而使 TurboQuant 能够有效地处理任何向量分布,并克服了二值量化中发现的关键限制。

Qdrant 对 TurboQuant 的实现扩展了原始算法,以缩小该算法的理论假设与现实世界嵌入之间的差距。

TurboQuant 自动使用非对称量化:仅压缩存储的向量,而查询则以全精度进行评分。这提高了准确性,且无需额外配置。

编码选项

TurboQuant 支持四种位深度

编码位深度压缩率
bits4 (默认)4 位
bits22 位16×
bits1_51.5 位24×
bits11 位32×

在我们的基准测试中,4 位 TurboQuant 在压缩比为标量量化两倍的情况下,提供了相似的召回率和速度。结果因数据集和嵌入模型而异:它可能会优于或略逊于标量量化。这使得 4 位 TurboQuant 成为许多用例的良好默认选择。

与二值量化相比,TurboQuant 在较低速度和同等存储预算下提供了更好的召回率。

默认编码是 bits4,它提供最佳的准确性。

距离度量支持

TurboQuant 完全支持余弦 (Cosine)、点积 (Dot) 和欧几里得 (L2) 距离,并具有 SIMD 加速评分功能。

支持曼哈顿 (L1) 距离,但每次比较需要进行完整的向量重构,因此比其他度量要慢得多。为获得 TurboQuant 的最佳性能,请使用余弦、点积或欧几里得距离。

标量量化

从 v1.1.0 版本开始可用

标量量化在向量搜索引擎的上下文中,是一种通过减少用于表示每个向量分量的位数来压缩向量的压缩技术。

例如,Qdrant 使用 32 位浮点数来表示原始向量分量。标量量化允许您将使用的位数减少到 8 位。换句话说,Qdrant 对每个向量分量执行 float32 -> uint8 转换。实际上,这意味着存储向量所需的内存量减少了 4 倍。

除了减少内存占用外,标量量化还加快了搜索过程。Qdrant 使用特殊的 SIMD CPU 指令来执行快速向量比较。该指令适用于 8 位整数,因此转换为 uint8 使 Qdrant 能够更快地执行比较。

标量量化的主要缺点是精度损失。float32 -> uint8 转换引入了误差,可能导致搜索质量略有下降。然而,这种误差通常可以忽略不计,对于高维向量而言,这种误差往往不太显著。在我们的实验中,我们发现标量量化引入的误差通常小于 1%。

但是,该值取决于数据和量化参数。请参阅“量化提示”部分,了解有关如何优化您的用例量化参数的更多信息。

二值量化

自 v1.5.0 起可用

二值量化是标量量化的一种极端情况。此功能允许您将每个向量分量表示为单个位,有效地将内存占用减少了 32 倍。这是最快的量化方法,因为它允许您使用几条 CPU 指令执行向量比较。与原始向量相比,二值量化可以实现高达 40 倍的加速。

然而,二值量化仅对高维向量有效,且要求向量分量呈中心化分布。

目前,二值量化在以下模型中显示出良好的准确性结果

  • OpenAI text-embedding-ada-002 - 1536d,使用 dbpedia 数据集测试,在 4 倍过采样下达到 0.98 的 recall@100
  • Cohere AI embed-english-v2.0 - 4096d,在维基百科嵌入上测试 - 在 2 倍过采样下达到 0.98 的 recall@50

对于维度较低或向量分量分布不同的模型,可能需要进行额外实验以找到最佳量化参数。

我们建议仅在启用重评分 (rescoring) 的情况下使用二值量化,因为这可以显著提高搜索质量。但是请注意,如果原始向量存储在磁盘上,重评分可能会显著降低搜索速度。

此外,过采样 (oversampling) 可用于在查询时调整搜索速度和搜索质量之间的权衡。

作为汉明距离的二值量化

此方法的另一个好处是,您可以有效地用点积来模拟汉明距离。

具体来说,如果原始向量包含 {-1, 1} 作为可能的值,那么通过简单地将 -1 替换为 0,将 1 替换为 1,两个向量的点积就等于汉明距离。

真值表示例
向量 1向量 2点积
111
1-1-1
-11-1
-1-11
向量 1向量 2汉明距离
110
101
011
000

如您所见,两个函数仅相差一个常数因子,这使得相似性搜索等效。二值量化使得使用这种表示法比较向量变得高效。

1.5 位和 2 位量化

从 v1.15.0 版本开始可用

二值量化存储可以使用每维度 2 位和 1.5 位,从而提高较小向量的精度。对于小于一千维的向量,一位压缩会导致显著的数据丢失和精度下降,通常需要昂贵的重评分。2 位量化相比 1 位量化实现了 16 倍压缩(而不是 32 倍),改善了较小向量维度的性能。1.5 位量化压缩提供 24 倍压缩和中间精度的效果。

二值量化的一个主要局限是对接近零的值处理不佳。2 位量化通过使用高效的评分机制显式表示零来解决此问题。对于 1.5 位量化,零位在两个值之间共享,平衡了二值量化的效率和 2 位量化的精度提升,尤其是在 2 位 BQ 需要过多内存时。

为了构建 2 位表示,Qdrant 计算值的分布,然后将位值分配给 3 个可能的存储桶 (buckets)

  • -1 - 00
  • 0 - 01
  • 1 - 11

1.5 位量化类似,但将元素对的存储桶合并为二进制三元组 (triptets)

2-bit quantization

2 位量化

请参阅以下部分了解如何设置 1.5 位和 2 位量化。

非对称量化 (Asymmetric Quantization)

从 v1.15.0 版本开始可用

非对称量化技术允许 Qdrant 对存储的向量和查询使用不同的向量编码算法。特别有趣的组合是二值化存储的向量与标量量化的查询。

Asymmetric quantization

非对称量化

这种方法保持了与二值量化相似的存储大小和 RAM 使用量,同时提供了更高的精度。这对于内存受限的部署,或者瓶颈在于磁盘 I/O 而非 CPU 的情况非常有利。这对于索引数百万个向量特别有用,因为它提高了精度而不会牺牲太多性能,因为在这种场景下限制因素是磁盘速度而非 CPU。这种方法在实现相同质量输出时需要较少的重评分。

请参阅以下部分了解如何设置非对称量化。

乘积量化

自 v1.2.0 起可用

乘积量化是一种通过将向量划分为块并分别量化每个段来压缩向量以最小化其内存使用的方法。每个块由代表原始向量分量的质心索引近似。质心的位置通过使用聚类算法(如 k-means)来确定。目前,Qdrant 仅使用 256 个质心,因此每个质心索引可以用单个字节表示。

乘积量化可以比标量量化实现更显著的压缩,但也有一些权衡。乘积量化的距离计算对 SIMD 不友好,因此比标量量化慢。此外,乘积量化存在精度损失,因此建议仅将其用于高维向量。

请参阅“量化提示”部分,了解有关如何优化您的用例量化参数的更多信息。

在 Qdrant 中设置量化

您可以通过在集合配置的 quantization_config 部分中指定量化参数来为集合配置量化。

量化将在索引过程中自动应用于所有向量。量化后的向量与原始向量一起存储在集合中,因此如果需要,您仍然可以访问原始向量。

自 v1.1.1 起可用

quantization_config 也可以通过在命名向量中指定它来按向量进行设置。

设置 TurboQuant

要启用 TurboQuant,请在集合配置的 quantization_config 部分中指定它。

在现有集合上启用 TurboQuant 时,请使用 PATCH 请求或相应的 update_collection 方法,并省略向量配置,因为它已经定义过了。

PUT /collections/{collection_name}
{
    "vectors": {
      "size": 1536,
      "distance": "Cosine"
    },
    "quantization_config": {
        "turbo": {
            "always_ram": true
        }
    }
}
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,
        ),
    ),
)
import { QdrantClient } from "@qdrant/js-client-rest";

client.createCollection("{collection_name}", {
  vectors: {
    size: 1536,
    distance: "Cosine",
  },
  quantization_config: {
    turbo: {
      always_ram: true,
    },
  },
});
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?;
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();
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 }
	}
);
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 - 编码位深度。默认为 bits4。可选值:bits4, bits2, bits1_5bits1。较低的位深度提供更高的压缩比,但会牺牲精度。

always_ram - 是否将量化后的向量始终缓存在 RAM 中。默认情况下,量化向量的加载方式与原始向量相同。将 always_ram 设置为 true 可将量化向量存储在 RAM 中。

选择位深度

要使用特定的压缩级别,请设置 bits 参数

PUT /collections/{collection_name}
{
    "vectors": {
      "size": 1536,
      "distance": "Cosine"
    },
    "quantization_config": {
        "turbo": {
            "bits": "bits2",
            "always_ram": true
        }
    }
}
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,
        ),
    ),
)
import { QdrantClient } from "@qdrant/js-client-rest";

client.createCollection("{collection_name}", {
  vectors: {
    size: 1536,
    distance: "Cosine",
  },
  quantization_config: {
    turbo: {
      always_ram: true,
      bits: "bits2",
    },
  },
});
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?;
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();
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 }
	}
);
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(),
		},
	),
})

设置标量量化

要启用标量量化,您需要在集合配置的 quantization_config 部分中指定量化参数。

在现有集合上启用标量量化时,请使用 PATCH 请求或相应的 update_collection 方法,并省略向量配置,因为它已经定义过了。

PUT /collections/{collection_name}
{
    "vectors": {
      "size": 768,
      "distance": "Cosine"
    },
    "quantization_config": {
        "scalar": {
            "type": "int8",
            "quantile": 0.99,
            "always_ram": true
        }
    }
}
from qdrant_client import QdrantClient, models

client = QdrantClient(url="https://:6333")

client.create_collection(
    collection_name="{collection_name}",
    vectors_config=models.VectorParams(size=768, distance=models.Distance.COSINE),
    quantization_config=models.ScalarQuantization(
        scalar=models.ScalarQuantizationConfig(
            type=models.ScalarType.INT8,
            quantile=0.99,
            always_ram=True,
        ),
    ),
)
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({ host: "localhost", port: 6333 });

client.createCollection("{collection_name}", {
  vectors: {
    size: 768,
    distance: "Cosine",
  },
  quantization_config: {
    scalar: {
      type: "int8",
      quantile: 0.99,
      always_ram: true,
    },
  },
});
use qdrant_client::qdrant::{
    CreateCollectionBuilder, Distance, QuantizationType, ScalarQuantizationBuilder,
    VectorParamsBuilder,
};
use qdrant_client::Qdrant;

let client = Qdrant::from_url("https://:6334").build()?;

client
    .create_collection(
        CreateCollectionBuilder::new("{collection_name}")
            .vectors_config(VectorParamsBuilder::new(768, Distance::Cosine))
            .quantization_config(
                ScalarQuantizationBuilder::default()
                    .r#type(QuantizationType::Int8.into())
                    .quantile(0.99)
                    .always_ram(true),
            ),
    )
    .await?;
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.QuantizationType;
import io.qdrant.client.grpc.Collections.ScalarQuantization;
import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.grpc.Collections.VectorsConfig;

QdrantClient client =
    new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());

client
    .createCollectionAsync(
        CreateCollection.newBuilder()
            .setCollectionName("{collection_name}")
            .setVectorsConfig(
                VectorsConfig.newBuilder()
                    .setParams(
                        VectorParams.newBuilder()
                            .setSize(768)
                            .setDistance(Distance.Cosine)
                            .build())
                    .build())
            .setQuantizationConfig(
                QuantizationConfig.newBuilder()
                    .setScalar(
                        ScalarQuantization.newBuilder()
                            .setType(QuantizationType.Int8)
                            .setQuantile(0.99f)
                            .setAlwaysRam(true)
                            .build())
                    .build())
            .build())
    .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

var client = new QdrantClient("localhost", 6334);

await client.CreateCollectionAsync(
 collectionName: "{collection_name}",
 vectorsConfig: new VectorParams { Size = 768, Distance = Distance.Cosine },
 quantizationConfig: new QuantizationConfig
 {
  Scalar = new ScalarQuantization
  {
   Type = QuantizationType.Int8,
   Quantile = 0.99f,
   AlwaysRam = true
  }
 }
);
import (
	"context"

	"github.com/qdrant/go-client/qdrant"
)

client, err := qdrant.NewClient(&qdrant.Config{
	Host: "localhost",
	Port: 6334,
})

client.CreateCollection(context.Background(), &qdrant.CreateCollection{
	CollectionName: "{collection_name}",
	VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
		Size:     768,
		Distance: qdrant.Distance_Cosine,
	}),
	QuantizationConfig: qdrant.NewQuantizationScalar(
		&qdrant.ScalarQuantization{
            Type:      qdrant.QuantizationType_Int8,
			Quantile:  qdrant.PtrOf(float32(0.99)),
			AlwaysRam: qdrant.PtrOf(true),
		},
	),
})

您可以在 quantization_config 部分中指定 3 个参数

type - 量化向量分量的类型。目前,Qdrant 仅支持 int8

quantile - 量化向量分量的分位数。分位数用于计算量化边界。例如,如果您指定 0.99 作为分位数,则 1% 的极值将被排除在量化边界之外。

如果您的向量分量中存在离群值,使用低于 1.0 的分位数可能很有用。此参数仅影响最终精度,不影响内存占用。如果您遇到搜索质量显著下降的情况,可能值得调整此参数。

always_ram - 是否将量化向量始终缓存在 RAM 中。默认情况下,量化向量的加载方式与原始向量相同。但是,在某些设置中,您可能希望将量化向量保留在 RAM 中以加快搜索过程。

在这种情况下,您可以将 always_ram 设置为 true,将量化向量存储在 RAM 中。

设置二值量化

要启用二值量化,您需要在集合配置的 quantization_config 部分中指定量化参数。

在现有集合上启用二值量化时,请使用 PATCH 请求或相应的 update_collection 方法,并省略向量配置,因为它已经定义过了。

PUT /collections/{collection_name}
{
    "vectors": {
      "size": 1536,
      "distance": "Cosine"
    },
    "quantization_config": {
        "binary": {
            "always_ram": true
        }
    }
}
from qdrant_client import QdrantClient, models

client = QdrantClient(url="https://:6333")

client.create_collection(
    collection_name="{collection_name}",
    vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
    quantization_config=models.BinaryQuantization(
        binary=models.BinaryQuantizationConfig(
            always_ram=True,
        ),
    ),
)
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({ host: "localhost", port: 6333 });

client.createCollection("{collection_name}", {
  vectors: {
    size: 1536,
    distance: "Cosine",
  },
  quantization_config: {
    binary: {
      always_ram: true,
    },
  },
});
use qdrant_client::qdrant::{
    BinaryQuantizationBuilder, CreateCollectionBuilder, Distance, VectorParamsBuilder,
};
use qdrant_client::Qdrant;

let client = Qdrant::from_url("https://:6334").build()?;

client
    .create_collection(
        CreateCollectionBuilder::new("{collection_name}")
            .vectors_config(VectorParamsBuilder::new(1536, Distance::Cosine))
            .quantization_config(BinaryQuantizationBuilder::new(true)),
    )
    .await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.BinaryQuantization;
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.VectorParams;
import io.qdrant.client.grpc.Collections.VectorsConfig;

QdrantClient client =
    new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());

client
    .createCollectionAsync(
        CreateCollection.newBuilder()
            .setCollectionName("{collection_name}")
            .setVectorsConfig(
                VectorsConfig.newBuilder()
                    .setParams(
                        VectorParams.newBuilder()
                            .setSize(1536)
                            .setDistance(Distance.Cosine)
                            .build())
                    .build())
            .setQuantizationConfig(
                QuantizationConfig.newBuilder()
                    .setBinary(BinaryQuantization.newBuilder().setAlwaysRam(true).build())
                    .build())
            .build())
    .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

var client = new QdrantClient("localhost", 6334);

await client.CreateCollectionAsync(
 collectionName: "{collection_name}",
 vectorsConfig: new VectorParams { Size = 1536, Distance = Distance.Cosine },
 quantizationConfig: new QuantizationConfig
 {
  Binary = new BinaryQuantization { AlwaysRam = true }
 }
);
import (
	"context"

	"github.com/qdrant/go-client/qdrant"
)

client, err := qdrant.NewClient(&qdrant.Config{
	Host: "localhost",
	Port: 6334,
})

client.CreateCollection(context.Background(), &qdrant.CreateCollection{
	CollectionName: "{collection_name}",
	VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
		Size:     1536,
		Distance: qdrant.Distance_Cosine,
	}),
	QuantizationConfig: qdrant.NewQuantizationBinary(
		&qdrant.BinaryQuantization{
			AlwaysRam: qdrant.PtrOf(true),
		},
	),
})

always_ram - 是否将量化向量始终缓存在 RAM 中。默认情况下,量化向量的加载方式与原始向量相同。但是,在某些设置中,您可能希望将量化向量保留在 RAM 中以加快搜索过程。

在这种情况下,您可以将 always_ram 设置为 true,将量化向量存储在 RAM 中。

设置位深度

要启用 2 位或 1.5 位量化,您需要在集合配置的 quantization_config 部分中指定 encoding 参数。可选值有 two_bitsone_and_half_bits

PUT /collections/{collection_name}
{
    "vectors": {
      "size": 1536,
      "distance": "Cosine"
    },
    "quantization_config": {
        "binary": {
            "encoding": "two_bits",
            "always_ram": true
        }
    }
}
from qdrant_client import QdrantClient, models

client = QdrantClient(url="https://:6333")

client.create_collection(
    collection_name="{collection_name}",
    vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
    quantization_config=models.BinaryQuantization(
        binary=models.BinaryQuantizationConfig(
            encoding=models.BinaryQuantizationEncoding.TWO_BITS,
            always_ram=True,
        ),
    ),
)
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({ host: "localhost", port: 6333 });

client.createCollection("{collection_name}", {
  vectors: {
    size: 1536,
    distance: "Cosine",
  },
  quantization_config: {
    binary: {
      encoding: "two_bits",
      always_ram: true,
    },
  },
});
use qdrant_client::qdrant::{
    BinaryQuantizationBuilder,
    CreateCollectionBuilder,
    Distance,
    VectorParamsBuilder,
    BinaryQuantizationEncoding,
};
use qdrant_client::Qdrant;

let client = Qdrant::from_url("https://:6334").build()?;

client
    .create_collection(
        CreateCollectionBuilder::new("{collection_name}")
            .vectors_config(VectorParamsBuilder::new(1536, Distance::Cosine))
            .quantization_config(BinaryQuantizationBuilder::new(true)
                .encoding(BinaryQuantizationEncoding::TwoBits)
            ),
    )
    .await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.BinaryQuantization;
import io.qdrant.client.grpc.Collections.BinaryQuantizationEncoding;
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.VectorParams;
import io.qdrant.client.grpc.Collections.VectorsConfig;

QdrantClient client =
    new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());

client
    .createCollectionAsync(
        CreateCollection.newBuilder()
            .setCollectionName("{collection_name}")
            .setVectorsConfig(
                VectorsConfig.newBuilder()
                    .setParams(
                        VectorParams.newBuilder()
                            .setSize(1536)
                            .setDistance(Distance.Cosine)
                            .build())
                    .build())
            .setQuantizationConfig(
                QuantizationConfig.newBuilder()
                    .setBinary(BinaryQuantization
                        .newBuilder()
                        .setEncoding(BinaryQuantizationEncoding.TwoBits)
                        .setAlwaysRam(true)
                        .build())
                    .build())
            .build())
    .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

var client = new QdrantClient("localhost", 6334);

await client.CreateCollectionAsync(
  collectionName: "{collection_name}",
  vectorsConfig: new VectorParams { Size = 1536, Distance = Distance.Cosine },
  quantizationConfig: new QuantizationConfig
  {
    Binary = new BinaryQuantization {
      Encoding = BinaryQuantizationEncoding.TwoBits,
      AlwaysRam = true
    }
  }
);
import (
    "context"

    "github.com/qdrant/go-client/qdrant"
)

client, err := qdrant.NewClient(&qdrant.Config{
    Host: "localhost",
    Port: 6334,
})

client.CreateCollection(context.Background(), &qdrant.CreateCollection{
    CollectionName: "{collection_name}",
    VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
        Size:     1536,
        Distance: qdrant.Distance_Cosine,
    }),
    QuantizationConfig: qdrant.NewQuantizationBinary(
        &qdrant.BinaryQuantization{
            Encoding: qdrant.BinaryQuantizationEncoding_TwoBits.Enum(),
            AlwaysRam: qdrant.PtrOf(true),
        },
    ),
})

设置非对称量化

要启用非对称量化,您需要在集合配置的 quantization_config 部分中指定 query_encoding 参数。可选值有

  • defaultbinary - 对查询使用常规二值量化。
  • scalar8bits - 对查询使用 8 位量化。
  • scalar4bits - 对查询使用 4 位量化。
PUT /collections/{collection_name}
{
    "vectors": {
      "size": 1536,
      "distance": "Cosine"
    },
    "quantization_config": {
        "binary": {
            "query_encoding": "scalar8bits",
            "always_ram": true
        }
    }
}
from qdrant_client import QdrantClient, models

client = QdrantClient(url="https://:6333")

client.create_collection(
    collection_name="{collection_name}",
    vectors_config=models.VectorParams(size=1536, distance=models.Distance.COSINE),
    quantization_config=models.BinaryQuantization(
        binary=models.BinaryQuantizationConfig(
            query_encoding=models.BinaryQuantizationQueryEncoding.SCALAR8BITS,
            always_ram=True,
        ),
    ),
)
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({ host: "localhost", port: 6333 });

client.createCollection("{collection_name}", {
  vectors: {
    size: 1536,
    distance: "Cosine",
  },
  quantization_config: {
    binary: {
      query_encoding: "scalar8bits",
      always_ram: true,
    },
  },
});
use qdrant_client::qdrant::{
    BinaryQuantizationBuilder,
    CreateCollectionBuilder,
    Distance,
    VectorParamsBuilder,
    BinaryQuantizationQueryEncoding,
};
use qdrant_client::Qdrant;

let client = Qdrant::from_url("https://:6334").build()?;

client
    .create_collection(
        CreateCollectionBuilder::new("{collection_name}")
            .vectors_config(VectorParamsBuilder::new(1536, Distance::Cosine))
            .quantization_config(
                BinaryQuantizationBuilder::new(true)
                    .query_encoding(BinaryQuantizationQueryEncoding::scalar8bits())
            ),
    )
    .await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.BinaryQuantization;
import io.qdrant.client.grpc.Collections.BinaryQuantizationQueryEncoding;
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.VectorParams;
import io.qdrant.client.grpc.Collections.VectorsConfig;

QdrantClient client =
    new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());

client
    .createCollectionAsync(
        CreateCollection.newBuilder()
            .setCollectionName("{collection_name}")
            .setVectorsConfig(
                VectorsConfig.newBuilder()
                    .setParams(
                        VectorParams.newBuilder()
                            .setSize(1536)
                            .setDistance(Distance.Cosine)
                            .build())
                    .build())
            .setQuantizationConfig(
                QuantizationConfig.newBuilder()
                    .setBinary(BinaryQuantization.newBuilder()
                        .setQueryEncoding(BinaryQuantizationQueryEncoding
                            .newBuilder()
                            .setSetting(BinaryQuantizationQueryEncoding.Setting.Scalar8Bits)
                            .build())
                        .setAlwaysRam(true)
                        .build())
                    .build())
            .build())
    .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

var client = new QdrantClient("localhost", 6334);

await client.CreateCollectionAsync(
  collectionName: "{collection_name}",
  vectorsConfig: new VectorParams { Size = 1536, Distance = Distance.Cosine },
  quantizationConfig: new QuantizationConfig
  {
    Binary = new BinaryQuantization {
      QueryEncoding = new BinaryQuantizationQueryEncoding
      {
        Setting = BinaryQuantizationQueryEncoding.Types.Setting.Scalar8Bits,
      },
      AlwaysRam = true
    }
  }
);
import (
    "context"

    "github.com/qdrant/go-client/qdrant"
)

client, err := qdrant.NewClient(&qdrant.Config{
    Host: "localhost",
    Port: 6334,
})

client.CreateCollection(context.Background(), &qdrant.CreateCollection{
    CollectionName: "{collection_name}",
    VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
        Size:     1536,
        Distance: qdrant.Distance_Cosine,
    }),
    QuantizationConfig: qdrant.NewQuantizationBinary(
        &qdrant.BinaryQuantization{
            QueryEncoding: qdrant.NewBinaryQuantizationQueryEncodingSetting(qdrant.BinaryQuantizationQueryEncoding_Scalar8Bits),
            AlwaysRam: qdrant.PtrOf(true),
        },
    ),
})

设置乘积量化

要启用乘积量化,您需要在集合配置的 quantization_config 部分中指定量化参数。

在现有集合上启用乘积量化时,请使用 PATCH 请求或相应的 update_collection 方法,并省略向量配置,因为它已经定义过了。

PUT /collections/{collection_name}
{
    "vectors": {
      "size": 768,
      "distance": "Cosine"
    },
    "quantization_config": {
        "product": {
            "compression": "x16",
            "always_ram": true
        }
    }
}
from qdrant_client import QdrantClient, models

client = QdrantClient(url="https://:6333")

client.create_collection(
    collection_name="{collection_name}",
    vectors_config=models.VectorParams(size=768, distance=models.Distance.COSINE),
    quantization_config=models.ProductQuantization(
        product=models.ProductQuantizationConfig(
            compression=models.CompressionRatio.X16,
            always_ram=True,
        ),
    ),
)
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({ host: "localhost", port: 6333 });

client.createCollection("{collection_name}", {
  vectors: {
    size: 768,
    distance: "Cosine",
  },
  quantization_config: {
    product: {
      compression: "x16",
      always_ram: true,
    },
  },
});
use qdrant_client::qdrant::{
    CompressionRatio, CreateCollectionBuilder, Distance, ProductQuantizationBuilder,
    VectorParamsBuilder,
};
use qdrant_client::Qdrant;

let client = Qdrant::from_url("https://:6334").build()?;

client
    .create_collection(
        CreateCollectionBuilder::new("{collection_name}")
            .vectors_config(VectorParamsBuilder::new(768, Distance::Cosine))
            .quantization_config(
                ProductQuantizationBuilder::new(CompressionRatio::X16.into()).always_ram(true),
            ),
    )
    .await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.CompressionRatio;
import io.qdrant.client.grpc.Collections.CreateCollection;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.ProductQuantization;
import io.qdrant.client.grpc.Collections.QuantizationConfig;
import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.grpc.Collections.VectorsConfig;

QdrantClient client =
    new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());

client
    .createCollectionAsync(
        CreateCollection.newBuilder()
            .setCollectionName("{collection_name}")
            .setVectorsConfig(
                VectorsConfig.newBuilder()
                    .setParams(
                        VectorParams.newBuilder()
                            .setSize(768)
                            .setDistance(Distance.Cosine)
                            .build())
                    .build())
            .setQuantizationConfig(
                QuantizationConfig.newBuilder()
                    .setProduct(
                        ProductQuantization.newBuilder()
                            .setCompression(CompressionRatio.x16)
                            .setAlwaysRam(true)
                            .build())
                    .build())
            .build())
    .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

var client = new QdrantClient("localhost", 6334);

await client.CreateCollectionAsync(
 collectionName: "{collection_name}",
 vectorsConfig: new VectorParams { Size = 768, Distance = Distance.Cosine },
 quantizationConfig: new QuantizationConfig
 {
  Product = new ProductQuantization { Compression = CompressionRatio.X16, AlwaysRam = true }
 }
);
import (
	"context"

	"github.com/qdrant/go-client/qdrant"
)

client, err := qdrant.NewClient(&qdrant.Config{
	Host: "localhost",
	Port: 6334,
})

client.CreateCollection(context.Background(), &qdrant.CreateCollection{
	CollectionName: "{collection_name}",
	VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
		Size:     768,
		Distance: qdrant.Distance_Cosine,
	}),
	QuantizationConfig: qdrant.NewQuantizationProduct(
		&qdrant.ProductQuantization{
			Compression: qdrant.CompressionRatio_x16,
			AlwaysRam:   qdrant.PtrOf(true),
		},
	),
})

您可以在 quantization_config 部分中指定两个参数

compression - 压缩比。压缩比表示量化向量大小(字节)除以原始向量大小(字节)。在这种情况下,量化向量将比原始向量小 16 倍。

always_ram - 是否将量化后的向量始终缓存在 RAM 中。默认情况下,量化向量的加载方式与原始向量相同。但是,在某些设置中,您可能希望将量化向量保留在 RAM 中以加快搜索过程。此时请将 always_ram 设置为 true

禁用量化

要禁用现有集合中的量化,您可以执行以下操作

PATCH /collections/{collection_name}
{
    "quantization_config": "Disabled"
}
curl -X PATCH https://:6333/collections/{collection_name} \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "quantization_config": "Disabled"
  }'
client.update_collection(
    collection_name="{collection_name}",
    quantization_config=models.Disabled.DISABLED,
)
client.updateCollection("{collection_name}", {
    quantization_config: 'Disabled'
});
use qdrant_client::qdrant::{Disabled, UpdateCollectionBuilder};

client
    .update_collection(UpdateCollectionBuilder::new("{collection_name}").quantization_config(Disabled {}))
    .await?;
import io.qdrant.client.grpc.Collections.Disabled;
import io.qdrant.client.grpc.Collections.QuantizationConfigDiff;
import io.qdrant.client.grpc.Collections.UpdateCollection;

client.updateCollectionAsync(
    UpdateCollection.newBuilder()
        .setCollectionName("{collection_name}")
        .setQuantizationConfig(
            QuantizationConfigDiff.newBuilder()
                .setDisabled(Disabled.getDefaultInstance())
                .build())
        .build());
using Qdrant.Client;
using Qdrant.Client.Grpc;

var client = new QdrantClient("localhost", 6334);

await client.UpdateCollectionAsync(
	collectionName: "{collection_name}",
	quantizationConfig: new QuantizationConfigDiff { Disabled = new Disabled() }
);
import (
	"context"

	"github.com/qdrant/go-client/qdrant"
)

client, err := qdrant.NewClient(&qdrant.Config{
	Host: "localhost",
	Port: 6334,
})

client.UpdateCollection(context.Background(), &qdrant.UpdateCollection{
	CollectionName:     "{collection_name}",
	QuantizationConfig: qdrant.NewQuantizationDiffDisabled(),
})

使用量化进行搜索

一旦您为集合配置了量化,就不需要执行任何额外操作即可使用量化进行搜索。如果量化向量可用,Qdrant 将自动使用它们。

但是,您可以使用一些选项来控制搜索过程

POST /collections/{collection_name}/points/query
{
    "query": [0.2, 0.1, 0.9, 0.7],
    "params": {
        "quantization": {
            "ignore": false,
            "rescore": true,
            "oversampling": 2.0
        }
    },
    "limit": 10
}
from qdrant_client import QdrantClient, models

client = QdrantClient(url="https://:6333")

client.query_points(
    collection_name="{collection_name}",
    query=[0.2, 0.1, 0.9, 0.7],
    search_params=models.SearchParams(
        quantization=models.QuantizationSearchParams(
            ignore=False,
            rescore=True,
            oversampling=2.0,
        )
    ),
)
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({ host: "localhost", port: 6333 });

client.query("{collection_name}", {
    query: [0.2, 0.1, 0.9, 0.7],
    params: {
        quantization: {
            ignore: false,
            rescore: true,
            oversampling: 2.0,
        },
    },
    limit: 10,
});
use qdrant_client::qdrant::{
    QuantizationSearchParamsBuilder, QueryPointsBuilder, SearchParamsBuilder,
};
use qdrant_client::Qdrant;

let client = Qdrant::from_url("https://:6334").build()?;

client
    .query(
        QueryPointsBuilder::new("{collection_name}")
            .query(vec![0.2, 0.1, 0.9, 0.7])
            .limit(10)
            .params(
                SearchParamsBuilder::default().quantization(
                    QuantizationSearchParamsBuilder::default()
                        .ignore(false)
                        .rescore(true)
                        .oversampling(2.0),
                ),
            ),
    )
    .await?;
import static io.qdrant.client.QueryFactory.nearest;

import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Points.QuantizationSearchParams;
import io.qdrant.client.grpc.Points.QueryPoints;
import io.qdrant.client.grpc.Points.SearchParams;

QdrantClient client =
    new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());

client.queryAsync(
        QueryPoints.newBuilder()
                .setCollectionName("{collection_name}")
                .setQuery(nearest(0.2f, 0.1f, 0.9f, 0.7f))
                .setParams(
                        SearchParams.newBuilder()
                                .setQuantization(
                                        QuantizationSearchParams.newBuilder()
                                                .setIgnore(false)
                                                .setRescore(true)
                                                .setOversampling(2.0)
                                                .build())
                                .build())
                .setLimit(10)
                .build())
        .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

var client = new QdrantClient("localhost", 6334);

await client.QueryAsync(
	collectionName: "{collection_name}",
	query: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
	searchParams: new SearchParams
	{
		Quantization = new QuantizationSearchParams
		{
			Ignore = false,
			Rescore = true,
			Oversampling = 2.0
		}
	},
	limit: 10
);
import (
	"context"

	"github.com/qdrant/go-client/qdrant"
)

client, err := qdrant.NewClient(&qdrant.Config{
	Host: "localhost",
	Port: 6334,
})

client.Query(context.Background(), &qdrant.QueryPoints{
	CollectionName: "{collection_name}",
	Query:          qdrant.NewQuery(0.2, 0.1, 0.9, 0.7),
	Params: &qdrant.SearchParams{
		Quantization: &qdrant.QuantizationSearchParams{
			Ignore:       qdrant.PtrOf(false),
			Rescore:      qdrant.PtrOf(true),
			Oversampling: qdrant.PtrOf(2.0),
		},
	},
})

ignore - 切换搜索过程中是否忽略量化向量。默认情况下,如果量化向量可用,Qdrant 将会使用它们。

rescore - Qdrant 可以使用原始向量重新评估 top-k 搜索结果。虽然这可以提高搜索质量,但可能会降低搜索速度,尤其是当原始向量存储在磁盘上时。在这种情况下,建议禁用重评分。默认情况下,仅对二值量化启用重评分。其他量化方法默认不进行重评分。

从 v1.3.0 版本开始可用

oversampling - 定义应使用量化索引预选多少额外向量,然后再使用原始向量进行重评分。例如,如果过采样为 2.4 且限制为 100,则将使用量化索引预选 240 个向量,然后在重评分后返回前 100 个结果。如果您想在查询时调整搜索速度和搜索质量之间的权衡,过采样非常有用。

量化提示

精度调整

在本节中,我们将讨论如何调整搜索精度。了解量化对搜索质量影响的最快方法是比较使用和不使用量化时的搜索结果。

为了禁用量化,您可以在搜索请求中将 ignore 设置为 true

POST /collections/{collection_name}/points/query
{
    "query": [0.2, 0.1, 0.9, 0.7],
    "params": {
        "quantization": {
            "ignore": true
        }
    },
    "limit": 10
}
from qdrant_client import QdrantClient, models

client = QdrantClient(url="https://:6333")

client.query_points(
    collection_name="{collection_name}",
    query=[0.2, 0.1, 0.9, 0.7],
    search_params=models.SearchParams(
        quantization=models.QuantizationSearchParams(
            ignore=True,
        )
    ),
)
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({ host: "localhost", port: 6333 });

client.query("{collection_name}", {
    query: [0.2, 0.1, 0.9, 0.7],
    params: {
        quantization: {
            ignore: true,
        },
    },
});
use qdrant_client::qdrant::{
    QuantizationSearchParamsBuilder, QueryPointsBuilder, SearchParamsBuilder,
};
use qdrant_client::Qdrant;

let client = Qdrant::from_url("https://:6334").build()?;

client
    .query(
        QueryPointsBuilder::new("{collection_name}")
            .query(vec![0.2, 0.1, 0.9, 0.7])
            .limit(3)
            .params(
                SearchParamsBuilder::default()
                    .quantization(QuantizationSearchParamsBuilder::default().ignore(true)),
            ),
    )
    .await?;
import static io.qdrant.client.QueryFactory.nearest;

import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Points.QuantizationSearchParams;
import io.qdrant.client.grpc.Points.QueryPoints;
import io.qdrant.client.grpc.Points.SearchParams;

QdrantClient client =
    new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());

client.queryAsync(
        QueryPoints.newBuilder()
                .setCollectionName("{collection_name}")
                .setQuery(nearest(0.2f, 0.1f, 0.9f, 0.7f))
                .setParams(
                        SearchParams.newBuilder()
                                .setQuantization(
                                        QuantizationSearchParams.newBuilder().setIgnore(true).build())
                                .build())
                .setLimit(10)
                .build())
        .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

var client = new QdrantClient("localhost", 6334);

await client.QueryAsync(
	collectionName: "{collection_name}",
	query: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
	searchParams: new SearchParams
	{
		Quantization = new QuantizationSearchParams { Ignore = true }
	},
	limit: 10
);
import (
	"context"

	"github.com/qdrant/go-client/qdrant"
)

client, err := qdrant.NewClient(&qdrant.Config{
	Host: "localhost",
	Port: 6334,
})

client.Query(context.Background(), &qdrant.QueryPoints{
	CollectionName: "{collection_name}",
	Query:          qdrant.NewQuery(0.2, 0.1, 0.9, 0.7),
	Params: &qdrant.SearchParams{
		Quantization: &qdrant.QuantizationSearchParams{
			Ignore: qdrant.PtrOf(false),
		},
	},
})
  • 调整分位数 (quantile) 参数:标量量化中的分位数参数决定了量化边界。通过将其设置为小于 1.0 的值,您可以从量化边界中排除极值(离群值)。例如,如果您将分位数设置为 0.99,则 1% 的极值将被排除。通过调整分位数,您可以找到为您的集合提供最佳搜索质量的最佳值。

  • 启用重评分:Qdrant 可以使用原始向量重新评估 top-k 搜索结果。虽然这可以提高搜索质量,但可能会降低搜索速度,尤其是当原始向量存储在磁盘上时。在这种情况下,建议禁用重评分。默认情况下,仅对二值量化启用重评分。其他量化方法默认不进行重评分。

内存和速度调整

在本节中,我们将讨论如何调整量化搜索过程的内存和速度。

Qdrant 集合中的向量存储有 3 种可能的模式

  • 全部在 RAM 中 - 所有向量(原始和量化)都被加载并保存在 RAM 中。这是最快的模式,但需要大量 RAM。默认启用。

  • 原始数据在磁盘上,量化数据在 RAM 中 - 这是一种混合模式,允许在速度和内存使用之间获得良好的平衡。如果您旨在缩小内存占用同时保持搜索速度,推荐使用此场景。

    此模式通过在使用 memmap 存储时将 always_ram 设置为 true 来启用

    PUT /collections/{collection_name}
    {
        "vectors": {
            "size": 768,
            "distance": "Cosine",
            "on_disk": true
        },
        "quantization_config": {
            "scalar": {
                "type": "int8",
                "always_ram": true
            }
        }
    }
    
    from qdrant_client import QdrantClient, models
    
    client = QdrantClient(url="https://:6333")
    
    client.create_collection(
        collection_name="{collection_name}",
        vectors_config=models.VectorParams(size=768, distance=models.Distance.COSINE, on_disk=True),
        quantization_config=models.ScalarQuantization(
            scalar=models.ScalarQuantizationConfig(
                type=models.ScalarType.INT8,
                always_ram=True,
            ),
        ),
    )
    
    import { QdrantClient } from "@qdrant/js-client-rest";
    
    const client = new QdrantClient({ host: "localhost", port: 6333 });
    
    client.createCollection("{collection_name}", {
      vectors: {
        size: 768,
        distance: "Cosine",
        on_disk: true,
      },
      quantization_config: {
        scalar: {
          type: "int8",
          always_ram: true,
        },
      },
    });
    
    use qdrant_client::qdrant::{
        CreateCollectionBuilder, Distance, QuantizationType, ScalarQuantizationBuilder,
        VectorParamsBuilder,
    };
    use qdrant_client::Qdrant;
    
    let client = Qdrant::from_url("https://:6334").build()?;
    
    client
        .create_collection(
            CreateCollectionBuilder::new("{collection_name}")
                .vectors_config(VectorParamsBuilder::new(768, Distance::Cosine))
                .quantization_config(
                    ScalarQuantizationBuilder::default()
                        .r#type(QuantizationType::Int8.into())
                        .always_ram(true),
                ),
        )
        .await?;
    
    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.OptimizersConfigDiff;
    import io.qdrant.client.grpc.Collections.QuantizationConfig;
    import io.qdrant.client.grpc.Collections.QuantizationType;
    import io.qdrant.client.grpc.Collections.ScalarQuantization;
    import io.qdrant.client.grpc.Collections.VectorParams;
    import io.qdrant.client.grpc.Collections.VectorsConfig;
    
    QdrantClient client =
        new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
    
    client
        .createCollectionAsync(
            CreateCollection.newBuilder()
                .setCollectionName("{collection_name}")
                .setVectorsConfig(
                    VectorsConfig.newBuilder()
                        .setParams(
                            VectorParams.newBuilder()
                                .setSize(768)
                                .setDistance(Distance.Cosine)
                                .setOnDisk(true)
                                .build())
                        .build())
                .setQuantizationConfig(
                    QuantizationConfig.newBuilder()
                        .setScalar(
                            ScalarQuantization.newBuilder()
                                .setType(QuantizationType.Int8)
                                .setAlwaysRam(true)
                                .build())
                        .build())
                .build())
        .get();
    
    using Qdrant.Client;
    using Qdrant.Client.Grpc;
    
    var client = new QdrantClient("localhost", 6334);
    
    await client.CreateCollectionAsync(
    	collectionName: "{collection_name}",
    	vectorsConfig: new VectorParams { Size = 768, Distance = Distance.Cosine, OnDisk = true },
    	quantizationConfig: new QuantizationConfig
    	{
    		Scalar = new ScalarQuantization { Type = QuantizationType.Int8, AlwaysRam = true }
    	}
    );
    
    import (
    	"context"
    
    	"github.com/qdrant/go-client/qdrant"
    )
    
    client, err := qdrant.NewClient(&qdrant.Config{
    	Host: "localhost",
    	Port: 6334,
    })
    
    client.CreateCollection(context.Background(), &qdrant.CreateCollection{
    	CollectionName: "{collection_name}",
    	VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
    		Size:     768,
    		Distance: qdrant.Distance_Cosine,
    		OnDisk:   qdrant.PtrOf(true),
    	}),
    	QuantizationConfig: qdrant.NewQuantizationScalar(&qdrant.ScalarQuantization{
    		Type:      qdrant.QuantizationType_Int8,
    		AlwaysRam: qdrant.PtrOf(true),
    	}),
    })
    

    在这种情况下,磁盘读取次数可能会在搜索速度中发挥重要作用。在磁盘延迟较高的系统中,重评分步骤可能成为瓶颈。

    考虑禁用 rescore 以提高搜索速度

    POST /collections/{collection_name}/points/query
    {
        "query": [0.2, 0.1, 0.9, 0.7],
        "params": {
            "quantization": {
                "rescore": false
            }
        },
        "limit": 10
    }
    
    from qdrant_client import QdrantClient, models
    
    client = QdrantClient(url="https://:6333")
    
    client.query_points(
        collection_name="{collection_name}",
        query=[0.2, 0.1, 0.9, 0.7],
        search_params=models.SearchParams(
            quantization=models.QuantizationSearchParams(rescore=False)
        ),
    )
    
    import { QdrantClient } from "@qdrant/js-client-rest";
    
    const client = new QdrantClient({ host: "localhost", port: 6333 });
    
    client.query("{collection_name}", {
        query: [0.2, 0.1, 0.9, 0.7],
        params: {
            quantization: {
                rescore: false,
            },
        },
    });
    
    use qdrant_client::qdrant::{
        QuantizationSearchParamsBuilder, QueryPointsBuilder, SearchParamsBuilder,
    };
    use qdrant_client::Qdrant;
    
    let client = Qdrant::from_url("https://:6334").build()?;
    
    client
        .query(
            QueryPointsBuilder::new("{collection_name}")
                .query(vec![0.2, 0.1, 0.9, 0.7])
                .limit(3)
                .params(
                    SearchParamsBuilder::default()
                        .quantization(QuantizationSearchParamsBuilder::default().rescore(false)),
                ),
        )
        .await?;
    
    import static io.qdrant.client.QueryFactory.nearest;
    
    import io.qdrant.client.QdrantClient;
    import io.qdrant.client.QdrantGrpcClient;
    import io.qdrant.client.grpc.Points.QuantizationSearchParams;
    import io.qdrant.client.grpc.Points.QueryPoints;
    import io.qdrant.client.grpc.Points.SearchParams;
    
    QdrantClient client =
        new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
    
    client.queryAsync(
            QueryPoints.newBuilder()
                    .setCollectionName("{collection_name}")
                    .setQuery(nearest(0.2f, 0.1f, 0.9f, 0.7f))
                    .setParams(
                            SearchParams.newBuilder()
                                    .setQuantization(
                                            QuantizationSearchParams.newBuilder().setRescore(false).build())
                                    .build())
                    .setLimit(3)
                    .build())
            .get();
    
    using Qdrant.Client;
    using Qdrant.Client.Grpc;
    
    var client = new QdrantClient("localhost", 6334);
    
    await client.QueryAsync(
    	collectionName: "{collection_name}",
    	query: new float[] { 0.2f, 0.1f, 0.9f, 0.7f },
    	searchParams: new SearchParams
    	{
    		Quantization = new QuantizationSearchParams { Rescore = false }
    	},
    	limit: 3
    );
    
    import (
    	"context"
    
    	"github.com/qdrant/go-client/qdrant"
    )
    
    client, err := qdrant.NewClient(&qdrant.Config{
    	Host: "localhost",
    	Port: 6334,
    })
    
    client.Query(context.Background(), &qdrant.QueryPoints{
    	CollectionName: "{collection_name}",
    	Query:          qdrant.NewQuery(0.2, 0.1, 0.9, 0.7),
    	Params: &qdrant.SearchParams{
    		Quantization: &qdrant.QuantizationSearchParams{
    			Rescore: qdrant.PtrOf(false),
    		},
    	},
    })
    

  • 全部在磁盘上 - 所有向量(原始和量化)都存储在磁盘上。此模式可以实现最小的内存占用,但会以搜索速度为代价。

    如果您拥有大型集合和快速存储(例如 SSD 或 NVMe),建议使用此模式。

    此模式通过在使用 mmap 存储时将 always_ram 设置为 false 来启用

    PUT /collections/{collection_name}
    {
        "vectors": {
          "size": 768,
          "distance": "Cosine",
          "on_disk": true
        },
        "quantization_config": {
            "scalar": {
                "type": "int8",
                "always_ram": false
            }
        }
    }
    
    from qdrant_client import QdrantClient, models
    
    client = QdrantClient(url="https://:6333")
    
    client.create_collection(
        collection_name="{collection_name}",
        vectors_config=models.VectorParams(size=768, distance=models.Distance.COSINE, on_disk=True),
        quantization_config=models.ScalarQuantization(
            scalar=models.ScalarQuantizationConfig(
                type=models.ScalarType.INT8,
                always_ram=False,
            ),
        ),
    )
    
    import { QdrantClient } from "@qdrant/js-client-rest";
    
    const client = new QdrantClient({ host: "localhost", port: 6333 });
    
    client.createCollection("{collection_name}", {
      vectors: {
        size: 768,
        distance: "Cosine",
        on_disk: true,
      },
      quantization_config: {
        scalar: {
          type: "int8",
          always_ram: false,
        },
      },
    });
    
    use qdrant_client::qdrant::{
        CreateCollectionBuilder, Distance, QuantizationType, ScalarQuantizationBuilder,
        VectorParamsBuilder,
    };
    use qdrant_client::Qdrant;
    
    let client = Qdrant::from_url("https://:6334").build()?;
    
    client
        .create_collection(
            CreateCollectionBuilder::new("{collection_name}")
                .vectors_config(VectorParamsBuilder::new(768, Distance::Cosine).on_disk(true))
                .quantization_config(
                    ScalarQuantizationBuilder::default()
                        .r#type(QuantizationType::Int8.into())
                        .always_ram(false),
                ),
        )
        .await?;
    
    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.OptimizersConfigDiff;
    import io.qdrant.client.grpc.Collections.QuantizationConfig;
    import io.qdrant.client.grpc.Collections.QuantizationType;
    import io.qdrant.client.grpc.Collections.ScalarQuantization;
    import io.qdrant.client.grpc.Collections.VectorParams;
    import io.qdrant.client.grpc.Collections.VectorsConfig;
    
    QdrantClient client =
        new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
    
    client
        .createCollectionAsync(
            CreateCollection.newBuilder()
                .setCollectionName("{collection_name}")
                .setVectorsConfig(
                    VectorsConfig.newBuilder()
                        .setParams(
                            VectorParams.newBuilder()
                                .setSize(768)
                                .setDistance(Distance.Cosine)
                                .setOnDisk(true)
                                .build())
                        .build())
                .setQuantizationConfig(
                    QuantizationConfig.newBuilder()
                        .setScalar(
                            ScalarQuantization.newBuilder()
                                .setType(QuantizationType.Int8)
                                .setAlwaysRam(false)
                                .build())
                        .build())
                .build())
        .get();
    
    using Qdrant.Client;
    using Qdrant.Client.Grpc;
    
    var client = new QdrantClient("localhost", 6334);
    
    await client.CreateCollectionAsync(
     collectionName: "{collection_name}",
     vectorsConfig: new VectorParams { Size = 768, Distance = Distance.Cosine, OnDisk = true},
     quantizationConfig: new QuantizationConfig
     {
      Scalar = new ScalarQuantization { Type = QuantizationType.Int8, AlwaysRam = false }
     }
    );
    
    import (
    	"context"
    
    	"github.com/qdrant/go-client/qdrant"
    )
    
    client, err := qdrant.NewClient(&qdrant.Config{
    	Host: "localhost",
    	Port: 6334,
    })
    
    client.CreateCollection(context.Background(), &qdrant.CreateCollection{
    	CollectionName: "{collection_name}",
    	VectorsConfig: qdrant.NewVectorsConfig(&qdrant.VectorParams{
    		Size:     768,
    		Distance: qdrant.Distance_Cosine,
    		OnDisk:   qdrant.PtrOf(true),
    	}),
    	QuantizationConfig: qdrant.NewQuantizationScalar(
    		&qdrant.ScalarQuantization{
    			Type:      qdrant.QuantizationType_Int8,
    			AlwaysRam: qdrant.PtrOf(false),
    		},
    	),
    })
    

此页面有用吗?

感谢您的反馈!🙏

很遗憾听到这个。😔 您可以在 GitHub 上编辑此页面,或者创建一个 GitHub Issue。