Photon: Budowa silnika wyszukiwania i rankingu od podstaw

Budowanie indeksu działa niezależnie od obsługi zapytań na żywo. Pillar eksportuje dane źródłowe, YTsaurus przygotowuje tablice w wersjach według shardów, a równoległe indesery zapisują gotowe do obsługi struktury indeksu w pamięci masowej obiektu. Węzły obsługujące łamią te struktury do pobierania i rankingu; współbieżność indeserów i liczba shardów są konfigurowane niezależnie.

AutorzyPerplexity Engineering

Wprowadzenie

Żądanie z usługi wyszukiwania wyższego poziomu dociera do brokera Photon za pośrednictwem modułu równoważenia obciążenia. Broker wybiera grupę shardów i przekazuje żądanie do każdego sharda, monitorując limity czasu i wysyłając dodatkowe żądania w razie potrzeby.

Aby przezwyciężyć te wyzwania, zbudowaliśmy Photon, nowy autorski silnik pobierania i rankingu. Jest to kontynuacja naszego podejścia polegającego od podstaw na budowaniu infrastruktury wyszukiwania opartej w pierwszej kolejności na AI, tak jak zrobiliśmy to w przypadku CobbleDB, naszej rozproszonej bazy danych klucz-wartość do obsługi rekordów stron, oraz naszego API wyszukiwania.

Photon używa kompaktowych formatów danych do odczytywania i dekodowania wyłącznie tego, czego wymaga każde zapytanie, wraz z buforowaniem uwzględniającym partie i asynchronicznymi odczytami, aby ograniczyć dostęp do dysku i nakładać na siebie oczekiwania. Budowanie indeksu działa niezależnie od obsługi zapytań, aktualizując jedną grupę obsługi naraz i rozgrzewając jej pamięci podręczne przed skierowaniem do niej zapytań na żywo.

Photon napędza teraz nasz potok wyszukiwania i stanowi również fundament nowego szybkiego presetu dla naszego API wyszukiwania, z opóźnieniem pojedynczego wywołania wyszukiwania wynoszącym 160 ms przy p50 i 230 ms przy p95. W sześciu publicznych benchmarkach szybki preset obniżył szacowany koszt modelu i wyszukiwania na zadanie o 68%, zachowując jednocześnie łączną jakość zadań porównywalną z domyślnym presetem. Wydajemy go dzisiaj, aby programiści mogli uzyskać dostęp do tych ulepszeń.

Samodzielnie zgłaszane opóźnienie pojedynczego wywołania wyszukiwania. PPLX Fast zgłasza opóźnienie p50 wynoszące 160 ms i opóźnienie p95 wynoszące 230 ms. Exa Instant zgłasza p90, a nie p95, dla wartości górnego ogona; wartości górnego ogona Parallel nie są publikowane. Zgłaszanego percentyle i konfiguracje pomiarowe nie stanowią kontrolowanego porównania typu "jeden do jednego".
Łączna jakość zadań w stosunku do szacowanego całkowitego kosztu modelu i wyszukiwania dla tych samych 3554 wybranych zadań. Wyniki są ważone liczbą zadań, a koszty obejmują cały zestaw zadań. PPLX Fast uzyskuje wynik 64,3% przy 59,73 USD, w porównaniu do 64,0% przy 187,60 USD dla domyślnego presetu PPLX, co oznacza około 68% niższy szacowany koszt dla tej samej liczby zadań.

Samodzielnie zgłaszane opóźnienie pojedynczego wywołania wyszukiwania. PPLX Fast zgłasza opóźnienie p50 na poziomie 160 ms i opóźnienie p95 na poziomie 230 ms. Exa Instant zgłasza p90 zamiast p95 dla wartości górnego ogona; wartości górnego ogona dla Parallel nie zostały opublikowane. Zgłaszanego percentyla i konfiguracji pomiarów nie można traktować jako kontrolowanego porównania typu „jeden do jednego”.

Dla każdego zapytania silnik pobierania i rankingowania przeszukuje duży, rozproszony indeks, aby wybrać i uporządkować mały zestaw powiązanych stron w ramach budżetu opóźnień stosu wyszukiwania. System musi również utrzymywać indeks w aktualnym stanie w miarę pojawiania się nowych stron i zmiany istniejących, nie pozwalając, aby ta praca spowalniała zapytania na żywo.

Pamięć podręczna została zaprojektowana z myślą o odczytach wsadowych. W szczególności:

Obszary, w których nasz poprzedni system niedomagał

Utrzymywaliśmy nasz własny fork, aby dostosować silnik do naszego rosnącego indeksu, jednak adresowanie kluczowych ograniczeń w coraz większym stopniu wymagało przeprojektowania dużych części platformy. Kilka ograniczeń okazało się trudnych do rozwiązania bez fundamentalnych zmian architektonicznych:

