集合

集合是点的命名集合(带有效载荷的向量),您可以在其中进行搜索。同一集合中每个点的向量必须具有相同的维度,并以单一指标进行比较。命名向量可用于在单个点中包含多个向量,每个向量可以有自己的维度和指标要求。

距离指标用于衡量向量之间的相似性。指标的选择取决于向量的获取方式,特别是神经网络编码器训练的方法。

Qdrant 支持以下最流行的指标类型

  • 点积:Dot - [wiki]
  • 余弦相似度:Cosine - [wiki]
  • 欧几里得距离:Euclid - [wiki]
  • 曼哈顿距离:Manhattan - [wiki]

除了指标和向量大小之外,每个集合都使用自己的一组参数来控制集合优化、索引构建和清理。这些设置可以随时通过相应的请求进行更改。

设置多租户

您应该创建多少个集合?在大多数情况下,您应该只使用一个基于有效载荷分区(payload-based partitioning)的集合。这种方法被称为多租户。它对大多数用户来说是高效的,但需要额外的配置。了解如何设置它

您什么时候应该创建多个集合?当您拥有有限的用户数量并且需要隔离时。这种方法很灵活,但成本可能更高,因为创建大量集合可能会导致资源开销。此外,您需要确保它们不会以任何方式相互影响,包括性能方面。

创建一个集合

PUT /collections/{collection_name}
{
    "vectors": {
      "size": 300,
      "distance": "Cosine"
    }
}
curl -X PUT https://:6333/collections/{collection_name} \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "vectors": {
      "size": 100,
      "distance": "Cosine"
    }
  }'
from qdrant_client import QdrantClient, models

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

client.create_collection(
    collection_name="{collection_name}",
    vectors_config=models.VectorParams(size=100, distance=models.Distance.COSINE),
)
import { QdrantClient } from "@qdrant/js-client-rest";

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

client.createCollection("{collection_name}", {
  vectors: { size: 100, distance: "Cosine" },
});
use qdrant_client::Qdrant;
use qdrant_client::qdrant::{CreateCollectionBuilder, VectorParamsBuilder, Distance};

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

client
    .create_collection(
        CreateCollectionBuilder::new("{collection_name}")
            .vectors_config(VectorParamsBuilder::new(100, Distance::Cosine)),
    )
    .await?;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;

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

client.createCollectionAsync("{collection_name}",
        VectorParams.newBuilder().setDistance(Distance.Cosine).setSize(100).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 = 100, Distance = Distance.Cosine }
);
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:     100,
		Distance: qdrant.Distance_Cosine,
	}),
})

除了必需的选项外,您还可以为以下集合选项指定自定义值

  • hnsw_config - 详情请参阅索引
  • wal_config - 与预写日志(Write-Ahead-Log)相关的配置。有关 WAL 的更多详细信息。
  • optimizers_config - 详情请参阅优化器
  • shard_number - 定义集合应该有多少个分片。详情请参阅分布式部署部分。
  • on_disk_payload - 定义有效载荷数据存储在哪里。如果为 true - 有效载荷将仅存储在磁盘上。对于大量有效载荷的情况,这可能有助于限制 RAM 使用。
  • quantization_config - 详情请参阅量化
  • strict_mode_config - 详情请参阅严格模式

可选集合参数的默认值在配置文件中定义。

有关集合和向量参数的更多信息,请参阅模式定义配置文件

自 v1.2.0 起可用

向量都存储在 RAM 中以便快速访问。on_disk 参数可以在向量配置中设置。如果为 true,所有向量都将存储在磁盘上。这将启用内存映射(memmaps)的使用,这适用于摄取大量数据。

多向量集合

自 v0.10.0 起可用

每个记录可以有多个向量。此功能允许每个集合有多个向量存储。为了区分同一记录中的向量,它们在创建集合时应定义一个唯一的名称。在此模式下,每个命名向量都有其距离和大小。

PUT /collections/{collection_name}
{
    "vectors": {
        "image": {
            "size": 4,
            "distance": "Dot"
        },
        "text": {
            "size": 8,
            "distance": "Cosine"
        }
    }
}
curl -X PUT https://:6333/collections/{collection_name} \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "vectors": {
        "image": {
            "size": 4,
            "distance": "Dot"
        },
        "text": {
            "size": 8,
            "distance": "Cosine"
        }
      }
    }'
from qdrant_client import QdrantClient, models


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

client.create_collection(
    collection_name="{collection_name}",
    vectors_config={
        "image": models.VectorParams(size=4, distance=models.Distance.DOT),
        "text": models.VectorParams(size=8, distance=models.Distance.COSINE),
    },
)
import { QdrantClient } from "@qdrant/js-client-rest";

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

client.createCollection("{collection_name}", {
  vectors: {
    image: { size: 4, distance: "Dot" },
    text: { size: 8, distance: "Cosine" },
  },
});
use qdrant_client::Qdrant;
use qdrant_client::qdrant::{
    CreateCollectionBuilder, Distance, VectorParamsBuilder, VectorsConfigBuilder,
};

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

