brief: | i18n.site stöder nu serverlös fulltextsökning.
Den här artikeln introducerar implementeringen av ren front-end fulltextsökteknik, inklusive inverterat index byggt av IndexedDB, prefixsökning, ordsegmenteringsoptimering och flerspråksstöd.
Jämfört med befintliga lösningar är i18n.sites rena frontend-fulltextsökning liten och snabb, lämplig för små och medelstora webbplatser som dokument och bloggar, och är tillgänglig offline.
Efter flera veckors utveckling stöder i18n.site (ett rent statiskt markdown multilingualtranslation & webbplatsbyggande verktyg) nu ren front-end fulltextsökning.
Den här artikeln kommer att dela den tekniska implementeringen av i18n.site
ren front-end full-text sökning. i18n.site för att uppleva sökeffekten.
Kod öppen : Sök kärnan / interaktivt gränssnitt
För små och medelstora rent statiska webbplatser som dokument/personliga bloggar är det för tungt att bygga en egenbyggd fulltextsökningsbackend, och tjänstefri fulltextsökning är det vanligaste valet.
Serverlösa fulltextsöklösningar delas in i två breda kategorier:
För det första, liknande algolia.com Tredjepartssöktjänstleverantörer tillhandahåller front-end-komponenter för fulltextsökning.
Sådana tjänster kräver betalning baserat på sökvolym och är ofta otillgängliga för användare i Kina på grund av problem som webbplatsefterlevnad.
Det kan inte användas offline, kan inte användas på intranätet och har stora begränsningar. Den här artikeln diskuterar inte mycket.
Den andra är ren front-end fulltextsökning.
För närvarande inkluderar vanliga rena front-end-fulltextsökningar lunrjs och ElasticLunr.js (baserat på lunrjs
sekundär utveckling).
lunrjs
Det finns två sätt att bygga index, och båda har sina egna problem.
Förbyggda indexfiler
Eftersom indexet innehåller ord från alla dokument är det stort. Närhelst ett dokument läggs till eller ändras måste en ny indexfil laddas. Det kommer att öka användarens väntetid och förbruka mycket bandbredd.
Ladda dokument och skapa index i farten
Att bygga ett index är en beräkningsintensiv uppgift Att bygga om indexet varje gång du kommer åt det kommer att orsaka uppenbara fördröjningar och dålig användarupplevelse.
Förutom lunrjs
finns det några andra fulltextsöklösningar, som :
fusejs , beräkna likheten mellan strängar för att söka.
Den här lösningens prestanda är extremt dålig och kan inte användas för fulltextsökning (se Fuse.js Lång fråga tar mer än 10 sekunder, hur optimerar man den? ).
TinySearch , använd Bloom-filtret för att söka, kan inte användas för prefixsökning (skriv till exempel goo
, sök good
, google
) och kan inte uppnå liknande automatisk slutförande.
På grund av bristerna i de befintliga lösningarna utvecklade i18n.site
en ny ren front-end fulltextsöklösning, som har följande egenskaper :
gzip
är 6.9KB
(för jämförelse, storleken på lunrjs
är 25KB
).indexedb
, som tar upp mindre minne och är snabbt.Nedan kommer i18n.site
tekniska implementeringsdetaljer att presenteras i detalj.
Ordsegmentering använder webbläsarens ursprungliga ordsegmentering Intl.Segmenter
, och alla vanliga webbläsare stöder detta gränssnitt.
Ordet segmentering coffeescript
koden är som följer
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()
i:
/\p{P}/
är ett reguljärt uttryck som matchar skiljetecken. Specifika matchande symboler inkluderar: ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _
{ | } ~. .</p><ul><li>
split('.')beror på att
Firefoxwebbläsarordsegmentering inte segment
. ` .
5 objektlagringstabeller skapades i IndexedDB
:
word
: id -doc
: id - Dokument url - Dokumentets versionsnummerdocWord
: Array av dokument id - word idprefix
: Array av prefix - ord idrindex
: Word id - Dokument id : Array av radnummerSkicka in arrayen för dokument url
och versionsnummer ver
och sök om dokumentet finns i tabell doc
Om det inte finns, skapa ett inverterat index. Ta samtidigt bort det inverterade indexet för de dokument som inte skickades in.
På detta sätt kan inkrementell indexering uppnås och mängden beräkningar minskas.
I front-end-interaktion kan indexets förloppsindikator visas för att undvika fördröjning vid laddning för första gången. Se "Förloppsindikator med animering, baserat på en singel progress + Ren css Implementering" engelska / kinesiska .
Projektet är idb baserat på den asynkrona inkapslingen av IndexedDB
IndexedDB läser och skriver är asynkrona. När du skapar ett index kommer dokument att laddas samtidigt för att skapa indexet.
För att undvika partiell dataförlust orsakad av konkurrerande skrivning, kan du hänvisa till coffeescript
koden nedan och lägga till en ing
cache mellan läsning och skrivning för att fånga upp konkurrerande skrivningar.
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()
Sökningen segmenterar först de sökord som användaren angett.
Antag att det finns N
ord efter ordsegmenteringen. När du returnerar resultat kommer resultat som innehåller alla nyckelord att returneras först, och sedan kommer resultat som innehåller N-1
, N-2
,..., 1
nyckelord att returneras.
Sökresultaten som visas först säkerställer att frågan är korrekt, och resultaten som laddas därefter (klicka på knappen Ladda mer) säkerställer återkallningsfrekvensen.
För att förbättra svarshastigheten använder sökningen yield
-generatorn för att implementera on-demand-laddning och returnerar limit
gång ett resultat efterfrågas.
Observera att varje gång du söker igen efter yield
måste du öppna en frågetransaktion på IndexedDB
igen.
För att visa sökresultat medan användaren skriver, till exempel när wor
skrivs in, visas ord med wor
som words
och work
prefix.
Sökkärnan kommer att använda prefix
tabellen för det sista ordet efter ordsegmentering för att hitta alla ord med prefix och söka i följd.
Anti-shake-funktionen debounce
används också i front-end-interaktion (implementerad enligt följande) för att minska frekvensen av användarinmatning som utlöser sökningar och minska mängden beräkningar.
export default (wait, func) => {
var timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(func.bind(this, ...args), wait);
};
}
Indextabellen lagrar inte originaltexten, bara orden, vilket minskar mängden lagring.
Att markera sökresultat kräver att originaltexten laddas om, och matchande service worker
kan undvika upprepade nätverksförfrågningar.
Samtidigt, eftersom service worker
cachar alla artiklar, är hela webbplatsen, inklusive sökningen, tillgänglig offline när användaren väl utför en sökning.
i18n.site
:s rena front-end söklösning är optimerad för MarkDown
dokument.
När du visar sökresultat kommer kapitelnamnet att visas och kapitlet navigeras när du klickar på det.
Inverterad fulltextsökning implementerad enbart på användargränssnittet, ingen server krävs. Den är mycket lämplig för små och medelstora webbplatser som dokument och personliga bloggar.
i18n.site
Öppen källkod egenutvecklad ren front-end-sökning, liten till storleken och snabb respons, löser bristerna i den nuvarande rena front-end-fulltextsökningen och ger en bättre användarupplevelse.