1. Koszty skalowania. Z czasem rosła zarówno liczba przechowywanych dokumentów, jak i ilość danych z każdego dokumentu, które musieliśmy pobierać i wykorzystywać do rankingu. Ten wzrost obciążał nasz sprzęt, zwłaszcza dostępną pamięć RAM. Aby kontrolować koszty, potrzebowaliśmy bardziej zwartych reprezentacji danych oraz dokładniejszej kontroli nad tym, co pozostaje w pamięci, a co jest odczytywane z dysku na żądanie.

2. Słabe opóźnienie ogonowe. W przypadku ruchu produkcyjnego czas odpowiedzi p99 starego systemu wynosił około 800 ms. Zestaw danych przekraczał dostępną pamięć RAM, więc nie mogliśmy użyć mlock, aby utrzymać go w całości w pamięci. Dostęp do danych nierezydentnych mógł wywołać poważne błędy strony, powodując zawieszanie wykonania zapytania, podczas gdy system operacyjny odczytywał dane z dysku.

Silnik okresowo scalał również swój główny indeks dyskowy z mniejszymi indeksami opróżnianymi z pamięci. Podczas tego procesu scalania indeksu dyskowego liczba błędów strony wzrosła jeszcze bardziej, a opóźnienie p99 osiągnęło około 1,2 s przez 10–15 minut. W miarę nagrzewania się pamięci podręcznych częstotliwość błędów strony i opóźnienia spadały, co sugerowało, że zimne odczyty były głównym czynnikiem powodującym skoki. Wstępne ładowanie danych i rozgrzewanie indeksu zmniejszyły skoki, ale nie rozwiązały odpowiednio problemu wysokich opóźnień ogona.

3. Długotrwałe odzyskiwanie i synchronizacja. W poprzednim systemie wdrożenie dodatkowego klastra i synchronizacja jego danych mogły zająć ponad tydzień. Synchronizacja była również wymagana podczas dodawania grup węzłów w celu przechowywania dodatkowych kopii danych lub odzyskiwania po awarii węzłów. Podczas odzyskiwania większa część odpowiedzi z wyszukiwania była częściowa, co obniżało końcowe wyniki jakości odpowiedzi.

Ostatecznie doszliśmy do wniosku, że prostsze i tańsze będzie zbudowanie systemu od zera niż dalsze dostosowywanie i utrzymywanie naszego forka. Czerpiąc z naszego doświadczenia w obsłudze poprzedniego systemu, mały zespół inżynieryjny pracował wraz z rojem uporczywych agentów kodujących nad stworzeniem Photona.

Miejsce Photona w stosie wyszukiwania

Photon został zaprojektowany z myślą o dwóch głównych przepływach pracy: obsłudze żądań wyszukiwania i pobieraniu aktualizacji z potoku przetwarzania.

Żądanie z wyższego poziomu usługi wyszukiwania dociera do brokera Photon za pośrednictwem modułu równoważenia obciążenia. Broker wybiera grupę shardów i przekazuje żądanie do każdego shardu, monitorując limity czasu i wysyłając dodatkowe żądania w razie potrzeby.

Selekcja przebiega następnie w trzech krokach:

Aktualizacje indeksu przebiegają osobną ścieżką. Pillar, nasza warstwa publikacji, przygotowuje dane i przechowuje je w tabelach YTsaurus. Indeksatory konwertują te tabele na struktury indeksu, które shardy mogą załadować do wyszukiwania. Kontroler koordynuje przygotowanie danych, budowanie indeksu i wdrażanie nowych wersji indeksu do grup obsługujących ruch. Przed obsłużeniem ruchu na żywo, każdy shard odtwarza rzeczywiste zapytania wyszukiwania, aby rozgrzać swoje pamięci podręczne.

Zapytanie przechodzi z wyższego poziomu usługi wyszukiwania przez moduł równoważenia obciążenia i brokera do wybranej grupy shardów. Każdy shard pobiera i rankinguje kandydatów; broker scala wyniki, pobiera pola dokumentów dla wybranych stron i zwraca je do wyższego poziomu usługi wyszukiwania. Numerowane kroki pokazują kolejność. Ciągłe strzałki przenoszą żądania, a przerywane strzałki zwracają wyniki z powrotem. Etykiety faz po lewej stronie odróżniają wybór kandydatów od odczytów podsumowań.

Projektowanie Photona z myślą o naszych przepływach pracy

Liczba shardów oraz liczba współbieżnie uruchomionych indeserów są konfigurowane niezależnie, dzięki czemu kompilacja może odbywać się w kilku falach lub można przydzielić więcej maszyn do pracy równoległej. Rozproszone przygotowanie i równoległe indusery pozwalają na zbudowanie całego indeksu internetowego w jednocyfrową liczbę godzin, co stanowi znaczącą poprawę w porównaniu z poprzednim systemem.