let mut vectors_config = VectorsConfigBuilder::default();
vectors_config
    .add_named_vector_params("image", VectorParamsBuilder::new(4, Distance::Dot).build());
vectors_config.add_named_vector_params(
    "text",
    VectorParamsBuilder::new(8, Distance::Cosine).build(),
);

client
    .create_collection(
        CreateCollectionBuilder::new("{collection_name}").vectors_config(vectors_config),
    )
    .await?;
import java.util.Map;

import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.VectorParams;

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

client
    .createCollectionAsync(
        "{collection_name}",
        Map.of(
            "image", VectorParams.newBuilder().setSize(4).setDistance(Distance.Dot).build(),
            "text",
                VectorParams.newBuilder().setSize(8).setDistance(Distance.Cosine).build()))
    .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

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

await client.CreateCollectionAsync(
	collectionName: "{collection_name}",
	vectorsConfig: new VectorParamsMap
	{
		Map =
		{
			["image"] = new VectorParams { Size = 4, Distance = Distance.Dot },
			["text"] = new VectorParams { Size = 8, Distance = Distance.Cosine },
		}
	}
);
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.NewVectorsConfigMap(
		map[string]*qdrant.VectorParams{
			"image": {
				Size:     4,
				Distance: qdrant.Distance_Dot,
			},
			"text": {
				Size:     8,
				Distance: qdrant.Distance_Cosine,
			},
		}),
})

对于不常见的用例,可以创建不带任何向量存储的集合。

自 v1.1.1 起可用

对于每个命名向量,您可以选择指定 hnsw_configquantization_config,以偏离集合配置。这对于在向量级别微调搜索性能非常有用。

自 v1.2.0 起可用

向量都存储在 RAM 中以便快速访问。对于每个向量,您可以将 on_disk 设置为 true,以便始终将所有向量存储在磁盘上。这将启用内存映射(memmaps)的使用,这适用于摄取大量数据。

向量数据类型

自 v1.9.0 起可用

一些嵌入提供商可能会提供预量化格式的嵌入。最著名的例子之一是 Cohere int8 和二进制嵌入。Qdrant 直接支持 uint8 嵌入,您也可以将其与二进制量化结合使用。

要创建具有 uint8 嵌入的集合,您可以使用以下配置

PUT /collections/{collection_name}
{
    "vectors": {
      "size": 1024,
      "distance": "Cosine",
      "datatype": "uint8"
    }
}
curl -X PUT https://:6333/collections/{collection_name} \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "vectors": {
      "size": 1024,
      "distance": "Cosine",
      "datatype": "uint8"
    }
  }'
from qdrant_client import QdrantClient, models

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

client.create_collection(
    collection_name="{collection_name}",
    vectors_config=models.VectorParams(
        size=1024,
        distance=models.Distance.COSINE,
        datatype=models.Datatype.UINT8,
    ),
)
import { QdrantClient } from "@qdrant/js-client-rest";

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

client.createCollection("{collection_name}", {
  vectors: {
    image: { size: 1024, distance: "Cosine", datatype: "uint8" },
  },
});
use qdrant_client::Qdrant;
use qdrant_client::qdrant::{
    CreateCollectionBuilder, Datatype, Distance, VectorParamsBuilder,
};

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

client
    .create_collection(
        CreateCollectionBuilder::new("{collection_name}").vectors_config(
            VectorParamsBuilder::new(1024, Distance::Cosine).datatype(Datatype::Uint8),
        ),
    )
    .await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.grpc.Collections.Datatype;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.VectorParams;

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

client
    .createCollectionAsync("{collection_name}",
        VectorParams.newBuilder()
            .setSize(1024)
            .setDistance(Distance.Cosine)
            .setDatatype(Datatype.Uint8)
            .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 = 1024, Distance = Distance.Cosine, Datatype = Datatype.Uint8
  }
);
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:     1024,
		Distance: qdrant.Distance_Cosine,
		Datatype: qdrant.Datatype_Uint8.Enum(),
	}),
})

具有 uint8 数据类型的向量以更紧凑的格式存储,这可以节省内存并提高搜索速度,但会牺牲一些精度。如果您选择使用 uint8 数据类型,向量的元素将存储为无符号 8 位整数,其取值范围为 0 到 255

稀疏向量集合

自 v1.7.0 起可用

Qdrant 将稀疏向量作为一等公民支持。

稀疏向量对于文本搜索很有用,其中每个单词都表示为一个单独的维度。

集合可以包含稀疏向量作为附加的命名向量,与单个点中的常规稠密向量并存。

与稠密向量不同,稀疏向量必须命名。此外,稀疏向量和稠密向量在集合中必须具有不同的名称。

PUT /collections/{collection_name}
{
    "sparse_vectors": {
        "text": { }
    }
}
curl -X PUT https://:6333/collections/{collection_name} \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "sparse_vectors": {
        "text": { }
    }
  }'
from qdrant_client import QdrantClient, models

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

