Heim  >  Artikel  >  Web-Frontend  >  Reine Front-End-invertierte Volltextsuche

Reine Front-End-invertierte Volltextsuche

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-10-14 14:27:29249Durchsuche

Originallink: https://i18n.site/blog/tech/search

Sequenz

Nach mehreren Wochen der Entwicklung unterstützt i18n.site (ein rein statisches mehrsprachiges Markdown-Übersetzungs- und Website-Erstellungstool) jetzt die reine Front-End-Volltextsuche.

Reine Front-End-invertierte VolltextsucheReine Front-End-invertierte Volltextsuche

In diesem Artikel wird die technische Implementierung der reinen Front-End-Volltextsuche von i18n.site vorgestellt. Besuchen Sie i18n.site, um die Suchfunktion kennenzulernen.

Code ist Open-Source: Suchkernel / Interaktive Schnittstelle

Ein Überblick über serverlose Volltextsuchlösungen

Für kleine und mittlere rein statische Websites wie Dokumente/persönliche Blogs ist der Aufbau eines selbst erstellten Volltextsuche-Backends zu aufwändig, und eine dienstfreie Volltextsuche ist die häufigere Wahl.

Serverlose Volltextsuchlösungen sind in zwei Hauptkategorien unterteilt:

Beim ersten handelt es sich um Drittanbieter von Suchdiensten wie algolia.com, die Frontend-Komponenten für die Volltextsuche anbieten.

Solche Dienste erfordern eine Bezahlung basierend auf dem Suchvolumen und sind aufgrund von Compliance-Problemen für Benutzer auf dem chinesischen Festland häufig nicht verfügbar.

Sie können nicht offline oder in Intranets verwendet werden und unterliegen erheblichen Einschränkungen. In diesem Artikel wird nicht näher darauf eingegangen.

Die zweite Kategorie ist die reine Front-End-Volltextsuche.

Zu den derzeit gängigen reinen Front-End-Volltextsuchtools gehören lunrjs und ElasticLunr.js (eine sekundäre Entwicklung, die auf lunrjs basiert).

lunrjs verfügt über zwei Methoden zum Erstellen von Indizes, beide mit ihren eigenen Problemen.

  1. Vorgefertigte Indexdateien

Da der Index alle Wörter aus den Dokumenten enthält, ist er groß.
Jedes Mal, wenn ein Dokument hinzugefügt oder geändert wird, muss eine neue Indexdatei geladen werden.
Dies erhöht die Wartezeit der Benutzer und verbraucht eine erhebliche Menge an Bandbreite.

  1. Dokumente laden und Indizes im Handumdrehen erstellen

Das Erstellen eines Index ist eine rechenintensive Aufgabe, und die Neuerstellung bei jedem Zugriff kann zu spürbaren Verzögerungen führen, was zu einer schlechten Benutzererfahrung führt.


Neben lunrjs gibt es noch andere Volltextsuchlösungen, wie zum Beispiel:

fusejs, das sucht, indem es die Ähnlichkeit zwischen Zeichenfolgen berechnet.

Diese Lösung weist eine schlechte Leistung auf und ist nicht für die Volltextsuche geeignet (siehe Fuse.js. Lange Abfrage dauert mehr als 10 Sekunden, wie optimiert man sie?).

TinySearch, das einen Bloom-Filter für die Suche verwendet, kann keine Präfixsuchen durchführen (z. B. Eingabe von „goo“, um nach „Gut“ oder „Google“ zu suchen) und keinen automatischen Vervollständigungseffekt erzielen.

Aufgrund der Nachteile bestehender Lösungen hat i18n.site eine neue reine Front-End-Volltextsuchlösung mit den folgenden Funktionen entwickelt:

  1. Unterstützt die mehrsprachige Suche bei kompakter Größe; Der Suchkernel ist, wenn er mit gzip gepackt ist, nur 6,9 KB groß (im Vergleich dazu ist lunrjs 25 KB groß)
  2. Erstellt einen invertierten Index basierend auf IndexedDB mit geringer Speichernutzung und schneller Leistung
  3. Wenn Dokumente hinzugefügt/geändert werden, werden nur die hinzugefügten oder geänderten Dokumente neu indiziert, wodurch sich der Berechnungsaufwand verringert
  4. Unterstützt die Präfixsuche und ermöglicht die Echtzeitanzeige von Suchergebnissen während der Eingabe durch den Benutzer
  5. Offline-Verfügbarkeit

Details zur technischen Implementierung von i18n.site werden unten vorgestellt.

Mehrsprachige Wortsegmentierung

Wortsegmentierung verwendet den nativen Intl.Segmenter des Browsers, der von allen gängigen Browsern unterstützt wird.

