筛选
使用 Qdrant 时,您可以在搜索或检索点时设置条件。例如,您可以对 payload(有效载荷) 和点的 id 施加条件。
当无法在嵌入(embedding)中表达对象的所有特征时,设置附加条件非常重要。例如各种业务需求:库存可用性、用户位置或期望的价格范围。
相关内容
| 向量搜索过滤的完整指南 | 关于正确用法和进阶实践的开发者建议。 |
|---|
过滤子句
Qdrant 允许您在子句中组合条件。子句是不同的逻辑运算,例如 OR、AND 和 NOT。子句可以递归嵌套,以便您可以重现任意布尔表达式。
让我们看看 Qdrant 中实现的子句。
假设我们有一组具有以下 payload 的点
[
{ "id": 1, "city": "London", "color": "green" },
{ "id": 2, "city": "London", "color": "red" },
{ "id": 3, "city": "London", "color": "blue" },
{ "id": 4, "city": "Berlin", "color": "red" },
{ "id": 5, "city": "Moscow", "color": "green" },
{ "id": 6, "city": "Moscow", "color": "blue" }
]
Must(必须)
使用 must 时,只有当 must 内部列出的每个条件都满足时,子句才为 true。从这个意义上说,must 等同于 AND 运算符。
示例
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{ "key": "city", "match": { "value": "London" } },
{ "key": "color", "match": { "value": "red" } }
]
}
...
}
from qdrant_client import QdrantClient, models
client = QdrantClient(url="https://:6333")
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
must=[
models.FieldCondition(
key="city",
match=models.MatchValue(value="London"),
),
models.FieldCondition(
key="color",
match=models.MatchValue(value="red"),
),
]
),
)
import { QdrantClient } from "@qdrant/js-client-rest";
const client = new QdrantClient({ host: "localhost", port: 6333 });
client.scroll("{collection_name}", {
filter: {
must: [
{
key: "city",
match: { value: "London" },
},
{
key: "color",
match: { value: "red" },
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
use qdrant_client::Qdrant;
let client = Qdrant::from_url("https://:6334").build()?;
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter::must([
Condition::matches("city", "london".to_string()),
Condition::matches("color", "red".to_string()),
])),
)
.await?;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
import java.util.List;
QdrantClient client =
new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addAllMust(
List.of(matchKeyword("city", "London"), matchKeyword("color", "red")))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
// & operator combines two conditions in an AND conjunction(must)
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("city", "London") & MatchKeyword("color", "red")
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewMatch("city", "London"),
qdrant.NewMatch("color", "red"),
},
},
})
过滤后的点将是
[{ "id": 2, "city": "London", "color": "red" }]
Should(应该)
使用 should 时,如果至少满足 should 内部列出的一个条件,则子句为 true。从这个意义上说,should 等同于 OR 运算符。
示例
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{ "key": "city", "match": { "value": "London" } },
{ "key": "color", "match": { "value": "red" } }
]
}
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
should=[
models.FieldCondition(
key="city",
match=models.MatchValue(value="London"),
),
models.FieldCondition(
key="color",
match=models.MatchValue(value="red"),
),
]
),
)
client.scroll("{collection_name}", {
filter: {
should: [
{
key: "city",
match: { value: "London" },
},
{
key: "color",
match: { value: "red" },
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
use qdrant_client::Qdrant;
let client = Qdrant::from_url("https://:6334").build()?;
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter::should([
Condition::matches("city", "london".to_string()),
Condition::matches("color", "red".to_string()),
])),
)
.await?;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
import java.util.List;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addAllShould(
List.of(matchKeyword("city", "London"), matchKeyword("color", "red")))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
// | operator combines two conditions in an OR disjunction(should)
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("city", "London") | MatchKeyword("color", "red")
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Should: []*qdrant.Condition{
qdrant.NewMatch("city", "London"),
qdrant.NewMatch("color", "red"),
},
},
})
过滤后的点将是
[
{ "id": 1, "city": "London", "color": "green" },
{ "id": 2, "city": "London", "color": "red" },
{ "id": 3, "city": "London", "color": "blue" },
{ "id": 4, "city": "Berlin", "color": "red" }
]
Must Not(必须不)
使用 must_not 时,如果 must_not 内部列出的条件均未满足,则子句为 true。从这个意义上说,must_not 等同于表达式 (NOT A) AND (NOT B) AND (NOT C)。
示例
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must_not": [
{ "key": "city", "match": { "value": "London" } },
{ "key": "color", "match": { "value": "red" } }
]
}
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
must_not=[
models.FieldCondition(key="city", match=models.MatchValue(value="London")),
models.FieldCondition(key="color", match=models.MatchValue(value="red")),
]
),
)
client.scroll("{collection_name}", {
filter: {
must_not: [
{
key: "city",
match: { value: "London" },
},
{
key: "color",
match: { value: "red" },
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
use qdrant_client::Qdrant;
let client = Qdrant::from_url("https://:6334").build()?;
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter::must_not([
Condition::matches("city", "london".to_string()),
Condition::matches("color", "red".to_string()),
])),
)
.await?;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
import java.util.List;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addAllMustNot(
List.of(matchKeyword("city", "London"), matchKeyword("color", "red")))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
// The ! operator negates the condition(must not)
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: !(MatchKeyword("city", "London") & MatchKeyword("color", "red"))
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
MustNot: []*qdrant.Condition{
qdrant.NewMatch("city", "London"),
qdrant.NewMatch("color", "red"),
},
},
})
过滤后的点将是
[
{ "id": 5, "city": "Moscow", "color": "green" },
{ "id": 6, "city": "Moscow", "color": "blue" }
]
子句组合
也可以同时使用多个子句
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{ "key": "city", "match": { "value": "London" } }
],
"must_not": [
{ "key": "color", "match": { "value": "red" } }
]
}
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
must=[
models.FieldCondition(key="city", match=models.MatchValue(value="London")),
],
must_not=[
models.FieldCondition(key="color", match=models.MatchValue(value="red")),
],
),
)
client.scroll("{collection_name}", {
filter: {
must: [
{
key: "city",
match: { value: "London" },
},
],
must_not: [
{
key: "color",
match: { value: "red" },
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter {
must: vec![Condition::matches("city", "London".to_string())],
must_not: vec![Condition::matches("color", "red".to_string())],
..Default::default()
}),
)
.await?;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addMust(matchKeyword("city", "London"))
.addMustNot(matchKeyword("color", "red"))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("city", "London") & !MatchKeyword("color", "red")
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewMatch("city", "London"),
},
MustNot: []*qdrant.Condition{
qdrant.NewMatch("color", "red"),
},
},
})
过滤后的点将是
[
{ "id": 1, "city": "London", "color": "green" },
{ "id": 3, "city": "London", "color": "blue" }
]
在这种情况下,条件通过 AND 组合。
此外,条件可以递归嵌套。示例
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must_not": [
{
"must": [
{ "key": "city", "match": { "value": "London" } },
{ "key": "color", "match": { "value": "red" } }
]
}
]
}
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
must_not=[
models.Filter(
must=[
models.FieldCondition(
key="city", match=models.MatchValue(value="London")
),
models.FieldCondition(
key="color", match=models.MatchValue(value="red")
),
],
),
],
),
)
client.scroll("{collection_name}", {
filter: {
must_not: [
{
must: [
{
key: "city",
match: { value: "London" },
},
{
key: "color",
match: { value: "red" },
},
],
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter::must_not([Filter::must(
[
Condition::matches("city", "London".to_string()),
Condition::matches("color", "red".to_string()),
],
)
.into()])),
)
.await?;
import static io.qdrant.client.ConditionFactory.filter;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
import java.util.List;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addMustNot(
filter(
Filter.newBuilder()
.addAllMust(
List.of(
matchKeyword("city", "London"),
matchKeyword("color", "red")))
.build()))
.build())
.build())
.get();
using Qdrant.Client;
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: new Filter { MustNot = { MatchKeyword("city", "London") & MatchKeyword("color", "red") } }
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
MustNot: []*qdrant.Condition{
qdrant.NewFilterAsCondition(&qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewMatch("city", "London"),
qdrant.NewMatch("color", "red"),
},
}),
},
},
})
过滤后的点将是
[
{ "id": 1, "city": "London", "color": "green" },
{ "id": 3, "city": "London", "color": "blue" },
{ "id": 4, "city": "Berlin", "color": "red" },
{ "id": 5, "city": "Moscow", "color": "green" },
{ "id": 6, "city": "Moscow", "color": "blue" }
]
过滤条件
Payload 中的不同值类型对应于我们可以应用于它们的不同查询类型。让我们看看现有的条件变体以及它们适用于哪些数据类型。
匹配 (Match)
{
"key": "color",
"match": {
"value": "red"
}
}
models.FieldCondition(
key="color",
match=models.MatchValue(value="red"),
)
{
key: 'color',
match: {value: 'red'}
}
Condition::matches("color", "red".to_string())
import static io.qdrant.client.ConditionFactory.matchKeyword;
matchKeyword("color", "red");
using static Qdrant.Client.Grpc.Conditions;
MatchKeyword("color", "red");
import "github.com/qdrant/go-client/qdrant"
qdrant.NewMatch("color", "red")
对于其他类型,匹配条件看起来完全一样,只是类型不同
{
"key": "count",
"match": {
"value": 0
}
}
models.FieldCondition(
key="count",
match=models.MatchValue(value=0),
)
{
key: 'count',
match: {value: 0}
}
Condition::matches("count", 0)
import static io.qdrant.client.ConditionFactory.match;
match("count", 0);
using static Qdrant.Client.Grpc.Conditions;
Match("count", 0);
import "github.com/qdrant/go-client/qdrant"
qdrant.NewMatchInt("count", 0)
最简单的条件是检查存储的值是否等于给定值。如果存储了多个值,则其中至少有一个必须符合条件。您可以将其应用于 keyword(关键字)、integer(整数) 和 bool(布尔) 类型的 payload。
匹配任意 (Match Any)
v1.1.0 起可用
如果您想检查存储的值是否为多个值之一,可以使用 Match Any(匹配任意)条件。Match Any 作用于给定值的逻辑 OR。它也可以描述为 IN 运算符。
您可以将其应用于 keyword 和 integer 类型的 payload。
示例
{
"key": "color",
"match": {
"any": ["black", "yellow"]
}
}
models.FieldCondition(
key="color",
match=models.MatchAny(any=["black", "yellow"]),
)
{
key: 'color',
match: {any: ['black', 'yellow']}
}
Condition::matches("color", vec!["black".to_string(), "yellow".to_string()])
import static io.qdrant.client.ConditionFactory.matchKeywords;
import java.util.List;
matchKeywords("color", List.of("black", "yellow"));
using static Qdrant.Client.Grpc.Conditions;
Match("color", ["black", "yellow"]);
import "github.com/qdrant/go-client/qdrant"
qdrant.NewMatchKeywords("color", "black", "yellow")
在此示例中,如果存储的值为 black 或 yellow,则条件满足。
如果存储的值是一个数组,它应该至少有一个值匹配给定的任何值。例如,如果存储的值是 ["black", "green"],则条件将满足,因为 "black" 在 ["black", "yellow"] 中。
匹配排除 (Match Except)
自 v1.2.0 起可用
如果您想检查存储的值是否不是多个值之一,可以使用 Match Except(匹配排除)条件。Match Except 作用于给定值的逻辑 NOR。它也可以描述为 NOT IN 运算符。
您可以将其应用于 keyword 和 integer 类型的 payload。
示例
{
"key": "color",
"match": {
"except": ["black", "yellow"]
}
}
models.FieldCondition(
key="color",
match=models.MatchExcept(**{"except": ["black", "yellow"]}),
)
{
key: 'color',
match: {except: ['black', 'yellow']}
}
use qdrant_client::qdrant::r#match::MatchValue;
Condition::matches(
"color",
!MatchValue::from(vec!["black".to_string(), "yellow".to_string()]),
)
import static io.qdrant.client.ConditionFactory.matchExceptKeywords;
import java.util.List;
matchExceptKeywords("color", List.of("black", "yellow"));
using static Qdrant.Client.Grpc.Conditions;
MatchExcept("color", ["black", "yellow"]);
import "github.com/qdrant/go-client/qdrant"
qdrant.NewMatchExcept("color", "black", "yellow")
在此示例中,如果存储的值既不是 black 也不是 yellow,则条件满足。
如果存储的值是一个数组,它应该至少有一个值不匹配给定的任何值。例如,如果存储的值是 ["black", "green"],则条件将满足,因为 "green" 既不匹配 "black" 也不匹配 "yellow"。
嵌套键
v1.1.0 起可用
由于 payload 是任意 JSON 对象,因此您很可能需要对嵌套字段进行过滤。
为了方便起见,我们使用了类似于 Jq 项目中的语法。
假设我们有一组具有以下 payload 的点
[
{
"id": 1,
"country": {
"name": "Germany",
"cities": [
{
"name": "Berlin",
"population": 3.7,
"sightseeing": ["Brandenburg Gate", "Reichstag"]
},
{
"name": "Munich",
"population": 1.5,
"sightseeing": ["Marienplatz", "Olympiapark"]
}
]
}
},
{
"id": 2,
"country": {
"name": "Japan",
"cities": [
{
"name": "Tokyo",
"population": 9.3,
"sightseeing": ["Tokyo Tower", "Tokyo Skytree"]
},
{
"name": "Osaka",
"population": 2.7,
"sightseeing": ["Osaka Castle", "Universal Studios Japan"]
}
]
}
}
]
您可以使用点表示法搜索嵌套字段。
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{
"key": "country.name",
"match": {
"value": "Germany"
}
}
]
}
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
should=[
models.FieldCondition(
key="country.name", match=models.MatchValue(value="Germany")
),
],
),
)
client.scroll("{collection_name}", {
filter: {
should: [
{
key: "country.name",
match: { value: "Germany" },
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter::should([
Condition::matches("country.name", "Germany".to_string()),
])),
)
.await?;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addShould(matchKeyword("country.name", "Germany"))
.build())
.build())
.get();
using Qdrant.Client;
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(collectionName: "{collection_name}", filter: MatchKeyword("country.name", "Germany"));
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Should: []*qdrant.Condition{
qdrant.NewMatch("country.name", "Germany"),
},
},
})
您还可以通过使用 [] 语法投影内部值来搜索数组。
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{
"key": "country.cities[].population",
"range": {
"gte": 9.0,
}
}
]
}
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
should=[
models.FieldCondition(
key="country.cities[].population",
range=models.Range(
gt=None,
gte=9.0,
lt=None,
lte=None,
),
),
],
),
)
client.scroll("{collection_name}", {
filter: {
should: [
{
key: "country.cities[].population",
range: {
gt: null,
gte: 9.0,
lt: null,
lte: null,
},
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, Range, ScrollPointsBuilder};
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter::should([
Condition::range(
"country.cities[].population",
Range {
gte: Some(9.0),
..Default::default()
},
),
])),
)
.await?;
import static io.qdrant.client.ConditionFactory.range;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Common.Range;
import io.qdrant.client.grpc.Points.ScrollPoints;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addShould(
range(
"country.cities[].population",
Range.newBuilder().setGte(9.0).build()))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: Range("country.cities[].population", new Qdrant.Client.Grpc.Range { Gte = 9.0 })
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Should: []*qdrant.Condition{
qdrant.NewRange("country.cities[].population", &qdrant.Range{
Gte: qdrant.PtrOf(9.0),
}),
},
},
})
此查询将仅输出 id 为 2 的点,因为只有日本有城市人口超过 9.0。
叶嵌套字段也可以是一个数组。
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{
"key": "country.cities[].sightseeing",
"match": {
"value": "Osaka Castle"
}
}
]
}
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
should=[
models.FieldCondition(
key="country.cities[].sightseeing",
match=models.MatchValue(value="Osaka Castle"),
),
],
),
)
client.scroll("{collection_name}", {
filter: {
should: [
{
key: "country.cities[].sightseeing",
match: { value: "Osaka Castle" },
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter::should([
Condition::matches("country.cities[].sightseeing", "Osaka Castle".to_string()),
])),
)
.await?;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addShould(matchKeyword("country.cities[].sightseeing", "Germany"))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("country.cities[].sightseeing", "Germany")
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Should: []*qdrant.Condition{
qdrant.NewMatch("country.cities[].sightseeing", "Germany"),
},
},
})
此查询将仅输出 id 为 2 的点,因为只有日本有城市将“Osaka castle”作为观光内容的一部分。
嵌套对象过滤
自 v1.2.0 起可用
默认情况下,条件会考虑点的整个 payload。
例如,给定两个具有以下 payload 的点
[
{
"id": 1,
"dinosaur": "t-rex",
"diet": [
{ "food": "leaves", "likes": false},
{ "food": "meat", "likes": true}
]
},
{
"id": 2,
"dinosaur": "diplodocus",
"diet": [
{ "food": "leaves", "likes": true},
{ "food": "meat", "likes": false}
]
}
]
以下查询将匹配两个点
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{
"key": "diet[].food",
"match": {
"value": "meat"
}
},
{
"key": "diet[].likes",
"match": {
"value": true
}
}
]
}
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
must=[
models.FieldCondition(
key="diet[].food", match=models.MatchValue(value="meat")
),
models.FieldCondition(
key="diet[].likes", match=models.MatchValue(value=True)
),
],
),
)
client.scroll("{collection_name}", {
filter: {
must: [
{
key: "diet[].food",
match: { value: "meat" },
},
{
key: "diet[].likes",
match: { value: true },
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter::must([
Condition::matches("diet[].food", "meat".to_string()),
Condition::matches("diet[].likes", true),
])),
)
.await?;
import static io.qdrant.client.ConditionFactory.match;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
import java.util.List;
QdrantClient client =
new QdrantClient(QdrantGrpcClient.newBuilder("localhost", 6334, false).build());
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addAllMust(
List.of(matchKeyword("diet[].food", "meat"), match("diet[].likes", true)))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: MatchKeyword("diet[].food", "meat") & Match("diet[].likes", true)
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewMatch("diet[].food", "meat"),
qdrant.NewMatchBool("diet[].likes", true),
},
},
})
这是因为两个点都满足这两个条件
- “t-rex”在
diet[1].food处匹配 food=meat,在diet[1].likes处匹配 likes=true - “diplodocus”在
diet[1].food处匹配 food=meat,在diet[0].likes处匹配 likes=true
要仅检索在数组元素基础上匹配条件的点(即本例中的 id 为 1 的点),您需要使用嵌套对象过滤器。
嵌套对象过滤器允许独立查询对象数组。
它是通过使用 nested 条件类型实现的,该类型由要聚焦的 payload 键和要应用的过滤器组成。
键应指向对象数组,并且可以使用或不使用括号表示法(“data” 或 “data[]”)。
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [{
"nested": {
"key": "diet",
"filter":{
"must": [
{
"key": "food",
"match": {
"value": "meat"
}
},
{
"key": "likes",
"match": {
"value": true
}
}
]
}
}
}]
}
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
must=[
models.NestedCondition(
nested=models.Nested(
key="diet",
filter=models.Filter(
must=[
models.FieldCondition(
key="food", match=models.MatchValue(value="meat")
),
models.FieldCondition(
key="likes", match=models.MatchValue(value=True)
),
]
),
)
)
],
),
)
client.scroll("{collection_name}", {
filter: {
must: [
{
nested: {
key: "diet",
filter: {
must: [
{
key: "food",
match: { value: "meat" },
},
{
key: "likes",
match: { value: true },
},
],
},
},
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, NestedCondition, ScrollPointsBuilder};
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter::must([NestedCondition {
key: "diet".to_string(),
filter: Some(Filter::must([
Condition::matches("food", "meat".to_string()),
Condition::matches("likes", true),
])),
}
.into()])),
)
.await?;
import static io.qdrant.client.ConditionFactory.match;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import static io.qdrant.client.ConditionFactory.nested;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
import java.util.List;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addMust(
nested(
"diet",
Filter.newBuilder()
.addAllMust(
List.of(
matchKeyword("food", "meat"), match("likes", true)))
.build()))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: Nested("diet", MatchKeyword("food", "meat") & Match("likes", true))
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewNestedFilter("diet", &qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewMatch("food", "meat"),
qdrant.NewMatchBool("likes", true),
},
}),
},
},
})
匹配逻辑被修改为应用于 payload 内的数组元素级别。
嵌套过滤器的作用方式与一次将嵌套过滤器应用于数组的一个元素相同。如果数组的至少一个元素匹配嵌套过滤器,则父文档被视为匹配条件。
限制
嵌套对象过滤器内不支持 has_id 条件。如果您需要它,请将其放在相邻的 must 子句中。
POST /collections/{collection_name}/points/scroll
{
"filter":{
"must":[
{
"nested":{
"key":"diet",
"filter":{
"must":[
{
"key":"food",
"match":{
"value":"meat"
}
},
{
"key":"likes",
"match":{
"value":true
}
}
]
}
}
},
{
"has_id":[
1
]
}
]
}
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
must=[
models.NestedCondition(
nested=models.Nested(
key="diet",
filter=models.Filter(
must=[
models.FieldCondition(
key="food", match=models.MatchValue(value="meat")
),
models.FieldCondition(
key="likes", match=models.MatchValue(value=True)
),
]
),
)
),
models.HasIdCondition(has_id=[1]),
],
),
)
client.scroll("{collection_name}", {
filter: {
must: [
{
nested: {
key: "diet",
filter: {
must: [
{
key: "food",
match: { value: "meat" },
},
{
key: "likes",
match: { value: true },
},
],
},
},
},
{
has_id: [1],
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, NestedCondition, ScrollPointsBuilder};
client
.scroll(
ScrollPointsBuilder::new("{collection_name}").filter(Filter::must([
NestedCondition {
key: "diet".to_string(),
filter: Some(Filter::must([
Condition::matches("food", "meat".to_string()),
Condition::matches("likes", true),
])),
}
.into(),
Condition::has_id([1]),
])),
)
.await?;
import static io.qdrant.client.ConditionFactory.hasId;
import static io.qdrant.client.ConditionFactory.match;
import static io.qdrant.client.ConditionFactory.matchKeyword;
import static io.qdrant.client.ConditionFactory.nested;
import static io.qdrant.client.PointIdFactory.id;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
import java.util.List;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addMust(
nested(
"diet",
Filter.newBuilder()
.addAllMust(
List.of(
matchKeyword("food", "meat"), match("likes", true)))
.build()))
.addMust(hasId(id(1)))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(
collectionName: "{collection_name}",
filter: Nested("diet", MatchKeyword("food", "meat") & Match("likes", true)) & HasId(1)
);
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewNestedFilter("diet", &qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewMatch("food", "meat"),
qdrant.NewMatchBool("likes", true),
},
}),
qdrant.NewHasID(qdrant.NewIDNum(1)),
},
},
})
全文匹配
自 v0.10.0 起可用
match 条件的一个特殊情况是 text 匹配条件。它允许您在文本字段中搜索特定的子字符串、词元或短语。
将匹配条件的精确文本取决于全文索引配置。配置是在索引创建期间定义的,并在 全文索引 中描述。
如果该字段没有全文索引,则该条件将作为精确子字符串匹配。
{
"key": "description",
"match": {
"text": "good cheap"
}
}
models.FieldCondition(
key="description",
match=models.MatchText(text="good cheap"),
)
{
key: 'description',
match: {text: 'good cheap'}
}
use qdrant_client::qdrant::Condition;
Condition::matches_text("description", "good cheap")
import static io.qdrant.client.ConditionFactory.matchText;
matchText("description", "good cheap");
using static Qdrant.Client.Grpc.Conditions;
MatchText("description", "good cheap");
import "github.com/qdrant/go-client/qdrant"
qdrant.NewMatchText("description", "good cheap")
如果查询有多个单词,则只有当它们全部存在于文本中时,条件才会满足。
全文任意匹配
自 v1.16.0 起可用
text_any 全文匹配条件类似于 text 条件,但有一个关键区别:虽然 text 仅匹配包含查询中*所有*项的文本字段,但 text_any 匹配包含查询中*任何*项的字段。换句话说,即使文本字段仅包含查询项中的一个,它也被视为匹配。
例如,查询 good cheap 同时匹配 cheap hardware 和 good performance。
{
"key": "description",
"match": {
"text_any": "good cheap"
}
}
models.FieldCondition(
key="description",
match=models.MatchTextAny(text_any="good cheap"),
)
{
key: 'description',
match: {text_any: 'good cheap'}
}
use qdrant_client::qdrant::Condition;
Condition::matches_text_any("description", "good cheap")
import static io.qdrant.client.ConditionFactory.matchTextAny;
matchTextAny("description", "good cheap");
using static Qdrant.Client.Grpc.Conditions;
MatchTextAny("description", "good cheap");
import "github.com/qdrant/go-client/qdrant"
qdrant.NewMatchTextAny("description", "good cheap")
短语匹配
从 v1.15.0 版本开始可用
phrase 匹配条件也利用了 全文索引 来执行精确的短语比较。它允许您在文本字段中搜索特定的词元短语。
例如,文本 "quick brown fox" 将被查询 "brown fox" 匹配,但不会被 "fox brown" 匹配。
如果该字段没有全文索引,则该条件将作为精确子字符串匹配。
{
"key": "description",
"match": {
"phrase": "brown fox"
}
}
models.FieldCondition(
key="description",
match=models.MatchPhrase(phrase="brown fox"),
)
{
key: 'description',
match: {phrase: 'brown fox'}
}
use qdrant_client::qdrant::Condition;
Condition::matches_phrase("description", "brown fox")
import static io.qdrant.client.ConditionFactory.matchPhrase;
matchPhrase("description", "brown fox");
using static Qdrant.Client.Grpc.Conditions;
MatchPhrase("description", "brown fox");
import "github.com/qdrant/go-client/qdrant"
qdrant.NewMatchPhrase("description", "brown fox")
范围
{
"key": "price",
"range": {
"gt": null,
"gte": 100.0,
"lt": null,
"lte": 450.0
}
}
models.FieldCondition(
key="price",
range=models.Range(
gt=None,
gte=100.0,
lt=None,
lte=450.0,
),
)
{
key: 'price',
range: {
gt: null,
gte: 100.0,
lt: null,
lte: 450.0
}
}
use qdrant_client::qdrant::{Condition, Range};
Condition::range(
"price",
Range {
gt: None,
gte: Some(100.0),
lt: None,
lte: Some(450.0),
},
)
import static io.qdrant.client.ConditionFactory.range;
import io.qdrant.client.grpc.Common.Range;
range("price", Range.newBuilder().setGte(100.0).setLte(450).build());
using static Qdrant.Client.Grpc.Conditions;
Range("price", new Qdrant.Client.Grpc.Range { Gte = 100.0, Lte = 450 });
import "github.com/qdrant/go-client/qdrant"
qdrant.NewRange("price", &qdrant.Range{
Gte: qdrant.PtrOf(100.0),
Lte: qdrant.PtrOf(450.0),
})
range 条件设置存储的 payload 值的可能范围。如果存储了多个值,则至少有一个必须符合条件。
可以使用的比较
gt- 大于gte- 大于或等于lt- 小于lte- 小于或等于
可应用于 float 和 integer 类型的 payload。
日期时间范围 (Datetime Range)
日期时间范围是一种独特的范围条件,用于支持 RFC 3339 格式的 datetime(日期时间) payload。您不需要将日期转换为 UNIX 时间戳。在比较期间,时间戳会被解析并转换为 UTC。
自 v1.8.0 起可用
{
"key": "date",
"range": {
"gt": "2023-02-08T10:49:00Z",
"gte": null,
"lt": null,
"lte": "2024-01-31 10:14:31Z"
}
}
models.FieldCondition(
key="date",
range=models.DatetimeRange(
gt="2023-02-08T10:49:00Z",
gte=None,
lt=None,
lte="2024-01-31T10:14:31Z",
),
)
{
key: 'date',
range: {
gt: '2023-02-08T10:49:00Z',
gte: null,
lt: null,
lte: '2024-01-31T10:14:31Z'
}
}
use qdrant_client::qdrant::{Condition, DatetimeRange, Timestamp};
Condition::datetime_range(
"date",
DatetimeRange {
gt: Some(Timestamp::date_time(2023, 2, 8, 10, 49, 0).unwrap()),
gte: None,
lt: None,
lte: Some(Timestamp::date_time(2024, 1, 31, 10, 14, 31).unwrap()),
},
)
import static io.qdrant.client.ConditionFactory.datetimeRange;
import com.google.protobuf.Timestamp;
import io.qdrant.client.grpc.Common.DatetimeRange;
import java.time.Instant;
long gt = Instant.parse("2023-02-08T10:49:00Z").getEpochSecond();
long lte = Instant.parse("2024-01-31T10:14:31Z").getEpochSecond();
datetimeRange("date",
DatetimeRange.newBuilder()
.setGt(Timestamp.newBuilder().setSeconds(gt))
.setLte(Timestamp.newBuilder().setSeconds(lte))
.build());
using Qdrant.Client.Grpc;
Conditions.DatetimeRange(
field: "date",
gt: new DateTime(2023, 2, 8, 10, 49, 0, DateTimeKind.Utc),
lte: new DateTime(2024, 1, 31, 10, 14, 31, DateTimeKind.Utc)
);
import (
"time"
"github.com/qdrant/go-client/qdrant"
"google.golang.org/protobuf/types/known/timestamppb"
)
qdrant.NewDatetimeRange("date", &qdrant.DatetimeRange{
Gt: timestamppb.New(time.Date(2023, 2, 8, 10, 49, 0, 0, time.UTC)),
Lte: timestamppb.New(time.Date(2024, 1, 31, 10, 14, 31, 0, time.UTC)),
})
UUID 匹配
自 v1.11.0 起可用
UUID 值的匹配方式类似于字符串的常规 match 条件。在功能上,它将与 keyword 和 uuid 索引完全一样地工作,但 uuid 索引的内存效率更高。
{
"key": "uuid",
"match": {
"value": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
}
models.FieldCondition(
key="uuid",
match=models.MatchValue(value="f47ac10b-58cc-4372-a567-0e02b2c3d479"),
)
{
key: 'uuid',
match: {value: 'f47ac10b-58cc-4372-a567-0e02b2c3d479'}
}
Condition::matches("uuid", "f47ac10b-58cc-4372-a567-0e02b2c3d479".to_string())
import static io.qdrant.client.ConditionFactory.matchKeyword;
matchKeyword("uuid", "f47ac10b-58cc-4372-a567-0e02b2c3d479");
using static Qdrant.Client.Grpc.Conditions;
MatchKeyword("uuid", "f47ac10b-58cc-4372-a567-0e02b2c3d479");
import "github.com/qdrant/go-client/qdrant"
qdrant.NewMatch("uuid", "f47ac10b-58cc-4372-a567-0e02b2c3d479")
地理位置
地理边界框
{
"key": "location",
"geo_bounding_box": {
"bottom_right": {
"lon": 13.455868,
"lat": 52.495862
},
"top_left": {
"lon": 13.403683,
"lat": 52.520711
}
}
}
models.FieldCondition(
key="location",
geo_bounding_box=models.GeoBoundingBox(
bottom_right=models.GeoPoint(
lon=13.455868,
lat=52.495862,
),
top_left=models.GeoPoint(
lon=13.403683,
lat=52.520711,
),
),
)
{
key: 'location',
geo_bounding_box: {
bottom_right: {
lon: 13.455868,
lat: 52.495862
},
top_left: {
lon: 13.403683,
lat: 52.520711
}
}
}
use qdrant_client::qdrant::{Condition, GeoBoundingBox, GeoPoint};
Condition::geo_bounding_box(
"location",
GeoBoundingBox {
bottom_right: Some(GeoPoint {
lon: 13.455868,
lat: 52.495862,
}),
top_left: Some(GeoPoint {
lon: 13.403683,
lat: 52.520711,
}),
},
)
import static io.qdrant.client.ConditionFactory.geoBoundingBox;
geoBoundingBox("location", 52.520711, 13.403683, 52.495862, 13.455868);
using static Qdrant.Client.Grpc.Conditions;
GeoBoundingBox("location", 52.520711, 13.403683, 52.495862, 13.455868);
import "github.com/qdrant/go-client/qdrant"
qdrant.NewGeoBoundingBox("location", 52.520711, 13.403683, 52.495862, 13.455868)
它匹配左上角坐标为 top_left,右下角坐标为 bottom_right 的矩形内的 location。
地理半径
{
"key": "location",
"geo_radius": {
"center": {
"lon": 13.403683,
"lat": 52.520711
},
"radius": 1000.0
}
}
models.FieldCondition(
key="location",
geo_radius=models.GeoRadius(
center=models.GeoPoint(
lon=13.403683,
lat=52.520711,
),
radius=1000.0,
),
)
{
key: 'location',
geo_radius: {
center: {
lon: 13.403683,
lat: 52.520711
},
radius: 1000.0
}
}
use qdrant_client::qdrant::{Condition, GeoPoint, GeoRadius};
Condition::geo_radius(
"location",
GeoRadius {
center: Some(GeoPoint {
lon: 13.403683,
lat: 52.520711,
}),
radius: 1000.0,
},
)
import static io.qdrant.client.ConditionFactory.geoRadius;
geoRadius("location", 52.520711, 13.403683, 1000.0f);
using static Qdrant.Client.Grpc.Conditions;
GeoRadius("location", 52.520711, 13.403683, 1000.0f);
import "github.com/qdrant/go-client/qdrant"
qdrant.NewGeoRadius("location", 52.520711, 13.403683, 1000.0)
它匹配以 center 为中心,半径为 radius 米的圆内的 location。
如果存储了多个值,则至少有一个必须符合条件。这些条件只能应用于符合 地理数据格式 的 payload。
地理多边形
地理多边形搜索在您想要查找不规则形状区域(例如国家边界或森林边界)内的点时很有用。多边形始终具有外环,并且可以选择性地包含内环。带岛屿的湖泊将是内环的一个例子。如果您想查找水中的点而不是岛上的点,您将为该岛创建一个内环。
定义环时,必须为您的点选择顺时针或逆时针排序。多边形的第一个点和最后一个点必须相同。
目前,我们仅支持未投影的全局坐标(十进制经度和纬度),并且与数据类型无关。
{
"key": "location",
"geo_polygon": {
"exterior": {
"points": [
{ "lon": -70.0, "lat": -70.0 },
{ "lon": 60.0, "lat": -70.0 },
{ "lon": 60.0, "lat": 60.0 },
{ "lon": -70.0, "lat": 60.0 },
{ "lon": -70.0, "lat": -70.0 }
]
},
"interiors": [
{
"points": [
{ "lon": -65.0, "lat": -65.0 },
{ "lon": 0.0, "lat": -65.0 },
{ "lon": 0.0, "lat": 0.0 },
{ "lon": -65.0, "lat": 0.0 },
{ "lon": -65.0, "lat": -65.0 }
]
}
]
}
}
models.FieldCondition(
key="location",
geo_polygon=models.GeoPolygon(
exterior=models.GeoLineString(
points=[
models.GeoPoint(
lon=-70.0,
lat=-70.0,
),
models.GeoPoint(
lon=60.0,
lat=-70.0,
),
models.GeoPoint(
lon=60.0,
lat=60.0,
),
models.GeoPoint(
lon=-70.0,
lat=60.0,
),
models.GeoPoint(
lon=-70.0,
lat=-70.0,
),
]
),
interiors=[
models.GeoLineString(
points=[
models.GeoPoint(
lon=-65.0,
lat=-65.0,
),
models.GeoPoint(
lon=0.0,
lat=-65.0,
),
models.GeoPoint(
lon=0.0,
lat=0.0,
),
models.GeoPoint(
lon=-65.0,
lat=0.0,
),
models.GeoPoint(
lon=-65.0,
lat=-65.0,
),
]
)
],
),
)
{
key: "location",
geo_polygon: {
exterior: {
points: [
{
lon: -70.0,
lat: -70.0
},
{
lon: 60.0,
lat: -70.0
},
{
lon: 60.0,
lat: 60.0
},
{
lon: -70.0,
lat: 60.0
},
{
lon: -70.0,
lat: -70.0
}
]
},
interiors: [
{
points: [
{
lon: -65.0,
lat: -65.0
},
{
lon: 0,
lat: -65.0
},
{
lon: 0,
lat: 0
},
{
lon: -65.0,
lat: 0
},
{
lon: -65.0,
lat: -65.0
}
]
}
]
}
}
use qdrant_client::qdrant::{Condition, GeoLineString, GeoPoint, GeoPolygon};
Condition::geo_polygon(
"location",
GeoPolygon {
exterior: Some(GeoLineString {
points: vec![
GeoPoint {
lon: -70.0,
lat: -70.0,
},
GeoPoint {
lon: 60.0,
lat: -70.0,
},
GeoPoint {
lon: 60.0,
lat: 60.0,
},
GeoPoint {
lon: -70.0,
lat: 60.0,
},
GeoPoint {
lon: -70.0,
lat: -70.0,
},
],
}),
interiors: vec![GeoLineString {
points: vec![
GeoPoint {
lon: -65.0,
lat: -65.0,
},
GeoPoint {
lon: 0.0,
lat: -65.0,
},
GeoPoint { lon: 0.0, lat: 0.0 },
GeoPoint {
lon: -65.0,
lat: 0.0,
},
GeoPoint {
lon: -65.0,
lat: -65.0,
},
],
}],
},
)
import static io.qdrant.client.ConditionFactory.geoPolygon;
import io.qdrant.client.grpc.Common.GeoLineString;
import io.qdrant.client.grpc.Common.GeoPoint;
import java.util.List;
geoPolygon(
"location",
GeoLineString.newBuilder()
.addAllPoints(
List.of(
GeoPoint.newBuilder().setLon(-70.0).setLat(-70.0).build(),
GeoPoint.newBuilder().setLon(60.0).setLat(-70.0).build(),
GeoPoint.newBuilder().setLon(60.0).setLat(60.0).build(),
GeoPoint.newBuilder().setLon(-70.0).setLat(60.0).build(),
GeoPoint.newBuilder().setLon(-70.0).setLat(-70.0).build()))
.build(),
List.of(
GeoLineString.newBuilder()
.addAllPoints(
List.of(
GeoPoint.newBuilder().setLon(-65.0).setLat(-65.0).build(),
GeoPoint.newBuilder().setLon(0.0).setLat(-65.0).build(),
GeoPoint.newBuilder().setLon(0.0).setLat(0.0).build(),
GeoPoint.newBuilder().setLon(-65.0).setLat(0.0).build(),
GeoPoint.newBuilder().setLon(-65.0).setLat(-65.0).build()))
.build()));
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
GeoPolygon(
field: "location",
exterior: new GeoLineString
{
Points =
{
new GeoPoint { Lat = -70.0, Lon = -70.0 },
new GeoPoint { Lat = 60.0, Lon = -70.0 },
new GeoPoint { Lat = 60.0, Lon = 60.0 },
new GeoPoint { Lat = -70.0, Lon = 60.0 },
new GeoPoint { Lat = -70.0, Lon = -70.0 }
}
},
interiors: [
new()
{
Points =
{
new GeoPoint { Lat = -65.0, Lon = -65.0 },
new GeoPoint { Lat = 0.0, Lon = -65.0 },
new GeoPoint { Lat = 0.0, Lon = 0.0 },
new GeoPoint { Lat = -65.0, Lon = 0.0 },
new GeoPoint { Lat = -65.0, Lon = -65.0 }
}
}
]
);
import "github.com/qdrant/go-client/qdrant"
qdrant.NewGeoPolygon("location",
&qdrant.GeoLineString{
Points: []*qdrant.GeoPoint{
{Lat: -70, Lon: -70},
{Lat: 60, Lon: -70},
{Lat: 60, Lon: 60},
{Lat: -70, Lon: 60},
{Lat: -70, Lon: -70},
},
}, &qdrant.GeoLineString{
Points: []*qdrant.GeoPoint{
{Lat: -65, Lon: -65},
{Lat: 0, Lon: -65},
{Lat: 0, Lon: 0},
{Lat: -65, Lon: 0},
{Lat: -65, Lon: -65},
},
})
匹配被认为是给定多边形外部内部或边界上的任何点位置,但不在任何内部范围内。
如果为一个点存储了多个位置值,则任何匹配的值都将把该点作为结果集中的候选点包含在内。这些条件只能应用于符合 地理数据格式 的 payload。
值计数
除了直接值比较外,还可以按值的数量进行过滤。
例如,给定数据
[
{ "id": 1, "name": "product A", "comments": ["Very good!", "Excellent"] },
{ "id": 2, "name": "product B", "comments": ["meh", "expected more", "ok"] }
]
我们只能在评论数超过两条的项目中执行搜索
{
"key": "comments",
"values_count": {
"gt": 2
}
}
models.FieldCondition(
key="comments",
values_count=models.ValuesCount(gt=2),
)
{
key: 'comments',
values_count: {gt: 2}
}
use qdrant_client::qdrant::{Condition, ValuesCount};
Condition::values_count(
"comments",
ValuesCount {
gt: Some(2),
..Default::default()
},
)
import static io.qdrant.client.ConditionFactory.valuesCount;
import io.qdrant.client.grpc.Common.ValuesCount;
valuesCount("comments", ValuesCount.newBuilder().setGt(2).build());
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
ValuesCount("comments", new ValuesCount { Gt = 2 });
import "github.com/qdrant/go-client/qdrant"
qdrant.NewValuesCount("comments", &qdrant.ValuesCount{
Gt: qdrant.PtrOf(uint64(2)),
})
结果将是
[{ "id": 2, "name": "product B", "comments": ["meh", "expected more", "ok"] }]
如果存储的值不是数组,则假定值的数量等于 1。
是否为空 (Is Empty)
有时过滤掉缺少某些值的记录也很有用。IsEmpty 条件可以帮助您做到这一点
{
"is_empty": {
"key": "reports"
}
}
models.IsEmptyCondition(
is_empty=models.PayloadField(key="reports"),
)
{
is_empty: {
key: "reports"
}
}
use qdrant_client::qdrant::Condition;
Condition::is_empty("reports")
import static io.qdrant.client.ConditionFactory.isEmpty;
isEmpty("reports");
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
IsEmpty("reports");
import "github.com/qdrant/go-client/qdrant"
qdrant.NewIsEmpty("reports")
此条件将匹配字段 reports 不存在、或者值为 null 或 [] 的所有记录。
是否为 Null (Is Null)
无法使用 match 条件测试 NULL 值。我们必须改用 IsNull 条件
{
"is_null": {
"key": "reports"
}
}
models.IsNullCondition(
is_null=models.PayloadField(key="reports"),
)
{
is_null: {
key: "reports"
}
}
use qdrant_client::qdrant::Condition;
Condition::is_null("reports")
import static io.qdrant.client.ConditionFactory.isNull;
isNull("reports");
using Qdrant.Client.Grpc;
using static Qdrant.Client.Grpc.Conditions;
IsNull("reports");
import "github.com/qdrant/go-client/qdrant"
qdrant.NewIsNull("reports")
此条件将匹配字段 reports 存在且值为 NULL 的所有记录。
Has id(拥有 id)
这种类型的查询与 payload 无关,但在某些情况下非常有用。例如,用户可以将某些特定的搜索结果标记为无关,或者我们只想在指定的点中进行搜索。
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{ "has_id": [1,3,5,7,9,11] }
]
}
...
}
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
must=[
models.HasIdCondition(has_id=[1, 3, 5, 7, 9, 11]),
],
),
)
client.scroll("{collection_name}", {
filter: {
must: [
{
has_id: [1, 3, 5, 7, 9, 11],
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
use qdrant_client::Qdrant;
let client = Qdrant::from_url("https://:6334").build()?;
client
.scroll(
ScrollPointsBuilder::new("{collection_name}")
.filter(Filter::must([Condition::has_id([1, 3, 5, 7, 9, 11])])),
)
.await?;
import static io.qdrant.client.ConditionFactory.hasId;
import static io.qdrant.client.PointIdFactory.id;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
import java.util.List;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addMust(hasId(List.of(id(1), id(3), id(5), id(7), id(9), id(11))))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(collectionName: "{collection_name}", filter: HasId([1, 3, 5, 7, 9, 11]));
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewHasID(
qdrant.NewIDNum(1),
qdrant.NewIDNum(3),
qdrant.NewIDNum(5),
qdrant.NewIDNum(7),
qdrant.NewIDNum(9),
qdrant.NewIDNum(11),
),
},
},
})
过滤后的点将是
[
{ "id": 1, "city": "London", "color": "green" },
{ "id": 3, "city": "London", "color": "blue" },
{ "id": 5, "city": "Moscow", "color": "green" }
]
Has vector(拥有向量)
v1.13.0 起可用
此条件支持通过点上是否存在给定的命名向量来进行过滤。
例如,如果我们的集合中有两个命名向量。
PUT /collections/{collection_name}
{
"vectors": {
"image": {
"size": 4,
"distance": "Dot"
},
"text": {
"size": 8,
"distance": "Cosine"
}
},
"sparse_vectors": {
"sparse-image": {},
"sparse-text": {},
},
}
集合中的某些点可能具有所有向量,某些点可能只具有其中的一个子集。
这就是您可以搜索定义了稠密 image 向量的点的方法
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{ "has_vector": "image" }
]
}
}
from qdrant_client import QdrantClient, models
client = QdrantClient(url="https://:6333")
client.scroll(
collection_name="{collection_name}",
scroll_filter=models.Filter(
must=[
models.HasVectorCondition(has_vector="image"),
],
),
)
client.scroll("{collection_name}", {
filter: {
must: [
{
has_vector: "image",
},
],
},
});
use qdrant_client::qdrant::{Condition, Filter, ScrollPointsBuilder};
use qdrant_client::Qdrant;
let client = Qdrant::from_url("https://:6334").build()?;
client
.scroll(
ScrollPointsBuilder::new("{collection_name}")
.filter(Filter::must([Condition::has_vector("image")])),
)
.await?;
import static io.qdrant.client.ConditionFactory.hasVector;
import static io.qdrant.client.PointIdFactory.id;
import io.qdrant.client.grpc.Common.Filter;
import io.qdrant.client.grpc.Points.ScrollPoints;
import java.util.List;
client
.scrollAsync(
ScrollPoints.newBuilder()
.setCollectionName("{collection_name}")
.setFilter(
Filter.newBuilder()
.addMust(hasVector("image"))
.build())
.build())
.get();
using Qdrant.Client;
using static Qdrant.Client.Grpc.Conditions;
var client = new QdrantClient("localhost", 6334);
await client.ScrollAsync(collectionName: "{collection_name}", filter: HasVector("image"));
import (
"context"
"github.com/qdrant/go-client/qdrant"
)
client, err := qdrant.NewClient(&qdrant.Config{
Host: "localhost",
Port: 6334,
})
client.Scroll(context.Background(), &qdrant.ScrollPoints{
CollectionName: "{collection_name}",
Filter: &qdrant.Filter{
Must: []*qdrant.Condition{
qdrant.NewHasVector(
"image",
),
},
},
})