client.create_collection(
    collection_name="{collection_name}",
    vectors_config={},
    sparse_vectors_config={
        "text": models.SparseVectorParams(),
    },
)
import { QdrantClient } from "@qdrant/js-client-rest";

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

client.createCollection("{collection_name}", {
  sparse_vectors: {
    text: { },
  },
});
use qdrant_client::Qdrant;
use qdrant_client::qdrant::{
    CreateCollectionBuilder, SparseVectorParamsBuilder, SparseVectorsConfigBuilder,
};

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

let mut sparse_vector_config = SparseVectorsConfigBuilder::default();

sparse_vector_config.add_named_vector_params("text", SparseVectorParamsBuilder::default());

client
    .create_collection(
        CreateCollectionBuilder::new("{collection_name}")
            .sparse_vectors_config(sparse_vector_config),
    )
    .await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Collections.CreateCollection;
import io.qdrant.client.grpc.Collections.SparseVectorConfig;
import io.qdrant.client.grpc.Collections.SparseVectorParams;

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

client
    .createCollectionAsync(
        CreateCollection.newBuilder()
            .setCollectionName("{collection_name}")
            .setSparseVectorsConfig(
                SparseVectorConfig.newBuilder()
                    .putMap("text", SparseVectorParams.getDefaultInstance()))
            .build())
    .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

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

await client.CreateCollectionAsync(
	collectionName: "{collection_name}",
	sparseVectorsConfig: ("text", new SparseVectorParams())
);
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}",
	SparseVectorsConfig: qdrant.NewSparseVectorsConfig(
		map[string]*qdrant.SparseVectorParams{
			"text": {},
		}),
})

除了唯一的名称外,稀疏向量没有必需的配置参数。

稀疏向量的距离函数始终为 Dot,无需指定。

但是,有一些可选参数可以调整底层稀疏向量索引

从另一个集合创建集合

要从另一个集合创建集合,请使用 迁移工具。您可以使用它在同一 Qdrant 实例中复制集合,或将集合复制到另一个实例。

例如,要将集合从本地实例复制到 Qdrant 云实例,请运行以下命令

docker run --net=host --rm -it registry.cloud.qdrant.io/library/qdrant-migration qdrant \
    --source.url 'https://:6334' \
    --source.collection 'source-collection' \
    --target.url 'https://example.cloud-region.cloud-provider.cloud.qdrant.io:6334' \
    --target.api-key 'qdrant-key' \
    --target.collection 'target-collection' \
    --migration.batch-size 64

检查集合是否存在

自 v1.8.0 起可用

GET https://:6333/collections/{collection_name}/exists
curl -X GET https://:6333/collections/{collection_name}/exists
client.collection_exists(collection_name="{collection_name}")
client.collectionExists("{collection_name}");
client.collection_exists("{collection_name}").await?;
client.collectionExistsAsync("{collection_name}").get();
await client.CollectionExistsAsync("{collection_name}");
import "context"

client.CollectionExists(context.Background(), "my_collection")

删除集合

DELETE https://:6333/collections/{collection_name}
curl -X DELETE https://:6333/collections/{collection_name}
client.delete_collection(collection_name="{collection_name}")
client.deleteCollection("{collection_name}");
client.delete_collection("{collection_name}").await?;
client.deleteCollectionAsync("{collection_name}").get();
await client.DeleteCollectionAsync("{collection_name}");
import "context"

client.DeleteCollection(context.Background(), "{collection_name}")

更新集合参数

动态参数更新可能很有帮助,例如,可以更有效地初始加载向量。例如,您可以在上传过程中禁用索引,并在上传完成后立即启用它。这样,您就不会浪费额外的计算资源来重建索引。

以下命令为存储向量超过 10000 kB 的分段启用索引

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

client
    .update_collection(
        UpdateCollectionBuilder::new("{collection_name}").optimizers_config(
            OptimizersConfigDiffBuilder::default().indexing_threshold(10000),
        ),
    )
    .await?;
import io.qdrant.client.grpc.Collections.OptimizersConfigDiff;
import io.qdrant.client.grpc.Collections.UpdateCollection;

client
    .updateCollectionAsync(
        UpdateCollection.newBuilder()
            .setCollectionName("{collection_name}")
            .setOptimizersConfig(
                OptimizersConfigDiff.newBuilder().setIndexingThreshold(10000).build())
            .build())
    .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

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

await client.UpdateCollectionAsync(
	collectionName: "{collection_name}",
	optimizersConfig: new OptimizersConfigDiff { IndexingThreshold = 10000 }
);
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}",
	OptimizersConfig: &qdrant.OptimizersConfigDiff{
		IndexingThreshold: qdrant.PtrOf(uint64(10000)),
	},
})

可以更新以下参数

  • optimizers_config - 详情请参阅优化器
  • hnsw_config - 详情请参阅索引
  • quantization_config - 详情请参阅量化
  • vectors_config - 向量特定配置,包括单独的 hnsw_configquantization_configon_disk 设置。
  • params - 其他集合参数,包括 write_consistency_factoron_disk_payload
  • strict_mode_config - 详情请参阅严格模式