Reine Front-End-invertierte Volltextsuche

Der Coffeescript-Code für die Wortsegmentierung lautet wie folgt:

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()

Wo:

  • /p{P}/ ist ein regulärer Ausdruck, der Satzzeichen übereinstimmt, einschließlich: ! " # $ % & ' ( ) * , - . / : ; < = > ? @ [ ] ^ _ { | } ~. .

    • split('.' ) liegt daran, dass die Firefox-Browser-Wortsegmentierung keine Segmentierung durchführt.` .

    Indexkonstruktion

    Fünf Objektspeichertabellen werden in IndexedDB erstellt:

    • Wort: id - Wort
    • doc: id – Dokument-URL – Dokumentversionsnummer
    • docWord: Dokument-ID – Array von Wort-IDs
    • Präfix: Präfix – Array von Wort-IDs
    • rindex: Wort-ID – Dokument-ID – Array von Zeilennummern

    Durch die Übergabe eines Arrays aus Dokument-URL und Versionsnummer ver wird die Dokumenttabelle auf die Existenz des Dokuments überprüft. Wenn er nicht vorhanden ist, wird ein invertierter Index erstellt. Gleichzeitig wird der invertierte Index für nicht übergebene Dokumente entfernt.

    Diese Methode ermöglicht eine inkrementelle Indizierung und reduziert so die Rechenlast.

    In the front-end interface, a progress bar for index loading can be displayed to avoid lag during the initial load. See "Animated Progress Bar, Based on a Single progress + Pure CSS Implementation" English / Chinese.

    IndexedDB High Concurrent Writing

    The project is developed based on the asynchronous encapsulation of IndexedDB, idb.

    IndexedDB reads and writes are asynchronous. When creating an index, documents are loaded concurrently to build the index.

    To avoid data loss due to concurrent writes, you can refer to the following coffeescript code, which adds a ing cache between reading and writing to intercept competitive writes.

    `coffee
    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()
    `

    Prefix Real-Time Search

    To display search results in real-time as the user types, for example, showing words like words and work that start with wor when wor is entered.

    Reine Front-End-invertierte Volltextsuche

    The search kernel uses the prefix table for the last word after segmentation to find all words with that prefix and search sequentially.

    An anti-shake function, debounce (implemented as follows), is used in the front-end interaction to reduce the frequency of searches triggered by user input, thus minimizing computational load.

    js
    export default (wait, func) => {
    var timeout;
    return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(func.bind(this, ...args), wait);
    };
    }

    Precision and Recall

    The search first segments the keywords entered by the user.

    Assuming there are N words after segmentation, the results are first returned with all keywords, followed by results with N-1, N-2, ..., 1 keywords.

    The search results displayed first ensure query precision, while subsequent loaded results (click the "Load More" button) ensure recall.

    Reine Front-End-invertierte Volltextsuche

    On-Demand Loading

    To improve response speed, the search uses the yield generator to implement on-demand loading, returning results after each limit query.

    Note that after each yield, a new IndexedDB query transaction must be opened for the next search.

    Prefix Real-Time Search

    To display search results in real-time as the user types, for example, showing words like words and work that start with wor when wor is entered.

    Reine Front-End-invertierte Volltextsuche

    The search kernel uses the prefix table for the last word after segmentation to find all words with that prefix and search sequentially.

    An anti-shake function, debounce (implemented as follows), is used in the front-end interaction to reduce the frequency of searches triggered by user input, thus minimizing computational load.

    js
    export default (wait, func) => {
    var timeout;
    return function(...args) {
    clearTimeout(timeout);
    timeout = setTimeout(func.bind(this, ...args), wait);
    };
    }

    Offline Availability

    The index table does not store the original text, only words, reducing storage space.

    Highlighting search results requires reloading the original text, and using service worker can avoid repeated network requests.

    Also, because service worker caches all articles, once a search is performed, the entire website, including search functionality, becomes offline available.

    Optimization for Displaying MarkDown Documents

    The pure front-end search solution provided by i18n.site is optimized for MarkDown documents.

    When displaying search results, the chapter name is shown, and clicking navigates to that chapter.

    Reine Front-End-invertierte Volltextsuche

    Summary

    The pure front-end implementation of inverted full-text search, without the need for a server, is very suitable for small to medium-sized websites such as documents and personal blogs.

    i18n.site's open-source self-developed pure front-end search is compact, responsive, and addresses the various shortcomings of current pure front-end full-text search solutions, providing a better user experience.

    Das obige ist der detaillierte Inhalt vonReine Front-End-invertierte Volltextsuche. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn