Hinzufügen eines Filters in einer Vektorabfrage in Azure AI Search

Sie können eine Vektorabfrageanforderung definieren, die einen Filterausdruck enthält, um Ihren Abfragen Ein- oder Ausschlusskriterien hinzuzufügen. In diesem Artikel werden folgende Vorgehensweisen behandelt:

In diesem Artikel wird REST zur Veranschaulichung verwendet. Codebeispiele in anderen Sprachen finden Sie im GitHub-Repository für Azure-Search-Vektorbeispiele für End-to-End-Lösungen, die Vektorabfragen enthalten.

Sie können auch den Such-Explorer im Azure-Portal verwenden, um Vektorinhalte abzufragen. Wenn Sie die JSON-Ansicht verwenden, können Sie Filter hinzufügen und den Filtermodus angeben.

Funktionsweise der Filterung in einer Vektorabfrage

Filter werden auf filterable-Nichtvektorfelder (bei denen es sich entweder um ein Zeichenfolgenfeld oder ein numerisches Feld handelt) angewendet, um Suchdokumente basierend auf Filterkriterien einzuschließen oder auszuschließen. Obwohl ein Vektorfeld nicht selbst gefiltert werden kann, können Filter auf andere Felder im selben Index angewendet werden, wobei Dokumente, die auch Vektorfelder enthalten können, ein- oder ausgeschlossen werden.

Filter werden basierend auf dem Parameter vor oder nach der vectorFilterMode Abfrageausführung angewendet.

Definieren eines -Filters

Filter bestimmen den Bereich einer Vektorabfrage. Filter werden festgelegt und über nicht Vektorzeichenfolgen und numerische Felder durchlaufen, die als filterable im Index zugeschrieben werden, aber der Zweck eines Filters bestimmt, was die Vektorabfrage ausgeführt wird: den gesamten durchsuchbaren Bereich oder den Inhalt eines Suchergebnisses.

Wenn Sie keine Quellfelder mit Text oder numerischen Werten haben, suchen Sie nach Dokumentmetadaten, z. B. „LastModified“ oder „CreatedBy“, die in einem Metadatenfilter nützlich sein könnten.

2024-07-01 ist die stabile Version für diese API. Es bietet Folgendes:

  • vectorFilterMode für prefilter (Standard) oder postfilter Filterungsdmethoden.
  • filter stellt die Kriterien bereit.

Im folgenden Beispiel ist der Vektor eine Darstellung dieser Abfragezeichenfolge: „Welche Azure-Dienste unterstützen die Volltextsuche“. Die Abfrage zielt auf das contentVector-Feld ab. Der tatsächliche Vektor verfügt über 1536 Einbettungen, sodass er in diesem Beispiel zur Lesbarkeit gekürzt wird.

Die Filterkriterien werden auf ein filterbares Textfeld (category in diesem Beispiel) angewendet, bevor die Vektorabfrage von der Suchmaschine ausgeführt wird.

POST https://{{search-service-name}}.search.windows.net/indexes/{{index-name}}/docs/search?api-version=2024-07-01
Content-Type: application/json
api-key: {{admin-api-key}}
{
    "count": true,
    "select": "title, content, category",
    "filter": "category eq 'Databases'",
    "vectorFilterMode": "preFilter",
    "vectorQueries": [
        {
            "kind": "vector",
            "vector": [
                -0.009154141,
                0.018708462,
                . . . 
                -0.02178128,
                -0.00086512347
            ],
            "exhaustive": true,
            "fields": "contentVector",
            "k": 5
        }
    ]
}

Festlegen des vectorFilterMode

Der vectorFilterMode-Abfrageparameter bestimmt, ob der Filter vor oder nach der Vektorabfrageausführung angewendet wird.

Vorfiltermodus

Bei der Vorfilterung wird der Filter vor der Abfrageausführung angewendet. Dadurch wird der Suchbereich verkleinert, in dem der Algorithmus für die Vektorsuche nach ähnlichen Inhalten sucht.

In einer Vektorabfrage ist preFilter die Standardeinstellung.

Diagramm der Vorfilter.

Nachfiltermodus

Bei der Nachfilterung werden Filter nach der Abfrageausführung angewendet, um die Suchergebnisse einzugrenzen.

Diagramm der Nachfilter.

Benchmarktests für Vektorfiltermodi

Um die Bedingungen zu verstehen, unter denen ein Filtermodus besser funktioniert als der andere, haben wir eine Reihe von Tests durchgeführt, um Abfrageergebnisse für kleine, mittlere und große Indizes auszuwerten.

  • Klein (100.000 Dokumente, 2,5 GB Index, 1.536 Dimensionen)
  • Mittel (1 Mio. Dokumente, 25 GB Index, 1.536 Dimensionen)
  • Groß (1 Mrd. Dokumente, 1,9 TB Index, 96 Dimensionen)

Für die kleinen und mittleren Workloads haben wir einen S2-Dienst (Standard 2) mit einer einzelnen Partition und einem einzelnen Replikat verwendet. Für die große Workload haben wir einen S3-Dienst (Standard 3) mit 12 Partitionen und einem einzelnen Replikat verwendet.