完整的 API 规范可在模式定义中找到。

对此端点的调用可能会阻塞,因为它会等待现有优化器完成。我们不建议在生产数据库中使用此功能,因为它可能会由于索引重建而引入巨大的开销。

更新向量参数

自 v1.4.0 起可用

Qdrant 1.4 添加了在运行时更新更多集合参数的支持。HNSW 索引、量化和磁盘配置现在可以在不重新创建集合的情况下进行更改。分段(带有索引和量化数据)将在后台自动重建以匹配更新的参数。

要将向量数据存入磁盘,对于没有命名向量的集合,请使用 "" 作为名称

PATCH /collections/{collection_name}
{
    "vectors": {
        "": {
            "on_disk": true
        }
    }
}
curl -X PATCH https://:6333/collections/{collection_name} \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "vectors": {
        "": { 
            "on_disk": true 
      }
    }
  }'

要将向量数据存入磁盘,对于命名向量的集合

注意:要创建向量名称,请遵循我们中的程序。

PATCH /collections/{collection_name}
{
    "vectors": {
        "my_vector": {
            "on_disk": true
        }
    }
}
curl -X PATCH https://:6333/collections/{collection_name} \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "vectors": {
        "my_vector": { 
           "on_disk": true 
      }
    }
  }'

在以下示例中,HNSW 索引和量化参数均已更新,包括整个集合和特定于 my_vector 的参数。

PATCH /collections/{collection_name}
{
    "vectors": {
        "my_vector": {
            "hnsw_config": {
                "m": 32,
                "ef_construct": 123
            },
            "quantization_config": {
                "product": {
                    "compression": "x32",
                    "always_ram": true
                }
            },
            "on_disk": true
        }
    },
    "hnsw_config": {
        "ef_construct": 123
    },
    "quantization_config": {
        "scalar": {
            "type": "int8",
            "quantile": 0.8,
            "always_ram": false
        }
    }
}
curl -X PATCH https://:6333/collections/{collection_name} \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "vectors": {
        "my_vector": {
            "hnsw_config": {
                "m": 32,
                "ef_construct": 123
            },
            "quantization_config": {
                "product": {
                    "compression": "x32",
                    "always_ram": true
                }
            },
            "on_disk": true
        }
    },
    "hnsw_config": {
        "ef_construct": 123
    },
    "quantization_config": {
        "scalar": {
            "type": "int8",
            "quantile": 0.8,
            "always_ram": false
        }
    }
}'
client.update_collection(
    collection_name="{collection_name}",
    vectors_config={
        "my_vector": models.VectorParamsDiff(
            hnsw_config=models.HnswConfigDiff(
                m=32,
                ef_construct=123,
            ),
            quantization_config=models.ProductQuantization(
                product=models.ProductQuantizationConfig(
                    compression=models.CompressionRatio.X32,
                    always_ram=True,
                ),
            ),
            on_disk=True,
        ),
    },
    hnsw_config=models.HnswConfigDiff(
        ef_construct=123,
    ),
    quantization_config=models.ScalarQuantization(
        scalar=models.ScalarQuantizationConfig(
            type=models.ScalarType.INT8,
            quantile=0.8,
            always_ram=False,
        ),
    ),
)
client.updateCollection("{collection_name}", {
  vectors: {
    my_vector: {
      hnsw_config: {
        m: 32,
        ef_construct: 123,
      },
      quantization_config: {
        product: {
          compression: "x32",
          always_ram: true,
        },
      },
      on_disk: true,
    },
  },
  hnsw_config: {
    ef_construct: 123,
  },
  quantization_config: {
    scalar: {
      type: "int8",
      quantile: 0.8,
      always_ram: true,
    },
  },
});
use std::collections::HashMap;

use qdrant_client::qdrant::{
    quantization_config_diff::Quantization, vectors_config_diff::Config, HnswConfigDiffBuilder,
    QuantizationType, ScalarQuantizationBuilder, UpdateCollectionBuilder, VectorParamsDiffBuilder,
    VectorParamsDiffMap,
};

client
    .update_collection(
        UpdateCollectionBuilder::new("{collection_name}")
            .hnsw_config(HnswConfigDiffBuilder::default().ef_construct(123))
            .vectors_config(Config::ParamsMap(VectorParamsDiffMap {
                map: HashMap::from([(
                    ("my_vector".into()),
                    VectorParamsDiffBuilder::default()
                        .hnsw_config(HnswConfigDiffBuilder::default().m(32).ef_construct(123))
                        .build(),
                )]),
            }))
            .quantization_config(Quantization::Scalar(
                ScalarQuantizationBuilder::default()
                    .r#type(QuantizationType::Int8.into())
                    .quantile(0.8)
                    .always_ram(true)
                    .build(),
            )),
    )
    .await?;