Reprezentacje danych do pobierania i rankingowania

Pobieranie i ranking uzyskują dostęp do danych dokumentów w odmienny sposób. Pobieranie leksykalne rozpoczyna się od terminów zapytania i znajduje dokumenty, które je zawierają. Ranking wymaga następnie szczegółowych informacji o każdym wybranym dokumencie, w tym częstotliwości terminów i ich pozycji.

Photon używa dwóch uzupełniających się reprezentacji, aby obsługiwać te wzorce dostępu. Indeks odwrócony przechowuje listę pasujących dokumentów dla każdego terminu, nazywaną listą wpisów, w celu wsparcia wyboru kandydatów. Oddzielne rekordy dla poszczególnych dokumentów zapewniają dane potrzebne do rankingu. Optymalizujemy również sposób przechowywania i przeglądania list wpisów, aby poprawić wybór w ramach stałego budżetu pracy.

Wyspecjalizowane reprezentacje danych pozwalają nam wydajniej przechowywać kluczowe dane. Bardziej kompaktowy indeks odwrócony zmniejsza ilość danych odczytywanych lub przemieszczanych na zapytanie, poprawiając opóźnienie poprzez wyeliminowanie niepotrzebnych operacji I/O. Format te umożliwiają również sprawdzenie, czy dokument pojawia się na liście bez jego pełnego dekodowania - właściwość, na której polega nasza logika przemierzania, aby kontrolować, ile pracy wykonuje zapytanie przy stałym budżecie. Optymalizacja rekordów dla poszczególnych dokumentów pozwala nam przechowywać więcej danych na dokument w celach rankingowych, jednocześnie zmniejszając koszty skalowania powiązane z naszym poprzednim systemem.

Indeks odwrócony

Format został skonstruowany tak, aby unikać dekodowania większej liczby elementów niż to konieczne. W obrębie docbloba pola są grupowane według analizatora tekstu. Każda grupa przechowuje posortowaną listę terminów zakodowaną za pomocą Elias-Fano, dzięki czemu termin zapytania można wyszukać bezpośrednio bez uprzedniego rozwijania całej listy. Maska pól zaznacza miejsce wystąpienia terminu, licznik częstotliwości śledzi, jak często to nastąpiło, a rzeczywiste pozycje znajdują się w oddzielnych blokach dla każdej pary termin-pole zakodowanych jako różnice pozycji. Dekodowane są tylko bloki dla terminów, które faktycznie pasowały, podczas gdy wszystko inne w rekordzie pozostaje w skompresowanym formacie.

Krótkie listy korzystają z reprezentacji wbudowanej, która mieści się na pojedynczej stronie i nie wymaga tabeli bloków. Dłuższe listy, które nie mieszczą się w formacie wbudowanym, są dzielone na bloki obejmujące stałe zakresy identyfikatorów dokumentów. Reprezentacja każdego bloku zależy od jego gęstości: rzadkie bloki przechowują posortowane tablice offsetów ID dokumentów, podczas gdy gęste bloki używają map bitowych. Rzadkie bloki wykorzystują wyszukiwanie galopujące (galloping search), które porusza się w coraz większych krokach, aby pomijać regiony listy. Gęste bloki umożliwiają sprawdzanie przynależności poprzez wyszukanie bitu odpowiadającego dokumentowi.

Częstotliwość zapytań o termin określa, gdzie jego lista wpisów jest umieszczana na dysku. Często wyszukiwane listy są przechowywane blisko siebie, co koncentruje gorące dane w mniejszym obszarze pamięci masowej. W obrębie każdej listy dokumenty są porządkowane według oddzielnego sygnału przydatności, dzięki czemu bardziej obiecujący kandydaci są napotykani wcześniej.

Photon wybiera reprezentację listy wpisów na podstawie długości i gęstości bloku. Krótkie listy mieszczą się wewnątrz strony. Dłuższe listy są podzielone na stałe zakresy identyfikatorów dokumentów, z posortowanymi tablicami przesunięć dla rzadkich bloków i mapami bitowymi dla gęstych bloków.

Przemierzanie list w ramach budżetu pracy

Ogólna jakość zadań a szacowany całkowity koszt modelu i wyszukiwania dla tych samych 3 554 wybranych zadań. Wyniki są ważone liczbą zadań, a koszty obejmują cały zestaw zadań. PPLX Fast uzyskuje wynik 64,3% przy koszcie 59,73 USD, w porównaniu do 64,0% przy 187,60 USD dla domyślnego ustawienia wstępnego PPLX, co oznacza w przybliżeniu o 68% niższy szacowany koszt dla tej samej liczby zadań.

