Filtry w zapytaniach wektorowych

Tryby filtru wektorowego można ustawić w zapytaniu wektorowym, aby określić, czy chcesz filtrować przed wykonaniem zapytania, czy po nim.

Filtry określają zakres zapytania wektorowego. Filtry są ustawiane i iterowane przez ciąg niewektorowy i pola liczbowe przypisane jako filterable w indeksie, ale cel filtru określa, co wykonuje zapytanie wektorowe: całe miejsce z możliwością wyszukiwania lub zawartość wyniku wyszukiwania.

W tym artykule opisano każdy tryb filtrowania i przedstawiono wskazówki dotyczące tego, kiedy należy używać każdego z nich.

Tryb filtrowania wstępnego

Filtrowanie wstępne stosuje filtry przed wykonaniem zapytania, zmniejszając obszar powierzchni wyszukiwania, na którym algorytm wyszukiwania wektorowego szuka podobnej zawartości. W zapytaniu preFilter wektorowym jest wartością domyślną.

Diagram of prefilters.

Tryb filtru słupkowego

Filtrowanie po filtrowaniu stosuje filtry po wykonaniu zapytania, zawężając wyniki wyszukiwania.

Diagram of post-filters.

Testowanie porównawcze trybów filtrowania wektorów

Aby zrozumieć warunki, w których jeden tryb filtrowania działa lepiej niż drugi, przeprowadziliśmy serię testów w celu oceny wyników zapytań w przypadku małych, średnich i dużych indeksów.

  • Mały (100 000 dokumentów, indeks 2,5 GB, 1536 wymiarów)
  • Średni (1 milion dokumentów, indeks 25 GB, 1536 wymiarów)
  • Duży (1 miliard dokumentów, indeks 1,9 TB, 96 wymiarów)

W przypadku małych i średnich obciążeń użyliśmy usługi Standardowa 2 (S2) z jedną partycją i jedną repliką. W przypadku dużego obciążenia użyliśmy usługi Standardowa 3 (S3) z 12 partycjami i jedną repliką.

Indeksy miały identyczną konstrukcję: jedno pole klucza, jedno pole wektorowe, jedno pole tekstowe i jedno pole filtrowalne liczbowo. Poniższy indeks jest zdefiniowany przy użyciu składni 2023-07-01-preview.

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,
              "vectorSearchConfiguration": "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":
        {
            "algorithmConfigurations": [
                {"name": "defaulthnsw", "kind": "hnsw", "hnswParameters": {"metric": "euclidean"}}
            ]
        }
    }

W zapytaniach użyliśmy identycznego filtru dla operacji filtrowania wstępnego i postfiltru. Użyliśmy prostego filtru, aby upewnić się, że zmiany wydajności były spowodowane trybem filtrowania, a nie złożonością filtrowania.

Wyniki zostały zmierzone w zapytaniach na sekundę (QPS).

Wnioski

  • Filtrowanie wstępne jest prawie zawsze wolniejsze niż pofiltrowaniu, z wyjątkiem małych indeksów, w których wydajność jest w przybliżeniu równa.

  • W przypadku większych zestawów danych filtrowanie wstępne jest o wielkości wolniejsze.

  • Dlaczego więc filtr wstępny jest domyślny, jeśli jest prawie zawsze wolniejszy? Wstępne filtrowanie gwarantuje, że k wyniki są zwracane, jeśli istnieją w indeksie, gdzie stronniczość sprzyja kompletności i precyzji z szybkością.

  • Filtrowanie końcowe jest przeznaczone dla klientów, którzy:

    • szybkość zaznaczenia (filtrowanie postfiltrujące może zwracać mniej niż k wyniki)
    • używanie filtrów, które nie są nadmiernie selektywne
    • mają indeksy o wystarczających rozmiarach, tak aby wydajność filtrowania wstępnego jest niedopuszczalna

Szczegóły

  • Biorąc pod uwagę zestaw danych z 100 000 wektorów o wymiarach 1536:

    • Podczas filtrowania ponad 30% zestawu danych porównywano filtrowanie wstępne i filtrowanie postfiltrujące.
    • Podczas filtrowania mniejszego niż 0,1% zestawu danych filtrowanie wstępne było o około 50% wolniejsze niż po filtrowaniu.
  • Biorąc pod uwagę zestaw danych z 1 milionami wektorów o wymiarach 1536:

    • Podczas filtrowania ponad 30% zestawu danych wstępne filtrowanie było o około 30% wolniejsze.
    • Podczas filtrowania mniejszego niż 2% zestawu danych wstępne filtrowanie było około siedmiu razy wolniejsze.
  • Biorąc pod uwagę zestaw danych z 1 miliardami wektorów o wymiarach 96:

    • Podczas filtrowania ponad 5% zestawu danych wstępne filtrowanie było o około 50% wolniejsze.
    • Podczas filtrowania mniejszego niż 10% zestawu danych wstępne filtrowanie było około siedmiu razy wolniejsze.

Na poniższym wykresie przedstawiono wstępne filtrowanie względne QPS obliczone jako wstępne filtrowanie QPS podzielone przez QPS postfilter.

Chart showing QPS performance for small, medium, and large indexes for relative QPS.

Oś pionowa to QPS wstępnego filtrowania na QPS po filtrowaniu. Na przykład wartość 0,0 oznacza, że filtrowanie wstępne jest o 100% wolniejsze, 0,5 na osi pionowej oznacza, że filtrowanie wstępne jest o 50% wolniejsze, 1,0 oznacza, że filtrowanie wstępne i filtrowanie po są równoważne.

Oś pozioma reprezentuje współczynnik filtrowania lub procent dokumentów kandydatów po zastosowaniu filtru. Na przykład oznacza, 1.00% że jeden procent korpusu wyszukiwania został wybrany przez kryteria filtru.