import io.qdrant.client.grpc.Collections.HnswConfigDiff;
import io.qdrant.client.grpc.Collections.QuantizationConfigDiff;
import io.qdrant.client.grpc.Collections.QuantizationType;
import io.qdrant.client.grpc.Collections.ScalarQuantization;
import io.qdrant.client.grpc.Collections.UpdateCollection;
import io.qdrant.client.grpc.Collections.VectorParamsDiff;
import io.qdrant.client.grpc.Collections.VectorParamsDiffMap;
import io.qdrant.client.grpc.Collections.VectorsConfigDiff;

client
    .updateCollectionAsync(
        UpdateCollection.newBuilder()
            .setCollectionName("{collection_name}")
            .setHnswConfig(HnswConfigDiff.newBuilder().setEfConstruct(123).build())
            .setVectorsConfig(
                VectorsConfigDiff.newBuilder()
                    .setParamsMap(
                        VectorParamsDiffMap.newBuilder()
                            .putMap(
                                "my_vector",
                                VectorParamsDiff.newBuilder()
                                    .setHnswConfig(
                                        HnswConfigDiff.newBuilder()
                                            .setM(3)
                                            .setEfConstruct(123)
                                            .build())
                                    .build())))
            .setQuantizationConfig(
                QuantizationConfigDiff.newBuilder()
                    .setScalar(
                        ScalarQuantization.newBuilder()
                            .setType(QuantizationType.Int8)
                            .setQuantile(0.8f)
                            .setAlwaysRam(true)
                            .build()))
            .build())
    .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

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

await client.UpdateCollectionAsync(
	collectionName: "{collection_name}",
	hnswConfig: new HnswConfigDiff { EfConstruct = 123 },
	vectorsConfig: new VectorParamsDiffMap
	{
		Map =
		{
			{
				"my_vector",
				new VectorParamsDiff
				{
					HnswConfig = new HnswConfigDiff { M = 3, EfConstruct = 123 }
				}
			}
		}
	},
	quantizationConfig: new QuantizationConfigDiff
	{
		Scalar = new ScalarQuantization
		{
			Type = QuantizationType.Int8,
			Quantile = 0.8f,
			AlwaysRam = true
		}
	}
);
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}",
	VectorsConfig: qdrant.NewVectorsConfigDiffMap(
		map[string]*qdrant.VectorParamsDiff{
			"my_vector": {
				HnswConfig: &qdrant.HnswConfigDiff{
					M:           qdrant.PtrOf(uint64(3)),
					EfConstruct: qdrant.PtrOf(uint64(123)),
				},
			},
		}),
	QuantizationConfig: qdrant.NewQuantizationDiffScalar(
		&qdrant.ScalarQuantization{
			Type:      qdrant.QuantizationType_Int8,
			Quantile:  qdrant.PtrOf(float32(0.8)),
			AlwaysRam: qdrant.PtrOf(true),
		}),
})

集合信息

Qdrant 允许确定现有集合的配置参数,以便更好地了解点的分布和索引方式。

GET /collections/{collection_name}
curl -X GET https://:6333/collections/{collection_name}
client.get_collection(collection_name="{collection_name}")
client.getCollection("{collection_name}");
client.collection_info("{collection_name}").await?;
client.getCollectionInfoAsync("{collection_name}").get();
await client.GetCollectionInfoAsync("{collection_name}");
import "context"

client.GetCollectionInfo(context.Background(), "{collection_name}")
预期结果
{
    "result": {
        "status": "green",
        "optimizer_status": "ok",
        "indexed_vectors_count": 1024232,
        "points_count": 1068786,
        "segments_count": 31,
        "config": {
            "params": {
                "vectors": {
                    "size": 384,
                    "distance": "Cosine"
                },
                "shard_number": 1,
                "replication_factor": 1,
                "write_consistency_factor": 1,
                "on_disk_payload": false
            },
            "hnsw_config": {
                "m": 16,
                "ef_construct": 100,
                "full_scan_threshold": 10000,
                "max_indexing_threads": 0
            },
            "optimizer_config": {
                "deleted_threshold": 0.2,
                "vacuum_min_vector_number": 1000,
                "default_segment_number": 0,
                "max_segment_size": null,
                "memmap_threshold": null,
                "indexing_threshold": 20000,
                "flush_interval_sec": 5,
                "max_optimization_threads": 1
            },
            "wal_config": {
                "wal_capacity_mb": 32,
                "wal_segments_ahead": 0
            }
        },
        "payload_schema": {}
    },
    "status": "ok",
    "time": 0.00010143
}

如果您将向量插入集合中,status 字段在优化期间可能会变为 yellow。一旦所有点都成功处理,它将变为 green

可能的状态颜色如下

  • 🟢 green: 集合就绪
  • 🟡 yellow: 集合正在优化
  • grey: 集合待优化 (帮助)
  • 🔴 red: 发生引擎无法恢复的错误

灰色集合状态

自 v1.9.0 起可用

集合可能显示灰色 ⚫ 状态或优化状态为“优化待定,等待更新操作”。这种情况通常是由于 Qdrant 实例在优化进行时重新启动造成的。

