Indeks
Jedną z kluczowych cech Qdrant jest skuteczne połączenie indeksu wektorowego z tradycyjnym indeksem. Jest to istotne, ponieważ posiadanie jedynie indeksu wektorowego nie wystarcza do umożliwienia efektywnego wyszukiwania wektorów w warunkach filtrowania. W prostych słowach, indeks wektorowy przyspiesza wyszukiwanie wektorów, podczas gdy indeks obciążenia przyspiesza filtrowanie.
Indeks wewnątrz akapitu istnieje niezależnie, ale parametry samego indeksu są skonfigurowane dla całego zestawu.
Nie wszystkie akapity automatycznie posiadają indeksy. Zależy to od wymagań ustawień optymalizacji i zazwyczaj zależy od liczby przechowywanych punktów.
Indeks obciążenia
Indeks obciążenia w Qdrant jest podobny do indeksu w tradycyjnej bazie danych zorientowanej na dokumenty. Ten indeks jest budowany dla określonych pól i typów, służy do szybkiego odzyskiwania punktów na podstawie odpowiadających warunków filtrowania.
Służy również do dokładnej oceny kardynalności warunków filtrowania, co pomaga plannerowi zapytań wybierać strategie wyszukiwania.
Tworzenie indeksu wymaga dodatkowych zasobów obliczeniowych i pamięci, dlatego kluczowe jest staranne wybranie pól do zaindeksowania. Qdrant nie dokonuje tego wyboru za Ciebie, ale powierza to użytkownikowi.
Aby oznaczyć pole jako zindeksowane, można użyć następującej metody:
PUT /collections/{collection_name}/index
{
"field_name": "nazwa pola do zaindeksowania",
"field_schema": "keyword"
}
Dostępne typy pól to:
-
keyword
- dla obciążenia słowami kluczowymi, wpływające na warunki filtrowania. -
integer
- dla obciążenia liczbami całkowitymi, wpływające na dopasowywanie i zakres warunków filtrowania. -
float
- dla obciążenia liczbami zmiennoprzecinkowymi, wpływające na warunki filtrowania zakresu. -
bool
- dla obciążenia typu logicznego, wpływające na warunki filtrowania dopasowania (dostępne od wersji 1.4.0). -
geo
- dla obciążenia geograficznego, wpływające na warunki filtrowania obszaru ograniczającego geograficznie i promienia geograficznego. -
text
- specjalny typ indeksu odpowiedni dla obciążenia słowami kluczowymi/ciągami znaków, wpływający na warunki filtrowania pełnotekstowego.
Indeksy obciążenia mogą zużywać dodatkową pamięć, dlatego zaleca się indeksowanie jedynie pól używanych w warunkach filtrowania. Jeśli potrzebujesz filtrować na podstawie wielu pól i ograniczenia pamięci nie pozwalają zaindeksować wszystkich z nich, zaleca się wybór pól, które najbardziej ograniczają wyniki wyszukiwania. Ogólnie rzecz biorąc, im więcej unikalnych wartości ma obciążenie, tym bardziej efektywne będzie użycie indeksu.
Indeks pełnotekstowy
Dostępny od wersji 0.10.0
Qdrant obsługuje wyszukiwanie pełnotekstowe dla obciążenia łańcuchami znaków. Indeks pełnotekstowy pozwala filtrować punkty na podstawie obecności słów lub fraz w polu obciążenia.
Konfigurowanie indeksu pełnotekstowego jest nieco złożone, ponieważ można określić parametry tokenizacji. Tokenizacja polega na podziale ciągu znaków na tokeny, a następnie zindeksowaniu tych tokenów w odwróconym indeksie.
Aby utworzyć indeks pełnotekstowy, można skorzystać z następującej metody:
PUT /collections/{collection_name}/index
{
"field_name": "nazwa pola do zindeksowania",
"field_schema": {
"type": "text",
"tokenizer": "word",
"min_token_len": 2,
"max_token_len": 20,
"lowercase": true
}
}
Dostępne metody tokenizacji to:
-
word
- Dzieli ciąg na podstawie spacji, interpunkcji i znaków specjalnych. -
whitespace
- Dzieli ciąg na podstawie spacji. -
prefix
- Dzieli ciąg na podstawie spacji, interpunkcji i znaków specjalnych, a następnie tworzy indeks prefiksowy dla każdego słowa. Na przykładhello
zostanie zindeksowane jakoh
,he
,hel
,hell
,hello
. -
multilingual
- Specjalny typ tokenizacji oparty na pakiecie charabia. Pozwala on na poprawną tokenizację i lematyzację wielu języków, w tym języków z nielatynskim alfabetem i separatorami innymi niż spacja. Aby uzyskać pełną listę obsługiwanych języków i opcji normalizacji, należy odwołać się do dokumentacji charabia. W domyślnej konfiguracji kompilacji, qdrant nie zawiera obsługi wszystkich języków, ponieważ zwiększyłoby to rozmiar plików binarnych. Chiny, Japonia i Korea nie są domyślnie włączone, ale można je włączyć, kompilując qdrant ze źródła przy użyciu flag--features multiling-chinese, multiling-japanese, multiling-korean
.
Proszę odnieść się do przykładów dopasowania pełnotekstowego dla przykładu użycia indeksu pełnotekstowego w zapytaniach.
Indeksowanie wektorowe
Indeksowanie wektorowe to struktura danych oparta na wektorach, skonstruowana za pomocą określonych modeli matematycznych. Dzięki indeksowaniu wektorowemu możemy efektywnie zapytywać wiele wektorów podobnych do wektora docelowego.
Obecnie Qdrant używa wyłącznie HNSW jako indeksu wektorowego.
HNSW (Hierarchical Navigable Small World Graph) to algorytm indeksowania oparty na grafach. Zgodnie z określonymi regułami konstruuje wielopoziomową strukturę nawigacyjną dla grafu. W tej strukturze górne warstwy są rzadsze, z większymi odległościami między węzłami. Dolne warstwy są gęstsze, z mniejszymi odległościami między węzłami. Wyszukiwanie rozpoczyna się od górnej warstwy, znajdując najbliższy węzeł do celu w tej warstwie, a następnie przechodzi do kolejnej warstwy w poszukiwaniu. Po wielu iteracjach algorytm może szybko zbliżyć się do celowej pozycji.
Dla poprawy wydajności, HNSW ogranicza maksymalny stopień węzłów na każdej warstwie grafu do m
. Dodatkowo, można określić zakres wyszukiwania za pomocą ef_construct
(podczas konstruowania indeksu) lub ef
(podczas wyszukiwania celu).
Te parametry można skonfigurować w pliku konfiguracyjnym:
storage:
hnsw_index:
m: 16
ef_construct: 100
full_scan_threshold: 10000
Podczas procesu tworzenia kolekcji parametr ef
można skonfigurować, domyślnie jest równy ef_construct
.
Wybór HNSW był podyktowany kilkoma powodami. Po pierwsze, HNSW jest w pełni kompatybilny z możliwością modyfikowania filtrów przez Qdrant w trakcie procesu wyszukiwania. Po drugie, zgodnie z publicznymi testami benchmarków, jest to jeden z najdokładniejszych i najszybszych algorytmów.
Dostępny od wersji 1.1.1
Parametry HNSW można również dostosować dla kolekcji i nazwanych wektorów, aby zoptymalizować wydajność wyszukiwania przez ustawienie hnsw_config
.
Indeks filtrowalny
Oddzielne indeksy ładunku i same indeksy wektorowe nie są w stanie w pełni rozwiązać użycia filtrów podczas wyszukiwania.
W przypadkach, gdy filtry są słabe, można bezpośrednio użyć indeksu HNSW. W przypadkach, gdy filtry są ścisłe, można użyć indeksu ładunku i całkowicie przeliczyć wyniki. Jednakże, w przypadkach pośrednich to podejście jest nieskuteczne.
Z jednej strony nie możemy sobie pozwolić na wykonanie pełnego skanowania zbyt wielu wektorów. Z drugiej strony, korzystając z zbyt restrykcyjnych filtrów, graf HNSW zaczyna rozpadać się.
Dodatkowe krawędzie pozwalają efektywnie wykorzystać indeks HNSW do wyszukiwania sąsiednich wektorów i stosować filtry podczas przeszukiwania grafu.
To podejście minimalizuje nadmiarowe koszty sprawdzania warunków, ponieważ musisz obliczyć warunki tylko dla małej części punktów biorących udział w wyszukiwaniu.