Algorytm dzieli listy na dwie grupy. Listy sterujące napędzają proces przemierzania i proponują dokumenty będące kandydatami. Listy sondujące wpisują się w wyniki tych kandydatów, ale nie generują samodzielnie kandydatów.

Punktacja kandydatów łączy ważone pokrycie terminów zapytań i udział częstotliwości, z normalizacją długości dokumentu oraz ograniczeniem zysków z powtarzających się terminów. Photon najpierw sprawdza obecność terminów w tablicach i bitach, aby ograniczyć maksymalny możliwy wynik każdego kandydata. Odczytuje dokładne częstotliwości terminów tylko dla kandydatów, którzy nadal mogą osiągnąć próg wyboru.

Wybór odbywa się następnie w trzech krokach:

  • Przechodzenie: Zacznij od ścisłego wymogu pokrycia zapytania. Jeśli zostanie znalezionych zbyt mało kandydatów, powtórz proces z łagodniejszym wymogiem.
  • Retencja: Kandydatisą trzymani w ograniczonym zestawie przy użyciu wyniku łączącego pokrycie i częstotliwość. W miarę poprawy zebranych najlepszych kandydatów próg przyjęcia rośnie.
  • Wybór ostateczny: Ostateczne wyniki dla przebiegu są wybierane z zachowanego zestawu na podstawie wyników częstotliwości. Każde pole wykonuje własny przebieg, a wyniki są łączone przy użyciu wag pól.

Algorytm tworzy zestaw kandydatów w postaci istotnych dokumentów, które mają zostać użyte w dalszym rankingu.

Ilustracyjne przechodzenie przez ograniczony zestaw kandydatów. Listy sterujące proponują dokumenty, podczas gdy górne granice pozwalają na odcięcie kandydatów znajdujących się poniżej bieżącego progu przyjęcia bez odczytywania list próbnika i dokładnych częstotliwości. Próg rośnie w miarę poprawy zachowanego zestawu. Wyniki zostały wymyślone w celach ilustracyjnych, a zatrzymani kandydaci nie stanowią gwarantowanego dokładnego top-k.

Docblob

Po wybraniu stron będących kandydatami faza rankingu potrzebuje częstotliwości terminów, pokrycia pól oraz lokalizacji i bliskości wystąpień. Uzyskanie tych danych za pomocą indeksu odwróconego wymagałoby rozproszonych dostępów w wielu parach termin-dokument. W Photon przechowujemy kompaktowy rekord dla każdego dokumentu o nazwie docblob, który zawiera częstotliwości terminów, pola, w których pojawił się termin, oraz miejsce w dokumencie, w którym wystąpił. W rezultacie ranking kandydata wymaga tylko jednego wyszukiwania na dokument.

Format został stworzony tak, aby unikać dekodowania większej liczby elementów niż to konieczne. W obrębie docbloba pola są grupowane według analizatora tekstu. Każda grupa przechowuje posortowaną listę terminów zakodowaną za pomocą algorytmu Elias-Fano, dzięki czemu termin zapytania można wyszukać bezpośrednio bez wcześniejszego rozwijania całej listy. Maska pola wskazuje, gdzie wystąpił termin, licznik częstotliwości śledzi, jak często, a faktyczne pozycje znajdują się w oddzielnych blokach dla każdej pary termin-pole zakodowanych jako różnice pozycji. Dekodowane są tylko bloki dla terminów, które faktycznie pasowały, podczas gdy wszystko inne w rekordzie pozostaje w formacie skompresowanym.

Selektywne dekodowanie pozwala docblob obsługiwać przechowywanie większej ilości danych na dokument bez proporcjonalnego wzrostu kosztów. Zwiększenie rozmiaru rekordu nie wymusza większej pracy na wyszukiwanie, ponieważ ranking dotyka wyłącznie elementów istotnych dla dopasowanych terminów, a nie całego rekordu.

Docblob grupuje dane rankingowe w kompaktowy rekord dla każdego dokumentu. Terminy zapytania są wyszukiwane na liście terminów zakodowanej metodą Elias–Fano; maski pól, częstotliwości i bloki pozycji dostarczają danych potrzebnych dla dopasowanych terminów, podczas gdy niepowiązane terminy pozostają skompresowane. Identyfikator terminów i pozycje mają charakter ilustracyjny.

Photon sprawdza partię znanych offsetów rekordów w swojej pamięci podręcznej przed wydaniem odczytów dyskowych. Trafienia w pamięci podręcznej są kopiowane do przygotowanego bufora; chybienia są przesyłane za pośrednictwem io_uring, dzięki czemu oczekiwania dysku mogą się na siebie nakładać, a zwrócone dane zapełniają pamięć podręczną. Rekordy i osie czasu mają charakter schematyczny, a nie zmierzonych opóźnień.