这意味着集合有待进行的优化,但它们已暂停。您必须发送任何更新操作才能再次触发并启动优化。

例如

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

client
    .update_collection(
        UpdateCollectionBuilder::new("{collection_name}")
            .optimizers_config(OptimizersConfigDiffBuilder::default()),
    )
    .await?;
import io.qdrant.client.grpc.Collections.OptimizersConfigDiff;
import io.qdrant.client.grpc.Collections.UpdateCollection;

client.updateCollectionAsync(
    UpdateCollection.newBuilder()
        .setCollectionName("{collection_name}")
        .setOptimizersConfig(
            OptimizersConfigDiff.getDefaultInstance())
        .build());
using Qdrant.Client;
using Qdrant.Client.Grpc;

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

await client.UpdateCollectionAsync(
	collectionName: "{collection_name}",
	optimizersConfig: new OptimizersConfigDiff { }
);
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}",
	OptimizersConfig: &qdrant.OptimizersConfigDiff{},
})

或者,您可以使用 Qdrant Web UI 中的 Trigger Optimizers 按钮。它显示在集合信息页面上灰色集合状态旁边。

近似点和向量计数

您可能对计数属性感兴趣

  • points_count - 集合中存储的对象(向量及其有效载荷)的总数
  • indexed_vectors_count - 存储在 HNSW 或稀疏索引中的向量总数。Qdrant 不会将所有向量存储在索引中,仅当给定配置可能创建索引段时才存储。

以上计数不精确,应视为近似值。根据您使用 Qdrant 的方式,这些计数可能与您预期的数字大相径庭。因此,不要依赖它们很重要。

更具体地说,这些数字表示 Qdrant 内部存储中点和向量的计数。在内部,Qdrant 可能会作为自动优化的一部分暂时复制点。它可能会保留已更改或已删除的点一段时间。它还可能会延迟新点的索引。所有这些都是出于优化原因。

因此,您所做的更新不会直接反映在这些数字中。如果您看到点数大相径庭,一旦新一轮自动优化完成,它很可能会自行解决。

澄清一下:这些数字不代表您插入的精确点数或向量数,也不代表您可以查询的可区分点数或向量的精确数量。如果您想知道精确计数,请参阅计数 API

注意:这些数字可能会在 Qdrant 的未来版本中删除。

在 HNSW 中索引向量

在某些情况下,您可能会惊讶于 indexed_vectors_count 的值低于您的预期。这是一个预期行为,取决于优化器配置。如果未索引向量的大小高于 indexing_threshold(以 kB 为单位)的值,则会构建新的索引段。如果您的集合非常小或向量的维度较低,则可能不会创建 HNSW 段,并且 indexed_vectors_count 可能等于 0

可以通过更新集合参数来减少现有集合的 indexing_threshold

集合元数据

自 v1.16.0 起可用

为了方便和更好的数据组织,Qdrant 允许以键值对的形式将自定义元数据附加到集合中。添加元数据被视为集合配置的一部分,并使用共识协议在集群中的所有节点之间同步。

集合元数据可以在集合创建期间指定

PUT /collections/{collection_name}
{
    "vectors": {
      "size": 300,
      "distance": "Cosine"
    },
    "metadata": {
      "my-metadata-field": "value-1",
      "another-field": 123
    }
}
curl -X PUT https://:6333/collections/{collection_name} \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "vectors": {
      "size": 300,
      "distance": "Cosine"
    },
    "metadata": {
      "my-metadata-field": "value-1",
      "another-field": 123
    }
  }'
from qdrant_client import QdrantClient, models

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

client.create_collection(
    collection_name="{collection_name}",
    metadata={
        "my-metadata-field": "value-1",
        "another-field": 123
    },
)
import { QdrantClient } from "@qdrant/js-client-rest";

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

client.createCollection("{collection_name}", {
  vectors: { size: 100, distance: "Cosine" },
  metadata: {
    "my-metadata-field": "value-1",
    "another-field": 123
  }
});
use qdrant_client::qdrant::{CreateCollectionBuilder, Distance, VectorParamsBuilder};
use qdrant_client::Qdrant;
use serde_json::{json, Value};
use std::collections::HashMap;

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


let mut metadata: HashMap<String, Value> = HashMap::new();
metadata.insert("my-metadata-field".to_string(), json!("value-1"));
metadata.insert("another-field".to_string(), json!(123));


client
    .create_collection(
        CreateCollectionBuilder::new("{collection_name}")
            .vectors_config(VectorParamsBuilder::new(100, Distance::Cosine))
            .metadata(metadata),
    )
    .await?;
import java.util.Map;

import static io.qdrant.client.ValueFactory.value;

import io.qdrant.client.grpc.Collections.CreateCollection;
import io.qdrant.client.grpc.Collections.Distance;
import io.qdrant.client.grpc.Collections.VectorParams;
import io.qdrant.client.grpc.Collections.VectorsConfig;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;

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

