Payload
Qdrant 的一项重要特性是能够与向量一起存储附加信息。在 Qdrant 术语中,此信息称为 payload
。
Qdrant 允许您存储任何可以使用 JSON 表示的信息。
这是一个典型 Payload 的示例
{
"name": "jacket",
"colors": ["red", "blue"],
"count": 10,
"price": 11.99,
"locations": [
{
"lon": 52.5200,
"lat": 13.4050
}
],
"reviews": [
{
"user": "alice",
"score": 4
},
{
"user": "bob",
"score": 5
}
]
}
Payload 类型
除了存储 Payload 外,Qdrant 还允许您基于特定类型的值进行搜索。此功能作为搜索期间的附加过滤器实现,使您能够在语义相似性之上加入自定义逻辑。
在过滤过程中,Qdrant 将检查与过滤条件类型匹配的值是否满足条件。如果存储的值类型不符合过滤条件,则认为不满足条件。
例如,如果您对字符串数据应用范围条件,您将获得一个空输出。
但是,数组(同类型的多个值)的处理方式略有不同。当我们对数组应用过滤器时,如果数组中至少有一个值满足条件,则过滤成功。
过滤过程在过滤章节中详细讨论。
让我们看看 Qdrant 支持用于搜索的数据类型
整数
integer
- 64 位整数,范围从 -9223372036854775808
到 9223372036854775807
。
单个和多个 integer
值的示例
{
"count": 10,
"sizes": [35, 36, 38]
}
浮点数
float
- 64 位浮点数。
单个和多个 float
值的示例
{
"price": 11.99,
"ratings": [9.1, 9.2, 9.4]
}
布尔值
Bool - 二进制值。等于 true
或 false
。
单个和多个 bool
值的示例
{
"is_delivered": true,
"responses": [false, false, true, false]
}
关键字
keyword
- 字符串值。
单个和多个 keyword
值的示例
{
"name": "Alice",
"friends": [
"bob",
"eva",
"jack"
]
}
地理位置
geo
用于表示地理坐标。
单个和多个 geo
值的示例
{
"location": {
"lon": 52.5200,
"lat": 13.4050
},
"cities": [
{
"lon": 51.5072,
"lat": 0.1276
},
{
"lon": 40.7128,
"lat": 74.0060
}
]
}
坐标应描述为一个包含两个字段的对象:lon
用于经度,lat
用于纬度。
日期时间
从 v1.8.0 版本开始可用
datetime
- RFC 3339 格式的日期和时间。
请看以下单个和多个 datetime
值的示例
{
"created_at": "2023-02-08T10:49:00Z",
"updated_at": [
"2023-02-08T13:52:00Z",
"2023-02-21T21:23:00Z"
]
}
支持以下格式
"2023-02-08T10:49:00Z"
(RFC 3339,UTC)"2023-02-08T11:49:00+01:00"
(RFC 3339,带时区)"2023-02-08T10:49:00"
(不带时区,假定为 UTC)"2023-02-08T10:49"
(不带时区和秒)"2023-02-08"
(仅日期,假定为午夜)
关于格式的注意事项
T
可以用空格代替。T
和Z
符号不区分大小写。- 未指定时区时,始终假定为 UTC。
- 时区可以采用以下格式:
±HH:MM
、±HHMM
、±HH
或Z
。 - 秒最多可以有 6 位小数,因此
datetime
的最精细粒度为微秒。
UUID
从 v1.11.0 版本开始可用
除了基本的 keyword
类型外,Qdrant 还支持 uuid
类型来存储 UUID 值。功能上,它的工作方式与 keyword
相同,内部存储解析后的 UUID 值。
{
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"uuids": [
"550e8400-e29b-41d4-a716-446655440000",
"550e8400-e29b-41d4-a716-446655440001"
]
}
UUID 的字符串表示(例如 550e8400-e29b-41d4-a716-446655440000
)占用 36 字节。但当使用数字表示时,只有 128 位(16 字节)。
建议在 Payload 较大的集合中使用 uuid
索引类型,以节省 RAM 并提高搜索性能。
创建带有 Payload 的点
REST API (模式)
PUT /collections/{collection_name}/points
{
"points": [
{
"id": 1,
"vector": [0.05, 0.61, 0.76, 0.74],
"payload": {"city": "Berlin", "price": 1.99}
},
{
"id": 2,
"vector": [0.19, 0.81, 0.75, 0.11],
"payload": {"city": ["Berlin", "London"], "price": 1.99}
},
{
"id": 3,
"vector": [0.36, 0.55, 0.47, 0.94],
"payload": {"city": ["Berlin", "Moscow"], "price": [1.99, 2.99]}
}
]
}
from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.upsert(
collection_name="{collection_name}",
points=[
models.PointStruct(
id=1,
vector=[0.05, 0.61, 0.76, 0.74],
payload={
"city": "Berlin",
"price": 1.99,
},
),
models.PointStruct(
id=2,
vector=[0.19, 0.81, 0.75, 0.11],
payload={
"city": ["Berlin", "London"],
"price": 1.99,
},
),
models.PointStruct(
id=3,
vector=[0.36, 0.55, 0.47, 0.94],
payload={
"city": ["Berlin", "Moscow"],
"price": [1.99, 2.99],
},
),
],
)
import { QdrantClient } from "@qdrant/js-client-rest";
const client = new QdrantClient({ host: "localhost", port: 6333 });
client.upsert("{collection_name}", {
points: [
{
id: 1,
vector: [0.05, 0.61, 0.76, 0.74],
payload: {
city: "Berlin",
price: 1.99,
},
},
{
id: 2,
vector: [0.19, 0.81, 0.75, 0.11],
payload: {
city: ["Berlin", "London"],
price: 1.99,
},
},
{
id: 3,
vector: [0.36, 0.55, 0.47, 0.94],
payload: {
city: ["Berlin", "Moscow"],
price: [1.99, 2.99],
},
},
],
});
use qdrant_client::qdrant::{PointStruct, UpsertPointsBuilder};
use qdrant_client::{Payload, Qdrant, QdrantError};
use serde_json::json;
let client = Qdrant::from_url("http://localhost:6334").build()?;
let points = vec![
PointStruct::new(
1,
vec![0.05, 0.61, 0.76, 0.74],
Payload::try_from(json!({"city": "Berlin", "price": 1.99})).unwrap(),
),
PointStruct::new(
2,
vec![0.19, 0.81, 0.75, 0.11],
Payload::try_from(json!({"city": ["Berlin", "London"]})).unwrap(),
),
PointStruct::new(
3,
vec![0.36, 0.55, 0.47, 0.94],
Payload::try_from(json!({"city": ["Berlin", "Moscow"], "price": [1.99, 2.99]}))
.unwrap(),
),
];
client
.upsert_points(UpsertPointsBuilder::new("{collection_name}", points).wait(true))
.await?;
import java.util.List;
import java.util.Map;
import static io.qdrant.client.PointIdFactory.id;
import static io.qdrant.client.ValueFactory.value;
import static io.qdrant.client.VectorsFactory.vectors;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Points.PointStruct;
QdrantClient client =
new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
client
.upsertAsync(
"{collection_name}",
List.of(
PointStruct.newBuilder()
.setId(id(1))
.setVectors(vectors(0.05f, 0.61f, 0.76f, 0.74f))
.putAllPayload(Map.of("city", value("Berlin"), "price", value(1.99)))
.build(),
PointStruct.newBuilder()
.setId(id(2))
.setVectors(vectors(0.19f, 0.81f, 0.75f, 0.11f))
.putAllPayload(
Map.of("city", list(List.of(value("Berlin"), value("London")))))
.build(),
PointStruct.newBuilder()
.setId(id(3))
.setVectors(vectors(0.36f, 0.55f, 0.47f, 0.94f))
.putAllPayload(
Map.of(
"city",
list(List.of(value("Berlin"), value("London"))),
"price",
list(List.of(value(1.99), value(2.99)))))
.build()))
.get();
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.UpsertAsync(
collectionName: "{collection_name}",
points: new List<PointStruct>
{
new PointStruct
{
Id = 1,
Vectors = new[] { 0.05f, 0.61f, 0.76f, 0.74f },
Payload = { ["city"] = "Berlin", ["price"] = 1.99 }
},
new PointStruct
{
Id = 2,
Vectors = new[] { 0.19f, 0.81f, 0.75f, 0.11f },
Payload = { ["city"] = new[] { "Berlin", "London" } }
},
new PointStruct
{
Id = 3,
Vectors = new[] { 0.36f, 0.55f, 0.47f, 0.94f },
Payload =
{
["city"] = new[] { "Berlin", "Moscow" },
["price"] = new Value
{
ListValue = new ListValue { Values = { new Value[] { 1.99, 2.99 } } }
}
}
}
}
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Upsert(context.Background(), &qdrant.UpsertPoints{
CollectionName: "{collection_name}",
Points: []*qdrant.PointStruct{
{
Id: qdrant.NewIDNum(1),
Vectors: qdrant.NewVectors(0.05, 0.61, 0.76, 0.74),
Payload: qdrant.NewValueMap(map[string]any{
"city": "Berlin", "price": 1.99}),
},
{
Id: qdrant.NewIDNum(2),
Vectors: qdrant.NewVectors(0.19, 0.81, 0.75, 0.11),
Payload: qdrant.NewValueMap(map[string]any{
"city": []any{"Berlin", "London"}}),
},
{
Id: qdrant.NewIDNum(3),
Vectors: qdrant.NewVectors(0.36, 0.55, 0.47, 0.94),
Payload: qdrant.NewValueMap(map[string]any{
"city": []any{"Berlin", "London"},
"price": []any{1.99, 2.99}}),
},
},
})
更新 Payload
Qdrant 中的 Payload 更新提供了灵活的方法来管理向量元数据。设置 Payload 方法更新特定字段,同时保留其他字段不变,而覆盖方法则替换整个 Payload。开发人员还可以使用清除 Payload 删除所有元数据,或使用删除字段来删除特定键而不影响其余部分。这些选项提供了精确的控制,以适应动态数据集。
设置 Payload
仅设置点上给定的 Payload 值。
REST API (模式)
POST /collections/{collection_name}/points/payload
{
"payload": {
"property1": "string",
"property2": "string"
},
"points": [
0, 3, 100
]
}
client.set_payload(
collection_name="{collection_name}",
payload={
"property1": "string",
"property2": "string",
},
points=[0, 3, 10],
)
client.setPayload("{collection_name}", {
payload: {
property1: "string",
property2: "string",
},
points: [0, 3, 10],
});
use qdrant_client::qdrant::{
PointsIdsList, SetPayloadPointsBuilder,
};
use qdrant_client::Payload,;
use serde_json::json;
client
.set_payload(
SetPayloadPointsBuilder::new(
"{collection_name}",
Payload::try_from(json!({
"property1": "string",
"property2": "string",
}))
.unwrap(),
)
.points_selector(PointsIdsList {
ids: vec![0.into(), 3.into(), 10.into()],
})
.wait(true),
)
.await?;
import java.util.List;
import java.util.Map;
import static io.qdrant.client.PointIdFactory.id;
import static io.qdrant.client.ValueFactory.value;
client
.setPayloadAsync(
"{collection_name}",
Map.of("property1", value("string"), "property2", value("string")),
List.of(id(0), id(3), id(10)),
true,
null,
null)
.get();
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.SetPayloadAsync(
collectionName: "{collection_name}",
payload: new Dictionary<string, Value> { { "property1", "string" }, { "property2", "string" } },
ids: new ulong[] { 0, 3, 10 }
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.SetPayload(context.Background(), &qdrant.SetPayloadPoints{
CollectionName: "{collection_name}",
Payload: qdrant.NewValueMap(
map[string]any{"property1": "string", "property2": "string"}),
PointsSelector: qdrant.NewPointsSelector(
qdrant.NewIDNum(0),
qdrant.NewIDNum(3)),
})
您无需知道要修改的点的 ID。另一种方法是使用过滤器。
POST /collections/{collection_name}/points/payload
{
"payload": {
"property1": "string",
"property2": "string"
},
"filter": {
"must": [
{
"key": "color",
"match": {
"value": "red"
}
}
]
}
}
client.set_payload(
collection_name="{collection_name}",
payload={
"property1": "string",
"property2": "string",
},
points=models.Filter(
must=[
models.FieldCondition(
key="color",
match=models.MatchValue(value="red"),
),
],
),
)
client.setPayload("{collection_name}", {
payload: {
property1: "string",
property2: "string",
},
filter: {
must: [
{
key: "color",
match: {
value: "red",
},
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, SetPayloadPointsBuilder};
use qdrant_client::Payload;
use serde_json::json;
client
.set_payload(
SetPayloadPointsBuilder::new(
"{collection_name}",
Payload::try_from(json!({
"property1": "string",
"property2": "string",
}))
.unwrap(),
)
.points_selector(Filter::must([Condition::matches(
"color",
"red".to_string(),
)]))
.wait(true),
)
.await?;
import java.util.Map;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import static io.qdrant.client.ValueFactory.value;
client
.setPayloadAsync(
"{collection_name}",
Map.of("property1", value("string"), "property2", value("string")),
Filter.newBuilder().addMust(matchKeyword("color", "red")).build(),
true,
null,
null)
.get();
using Qdrant.Client;
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.SetPayloadAsync(
collectionName: "{collection_name}",
payload: new Dictionary<string, Value> { { "property1", "string" }, { "property2", "string" } },
filter: MatchKeyword("color", "red")
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.SetPayload(context.Background(), &qdrant.SetPayloadPoints{
CollectionName: "{collection_name}",
Payload: qdrant.NewValueMap(
map[string]any{"property1": "string", "property2": "string"}),
PointsSelector: qdrant.NewPointsSelectorFilter(&qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewMatch("color", "red"),
},
}),
})
从 v1.8.0 版本开始可用
通过使用 key
参数,可以只修改 Payload 的特定键。
例如,给定点上的以下 Payload JSON 对象
{
"property1": {
"nested_property": "foo",
},
"property2": {
"nested_property": "bar",
}
}
您可以使用以下请求修改 property1
的 nested_property
POST /collections/{collection_name}/points/payload
{
"payload": {
"nested_property": "qux",
},
"key": "property1",
"points": [1]
}
结果 Payload 如下
{
"property1": {
"nested_property": "qux",
},
"property2": {
"nested_property": "bar",
}
}
覆盖 Payload
用给定的 Payload 完全替换任何现有 Payload。
REST API (模式)
PUT /collections/{collection_name}/points/payload
{
"payload": {
"property1": "string",
"property2": "string"
},
"points": [
0, 3, 100
]
}
client.overwrite_payload(
collection_name="{collection_name}",
payload={
"property1": "string",
"property2": "string",
},
points=[0, 3, 10],
)
client.overwritePayload("{collection_name}", {
payload: {
property1: "string",
property2: "string",
},
points: [0, 3, 10],
});
use qdrant_client::qdrant::{PointsIdsList, SetPayloadPointsBuilder};
use qdrant_client::Payload;
use serde_json::json;
client
.overwrite_payload(
SetPayloadPointsBuilder::new(
"{collection_name}",
Payload::try_from(json!({
"property1": "string",
"property2": "string",
}))
.unwrap(),
)
.points_selector(PointsIdsList {
ids: vec![0.into(), 3.into(), 10.into()],
})
.wait(true),
)
.await?;
import java.util.List;
import static io.qdrant.client.PointIdFactory.id;
import static io.qdrant.client.ValueFactory.value;
client
.overwritePayloadAsync(
"{collection_name}",
Map.of("property1", value("string"), "property2", value("string")),
List.of(id(0), id(3), id(10)),
true,
null,
null)
.get();
using Qdrant.Client;
using Qdrant.Client.Grpc;
var client = new QdrantClient("localhost", 6334);
await client.OverwritePayloadAsync(
collectionName: "{collection_name}",
payload: new Dictionary<string, Value> { { "property1", "string" }, { "property2", "string" } },
ids: new ulong[] { 0, 3, 10 }
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.OverwritePayload(context.Background(), &qdrant.SetPayloadPoints{
CollectionName: "{collection_name}",
Payload: qdrant.NewValueMap(
map[string]any{"property1": "string", "property2": "string"}),
PointsSelector: qdrant.NewPointsSelector(
qdrant.NewIDNum(0),
qdrant.NewIDNum(3)),
})
与设置 Payload 类似,您无需知道要修改的点的 ID。另一种方法是使用过滤器。
清除 Payload
此方法从指定点移除所有 Payload 键
REST API (模式)
POST /collections/{collection_name}/points/payload/clear
{
"points": [0, 3, 100]
}
client.clear_payload(
collection_name="{collection_name}",
points_selector=[0, 3, 100],
)
client.clearPayload("{collection_name}", {
points: [0, 3, 100],
});
use qdrant_client::qdrant::{ClearPayloadPointsBuilder, PointsIdsList};
client
.clear_payload(
ClearPayloadPointsBuilder::new("{collection_name}")
.points(PointsIdsList {
ids: vec![0.into(), 3.into(), 10.into()],
})
.wait(true),
)
.await?;
import java.util.List;
import static io.qdrant.client.PointIdFactory.id;
client
.clearPayloadAsync("{collection_name}", List.of(id(0), id(3), id(100)), true, null, null)
.get();
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.ClearPayloadAsync(collectionName: "{collection_name}", ids: new ulong[] { 0, 3, 100 });
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.ClearPayload(context.Background(), &qdrant.ClearPayloadPoints{
CollectionName: "{collection_name}",
Points: qdrant.NewPointsSelector(
qdrant.NewIDNum(0),
qdrant.NewIDNum(3)),
})
删除 Payload 键
从点删除指定的 Payload 键。
REST API (模式)
POST /collections/{collection_name}/points/payload/delete
{
"keys": ["color", "price"],
"points": [0, 3, 100]
}
client.delete_payload(
collection_name="{collection_name}",
keys=["color", "price"],
points=[0, 3, 100],
)
client.deletePayload("{collection_name}", {
keys: ["color", "price"],
points: [0, 3, 100],
});
use qdrant_client::qdrant::{DeletePayloadPointsBuilder, PointsIdsList};
client
.delete_payload(
DeletePayloadPointsBuilder::new(
"{collection_name}",
vec!["color".to_string(), "price".to_string()],
)
.points_selector(PointsIdsList {
ids: vec![0.into(), 3.into(), 10.into()],
})
.wait(true),
)
.await?;
import java.util.List;
import static io.qdrant.client.PointIdFactory.id;
client
.deletePayloadAsync(
"{collection_name}",
List.of("color", "price"),
List.of(id(0), id(3), id(100)),
true,
null,
null)
.get();
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.DeletePayloadAsync(
collectionName: "{collection_name}",
keys: ["color", "price"],
ids: new ulong[] { 0, 3, 100 }
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.DeletePayload(context.Background(), &qdrant.DeletePayloadPoints{
CollectionName: "{collection_name}",
Keys: []string{"color", "price"},
PointsSelector: qdrant.NewPointsSelector(
qdrant.NewIDNum(0),
qdrant.NewIDNum(3)),
})
或者,您可以使用过滤器从点删除 Payload 键。
POST /collections/{collection_name}/points/payload/delete
{
"keys": ["color", "price"],
"filter": {
"must": [
{
"key": "color",
"match": {
"value": "red"
}
}
]
}
}
client.delete_payload(
collection_name="{collection_name}",
keys=["color", "price"],
points=models.Filter(
must=[
models.FieldCondition(
key="color",
match=models.MatchValue(value="red"),
),
],
),
)
client.deletePayload("{collection_name}", {
keys: ["color", "price"],
filter: {
must: [
{
key: "color",
match: {
value: "red",
},
},
],
},
});
use qdrant_client::qdrant::{Condition, DeletePayloadPointsBuilder, Filter};
client
.delete_payload(
DeletePayloadPointsBuilder::new(
"{collection_name}",
vec!["color".to_string(), "price".to_string()],
)
.points_selector(Filter::must([Condition::matches(
"color",
"red".to_string(),
)]))
.wait(true),
)
.await?;
import java.util.List;
import static io.qdrant.client.ConditionFactory.matchKeyword;
client
.deletePayloadAsync(
"{collection_name}",
List.of("color", "price"),
Filter.newBuilder().addMust(matchKeyword("color", "red")).build(),
true,
null,
null)
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.DeletePayloadAsync(
collectionName: "{collection_name}",
keys: ["color", "price"],
filter: MatchKeyword("color", "red")
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.DeletePayload(context.Background(), &qdrant.DeletePayloadPoints{
CollectionName: "{collection_name}",
Keys: []string{"color", "price"},
PointsSelector: qdrant.NewPointsSelectorFilter(
&qdrant.Filter{
Must: []*qdrant.Condition{qdrant.NewMatch("color", "red")},
},
),
})
Payload 索引
为了更有效地使用过滤器进行搜索,Qdrant 允许您通过指定 Payload 字段的名称和预期类型来为其创建索引。
索引字段也会影响向量索引。有关详细信息,请参见索引。
在实践中,我们建议对那些可能最大限度地约束结果的字段创建索引。例如,对对象 ID 使用索引将比按颜色索引(颜色只有少数可能的值)效率高得多,因为对象 ID 对于每条记录都是唯一的。
在涉及多个字段的复合查询中,Qdrant 将首先尝试使用限制性最强的索引。
要为字段创建索引,您可以使用以下方法
REST API (模式)
PUT /collections/{collection_name}/index
{
"field_name": "name_of_the_field_to_index",
"field_schema": "keyword"
}
client.create_payload_index(
collection_name="{collection_name}",
field_name="name_of_the_field_to_index",
field_schema="keyword",
)
client.createPayloadIndex("{collection_name}", {
field_name: "name_of_the_field_to_index",
field_schema: "keyword",
});
use qdrant_client::qdrant::{CreateFieldIndexCollectionBuilder, FieldType};
client
.create_field_index(
CreateFieldIndexCollectionBuilder::new(
"{collection_name}",
"name_of_the_field_to_index",
FieldType::Keyword,
)
.wait(true),
)
.await?;
import io.qdrant.client.grpc.Collections.PayloadSchemaType;
client.createPayloadIndexAsync(
"{collection_name}",
"name_of_the_field_to_index",
PayloadSchemaType.Keyword,
null,
true,
null,
null);
using Qdrant.Client;
var client = new QdrantClient("localhost", 6334);
await client.CreatePayloadIndexAsync(
collectionName: "{collection_name}",
fieldName: "name_of_the_field_to_index"
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.CreateFieldIndex(context.Background(), &qdrant.CreateFieldIndexCollection{
CollectionName: "{collection_name}",
FieldName: "name_of_the_field_to_index",
FieldType: qdrant.FieldType_FieldTypeKeyword.Enum(),
})
索引使用标志在 Payload 模式中通过集合信息 API 显示。
Payload 模式示例
{
"payload_schema": {
"property1": {
"data_type": "keyword"
},
"property2": {
"data_type": "integer"
}
}
}
分面计数
从 v1.12.0 版本开始可用
分面是一种特殊的计数技术,可用于多种目的
- 了解 Payload 键存在哪些唯一值。
- 了解包含每个唯一值的点数。
- 了解通过匹配特定值,过滤器会变得多么严格。
具体来说,它是对字段中值的计数聚合,类似于 SQL 中的 GROUP BY
和 COUNT(*)
命令。
特定字段的这些结果称为“分面”。例如,当您查看电商搜索结果页面时,您可能会在侧边栏看到一个品牌列表,显示每个品牌的商品数量。这将是 "brand"
字段的分面。
要获取字段的分面计数,您可以使用以下方法
REST API (分面)
POST /collections/{collection_name}/facet
{
"key": "size",
"filter": {
"must": {
"key": "color",
"match": { "value": "red" }
}
}
}
from qdrant_client import QdrantClient, models
client = QdrantClient(url="http://localhost:6333")
client.facet(
collection_name="{collection_name}",
key="size",
facet_filter=models.Filter(must=[models.Match("color", "red")]),
)
import { QdrantClient } from "@qdrant/js-client-rest";
const client = new QdrantClient({ host: "localhost", port: 6333 });
client.facet("{collection_name}", {
filter: {
must: [
{
key: "color",
match: {
value: "red",
},
},
],
},
key: "size",
});
use qdrant_client::qdrant::{Condition, FacetCountsBuilder, Filter};
use qdrant_client::Qdrant;
let client = Qdrant::from_url("http://localhost:6334").build()?;
client
.facet(
FacetCountsBuilder::new("{collection_name}", "size")
.limit(10)
.filter(Filter::must(vec![Condition::matches(
"color",
"red".to_string(),
)])),
)
.await?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import io.qdrant.client.grpc.Points;
import io.qdrant.client.grpc.Filter;
QdrantClient client = new QdrantClient(
QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
client
.facetAsync(
Points.FacetCounts.newBuilder()
.setCollectionName(collection_name)
.setKey("size")
.setFilter(Filter.newBuilder().addMust(matchKeyword("color", "red")).build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.FacetAsync(
"{collection_name}",
key: "size",
filter: MatchKeyword("color", "red")
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
res, err := client.Facet(ctx, &qdrant.FacetCounts{
CollectionName: "{collection_name}",
Key: "size",
Filter: &qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewMatch("color", "red"),
},
},
})
响应将包含字段中每个唯一值的计数
{
"response": {
"hits": [
{"value": "L", "count": 19},
{"value": "S", "count": 10},
{"value": "M", "count": 5},
{"value": "XL", "count": 1},
{"value": "XXL", "count": 1}
]
},
"time": 0.0001
}
结果按计数降序排序,然后按值升序排序。仅返回非零计数值。
默认情况下,Qdrant 对每个值的计数是近似的,以实现快速结果。这对于大多数情况来说已经足够准确,但如果您需要调试存储,可以使用 exact
参数获取精确计数。
POST /collections/{collection_name}/facet
{
"key": "size",
"exact": true
}
client.facet(
collection_name="{collection_name}",
key="size",
exact=True,
)
client.facet("{collection_name}", {
key: "size",
exact: true,
});
use qdrant_client::qdrant::FacetCountsBuilder;
client
.facet(
FacetCountsBuilder::new("{collection_name}", "size")
.limit(10)
.exact(true),
)
.await?;
client
.facetAsync(
Points.FacetCounts.newBuilder()
.setCollectionName(collection_name)
.setKey("foo")
.setExact(true)
.build())
.get();
using Qdrant.Client;
await client.FacetAsync(
"{collection_name}",
key: "size",
exact: true,
);
res, err := client.Facet(ctx, &qdrant.FacetCounts{
CollectionName: "{collection_name}",
Key: "key",
Exact: true,
})