Filtern
Mit Qdrant können Sie Bedingungen für die Suche oder das Abrufen von Punkten festlegen, was bedeutet, dass Sie neben Ähnlichkeitssuchen für Vektoren nach Attributen filtern können, ähnlich wie das Festlegen von SQL where
-Bedingungen. Beispielsweise können Sie Bedingungen für die Nutzlast und die id
des Punktes festlegen.
Es ist wichtig, zusätzliche Bedingungen festzulegen, wenn nicht alle Merkmale eines Objekts in einer Einbettung ausgedrückt werden können. Beispielsweise verschiedene Geschäftsanforderungen wie Lagerverfügbarkeit, Benutzerstandort oder erwarteter Preiskorridor.
Filterbedingungen
Qdrant ermöglicht es Ihnen, Bedingungen in Klauseln zu kombinieren. Klauseln sind verschiedene logische Operationen wie ODER
, UND
und NICHT
. Die Klauseln können rekursiv ineinander verschachtelt werden, so dass Sie jeden booleschen Ausdruck nachbilden können.
Schauen wir uns die implementierten Klauseln in Qdrant an.
Angenommen, wir haben eine Reihe von Punkten mit Nutzlasten:
[
{ "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": "Moskau", "color": "grün" },
{ "id": 6, "city": "Moskau", "color": "blau" }
]
Muss
Beispiel:
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{ "key": "city", "match": { "value": "London" } },
{ "key": "color", "match": { "value": "rot" } }
]
}
...
}
Der gefilterte Punkt wird sein:
[{ "id": 2, "city": "London", "color": "red" }]
Bei Verwendung von must
ist die Klausel nur dann true
, wenn jede in must
aufgeführte Bedingung erfüllt ist. In diesem Sinne entspricht must
dem UND
-Operator.
Sollte
Should
ist ähnlich wie der ODER
-Operator in SQL.
Beispiel:
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{ "key": "city", "match": { "value": "London" } },
{ "key": "color", "match": { "value": "rot" } }
]
}
...
}
Die gefilterten Punkte werden sein:
[
{ "id": 1, "city": "London", "color": "grün" },
{ "id": 2, "city": "London", "color": "rot" },
{ "id": 3, "city": "London", "color": "blau" },
{ "id": 4, "city": "Berlin", "color": "rot" }
]
Bei Verwendung von should
ist die Klausel true
, solange mindestens eine in should
aufgeführte Bedingung erfüllt ist. In diesem Sinne entspricht should
dem ODER
-Operator.
Muss nicht
Beispiel:
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must_not": [
{ "key": "city", "match": { "value": "London" } },
{ "key": "color", "match": { "value": "rot" } }
]
}
...
}
Die gefilterten Punkte werden sein:
[
{ "id": 5, "city": "Moskau", "color": "grün" },
{ "id": 6, "city": "Moskau", "color": "blau" }
]
Bei Verwendung von must_not
ist die Unterklausel nur dann true
, wenn keine der in must_not
aufgeführten Bedingungen erfüllt ist. In diesem Sinne entspricht must_not
dem Ausdruck (NICHT A) UND (NICHT B) UND (NICHT C)
.
Kombination von Bedingungen
Es ist möglich, mehrere Bedingungen gleichzeitig zu verwenden:
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{ "key": "city", "match": { "value": "London" } }
],
"must_not": [
{ "key": "color", "match": { "value": "rot" } }
]
}
...
}
Die gefilterten Punkte werden sein:
[
{ "id": 1, "city": "London", "color": "grün" },
{ "id": 3, "city": "London", "color": "blau" }
]
In diesem Fall werden die Bedingungen mit UND
kombiniert.
Zusätzlich können Bedingungen rekursiv verschachtelt werden. Zum Beispiel:
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must_not": [
{
"must": [
{ "key": "city", "match": { "value": "London" } },
{ "key": "color", "match": { "value": "rot" } }
]
}
]
}
...
}
Die gefilterten Punkte werden sein:
[
{ "id": 1, "city": "London", "color": "grün" },
{ "id": 3, "city": "London", "color": "blau" },
{ "id": 4, "city": "Berlin", "color": "rot" },
{ "id": 5, "city": "Moskau", "color": "grün" },
{ "id": 6, "city": "Moskau", "color": "blau" }
]
Bedingungsfilterung
In der Nutzlast entsprechen unterschiedliche Wertetypen verschiedenen Arten von Abfragen, die auf sie angewendet werden können. Schauen wir uns die vorhandenen Bedingungsvarianten und die Datentypen an, auf die sie angewendet werden.
Übereinstimmung
{
"key": "color",
"match": {
"value": "rot"
}
}
Für andere Typen sehen die Übereinstimmungsbedingungen genau gleich aus, nur mit unterschiedlichen verwendeten Typen:
{
"key": "anzahl",
"match": {
"value": 0
}
}
Die einfachste Bedingung überprüft, ob der gespeicherte Wert gleich dem angegebenen Wert ist. Wenn mehrere Werte gespeichert sind, sollte mindestens einer von ihnen die Bedingung erfüllen. Dies kann auf Schlüsselwort-, Ganzzahl- und Boolesche Nutzlasten angewendet werden.
Jede Übereinstimmung
Verfügbar seit v1.1.0
Wenn Sie überprüfen möchten, ob der gespeicherte Wert einer von mehreren Werten ist, können Sie die Bedingung für jede Übereinstimmung verwenden. Die Bedingung für jede Übereinstimmung behandelt den angegebenen Wert als logische ODER-Operation. Sie kann auch als Operator IN
beschrieben werden.
Sie können sie auf Schlüsselwort- und Ganzzahlnutzlasten anwenden.
Beispiel:
{
"key": "color",
"match": {
"any": ["schwarz", "gelb"]
}
}
In diesem Beispiel wird die Bedingung erfüllt, wenn der gespeicherte Wert schwarz
oder gelb
ist.
Wenn der gespeicherte Wert ein Array ist, sollte er mindestens einen Wert enthalten, der zu einem der gegebenen Werte passt. Zum Beispiel, wenn der gespeicherte Wert ["schwarz", "grün"]
ist, wird die Bedingung erfüllt, weil "schwarz"
in ["schwarz", "gelb"]
ist.
Ausschlussübereinstimmung
Verfügbar seit v1.2.0
Wenn Sie überprüfen möchten, ob der gespeicherte Wert keiner von mehreren Werten ist, können Sie die Bedingung für die Ausschlussübereinstimmung verwenden. Die Bedingung für die Ausschlussübereinstimmung behandelt den angegebenen Wert als logische NOR-Operation. Sie kann auch als Operator NICHT IN
beschrieben werden.
Sie können sie auf Schlüsselwort- und Ganzzahlnutzlasten anwenden.
Beispiel:
{
"key": "color",
"match": {
"except": ["schwarz", "gelb"]
}
}
In diesem Beispiel wird die Bedingung erfüllt, wenn der gespeicherte Wert weder schwarz
noch gelb
ist.
Wenn der gespeicherte Wert ein Array ist, sollte er mindestens einen Wert enthalten, der zu keinem der gegebenen Werte passt. Zum Beispiel, wenn der gespeicherte Wert ["schwarz", "grün"]
ist, wird die Bedingung erfüllt, weil "grün"
nicht zu "schwarz"
oder "gelb"
passt.
Verschachtelte Schlüssel
Verfügbar ab Version v1.1.0
Da das Nutzlastobjekt ein beliebiges JSON-Objekt ist, müssen möglicherweise verschachtelte Felder gefiltert werden.
Aus Gründen der Bequemlichkeit verwenden wir eine Syntax, die dem Jq Projekt ähnelt.
Angenommen, wir haben eine Reihe von Punkten mit der folgenden Nutzlast:
[
{
"id": 1,
"country": {
"name": "Deutschland",
"cities": [
{
"name": "Berlin",
"population": 3.7,
"sightseeing": ["Brandenburger Tor", "Reichstag"]
},
{
"name": "München",
"population": 1.5,
"sightseeing": ["Marienplatz", "Olympiapark"]
}
]
}
},
{
"id": 2,
"country": {
"name": "Japan",
"cities": [
{
"name": "Tokio",
"population": 9.3,
"sightseeing": ["Tokyo Tower", "Tokyo Skytree"]
},
{
"name": "Osaka",
"population": 2.7,
"sightseeing": ["Osaka Castle", "Universal Studios Japan"]
}
]
}
}
]
Sie können die Punkt-Notation verwenden, um nach verschachtelten Feldern zu suchen.
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{
"key": "country.name",
"match": {
"value": "Deutschland"
}
}
]
}
}
Sie können auch die [ ]
-Syntax verwenden, um das Array durch die Projektion innerer Werte zu durchsuchen.
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{
"key": "country.cities[].population",
"range": {
"gte": 9.0,
}
}
]
}
}
Diese Abfrage gibt nur den Punkt mit der id 2 aus, da nur Japan eine Stadt mit einer Bevölkerung von mehr als 9.0 hat.
Verschachtelte Felder können auch ein Array sein.
POST /collections/{collection_name}/points/scroll
{
"filter": {
"should": [
{
"key": "country.cities[].sightseeing",
"match": {
"value": "Osaka Castle"
}
}
]
}
}
Diese Abfrage gibt nur den Punkt mit der id 2 aus, da nur Japan eine Stadt mit einer Sehenswürdigkeit enthält, die "Osaka Castle" einschließt.
Filterung von verschachtelten Objekten
Verfügbar ab Version 1.2.0
Standardmäßig berücksichtigen die Bedingungen das gesamte Nutzlast eines Punktes.
Beispielsweise würden die folgenden zwei Punkte in der Nutzlast übereinstimmen:
[
{
"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}
]
}
]
Die folgende Abfrage würde diese beiden Punkte erfüllen:
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
{
"key": "diet[].food",
"match": {
"value": "meat"
}
},
{
"key": "diet[].likes",
"match": {
"value": true
}
}
]
}
}
Die beiden Punkte oben werden aufgrund der Erfüllung dieser beiden Bedingungen übereinstimmen:
- "t-rex" erfüllt
diet[1].food
mit food = meat unddiet[1].likes
mit likes = true - "diplodocus" erfüllt
diet[1].food
mit food = meat unddiet[0].likes
mit likes = true
Um nur Punkte zu erhalten, die den Bedingungen für Array-Elemente entsprechen, z.B. den Punkt mit der ID 1 in diesem Beispiel, müssen Sie verschachtelte Objektfilter verwenden.
Verschachtelte Objektfilter ermöglichen das unabhängige Abfragen von Objektarrays.
Dies kann durch die Verwendung des nested
-Bedingungstyps erreicht werden, der aus dem interessierenden Nutzlastschlüssel und dem anzuwendenden Filter besteht.
Der Schlüssel sollte auf ein Objektarray verweisen und optional die eckige Klammern-Notation verwenden ("data" oder "data[]").
POST /collections/{collection_name}/points/scroll
{
"filter": {
"must": [
"nested": {
{
"key": "diet",
"filter": {
"must": [
{
"key": "food",
"match": {
"value": "meat"
}
},
{
"key": "likes",
"match": {
"value": true
}
}
]
}
}
}
]
}
}
Die Übereinstimmungslogik wird so geändert, dass sie auf der Array-Elementebene innerhalb der Nutzlast angewendet wird.
Der verschachtelte Filter funktioniert genauso wie beim Anwenden eines verschachtelten Filters auf ein einzelnes Element eines Arrays. Solange mindestens ein Element des Arrays dem verschachtelten Filter entspricht, gilt das übergeordnete Dokument als Erfüllung der Bedingung.
Einschränkung
Verschachtelte Objektfilter unterstützen die has_id
-Bedingung nicht. Wenn Sie diese benötigen, platzieren Sie diese in einer benachbarten must
-Klausel.
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] }
]
}
}
Genauetext-Übereinstimmung
Verfügbar ab Version 0.10.0
Ein spezieller Fall der match
-Bedingung ist die Bedingung für die text
-Übereinstimmung. Sie ermöglicht die Suche nach spezifischen Teilstrings, Token oder Phrasen innerhalb des Textfelds.
Die genauen Texte, die diese Bedingung erfüllen, hängen von der Konfiguration des Volltextindexes ab. Die Konfiguration wird beim Erstellen des Index definiert und ist im Volltextindex beschrieben.
Wenn das Feld keinen Volltextindex hat, funktioniert diese Bedingung basierend auf der genauen Teilstring-Übereinstimmung.
{
"key": "description",
"match": {
"text": "gut und günstig"
}
}
Wenn die Abfrage mehrere Wörter enthält, wird diese Bedingung nur erfüllt, wenn alle Wörter im Text erscheinen.
Bereich
{
"key": "Preis",
"range": {
"gt": null,
"gte": 100.0,
"lt": null,
"lte": 450.0
}
}
Die Bedingung range
legt den möglichen Wertebereich für das gespeicherte Payload fest. Wenn mehrere Werte gespeichert sind, muss mindestens ein Wert der Bedingung entsprechen.
Verfügbare Vergleichsoperationen umfassen:
-
gt
- größer als -
gte
- größer als oder gleich -
lt
- kleiner als -
lte
- kleiner als oder gleich
Es kann auf Gleitkommazahlen und ganzzahlige Payloads angewendet werden.
Geografisches Begrenzungsquadrat
{
"key": "Standort",
"geo_bounding_box": {
"bottom_right": {
"lat": 52.495862,
"lon": 13.455868
},
"top_left": {
"lat": 52.520711,
"lon": 13.403683
}
}
}
Es stimmt mit dem Standort
innerhalb des Rechtecks mit Koordinaten an der unteren rechten Ecke als bottom_right
und Koordinaten an der oberen linken Ecke als top_left
überein.
Geografischer Radius
{
"key": "Standort",
"geo_radius": {
"center": {
"lat": 52.520711,
"lon": 13.403683
},
"radius": 1000.0
}
}
Es stimmt mit dem Standort
innerhalb des Kreises mit dem Zentrum bei center
und einem Radius von radius
Metern überein.
Wenn mehrere Werte gespeichert sind, muss mindestens ein Wert der Bedingung entsprechen. Diese Bedingungen können nur auf Payloads angewendet werden, die dem geografischen Datenformat entsprechen.
Wertanzahl
Neben dem direkten Wertvergleich kann die Filterung auch auf der Anzahl der Werte basieren.
Beispielsweise ausgehend von den folgenden Daten:
[
{ "id": 1, "name": "Produkt A", "comments": ["Sehr gut!", "Ausgezeichnet"] },
{ "id": 2, "name": "Produkt B", "comments": ["Fair", "Erwarte mehr", "Gut"] }
]
Wir können nur nach Elementen mit mehr als zwei Kommentaren suchen:
{
"key": "comments",
"values_count": {
"gt": 2
}
}
Das Ergebnis wird sein:
[{ "id": 2, "name": "Produkt B", "comments": ["Fair", "Erwarte mehr", "Gut"] }]
Wenn der gespeicherte Wert kein Array ist, wird davon ausgegangen, dass die Wertanzahl gleich 1 ist.
Ist leer
Manchmal ist es nützlich, Datensätze ohne bestimmte Werte zu filtern. Die IsEmpty
-Bedingung kann Ihnen dabei helfen:
{
"is_empty": {
"key": "Berichte"
}
}
Diese Bedingung entspricht allen Datensätzen, in denen das Feld Berichte
nicht existiert oder den Wert null
oder []
hat.
IsEmpty ist oft sehr nützlich, wenn es in Verbindung mit der logischen Negation must_not verwendet wird. In diesem Fall werden alle nicht leeren Werte ausgewählt.
Ist Null
Die match-Bedingung kann keine NULL
-Werte testen. Wir müssen die IsNull
-Bedingung verwenden:
{
"is_null": {
"key": "Berichte"
}
}
Diese Bedingung entspricht allen Datensätzen, in denen das Feld Berichte
existiert und den Wert NULL
hat.
Hat ID
Diese Art der Abfrage ist unabhängig von Payloads, aber in bestimmten Situationen sehr nützlich. Zum Beispiel möchten Benutzer bestimmte Suchergebnisse als irrelevant markieren, oder wir möchten nur zwischen bestimmten Punkten suchen.
POST /Sammlungen/{Sammlungsname}/Punkte/scrollen
{
"Filter": {
"muss": [
{ "hat_id": [1,3,5,7,9,11] }
]
}
...
}
Die gefilterten Punkte werden sein:
[
{ "id": 1, "Stadt": "London", "Farbe": "grün" },
{ "id": 3, "Stadt": "London", "Farbe": "blau" },
{ "id": 5, "Stadt": "Moskau", "Farbe": "grün" }
]