client
    .createCollectionAsync(
        CreateCollection.newBuilder()
            .setCollectionName("{collection_name}")
            .setVectorsConfig(
                VectorsConfig.newBuilder()
                    .setParams(
                        VectorParams.newBuilder()
                            .setDistance(Distance.Cosine)
                            .setSize(100)
                            .build())
                    .build())
            .putAllMetadata(
                Map.of(
                    "my-metadata-field", value("value-1"),
                    "another-field", value(123)))
            .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 = 100, Distance = Distance.Cosine },
	metadata: new()
	{
		["my-metadata-field"] = "value-1",
		["another-field"] = 123
	}
);
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:     100,
		Distance: qdrant.Distance_Cosine,
	}),
	Metadata: qdrant.NewValueMap(map[string]any{
		"my-metadata-field": "value-1",
		"another-field":     123,
	}),
})

也可以稍后更新

PATCH /collections/{collection_name}
{
    "metadata": {
        "my-metadata-field": {
            "key-a": "value-a",
            "key-b": 42
        }
    }
}
curl -X PATCH https://:6333/collections/{collection_name} \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "metadata": {
      "my-metadata-field": {
        "key-a": "value-a",
        "key-b": 42    
      }
    }
  }'
client.update_collection(
    collection_name="{collection_name}",
    metadata={
        "my-metadata-field": {
            "key-a": "value-a",
            "key-b": 42
        }
    },
)
client.updateCollection("{collection_name}", {
  metadata: {
    "my-metadata-field": {
      "key-a": "value-a",
      "key-b": 42
    }
  },
});
use qdrant_client::qdrant::{UpdateCollectionBuilder};
use qdrant_client::Qdrant;
use serde_json::{json, Value};
use std::collections::HashMap;

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

let mut metadata: HashMap<String, Value> = HashMap::new();
metadata.insert("my-metadata-field".to_string(), json!({
    "key-a": "value-a",
    "key-b": 42
}));

client
    .update_collection(
        UpdateCollectionBuilder::new("{collection_name}").metadata(metadata),
    )
    .await?;
import java.util.Map;

import static io.qdrant.client.ValueFactory.value;

import io.qdrant.client.grpc.Collections.OptimizersConfigDiff;
import io.qdrant.client.grpc.Collections.UpdateCollection;

client
    .updateCollectionAsync(
        UpdateCollection.newBuilder()
            .setCollectionName("{collection_name}")
            .setOptimizersConfig(
                OptimizersConfigDiff.newBuilder().setIndexingThreshold(10000).build())
            .putAllMetadata(
                Map.of(
                    "my-metadata-field",
                    value(
                        Map.of(
                            "key-a", value("value-a"),
                            "key-b", value(42)))))
            .build())
    .get();
using Qdrant.Client;
using Qdrant.Client.Grpc;

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

await client.UpdateCollectionAsync(
	collectionName: "{collection_name}",
	optimizersConfig: new OptimizersConfigDiff { IndexingThreshold = 10000 },
	metadata: new()
	{
		["my-metadata-field"] = new Dictionary<string, Value>
		{
			["key-a"] = "value-a",
			["key-b"] = 42
		},
	}
);
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}",
	OptimizersConfig: &qdrant.OptimizersConfigDiff{
		IndexingThreshold: qdrant.PtrOf(uint64(10000)),
	},
	Metadata: qdrant.NewValueMap(map[string]any{
		"my-metadata-field": map[string]any{
			"key-a": "value-a",
			"key-b": 42,
		},
	}),
})

请注意,更新操作只修改指定的元数据字段,而其他字段保持不变。

指定后,元数据将作为集合信息的一部分返回

{
    "result": {
        "config": {
            "metadata": {
                "my-metadata-field": {
                    "key-a": "value-a",
                    "key-b": 42
                },
                "another-field": 123
            }
        }
    }
}

集合别名

在生产环境中,有时需要无缝切换不同版本的向量。例如,当升级到新版本的神经网络时。

在这些情况下,无法停止服务并用新向量重建集合。别名是现有集合的附加名称。对集合的所有查询也可以通过使用别名而不是集合名称来完成。

因此,可以在后台构建第二个集合,然后将别名从旧集合切换到新集合。由于所有别名更改都是原子发生的,因此在切换期间不会影响任何并发请求。

创建别名

POST /collections/aliases
{
    "actions": [
        {
            "create_alias": {
                "collection_name": "example_collection",
                "alias_name": "production_collection"
            }
        }
    ]
}
curl -X POST https://:6333/collections/aliases \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "actions": [
        {
            "create_alias": {
                "collection_name": "example_collection",
                "alias_name": "production_collection"
            }
        }
    ]
}'
client.update_collection_aliases(
    change_aliases_operations=[
        models.CreateAliasOperation(
            create_alias=models.CreateAlias(
                collection_name="example_collection", alias_name="production_collection"
            )
        )
    ]
)
client.updateCollectionAliases({
  actions: [
    {
      create_alias: {
        collection_name: "example_collection",
        alias_name: "production_collection",
      },
    },
  ],
});
use qdrant_client::qdrant::CreateAliasBuilder;

