Milvus, baza wektorowa dla miliardowej skali
Milvus to otwarta baza wektorowa na licencji Apache 2.0, rozwijana w fundacji LF AI & Data i zaprojektowana pod zbiory, w których liczba wektorów idzie w miliardy. Od reszty kategorii odróżnia ją rozdzielenie przechowywania od obliczeń, co pozwala skalować każdą warstwę osobno. Wersja 3.0 ukazała się 29 lipca 2026 roku i przynosi zapytania do danych leżących poza bazą oraz zmianę schematu bez przestoju.
Kiedy w ogóle potrzebujesz bazy wektorowej
Zacznę od pytania, które oszczędza sporo pracy, jeśli zada się je przed wdrożeniem, a nie po nim. Baza wektorowa jest potrzebna wtedy, gdy liczba wektorów przestaje mieścić się w pamięci procesu albo gdy potrzebujesz operacji, których biblioteka indeksu nie ma: filtrowania po metadanych, aktualizacji rekordów, trwałości po restarcie, kontroli dostępu.
Poniżej mniej więcej stu tysięcy wektorów żadne z tych wymagań zwykle nie występuje. Zwykła tablica w pamięci i mnożenie macierzy przez bibliotekę numeryczną odpowiadają szybciej niż jakakolwiek baza, bo nie ma tu ani serializacji, ani ruchu sieciowego. Przy milionie wektorów zaczyna się rachunek pamięci: tysiąc wymiarów w liczbach zmiennoprzecinkowych pojedynczej precyzji to cztery kilobajty na wektor, czyli cztery gigabajty na sam zbiór, bez indeksu i bez metadanych. Powyżej tego progu decyzja o bazie zapada sama.
Milvus celuje w górny koniec tej skali. Jeśli Twój zbiór ma pół miliona wektorów i nie planujesz wzrostu, ta baza będzie działać poprawnie, ale zapłacisz za to złożonością operacyjną, której nie potrzebujesz. Prostsze rozwiązania, na przykład pgvector w bazie, którą i tak już masz, albo Chroma w prototypie, będą wtedy rozsądniejszym wyborem.
Trzy tryby uruchomienia i realna różnica między nimi
| Tryb | Sposób uruchomienia | Dostępne indeksy | Typowe zastosowanie |
|---|---|---|---|
| Milvus Lite | biblioteka w procesie Pythona | FLAT, IVF, HNSW, rzadkie i skalarne | prototyp, notatnik, testy |
| Standalone | jeden kontener | pełny zestaw | pojedynczy serwer, do kilkudziesięciu milionów wektorów |
| Distributed | klaster na Kubernetesie | pełny zestaw | skala miliardowa, rozdzielone warstwy |
Milvus Lite to wariant, od którego warto zacząć, bo znika tu cała warstwa wdrożeniowa. Instalujesz pakiet i podajesz ścieżkę do pliku:
pip install -U "pymilvus[milvus-lite]"from pymilvus import MilvusClient
client = MilvusClient("./milvus_demo.db")
client.create_collection(
collection_name="dokumenty",
dimension=768,
)Interfejs jest ten sam co w wersji serwerowej, więc przejście z prototypu na klaster sprowadza się do podmiany argumentu na adres serwera. To najmocniejsza strona tego rozwiązania i powód, dla którego warto zaczynać właśnie tutaj, zamiast od razu stawiać kontenery.
Lite w wersji trzeciej, wydanej w maju 2026 roku, został napisany od nowa w czystym Pythonie i wygląda inaczej, niż opisuje go większość starszych materiałów. Zamiast opakowania na rdzeń w C++ jest tu silnik składowania w stylu drzewa scalającego, z dziennikiem zapisu, segmentami w formacie Parquet i indeksami z biblioteki FAISS. Dostępne indeksy to FLAT, BRUTE_FORCE, IVF_FLAT, IVF_SQ8, HNSW, HNSW_SQ i AUTOINDEX, do tego rzadki SPARSE_INVERTED_INDEX oraz skalarny INVERTED. Są partycje, aliasy, nazwane bazy, iteratory, grupowanie wyników i wyszukiwanie hybrydowe.
Czego w Lite nadal nie ma, warto sprawdzić przed decyzją. Nie ma uwierzytelniania, użytkowników, ról ani szyfrowania połączenia, więc lokalnego serwera nie wystawia się do sieci. Nie ma wektorów binarnych, połowicznej precyzji ani całkowitoliczbowych, ani indeksów z kwantyzacją produktową. Jeden katalog danych obsługuje jeden proces, a zapisy do tej samej kolekcji muszą iść po kolei. Wymagany jest Python od wersji 3.10, a systemem może być Linux, macOS albo Windows, o ile dla zależności takich jak faiss-cpu i pyarrow istnieją tam gotowe paczki. Pliki bazy z poprzedniego silnika nie otwierają się w nowym i nie ma automatycznej migracji, jest tylko eksport do plików importu.
Wariant Standalone to jeden kontener z pełnym zestawem indeksów. Sprawdza się do kilkudziesięciu milionów wektorów i jest tym, na czym stoi większość wdrożeń, które widziałem. Distributed rozdziela węzły zapytań, danych, indeksowania i koordynacji, dzięki czemu można skalować osobno odczyt i osobno indeksowanie, ale wymaga Kubernetesa i kogoś, kto go utrzyma.
Dobór indeksu, czyli miejsce, gdzie zapadają realne decyzje
Wybór indeksu ma większy wpływ na koszt i opóźnienie niż wybór samej bazy. Warto rozumieć trzy podstawowe rodziny.
FLAT to przegląd wszystkich wektorów. Daje dokładność stuprocentową i jest najwolniejszy. Ma sens przy zbiorach do kilkudziesięciu tysięcy wektorów albo jako punkt odniesienia, względem którego mierzysz jakość szybszych indeksów.
Rodzina IVF dzieli przestrzeń na obszary i przeszukuje tylko część z nich. Parametr nlist mówi, na ile obszarów podzielić zbiór, a nprobe, ile z nich odwiedzić przy zapytaniu. Podniesienie nprobe poprawia trafność i wydłuża czas odpowiedzi, więc to najprostsza gałka, którą regulujesz kompromis między jakością a szybkością już po wdrożeniu, bez przebudowy indeksu.
HNSW buduje wielopoziomowy graf sąsiedztwa i jest domyślnym wyborem dla większości zastosowań, w których dane mieszczą się w pamięci. Płacisz za to zużyciem pamięci wyraźnie większym niż sam rozmiar wektorów. DISKANN z kolei trzyma graf na dysku i pozwala obsłużyć zbiory, które do pamięci nie wchodzą, kosztem opóźnienia zależnego od nośnika. Na dyskach NVMe różnica bywa akceptowalna, na wolniejszych zauważalna od razu.
Osobnym tematem jest kwantyzacja, czyli zapisywanie wektorów z mniejszą precyzją. Wersja 2.6 wprowadziła kwantyzację jednobitową, dla której zespół projektu raportował ograniczenie zużycia pamięci o 72 procent przy zachowaniu trafności. To liczba z materiałów producenta, więc traktuj ją jako punkt wyjścia do własnego pomiaru, a nie jako gwarancję. Mechanizm jest jednak realny i przy dużych zbiorach to właśnie kwantyzacja, a nie zmiana bazy, przynosi największą oszczędność.
Co nowego w Milvus 3.0
Wydanie z 29 lipca 2026 roku jest jednym z większych w historii projektu i warto znać kilka zmian, bo zmieniają sposób projektowania systemu.
Kolekcje zewnętrzne pozwalają odpytywać dane leżące w formatach Parquet, Lance i Iceberg bez kopiowania ich do bazy, z przyrostowym odświeżaniem. To odwrócenie dotychczasowego założenia, w którym wszystko trzeba było najpierw zaimportować. Przy zbiorach, które i tak żyją w jeziorze danych, znika cały krok kopiowania i utrzymywania dwóch kopii w spójnym stanie.
Elastyczny schemat umożliwia dodawanie, uzupełnianie i usuwanie kolumn bez przestoju i bez przebudowy kolekcji. Kto próbował dodać pole do kolekcji z kilkuset milionami wektorów pod ruchem produkcyjnym, doceni tę zmianę bardziej niż wszystkie pozostałe razem wzięte.
Indeksy rzadkie przeszły przebudowę i doszły algorytmy SINDI, Block-Max WAND oraz Block-Max MaxScore z lepszą kompresją. Rzadkie reprezentacje odpowiadają za dopasowanie po słowach kluczowych, więc jest to warstwa, na której stoi wyszukiwanie hybrydowe.
Doszły też agregacje i wyszukiwanie fasetowe, czyli zwracanie najczęstszych wartości wraz z funkcjami COUNT i AVG w jednym żądaniu. Wcześniej wymagało to osobnego zapytania do innej bazy. Pola typu TEXT przechowują teraz teksty dłuższe niż 64 kilobajty obok wektorów, przy czym wartości powyżej tego progu lądują w osobnych plikach, a kolumna trzyma tylko odwołanie. Ta funkcja wymaga magazynu w wersji trzeciej, o czym niżej. Przejście przez FAISS pozwala z kolei podać dowolny łańcuch fabryki indeksów z tej biblioteki i odtworzyć wprost przepis użyty w badaniach.
Dwie zmiany wymagają uwagi przy aktualizacji. Magazyn w wersji trzeciej jest domyślnie wyłączony i włącza się go ręcznie przez common.storage.useLoonFFI. Powrót z 3.0 do 2.6 jest możliwy, o ile nie włączyłeś magazynu w wersji trzeciej ani funkcji zmieniających format zapisu, więc jeśli chcesz zachować drogę odwrotu, zostaw te opcje wyłączone przez pierwsze tygodnie. Obrazy z obsługą kart graficznych przeszły na CUDA 12.9, co kończy zgodność z Ubuntu 20.04 w wariancie GPU.
Wyszukiwanie hybrydowe i filtrowanie
Samo podobieństwo wektorowe rzadko wystarcza w produkcie. Użytkownik szukający „umowa najmu 2025" oczekuje, że dokument z dokładnie takim numerem roku znajdzie się wyżej niż semantycznie podobny dokument z innego roku, a tego dopasowanie gęstych wektorów nie gwarantuje.
Rozwiązaniem jest łączenie wyników z wektorów gęstych i rzadkich, z ponownym uszeregowaniem na końcu. Milvus 3.0 dokłada do tego składalny łańcuch przeszeregowania, w którym kolejne etapy przeliczają wyniki i redukują zbiór.
from pymilvus import MilvusClient, AnnSearchRequest, RRFRanker
client = MilvusClient(uri="http://localhost:19530")
zapytanie_geste = AnnSearchRequest(
data=[wektor_pytania],
anns_field="wektor_gesty",
param={"nprobe": 32},
limit=50,
)
wyniki = client.hybrid_search(
collection_name="dokumenty",
reqs=[zapytanie_geste, zapytanie_rzadkie],
ranker=RRFRanker(),
limit=10,
output_fields=["tytul", "rok"],
)Filtrowanie po metadanych zasługuje na osobną uwagę, bo tu najczęściej psuje się wydajność. Wyrażenie filtrujące przekazujesz jako parametr filter, a baza decyduje, czy zastosować je przed przeszukaniem indeksu, czy po. Przy filtrze bardzo wąskim, odsiewającym 99 procent zbioru, przeszukiwanie indeksu przybliżonego staje się nieopłacalne i lepszy bywa zwykły przegląd tego, co zostało. Przy filtrze szerokim jest odwrotnie. Jeśli widzisz nieprzewidywalne czasy odpowiedzi, sprawdź właśnie selektywność filtrów, zanim zaczniesz stroić parametry indeksu.
Milvus a alternatywy
| Cecha | Milvus | Qdrant | Weaviate | Pinecone |
|---|---|---|---|---|
| Licencja | Apache 2.0 | Apache 2.0 | BSD 3 | zamknięta, usługa |
| Self hosting | tak | tak | tak | nie |
| Tryb wbudowany | tak, Lite | nie | tak, embedded | nie |
| Rozdzielenie zapisu i obliczeń | tak | częściowo | częściowo | tak, po stronie usługi |
| Próg wejścia operacyjnego | wysoki | niski | średni | żaden |
| Docelowa skala | miliardy | dziesiątki milionów | dziesiątki milionów | miliardy |
Wybór między nimi rzadko rozstrzyga lista funkcji, bo w typowym zastosowaniu wszystkie zrobią to samo. Rozstrzyga skala i to, kto będzie utrzymywał wdrożenie. Milvus w wariancie rozproszonym wymaga Kubernetesa i realnej wiedzy operacyjnej. Qdrant przy dziesięciu milionach wektorów postawisz w godzinę i będzie działać, a przy miliardzie zaczniesz walczyć. Pinecone zdejmuje z Ciebie całą warstwę utrzymania i obciąża za to rachunek, który przy dużych zbiorach rośnie szybciej, niż wynikałoby z intuicji.
Praktyczna rada: wybierając bazę, policz najpierw docelową liczbę wektorów za dwa lata, a nie dzisiejszą. Migracja między tymi bazami jest wykonalna, bo wszystkie przyjmują te same wektory, ale przepisanie warstwy zapytań, filtrów i przeszeregowania zajmuje więcej czasu, niż się zakłada.
Typowe błędy
Najczęstszy to brak wywołania ładowania kolekcji przed wyszukiwaniem. Milvus rozdziela stan trwały od stanu w pamięci, więc kolekcja zapisana na dysku nie jest automatycznie gotowa do odpytywania. Objawem jest błąd o niezaładowanej kolekcji, który bywa mylnie brany za problem z połączeniem.
Drugi to oczekiwanie natychmiastowej widoczności zapisu. Dane trafiają najpierw do dziennika zapisu, a dopiero potem do indeksu, więc wektor wstawiony przed chwilą może nie pojawić się w wynikach kolejnego zapytania. Jeśli test integracyjny wstawia i od razu szuka, potrzebuje wymuszenia spójności albo krótkiego oczekiwania.
Trzeci to nieprzemyślany wybór miary podobieństwa. Iloczyn skalarny i odległość kosinusowa dają te same uszeregowanie tylko dla wektorów znormalizowanych. Model osadzeń, który nie normalizuje wyjścia, w połączeniu z niewłaściwą miarą daje wyniki wyglądające na poprawne i systematycznie przekrzywione. Sprawdź to na dziesięciu znanych przypadkach, zanim uznasz jakość za zadowalającą.
Czwarty to traktowanie pomiarów z Lite jako prognozy dla klastra. Lite jest jednym procesem Pythona z zapisami do kolekcji szeregowanymi po kolei, a statystyki dla dopasowania po słowach liczy w obrębie segmentu, nie globalnie. Nawet przy tym samym indeksie HNSW liczby z prototypu nie opisują zachowania wdrożenia rozproszonego.
Piąty to niedoszacowanie pamięci. Do rozmiaru samych wektorów trzeba doliczyć narzut indeksu, który przy HNSW bywa porównywalny z rozmiarem danych. Klaster policzony na podstawie samych wektorów zabraknie pamięci przy pierwszym pełnym załadowaniu.
Wpięcie w istniejący stos
W typowym systemie wyszukiwania wspomaganego generowaniem Milvus jest warstwą składowania, a nad nim siedzi biblioteka orkiestrująca. Zarówno LangChain, jak i LlamaIndex mają gotowe integracje, więc podmiana bazy pod spodem sprowadza się do zmiany klasy magazynu wektorów.
Jedna decyzja projektowa wraca w każdym takim wdrożeniu i warto podjąć ją świadomie na początku. Chodzi o to, gdzie trzymać treść dokumentów. Kuszące jest umieszczenie całego tekstu w polu obok wektora, co upraszcza kod, bo jedno zapytanie zwraca wszystko. Kosztem jest rozmiar kolekcji i to, że każda zmiana treści wymaga aktualizacji rekordu w bazie wektorowej. Alternatywa to trzymanie w bazie wektorowej wyłącznie identyfikatorów i pobieranie treści z PostgreSQL albo magazynu obiektowego. Przy dokumentach dłuższych i często zmienianych drugie podejście starzeje się lepiej, a wprowadzone w wersji 3.0 pola TEXT powyżej 64 kilobajtów sprawiają, że pierwsze przestało być wykluczone technicznie.
FAQ
Czy Milvus jest darmowy?
Tak, Milvus jest wydawany na licencji Apache 2.0 i można go używać komercyjnie bez opłat, także w wariancie rozproszonym. Płatna jest usługa zarządzana Zilliz Cloud, prowadzona przez firmę stojącą za projektem, oraz wsparcie komercyjne.
Czym Milvus Lite różni się od pełnej wersji?
Lite działa jako biblioteka w procesie Pythona i zapisuje dane do pliku lokalnego. Ma ten sam interfejs, a od wersji trzeciej także indeksy FLAT, IVF i HNSW, indeksy rzadkie i skalarne, partycje oraz aliasy. Nie ma uwierzytelniania, użytkowników ani ról, obsługuje jeden proces na katalog danych i jest pomyślany jako środowisko do prototypów i notatników, nie do produkcji.
Czy Milvus działa na Windowsie?
Milvus Lite w wersji trzeciej jest napisany w czystym Pythonie i uruchamia się na Linuksie, macOS oraz Windowsie, o ile dla jego zależności są tam gotowe paczki; testy ciągłe projektu obejmują Windows na Pythonie 3.10. Pełną wersję serwerową na Windowsie uruchamiasz przez Dockera albo przez podsystem Linuksa, co w praktyce oznacza uruchomienie jej w kontenerze.
Który indeks wybrać na start?
HNSW, o ile dane mieszczą się w pamięci. Daje dobry stosunek trafności do opóźnienia bez strojenia. Gdy zbiór przestaje mieścić się w pamięci, przejdź na DISKANN albo dołóż kwantyzację, zamiast od razu powiększać klaster.
Czy przejście z Milvus 2.6 na 3.0 jest bezpieczne?
Powrót do wersji 2.6 pozostaje możliwy, dopóki nie włączysz magazynu w wersji trzeciej ani innych funkcji zmieniających format zapisu. Magazyn w wersji trzeciej jest domyślnie wyłączony, a nowe wersje indeksów wymagają świadomego włączenia, więc bezpieczna ścieżka to najpierw aktualizacja bez tych opcji.
Szczegóły wydań opisują notatki wydawnicze Milvus, a kod źródłowy znajdziesz w repozytorium projektu.