Gdzie nasz poprzedni system zawiódł

Photon sprawdza partię znanych przesunięć rekordów w swojej pamięci podręcznej przed wydaniem odczytów dyskowych. Trafienia w pamięci podręcznej są kopiowane do przygotowanego bufora; chybienia są przesyłane przez io_uring, dzięki czemu oczekiwania dyskowe mogą się na siebie nakładać, a zwrócone dane zapełniają pamięć podręczną. Rekordy i osie czasu mają charakter schematyczny, a nie zmierzonych opóźnień.

Nakładające się oczekiwania dysku

Ranking wymaga pobrania cech stu dokumentów znajdujących się w różnych częściach pliku. Nasz poprzedni system używał mmap do mapowania pliku w wirtualnej przestrzeni adresowej, aby można było go odczytywać za pomocą wskaźników do pamięci. Jednak dostęp do strony, której nie było w pamięci, nadal wymagał odczytu z dysku. Wątek musiał poczekać na dane, zanim mógł kontynuować obliczenia, a ten czas oczekiwania kumulował się, gdy proces musiał sekwencyjnie odczytywać rekordy nieobecne w pamięci.

Photon korzysta z faktu, że offsety rekordów są znane z góry, dzięki czemu możemy przesłać kilka odczytów naraz. Zarządza tym reaktor: dedykowane wątki robocze przesyłają partie za pośrednictwem io_uring i przekazują odczytane dane do kodu wywołującego. Każdy wątek utrzymuje własne io_uring; partie są wysyłane do najmniej obciążonego reaktora. Wstępnie zarejestrowane deskryptory plików i pule buforów ograniczają narzut powtarzanych odczytów. Ta asynchroniczna egzekucja pozwala na nakładanie się oczekiwań na kilka operacji, co skraca opóźnienie ogonowe.

Zmniejszenie liczby dostępów do dysku

Photon zasila teraz nasz potok wyszukiwania, a także stanowi fundament nowego szybkiego ustawienia wstępnego dla naszego API wyszukiwania, z opóźnieniem pojedynczego wywołania wyszukiwania wynoszącym 160 ms dla p50 i 230 ms dla p95. W sześciu publicznych benchmarkach szybkie ustawienie wstępne obniżyło szacowany koszt modelu i wyszukiwania na zadanie o 68%, zachowując ogólną jakość zadań porównywalną z domyślnym ustawieniem wstępnym. Udostępniamy je dzisiaj, aby programistom zapewnić dostęp do tych ulepszeń.

Pamięć podręczna została zaprojektowana z myślą o odczytach w partiach. W szczególności:

  • W przypadku trafienia nie następuje osobna alokacja pamięci. Zamiast tego dane są kopiowane do bufora przygotowanego wcześniej przez kod wywołujący.
  • Algorytm tworzy zestaw kandydatów składający się z odpowiednich dokumentów, które zostaną użyte w dalszym rankingu.
  • Photon został zaprojektowany z myślą o dwóch głównych przepływach pracy: obsłudze żądań wyszukiwania oraz pozyskiwaniu aktualizacji z potoku przetwarzania.
  • Wykorzystuje on pobieranie z wyprzedzeniem z pamięci podręcznej procesora (CPU cache prefetching), w ramach którego metadane i dane dla nadchodzących rekordów są żądane z wyprzedzeniem.

Te optymalizacje zmniejszają opóźnienia bez pogarszania wydajności przy obciążeniach, na których nam zależy.

Po wybraniu stron kandydujących faza rankingu wymaga częstotliwości terminów, pokrycia pól oraz lokalizacji i bliskości wystąpień. Uzyskanie tych danych za pośrednictwem indeksu odwróconego wymagałoby rozproszonych dostępów do wielu par termin-dokument. W Phonie przechowujemy kompaktowy rekord dla każdego dokumentu zwany docblob, który zawiera częstotliwości terminów, pola, w których pojawił się termin, oraz miejsce jego wystąpienia w dokumencie. W rezultacie ranking kandydata wymaga tylko jednego wyszukania na dokument.

Wykres punktowy porównujący wyniki benchmarku ważone zadaniami z szacowanym całkowitym kosztem modelu i wyszukiwania w sześciu konfiguracjach.