client
    .create_alias(CreateAliasBuilder::new(
        "example_collection",
        "production_collection",
    ))
    .await?;
client.createAliasAsync("production_collection", "example_collection").get();
await client.CreateAliasAsync(aliasName: "production_collection", collectionName: "example_collection");
import "context"

client.CreateAlias(context.Background(), "production_collection", "example_collection")

删除别名

POST /collections/aliases
{
    "actions": [
        {
            "delete_alias": {
                "alias_name": "production_collection"
            }
        }
    ]
}
curl -X POST https://:6333/collections/aliases \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "actions": [
        {
            "delete_alias": {
                "alias_name": "production_collection"
            }
        }
    ]
}'
client.update_collection_aliases(
    change_aliases_operations=[
        models.DeleteAliasOperation(
            delete_alias=models.DeleteAlias(alias_name="production_collection")
        ),
    ]
)
client.updateCollectionAliases({
  actions: [
    {
      delete_alias: {
        alias_name: "production_collection",
      },
    },
  ],
});
client.delete_alias("production_collection").await?;
client.deleteAliasAsync("production_collection").get();
await client.DeleteAliasAsync("production_collection");
import "context"

client.DeleteAlias(context.Background(), "production_collection")

切换集合

多个别名操作是原子执行的。例如,您可以使用以下命令切换底层集合

POST /collections/aliases
{
    "actions": [
        {
            "delete_alias": {
                "alias_name": "production_collection"
            }
        },
        {
            "create_alias": {
                "collection_name": "example_collection",
                "alias_name": "production_collection"
            }
        }
    ]
}
curl -X POST https://:6333/collections/aliases \
  -H 'Content-Type: application/json' \
  --data-raw '{
    "actions": [
        {
            "delete_alias": {
                "alias_name": "production_collection"
            }
        },
        {
            "create_alias": {
                "collection_name": "example_collection",
                "alias_name": "production_collection"
            }
        }
    ]
}'
client.update_collection_aliases(
    change_aliases_operations=[
        models.DeleteAliasOperation(
            delete_alias=models.DeleteAlias(alias_name="production_collection")
        ),
        models.CreateAliasOperation(
            create_alias=models.CreateAlias(
                collection_name="example_collection", alias_name="production_collection"
            )
        ),
    ]
)
client.updateCollectionAliases({
  actions: [
    {
      delete_alias: {
        alias_name: "production_collection",
      },
    },
    {
      create_alias: {
        collection_name: "example_collection",
        alias_name: "production_collection",
      },
    },
  ],
});
use qdrant_client::qdrant::CreateAliasBuilder;

client.delete_alias("production_collection").await?;
client
    .create_alias(CreateAliasBuilder::new(
        "example_collection",
        "production_collection",
    ))
    .await?;
client.deleteAliasAsync("production_collection").get();
client.createAliasAsync("production_collection", "example_collection").get();
await client.DeleteAliasAsync("production_collection");
await client.CreateAliasAsync(aliasName: "production_collection", collectionName: "example_collection");
import "context"

client.DeleteAlias(context.Background(), "production_collection")
client.CreateAlias(context.Background(), "production_collection", "example_collection")

列出集合别名

GET /collections/{collection_name}/aliases
curl -X GET https://:6333/collections/{collection_name}/aliases
from qdrant_client import QdrantClient

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

client.get_collection_aliases(collection_name="{collection_name}")
import { QdrantClient } from "@qdrant/js-client-rest";

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

client.getCollectionAliases("{collection_name}");
use qdrant_client::Qdrant;

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

client.list_collection_aliases("{collection_name}").await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;

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

client.listCollectionAliasesAsync("{collection_name}").get();
using Qdrant.Client;

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

await client.ListCollectionAliasesAsync("{collection_name}");
import (
	"context"

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

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

client.ListCollectionAliases(context.Background(), "{collection_name}")

列出所有别名

GET /aliases
curl -X GET https://:6333/aliases
from qdrant_client import QdrantClient

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

client.get_aliases()
import { QdrantClient } from "@qdrant/js-client-rest";

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

client.getAliases();
use qdrant_client::Qdrant;

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

client.list_aliases().await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;

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

client.listAliasesAsync().get();
using Qdrant.Client;

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

await client.ListAliasesAsync();
import (
	"context"

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

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

client.ListAliases(context.Background())

列出所有集合

GET /collections
curl -X GET https://:6333/collections
from qdrant_client import QdrantClient

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

client.get_collections()
import { QdrantClient } from "@qdrant/js-client-rest";

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

client.getCollections();
use qdrant_client::Qdrant;

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

client.list_collections().await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;

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

client.listCollectionsAsync().get();
using Qdrant.Client;

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

await client.ListCollectionsAsync();
import (
	"context"

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

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

client.ListCollections(context.Background())
此页面有用吗?

感谢您的反馈!🙏

很抱歉听到这个消息。😔 您可以在 GitHub 上编辑此页面,或者创建一个 GitHub 问题。