Gefilterte Suche
Eine ANN-Suche findet Vektoreinbettungen, die den angegebenen Vektoreinbettungen am ähnlichsten sind. Die Suchergebnisse sind jedoch nicht immer korrekt. Sie können Filterbedingungen in eine Suchanfrage aufnehmen, so dass Milvus vor der ANN-Suche eine Metadatenfilterung durchführt und den Suchbereich von der gesamten Sammlung auf die Entitäten reduziert, die den angegebenen Filterbedingungen entsprechen.
Übersicht
In Milvus werden gefilterte Suchen in zwei Typen unterteilt - Standardfilterung und iterative Filterung - je nachdem, in welchem Stadium die Filterung angewendet wird.
Standard-Filterung
Wenn eine Sammlung sowohl Vektoreinbettungen als auch deren Metadaten enthält, können Sie die Metadaten vor der ANN-Suche filtern, um die Relevanz des Suchergebnisses zu verbessern. Sobald Milvus eine Suchanfrage mit einer Filterbedingung erhält, schränkt es den Suchbereich auf die Entitäten ein, die der angegebenen Filterbedingung entsprechen.
Gefilterte Suche
Wie im obigen Diagramm dargestellt, enthält die Suchanfrage chunk like "%red%" als Filterbedingung, was anzeigt, dass Milvus die ANN-Suche in allen Entitäten durchführen soll, die das Wort red im Feld chunk enthalten. Konkret geht Milvus wie folgt vor:
Filterung der Entitäten, die mit den Filterbedingungen in der Suchanfrage übereinstimmen.
Führt die ANN-Suche innerhalb der gefilterten Entitäten durch.
Gibt die Top-K Entitäten zurück.
Iterative Filterung
Der Standard-Filterungsprozess schränkt den Suchbereich effektiv auf einen kleinen Bereich ein. Zu komplexe Filterausdrücke können jedoch zu einer sehr hohen Suchlatenz führen. In solchen Fällen kann die iterative Filterung als Alternative dienen und dazu beitragen, die Arbeitslast der skalaren Filterung zu verringern.
Iterative Filterung
Wie im obigen Diagramm dargestellt, führt eine Suche mit iterativer Filterung die Vektorsuche in Iterationen durch. Jede Entität, die vom Iterator zurückgegeben wird, wird einer skalaren Filterung unterzogen, und dieser Prozess wird fortgesetzt, bis die angegebenen TopK-Ergebnisse erreicht sind.
Diese Methode reduziert die Anzahl der Entitäten, die einer skalaren Filterung unterzogen werden, erheblich und ist daher besonders vorteilhaft für den Umgang mit sehr komplexen Filterausdrücken.
Es ist jedoch wichtig zu beachten, dass der Iterator die Entitäten einzeln verarbeitet. Dieser sequenzielle Ansatz kann zu längeren Verarbeitungszeiten oder potenziellen Leistungsproblemen führen, insbesondere wenn eine große Anzahl von Entitäten der skalaren Filterung unterzogen wird.
Beispiele
Dieser Abschnitt demonstriert, wie eine gefilterte Suche durchgeführt werden kann. Die Codeschnipsel in diesem Abschnitt gehen davon aus, dass Sie bereits die folgenden Entitäten in Ihrer Sammlung haben. Jede Entität hat vier Felder, nämlich id, vector, color und likes.
[
{"id": 0, "vector": [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592], "color": "pink_8682", "likes": 165},
{"id": 1, "vector": [0.19886812562848388, 0.06023560599112088, 0.6976963061752597, 0.2614474506242501, 0.838729485096104], "color": "red_7025", "likes": 25},
{"id": 2, "vector": [0.43742130801983836, -0.5597502546264526, 0.6457887650909682, 0.7894058910881185, 0.20785793220625592], "color": "orange_6781", "likes": 764},
{"id": 3, "vector": [0.3172005263489739, 0.9719044792798428, -0.36981146090600725, -0.4860894583077995, 0.95791889146345], "color": "pink_9298", "likes": 234},
{"id": 4, "vector": [0.4452349528804562, -0.8757026943054742, 0.8220779437047674, 0.46406290649483184, 0.30337481143159106], "color": "red_4794", "likes": 122},
{"id": 5, "vector": [0.985825131989184, -0.8144651566660419, 0.6299267002202009, 0.1206906911183383, -0.1446277761879955], "color": "yellow_4222", "likes": 12},
{"id": 6, "vector": [0.8371977790571115, -0.015764369584852833, -0.31062937026679327, -0.562666951622192, -0.8984947637863987], "color": "red_9392", "likes": 58},
{"id": 7, "vector": [-0.33445148015177995, -0.2567135004164067, 0.8987539745369246, 0.9402995886420709, 0.5378064918413052], "color": "grey_8510", "likes": 775},
{"id": 8, "vector": [0.39524717779832685, 0.4000257286739164, -0.5890507376891594, -0.8650502298996872, -0.6140360785406336], "color": "white_9381", "likes": 876},
{"id": 9, "vector": [0.5718280481994695, 0.24070317428066512, -0.3737913482606834, -0.06726932177492717, -0.6980531615588608], "color": "purple_4976", "likes": 765}
]
Suche mit Standardfilterung
Die folgenden Codeschnipsel demonstrieren eine Suche mit Standardfilterung. Die Anfrage im folgenden Codeschnipsel enthält eine Filterungsbedingung und mehrere Ausgabefelder.
from pymilvus import MilvusClient
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus"
)
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
collection_name="my_collection",
data=[query_vector],
limit=5,
# highlight-start
filter='color like "red%" and likes > 50',
output_fields=["color", "likes"]
# highlight-end
)
for hits in res:
print("TopK results:")
for hit in hits:
print(hit)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.SearchReq
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("http://localhost:19530")
.token("root:Milvus")
.build());
FloatVec queryVector = new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f});
SearchReq searchReq = SearchReq.builder()
.collectionName("my_collection")
.data(Collections.singletonList(queryVector))
.topK(5)
.filter("color like \"red%\" and likes > 50")
.outputFields(Arrays.asList("color", "likes"))
.build();
SearchResp searchResp = client.search(searchReq);
List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
System.out.println("TopK results:");
for (SearchResp.SearchResult result : results) {
System.out.println(result);
}
}
// Output
// TopK results:
// SearchResp.SearchResult(entity={color=red_4794, likes=122}, score=0.5975797, id=4)
// SearchResp.SearchResult(entity={color=red_9392, likes=58}, score=-0.24996188, id=6)
import (
"context"
"fmt"
"github.com/milvus-io/milvus/client/v2/entity"
"github.com/milvus-io/milvus/client/v2/milvusclient"
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
milvusAddr := "localhost:19530"
token := "root:Milvus"
client, err := client.New(ctx, &client.ClientConfig{
Address: milvusAddr,
APIKey: token,
})
if err != nil {
fmt.Println(err.Error())
// handle error
}
defer client.Close(ctx)
queryVector := []float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"my_collection", // collectionName
5, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithConsistencyLevel(entity.ClStrong).
WithANNSField("vector").
WithFilter("color like 'red%' and likes > 50").
WithOutputFields("color", "likes"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
fmt.Println("color: ", resultSet.GetColumn("color").FieldData().GetScalars())
fmt.Println("likes: ", resultSet.GetColumn("likes").FieldData().GetScalars())
}
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const address = "http://localhost:19530";
const token = "root:Milvus";
const client = new MilvusClient({address, token});
const query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
const res = await client.search({
collection_name: "my_collection",
data: [query_vector],
limit: 5,
// highlight-start
filters: 'color like "red%" and likes > 50',
output_fields: ["color", "likes"]
// highlight-end
})
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
],
"annsField": "vector",
"filter": "color like \"red%\" and likes > 50",
"limit": 5,
"outputFields": ["color", "likes"]
}'
# {"code":0,"cost":0,"data":[]}
Die in der Suchanfrage enthaltene Filterbedingung lautet color like "red%" and likes > 50. Sie verwendet den Operator and, um zwei Bedingungen einzuschließen: Die erste fragt nach Entitäten, deren Wert im Feld color mit red beginnt, und die andere fragt nach Entitäten, deren Wert im Feld likes größer als 50 ist. Es gibt nur zwei Entitäten, die diese Bedingungen erfüllen. Wenn das Top-K auf 3 gesetzt ist, berechnet Milvus den Abstand zwischen diesen beiden Entitäten zum Abfragevektor und gibt sie als Suchergebnisse zurück.
[
{
"id": 4,
"distance": 0.3345786594834839,
"entity": {
"vector": [0.4452349528804562, -0.8757026943054742, 0.8220779437047674, 0.46406290649483184, 0.30337481143159106],
"color": "red_4794",
"likes": 122
}
},
{
"id": 6,
"distance": 0.6638239834383389,
"entity": {
"vector": [0.8371977790571115, -0.015764369584852833, -0.31062937026679327, -0.562666951622192, -0.8984947637863987],
"color": "red_9392",
"likes": 58
}
},
]
Weitere Informationen zu den Operatoren, die Sie beim Filtern von Metadaten verwenden können, finden Sie unter Filtern.
Suche mit iterativer Filterung
Um eine gefilterte Suche mit iterativer Filterung durchzuführen, können Sie wie folgt vorgehen:
from pymilvus import MilvusClient
client = MilvusClient(
uri="http://localhost:19530",
token="root:Milvus"
)
query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
res = client.search(
collection_name="my_collection",
data=[query_vector],
limit=5,
# highlight-start
filter='color like "red%" and likes > 50',
output_fields=["color", "likes"],
search_params={
"hints": "iterative_filter"
}
# highlight-end
)
for hits in res:
print("TopK results:")
for hit in hits:
print(hit)
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.service.vector.request.SearchReq;
import io.milvus.v2.service.vector.request.data.FloatVec;
import io.milvus.v2.service.vector.response.SearchResp;
MilvusClientV2 client = new MilvusClientV2(ConnectConfig.builder()
.uri("http://localhost:19530")
.token("root:Milvus")
.build());
FloatVec queryVector = new FloatVec(new float[]{0.3580376395471989f, -0.6023495712049978f, 0.18414012509913835f, -0.26286205330961354f, 0.9029438446296592f});
SearchReq searchReq = SearchReq.builder()
.collectionName("my_collection")
.data(Collections.singletonList(queryVector))
.topK(5)
.filter("color like \"red%\" and likes > 50")
.outputFields(Arrays.asList("color", "likes"))
.searchParams(new HashMap<>("hints", "iterative_filter"))
.build();
SearchResp searchResp = client.search(searchReq);
List<List<SearchResp.SearchResult>> searchResults = searchResp.getSearchResults();
for (List<SearchResp.SearchResult> results : searchResults) {
System.out.println("TopK results:");
for (SearchResp.SearchResult result : results) {
System.out.println(result);
}
}
// Output
// TopK results:
// SearchResp.SearchResult(entity={color=red_4794, likes=122}, score=0.5975797, id=4)
// SearchResp.SearchResult(entity={color=red_9392, likes=58}, score=-0.24996188, id=6)
import (
"context"
"fmt"
"github.com/milvus-io/milvus/client/v2/entity"
"github.com/milvus-io/milvus/client/v2/milvusclient"
)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
milvusAddr := "localhost:19530"
token := "root:Milvus"
client, err := client.New(ctx, &client.ClientConfig{
Address: milvusAddr,
APIKey: token,
})
if err != nil {
fmt.Println(err.Error())
// handle error
}
defer client.Close(ctx)
queryVector := []float32{0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592}
resultSets, err := client.Search(ctx, milvusclient.NewSearchOption(
"my_collection", // collectionName
5, // limit
[]entity.Vector{entity.FloatVector(queryVector)},
).WithConsistencyLevel(entity.ClStrong).
WithANNSField("vector").
WithFilter("color like 'red%' and likes > 50").
WithOutputFields("color", "likes").
WithSearchParam("hints", "iterative_filter"))
if err != nil {
fmt.Println(err.Error())
// handle error
}
for _, resultSet := range resultSets {
fmt.Println("IDs: ", resultSet.IDs.FieldData().GetScalars())
fmt.Println("Scores: ", resultSet.Scores)
fmt.Println("color: ", resultSet.GetColumn("color").FieldData().GetScalars())
fmt.Println("likes: ", resultSet.GetColumn("likes").FieldData().GetScalars())
}
import { MilvusClient, DataType } from "@zilliz/milvus2-sdk-node";
const address = "http://localhost:19530";
const token = "root:Milvus";
const client = new MilvusClient({address, token});
const query_vector = [0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
const res = await client.search({
collection_name: "filtered_search_collection",
data: [query_vector],
limit: 5,
// highlight-start
filters: 'color like "red%" and likes > 50',
hints: "iterative_filter",
output_fields: ["color", "likes"]
// highlight-end
})
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/entities/search" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"data": [
[0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592]
],
"annsField": "vector",
"filter": "color like \"red%\" and likes > 50",
"searchParams": {"hints": "iterative_filter"},
"limit": 5,
"outputFields": ["color", "likes"]
}'
# {"code":0,"cost":0,"data":[]}