To rozdzielenie rozwiązuje wąskie gardła odzyskiwania i synchronizacji występujące w poprzedniej implementacji. Ponieważ budowanie indeksu odbywa się wewnątrz tego samego klastra, który obsługuje zapytania, odzyskanie uszkodzonego węzła lub dodanie nowej kopii danych mogło oznaczać ponowne indeksowanie dokumentów w miejscu – proces, który zajmował dni i zwiększał liczbę częściowych odpowiedzi podczas odzyskiwania. Photon usuwa to powiązanie; indeksatory działają jako zadania rozproszone, które generują wersjonowane, gotowe do obsługi struktury indeksu niezależnie od węzłów obsługujących ruch, dzięki czemu budowanie kolejnej wersji indeksu nie konkuruje już z ruchem na żywo.

Budowanie indeksu działa niezależnie od obsługi zapytań na żywo. Pillar eksportuje dane źródłowe, YTsaurus przygotowuje wersjonowane tabele według shardów, a równoległe indeksatory zapisują gotowe do obsługi struktury indeksu w pamięci masowej obiektów. Węzły obsługujące ładują te struktury do pobierania i rankingu; współbieżność indeksatora i liczba shardów są konfigurowane niezależnie.

Sekwencja zapytań Photona ze strzałkami żądań oznaczonymi ciągłą linią oraz strzałkami zwrotnymi oznaczonymi linią przerywaną między wyszukiwaniem wyższego poziomu, modułem równoważenia obciążenia, brokerem i shardami; tytuły faz selekcji kandydatów i odczytu podsumowań znajdują się po lewej stronie.

Budowanie rozpoczyna się od wyboru dokumentów dla aktywnego indeksu i przygotowania eksportu źródłowego. Kontroler rejestruje wersję źródłową, tabele wejściowe i oczekiwaną liczbę shardów. Zadania MapReduce w YTsaurus przygotowują tekst, metadane, fragmenty, cechy i wcześniej obliczone osadzenia do tabel wersjonowanych podzielonych na shardy. Każdy indeksator przesyła strumieniowo przygotowaną tabelę, buduje struktury dla swojego shardu i scala segmenty tekstu. Gotowy indeks wraz z opisem jego komponentów jest przesyłany do pamięci masowej obiektów.

Liczba shardów i liczba współbieżnie uruchomionych indeksatorów są konfigurowane niezależnie, dzięki czemu kompilacja może odbywać się w kilku falach lub do pracy można przydzielić więcej maszyn działających równolegle. Rozproszone przygotowanie i równoległe indeksatory pozwalają na zbudowanie całego indeksu sieci Web w jednocyfrową liczbę godzin, co stanowi znaczącą poprawę w porównaniu z poprzednim systemem.

Gdy istnieje wiele grup obsługi, kontroler aktualizuje je pojedynczo. Najpierw usuwa grupę z routingu brokera i uruchamia ją na nowej wersji indeksu. Przed obsługą żądań shardy przechodzą przez oddzielny etap rozgrzewania oparty na dziennikach wyszukiwania, co wstępnie zapełnia stan początkowy i sprawia, że przejście na prawdziwy ruch jest płynniejsze. Po rozgrzaniu kontroler sprawdza stan indeksu i gotowość, a następnie zwraca grupę do routingu. Pozostałe grupy nadal obsługują żądania w tym czasie. Ponieważ stan operacyjny jest utrwalany, ponowne uruchomienie nie wymusza ponownego rozpoczęcia budowania; kontroler może ponownie podpiąć się do trwającego już przygotowania, ponownie wykorzystać gotowy wynik lub kontynuować przerwaną rotację od zapisanego kroku.

Partia odczytu dzieli się na trafienia i chybienia w pamięci podręcznej, przy czym asynchroniczne odczyty dyskowe nakładają się na oczekiwania na brakujące rekordy.

Gdy istnieje wiele grup obsługujących ruch, kontroler aktualizuje je pojedynczo. Najpierw usuwa grupę z routingu brokera i uruchamia ją na nowej wersji indeksu. Przed obsługą żądań shardy przechodzą przez oddzielny etap rozgrzewania oparty na logach wyszukiwania, co wstępnie zapełnia stan początkowy i sprawia, że przejście do rzeczywistego ruchu jest płynniejsze. Po rozgrzewaniu kontroler sprawdza stan indeksu i gotowość, a następnie przywraca grupę do routingu. Pozostałe grupy kontynuują obsługę żądań w tym czasie. Ponieważ stan operacyjny jest utrwalany, ponowne uruchomienie nie wymusza ponownego rozpoczęcia budowania; kontroler może ponownie podpiąć się do trwającego już przygotowania, ponownie wykorzystać gotowy wynik lub kontynuować przerwany obrót od zapisanego kroku.

Czasy aktualizacji danych różnią się w zależności od pionów wyszukiwania. W przypadku pionów o wysokich wymaganiach dotyczących świeżości dostarczenie dokumentu zajmuje jednocyfrową liczbę minut. Dodatkową kopię danych można wdrożyć w około pół godziny; gotowe indeksy są ładowane i dołączane do shardów bez ponownego indeksowania dokumentów źródłowych.