Die Indizes waren gleich aufgebaut und umfassten ein Schlüsselfeld, ein Vektorfeld, ein Textfeld und ein numerisches filterbares Feld. Der folgende Index wird mithilfe der 2023-11-03-Syntax definiert.

def get_index_schema(self, index_name, dimensions):
    return {
        "name": index_name,
        "fields": [
            {"name": "id", "type": "Edm.String", "key": True, "searchable": True},
            {"name": "content_vector", "type": "Collection(Edm.Single)", "dimensions": dimensions,
              "searchable": True, "retrievable": True, "filterable": False, "facetable": False, "sortable": False,
              "vectorSearchProfile": "defaulthnsw"},
            {"name": "text", "type": "Edm.String", "searchable": True, "filterable": False, "retrievable": True,
              "sortable": False, "facetable": False},
            {"name": "score", "type": "Edm.Double", "searchable": False, "filterable": True,
              "retrievable": True, "sortable": True, "facetable": True}
        ],
      "vectorSearch": {
        "algorithms": [
            {
              "name": "defaulthnsw",
              "kind": "hnsw",
              "hnswParameters": { "metric": "euclidean" }
            }
          ],
          "profiles": [
            {
              "name": "defaulthnsw",
              "algorithm": "defaulthnsw"
            }
        ]
      }
    }

In Abfragen wurde sowohl für Vorfilter- als auch für Nachfiltervorgänge ein identischer Filter verwendet. Wir haben einen einfachen Filter verwendet, um sicherzustellen, dass Leistungsabweichungen auf den Modus und nicht auf die Komplexität des Filters zurückzuführen sind.

Die Ergebnisse wurden in Abfragen pro Sekunde (Queries Per Second, QPS) gemessen.

Wesentliche Punkte

  • Die Vorfilterung ist fast immer langsamer als die Nachfilterung (außer bei kleinen Indizes, wo die Leistung ungefähr gleich bleibt).

  • Bei größeren Datasets ist die Vorfilterung erheblich langsamer.

  • Warum also wird als Standard die Vorfilterung verwendet, wenn sie fast immer langsamer ist? Die Vorfilterung sorgt dafür, dass k Ergebnisse zurückgegeben werden, wenn sie im Index vorhanden sind. Dabei haben Abruf und Genauigkeit Vorrang vor Geschwindigkeit.

  • Die Nachfilterung ist für Kunden gedacht, für die Folgendes gilt:

    • Sie legen mehr Wert auf Geschwindigkeit als auf die Auswahl. (Bei der Nachfilterung können weniger als k Ergebnisse zurückgeben werden.)
    • Sie verwenden Filter, die nicht allzu selektiv sind.
    • Sie verfügen über Indizes mit einer Größe, die zu einer nicht akzeptablen Vorfilterleistung führt.

Details

  • Bei einem Dataset mit 100.000 Vektoren und 1.536 Dimensionen wurden folgende Ergebnisse ermittelt:

    • Bei der Filterung von mehr als 30 Prozent des Datasets waren Vor- und Nachfilterung vergleichbar.
    • Bei der Filterung von weniger als 0,1 Prozent des Datasets war die Vorfilterung etwa 50 Prozent langsamer als die Nachfilterung.
  • Bei einem Dataset mit 1 Mio. Vektoren und 1.536 Dimensionen wurden folgende Ergebnisse ermittelt:

    • Bei der Filterung von mehr als 30 Prozent des Datasets war die Vorfilterung ca. 30 Prozent langsamer.
    • Bei der Filterung von weniger als zwei Prozent des Datasets war die Vorfilterung ca. sieben Mal langsamer.
  • Bei einem Dataset mit 1 Mrd. Vektoren und 96 Dimensionen wurden folgende Ergebnisse ermittelt:

    • Bei der Filterung von mehr als fünf Prozent des Datasets war die Vorfilterung ca. 50 Prozent langsamer.
    • Bei der Filterung von weniger als zehn Prozent des Datasets war die Vorfilterung ca. sieben Mal langsamer.

Die folgende Abbildung zeigt die relativen QPS der Vorfilterung (Vorfilter-QPS dividiert durch Nachfilter-QPS).

Diagramm mit QPS-Leistung für kleine, mittlere und große Indizes für relative QPS.

Die vertikale Achse stellt die QPS der Vorfilterung den QPS der Nachfilterung gegenüber. Der Wert 0,0 bedeutet beispielsweise, dass die Vorfilterung 100 Prozent langsamer ist. 0,5 auf der vertikalen Achse bedeutet, dass die Vorfilterung 50 Prozent langsamer ist, und 1,0 bedeutet, dass Vor- und Nachfilterung gleich sind.

Die horizontale Achse stellt die Filterrate oder den Prozentsatz der Kandidatendokumente nach Anwendung des Filters dar. 1.00% bedeutet beispielsweise, dass durch die Filterkriterien ein Prozent des Suchkorpus ausgewählt wurde.