brief: | i18n.site obsługuje teraz bezserwerowe wyszukiwanie pełnotekstowe.
W tym artykule przedstawiono implementację czystej technologii wyszukiwania pełnotekstowego z przodu, w tym odwróconego indeksu zbudowanego przez IndexedDB, wyszukiwania prefiksów, optymalizacji segmentacji słów i obsługi wielu języków.
W porównaniu z istniejącymi rozwiązaniami, wyszukiwanie pełnotekstowe w i18n.site jest niewielkie i szybkie, odpowiednie dla małych i średnich witryn internetowych, takich jak dokumenty i blogi, i jest dostępne w trybie offline.
Po kilku tygodniach rozwoju, i18n.site (czysto statyczne narzędzie do tworzenia stron internetowych markdown multilingualtranslation & ) obsługuje teraz wyłącznie wyszukiwanie pełnotekstowe w interfejsie użytkownika.
W tym artykule opisano techniczną implementację wyszukiwania pełnotekstowego w i18n.site
front-end. Odwiedź i18n.site aby doświadczyć efektu wyszukiwania.
Kod open source : Szukaj jądra / interaktywny interfejs
W przypadku małych i średnich, czysto statycznych witryn internetowych, takich jak dokumenty/blogi osobiste, zbudowanie samodzielnie zbudowanego zaplecza wyszukiwania pełnotekstowego jest zbyt skomplikowane i częstszym wyborem jest wyszukiwanie pełnotekstowe bez usług.
Bezserwerowe rozwiązania do wyszukiwania pełnotekstowego można podzielić na dwie szerokie kategorie:
Po algolia.com , zewnętrzni dostawcy usług wyszukiwania udostępniają komponenty front-end do wyszukiwania pełnotekstowego.
Usługi takie wymagają płatności na podstawie liczby wyszukiwań i często są niedostępne dla użytkowników w Chinach kontynentalnych ze względu na problemy, takie jak zgodność witryny internetowej.
Nie można go używać w trybie offline, nie można go używać w intranecie i ma duże ograniczenia. Ten artykuł nie omawia zbyt wiele.
Drugie to wyszukiwanie pełnotekstowe w trybie front-end.
Obecnie popularne wyszukiwania pełnotekstowe wyłącznie w interfejsie użytkownika obejmują lunrjs i ElasticLunr.js (w oparciu o lunrjs
rozwiązań wtórnych).
lunrjs
Istnieją dwa sposoby budowania indeksów i oba mają swoje własne problemy.
Gotowe pliki indeksowe
Ponieważ indeks zawiera słowa ze wszystkich dokumentów, jest on duży. Za każdym razem, gdy dokument jest dodawany lub modyfikowany, należy załadować nowy plik indeksu. Wydłuży to czas oczekiwania użytkownika i zajmie dużo przepustowości.
Ładuj dokumenty i twórz indeksy na bieżąco
Tworzenie indeksu to zadanie wymagające dużej mocy obliczeniowej. Odbudowa indeksu za każdym razem, gdy uzyskujesz do niego dostęp, spowoduje oczywiste opóźnienia i pogorszenie komfortu użytkowania.
Oprócz lunrjs
istnieją inne rozwiązania do wyszukiwania pełnotekstowego, takie jak :
fusejs , oblicz podobieństwo między ciągami do przeszukania.
Wydajność tego rozwiązania jest wyjątkowo słaba i nie można go używać do wyszukiwania pełnotekstowego (patrz Fuse.js Długie zapytanie zajmuje więcej niż 10 sekundy, jak to zoptymalizować? ).
TinySearch , użyj filtru Bloom do wyszukiwania, nie można go używać do wyszukiwania prefiksów (na przykład wpisz goo
, szukaj good
, google
) i nie można uzyskać podobnego efektu automatycznego uzupełniania.
Ze względu na wady istniejących rozwiązań i18n.site
opracowała nowe, całkowicie front-endowe rozwiązanie do wyszukiwania pełnotekstowego, które ma następujące cechy :
gzip
wynosi 6.9KB
(dla porównania rozmiar lunrjs
wynosi 25KB
).indexedb
, który zajmuje mniej pamięci i jest szybki.Poniżej zostaną szczegółowo przedstawione i18n.site
szczegółów technicznych wdrożenia.
Segmentacja słów wykorzystuje natywną segmentację słów przeglądarki Intl.Segmenter
i wszystkie popularne przeglądarki obsługują ten interfejs.
Kod segmentacji słów coffeescript
jest następujący
SEG = new Intl.Segmenter 0, granularity: "word"
seg = (txt) =>
r = []
for {segment} from SEG.segment(txt)
for i from segment.split('.')
i = i.trim()
if i and !'| `'.includes(i) and !/\p{P}/u.test(i)
r.push i
r
export default seg
export segqy = (q) =>
seg q.toLocaleLowerCase()
W:
/\p{P}/
to wyrażenie regularne pasujące do znaków interpunkcyjnych. Do określonych pasujących symboli należą: ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _
{ | } .</p><ul><li>
split('.')wynika z tego, że segmentacja słów w przeglądarce
Firefoxnie obejmuje segmentacji
. ` .
W IndexedDB
utworzono 5 tabel do przechowywania obiektów :
word
: id -doc
: id - url - dokumentu Numer wersji dokumentudocWord
: Tablica dokumentu id - słowo idprefix
: Tablica przedrostków - słowa idrindex
: Słowo id - Dokument id : Tablica numerów liniiPrzekaż tablicę dokumentu url
i numer wersji ver
i sprawdź, czy dokument istnieje w tabeli doc
Jeśli nie istnieje, utwórz odwrócony indeks. Jednocześnie usuń odwrócony indeks dla tych dokumentów, które nie zostały przekazane.
W ten sposób można osiągnąć indeksowanie przyrostowe i zmniejszyć ilość obliczeń.
Podczas interakcji z interfejsem użytkownika można wyświetlić pasek postępu ładowania indeksu, aby uniknąć opóźnień podczas ładowania po raz pierwszy. Zobacz „Pasek postępu z animacją, oparty na pojedynczej progress + Czystej css implementacji” Angielski / Chiński .
Projekt idb jest w oparciu o asynchroniczną enkapsulację IndexedDB
Odczyty i zapisy IndexedDB są asynchroniczne. Podczas tworzenia indeksu dokumenty będą ładowane jednocześnie w celu utworzenia indeksu.
Aby uniknąć częściowej utraty danych spowodowanej zapisem konkurencyjnym, możesz odwołać się do poniższego kodu coffeescript
i dodać pamięć podręczną ing
pomiędzy odczytem a zapisem, aby przechwycić konkurencyjne zapisy.
pusher = =>
ing = new Map()
(table, id, val)=>
id_set = ing.get(id)
if id_set
id_set.add val
return
id_set = new Set([val])
ing.set id, id_set
pre = await table.get(id)
li = pre?.li or []
loop
to_add = [...id_set]
li.push(...to_add)
await table.put({id,li})
for i from to_add
id_set.delete i
if not id_set.size
ing.delete id
break
return
rindexPush = pusher()
prefixPush = pusher()
Wyszukiwanie najpierw segmentuje słowa kluczowe wprowadzone przez użytkownika.
Załóżmy, że po słowie segmentacja jest N
słów. Podczas zwracania wyników najpierw zostaną zwrócone wyniki zawierające wszystkie słowa kluczowe, a następnie zostaną zwrócone wyniki zawierające N-1
, N-2
,..., 1
słowa kluczowe.
Wyniki wyszukiwania wyświetlane w pierwszej kolejności zapewniają trafność zapytania, a wyniki ładowane później (kliknij przycisk Załaduj więcej) zapewniają szybkość przypominania.
Aby poprawić szybkość odpowiedzi, wyszukiwanie wykorzystuje generator yield
do implementowania ładowania na żądanie i powraca limit
razem, gdy zapytanie o wynik.
Pamiętaj, że za każdym razem, gdy będziesz szukać ponownie po yield
, musisz ponownie otworzyć transakcję zapytania o IndexedDB
.
Aby wyświetlić wyniki wyszukiwania, gdy użytkownik wpisuje np. wor
, wyświetlane są słowa poprzedzone cyfrą wor
np. words
i work
.
Jądro wyszukiwania użyje tabeli prefix
do segmentacji ostatniego słowa po słowie, aby znaleźć wszystkie słowa z nią poprzedzone i wyszukać po kolei.
Funkcja przeciwwstrząsowa debounce
jest również używana w interakcji z interfejsem użytkownika (zaimplementowana w następujący sposób) w celu zmniejszenia częstotliwości wprowadzania danych przez użytkownika wyzwalających wyszukiwania i zmniejszenia ilości obliczeń.
export default (wait, func) => {
var timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(func.bind(this, ...args), wait);
};
}
Tabela indeksowa nie przechowuje oryginalnego tekstu, tylko słowa, co zmniejsza ilość miejsca.
Podświetlanie wyników wyszukiwania wymaga ponownego załadowania oryginalnego tekstu, a dopasowanie service worker
pozwala uniknąć powtarzających się żądań sieciowych.
Jednocześnie, ponieważ service worker
buforuje wszystkie artykuły, po przeprowadzeniu wyszukiwania przez użytkownika cała witryna internetowa, łącznie z wyszukiwaniem, jest dostępna w trybie offline.
Rozwiązanie do wyszukiwania wyłącznie z przodu i18n.site
jest zoptymalizowane pod kątem MarkDown
dokumentów.
Podczas wyświetlania wyników wyszukiwania zostanie wyświetlona nazwa rozdziału, a kliknięcie umożliwi nawigację po rozdziale.
Odwrócone wyszukiwanie pełnotekstowe zaimplementowane wyłącznie w interfejsie użytkownika, bez konieczności stosowania serwera. Jest bardzo odpowiedni dla małych i średnich stron internetowych, takich jak dokumenty i blogi osobiste.
i18n.site
Samodzielnie opracowane, czyste wyszukiwanie typu open source, niewielkie rozmiary i szybka reakcja, rozwiązują niedociągnięcia obecnego wyszukiwania pełnotekstowego w trybie czysto front-end i zapewniają lepszą wygodę użytkownika.