Kontroler sprawdza, czy nowy indeks jest kompletny, a następnie rotuje po jednej grupie obsługi naraz. Grupa opuszcza routing brokera, ładuje nową wersję, rozgrzewa swoje pamięci podręczne za pomocą zapytań z dziennika wyszukiwania i przechodzi kontrole gotowości przed powrotem do obsługi ruchu. Pozostałe grupy kontynuują obsługę, a utrwalony stan kontrolera pozwala na wznowienie przerwanej rotacji.

Migracja i walidacja w naszym stosie wyszukiwania

Aktualizacje indeksu przebiegają osobną ścieżką. Pillar, nasza warstwa publikacji, przygotowuje dane i przechowuje je w tabelach YTsaurus. Indesery przekształcają te tablice w struktury indeksu, które shardy mogą załadować do wyszukiwania. Kontroler koordynuje przygotowanie danych, budowanie indeksu oraz wdrażanie nowych wersji indeksu do grup obsługi. Przed obsłużeniem ruchu na żywo każdy shard odtwarza prawdziwe zapytania wyszukiwania, aby rozgrzać swoje pamięci podręczne.

Testy obciążeniowe i ewaluacje

W celach testów wydajnościowych zbudowaliśmy narzędzie do testów obciążeniowych, które odtwarza zapytania z naszych logów wyszukiwania przy konfigurowalnych częstotliwościach nadejścia. Porównuje ono wyniki pomiędzy uruchomieniami i stosuje testy statystyczne w celu oceny, czy zaobserwowane różnice w wydajności są spójne. Niezależnie od tego oceniliśmy Photon i stary system na tych samych zestawach danych w naszych wewnętrznych systemach ewaluacji offline pod kątem regresji jakości.

Po tych sprawdzianach wysłaliśmy zapytania na żywo do obu silników jednocześnie, używając ruchu w tle (shadow traffic). Umożliwiło nam to porównanie ich wydajności i wyników przy obciążeniach produkcyjnych przed zmianą silnika obsługującego użytkowników. Następnie włączyliśmy Photona dla małych podzbiorów użytkowników i stopniowo powiększaliśmy zasięg wdrażania, stale monitorując jakość i wydajność. Pierwsza wersja przeszła testy akceptacyjne bez regresji jakości, a my kontynuowaliśmy wdrażanie, aż Photon zaczął obsługiwać cały ruch produkcyjny.

Dla każdego zapytania silnik pobierania i rankingu przeszukuje duży, rozproszony indeks, aby wybrać i uporządkować mały zestaw istotnych stron w ramach budżetu opóźnień stosu wyszukiwania. System musi także utrzymywać indeks w aktualnym stanie w miarę pojawiania się nowych stron i zmian na stronach istniejących, nie pozwalając, aby ta praca spowalniała zapytania na żywo.

Wyspecjalizowanę reprezentacje danych pozwalają nam wydajniej przechowywać kluczowe dane. Bardziej kompaktowy indeks odwrócony zmniejsza ilość danych odczytywanych lub przenoszonych na zapytanie, co poprawia opóźnienie poprzez wyeliminowanie niepotrzebnych operacji I/O. Formaty te umożliwiają również sprawdzenie, czy dokument pojawia się na liście bez jego pełnego dekodowania, na czym polega nasza logika przechodzenia, aby kontrolować ilość pracy wykonywanej przez zapytanie w ramach ustalonego budżetu. Optymalizacja rekordów dla poszczególnych dokumentów pozwala nam przechowywać więcej danych na dokument do celów rankingu, a jednocześnie zmniejsza koszty skalowania związane z naszym poprzednim systemem.

Wykres opóźnień pojedynczego wywołania wyszukiwania przedstawiający mediany zgłaszane przez dostawców oraz dostępne percentyle ogonowe, w tym Exa Instant p90 zamiast p95.

Photon zmniejsza również ilość danych, które muszą pozostać w pamięci RAM. Przypięcie tego samego zestawu danych Photona w pamięci RAM za pomocą mlock wymagałoby szacunkowo 4,6 razy więcej pamięci rezydentnej niż Photon zużywa obecnie.

Nadal ulepszamy wydajność i efektywność pamięci masowej Photona. Naszym celem jest obsługa większego indeksu i bogatszych danych dokumentów na tym samym sprzęcie przy jednoczesnym zachowaniu szybkiego wyszukiwania w miarę wzrostu obciążeń.

Użyliśmy również Photona jako bazy dla nowego szybkiego presetu dla naszego API wyszukiwania, zaprojektowanego z myślą o obciążeniach wrażliwych na opóźnienia. Zgodnie z naszymi pomiarami, opóźnienie pojedynczego wywołania wyszukiwania dla szybkiego presetu wynosi 160 ms przy p50 i 230 ms przy p95, czyli jest niższe lub porównywalne z wartościami podawanymi przez innych dostawców API wyszukiwania, choć zgłaszane percentyle ogona się różnią.

Oceniliśmy szybki preset w sześciu benchmarkach agentowych: WideSearch, BrowseComp, DSQA, FRAMES, SEAL-0 i SEAL-Hard. W tych ocenach uzyskał on najniższy szacowany całkowity koszt modelu i wyszukiwania oraz najwyższy łączny wynik zadań spośród testowanych konfiguracji.

Szybkie ustawienie wstępne łączy Photon z rankingiem zoptymalizowanym pod kątem przepływów pracy agenta, zapewniając wydajność porównywalną z domyślnym ustawieniem wstępnym przy znacznie niższych kosztach. Wiąże się to jednak z kompromisem w zakresie szerszej jakości wyszukiwania. Szybkie ustawienie wstępne zużywa mniej mocy obliczeniowej na ranking niż ustawienie domyślne. W wewnętrznych testach porównawczych obejmujących zapytania niszowe, szeroki zasięg i różnorodność wyników uzyskuje wynik o 0,24 punktu niższy pod względem trafności i o około 3 punkty procentowe niższy pod względem dostępności odpowiedzi. Uważamy to za rozsądny kompromis w przypadku przepływów pracy agenta, ponieważ własne rozumowanie i wiedza modelu mogą pomóc w zrekompensowaniu tej różnicy.

Wewnętrzne porównanie jakości pobierania pomiędzy domyślnym presetem PPLX a PPLX Fast. Istotność (DCG) spada z 2,45 do 2,21, co oznacza spadek o 0,24 punktu; dostępność odpowiedzi spada z 0,596 do 0,567, co oznacza spadek o 2,9 punktu procentowego. Oba panele używają różnych, niezerowych punktów odniesienia osi, więc wysokość słupków podkreśla luki, a nie różnice proporcjonalne.

Zalecamy szybkie ustawienie wstępne do codziennych zadań opartych na agentach. W przypadku trudniejszych lub bardziej niejednoznacznych pytań, które są mniej wrażliwe na czas, domyślne ustawienie wstępne oferuje wyższą jakość, co uzasadnia jego wyższe opóźnienie i koszt.

Podsumowanie

Czasy aktualizacji danych różnią się w zależności od segmentów wyszukiwania. W przypadku segmentów o wysokich wymaganiach dotyczących świeżości dostarczenie dokumentu trwa jednocyfrową liczbę minut. Dodatkową kopię danych można wdrożyć w około pół godziny; gotowe indeksy są ładowane i dołączane do shardów bez ponownego indeksowania dokumentów źródłowych.

Photon umożliwił szybsze wyszukiwanie w produktach Perplexity i stanowi fundament nowego szybkiego presetu w API wyszukiwania. Po migracji opóźnienie pobierania i rankingu p99 spadło z około 800 ms do 65 ms. Nasze kompaktowe formaty danych pozwalają nam również przechowywać 2,5 razy więcej danych na dokument, zapewniając pobieraniu i rankingowi dostęp do bogatszych informacji o dokumencie.

Szybkie ustawienie wstępne zapewnia opóźnienie pojedynczego wywołania wyszukiwania na poziomie 160 ms dla p50 i 230 ms dla p95. We wszystkich sześciu ocenianych benchmarkach opartych na agentach obniżyło ono szacowany koszt modelu i wyszukiwania na zadanie o 68% w stosunku do domyślnego ustawienia wstępnego, zachowując przy tym porównywalną ogólną jakość zadań. Wyniki te demonstrują praktyczne korzyści wynikające z infrastruktury zaprojektowanej wokół naszych obciążeń związanych z wyszukiwaniem, zarówno w przypadku produktów Perplexity, jak i programistów budujących rozwiązania przy użyciu naszego API.

Nadal ulepszamy wydajność i efektywność pamięci masowej Photona. Naszym celem jest obsługa większego indeksu i bogatszych danych dokumentów na tym samym sprzęcie, przy jednoczesnym zachowaniu szybkiego wyszukiwania wraz ze wzrostem naszych obciążeń.

Cytat

BibTeX
@online{perplexity2026Photon,
  author = {{Perplexity} and Maksim Morozov and Bogdan Savko and Ruslan Kovalev and Aleksei Bykov and Artur Zayats and Denis Bykov and Nikita Kireev and Jarrod Bryan and Claire Beamer and Jeremy Yang},
  title = {{Photon: Building a retrieval and ranking engine from scratch}},
  date = {2026-09-24},
  url = {https://www.perplexity.ai/hub/blog/photon}
}