Eine wirklich intelligente Suche durchführen: Schritt-für-Schritt-Anleitung

Suche im Unternehmensinformationssystem - schon von diesem Satz selbst bleibt es im Mund stecken. Es ist gut, wenn Sie überhaupt eine haben, müssen Sie nicht einmal über eine positive Benutzererfahrung nachdenken. Wie kann man die Einstellung der von Suchmaschinen verwöhnten Benutzer umkehren und ein schnelles, genaues und perfekt verständliches Produkt erstellen? Wir müssen ein gutes Stück Elasticsearch, eine Handvoll intelligenter Dienste, nehmen und sie in diesem Handbuch kneten.


Es gibt viele Artikel darüber, wie Sie die Volltextsuche basierend auf Elasticsearch in die vorhandene Datenbank integrieren können. Aber es gibt eindeutig nicht genug Artikel darüber, wie man eine wirklich kluge Suche durchführt.


Gleichzeitig hat sich der Ausdruck "Smart Search" selbst bereits zu einem Schlagwort entwickelt und ist an den Ort gewöhnt und nicht. Was sollte eine Suchmaschine tun, um als intelligent zu gelten? Letztendlich kann dies so beschrieben werden, dass das Ergebnis angegeben wird, das der Benutzer tatsächlich benötigt, auch wenn dieses Ergebnis nicht ganz mit dem Text der Anforderung übereinstimmt. Beliebte Suchmaschinen wie Google und Yandex gehen noch weiter und finden nicht nur die benötigten Informationen, sondern beantworten direkt Benutzerfragen.

Okay, wir werden nicht sofort eine Ultimatum-Entscheidung treffen, aber was kann getan werden, um eine regelmäßige Volltextsuche einer intelligenten näher zu bringen?


Elemente der Intelligenz


Intelligente Suche - Dies ist nur dann der Fall, wenn die Quantität in Qualität gehen kann und viele kleine und ziemlich einfache Funktionen ein Gefühl der Magie erzeugen können.


  • Korrektur von Benutzerfehlern - ob es sich um einen Tippfehler, ein falsches Layout oder möglicherweise eine Anfrage mit einer verdächtig geringen Anzahl von Ergebnissen handelt, die jedoch einer Anfrage ähnelt, für die es viel mehr Informationen gibt.
  • Für th NLP-Chats (Verarbeitung natürlicher Sprache, nicht das, was Sie dachten) - Wenn der Benutzer im letzten Jahr kommerzielle Angebote eingegeben hat, wollte er wirklich im Text aller Dokumente nach diesen Wörtern suchen oder brauchte er wirklich nur kommerzielle Angebote und erst im letzten Jahr ?
  • Prognostizieren Sie Eingaben basierend auf früheren Abfragen oder beliebten Dokumenten.
  • Die Präsentation des Ergebnisses ist das übliche Highlight des gefundenen Fragments. Zusätzliche Informationen hängen davon ab, wonach Sie gesucht haben. Da im vorherigen Absatz kommerzielle Vorschläge erforderlich waren, ist es möglicherweise sinnvoll, das Thema des Vorschlags und die Organisation, von der er stammt, sofort anzuzeigen.
  • Einfacher Drilldown - die Möglichkeit, die Suchabfrage mithilfe zusätzlicher Filter und Facetten zu verfeinern.

Einführung


Es gibt ein ECM-DIRECTUM mit vielen Dokumenten. Das Dokument besteht aus einer Karte mit Metainformationen und einem Textkörper, der mehrere Versionen haben kann.


Ziel ist es, schnell und bequem nach Informationen in diesen Dokumenten zu suchen, wie es für einen Benutzer von Suchmaschinen üblich ist.


Indizierung


Um nach etwas Gutem zu suchen, müssen Sie es zuerst gut indizieren.

Dokumente in ECM sind nicht statisch. Benutzer ändern Text, erstellen neue Versionen und ändern Daten auf Karten. Es werden ständig neue Dokumente erstellt und alte manchmal gelöscht.
Um die aktuellen Informationen in Elasticsearch auf dem neuesten Stand zu halten, müssen Dokumente ständig neu indiziert werden. Glücklicherweise verfügt ECM bereits über eine eigene Warteschlange für asynchrone Ereignisse. Wenn Sie also ein Dokument ändern, fügen Sie es einfach zur Indizierung in die Warteschlange ein.


Zuordnen von ECM-Dokumenten zu Elasticsearch-Dokumenten


Ein Dokumentkörper in ECM kann mehrere Versionen haben. In Elasticsearch könnte dies als ein Array verschachtelter Objekte betrachtet werden, aber dann wird es unpraktisch, mit ihnen zu arbeiten. Es wird schwieriger, Abfragen zu schreiben. Wenn Sie eine der Versionen ändern, müssen Sie alles neu indizieren. Verschiedene Versionen desselben Dokuments können nicht in verschiedenen Indizes gespeichert werden (warum ist dies möglicherweise erforderlich?) im nächsten Abschnitt). Daher denormalisieren wir ein Dokument aus ECM in mehrere Elasticsearch-Dokumente mit derselben Karte, aber unterschiedlichen Körpern.


Zusätzlich zu Karte und Körper werden dem Elasticsearch-Dokument verschiedene Serviceinformationen hinzugefügt, die separat erwähnt werden sollten:


  • eine Liste von IDs von Gruppen und Benutzern, die Rechte an dem Dokument haben - für Suchen mit Rechten;
  • die Anzahl der Aufrufe des Dokuments - zur Optimierung der Relevanz;
  • Zeitpunkt der letzten Indizierung.

Indexzusammensetzung


Ja, Pluralindizes. Normalerweise werden mehrere Indizes zum Speichern von Informationen mit ähnlicher Bedeutung in Elasticsearch nur verwendet, wenn diese Informationen unveränderlich und an einen bestimmten Zeitraum gebunden sind, z. B. Protokolle. Dann werden die Indizes je nach Intensität der Belastung jeden Monat / Tag oder häufiger erstellt. In unserem Fall kann jedes Dokument geändert werden, und es wäre möglich, alles in einem Index zu speichern.


Aber - die Dokumente im System können in verschiedenen Sprachen vorliegen, und das Speichern mehrsprachiger Daten in Elasticsearch bringt zwei Probleme mit sich:


  • Falsches Stemming. Bei einigen Wörtern wird die Basis korrekt gefunden, bei einigen - falsch (es gibt ein anderes Wort im Index), bei einigen - wird sie überhaupt nicht gefunden (der Index wird mit Wortformen verstopft). Bei einigen Wörtern aus verschiedenen Sprachen und mit unterschiedlichen Bedeutungen ist die Basis dieselbe, und dann geht die Bedeutung des Wortes verloren. Die Verwendung mehrerer Stemmers hintereinander kann zu einer zusätzlichen Berechnung der Basis für einen bereits berechneten führen.

Stamming - die Basis des Wortes finden. Der Stamm muss nicht die Wurzel des Wortes oder seine normale Form sein. Normalerweise reicht es aus, wenn die zugehörigen Wörter in ein Framework projiziert werden.
Lemmatisierung ist eine Art von Stemming, bei der die normale (Vokabular-) Form eines Wortes als Grundlage betrachtet wird.

  • Falsche Worthäufigkeit. Einige Relevanzbestimmungsmechanismen in ES berücksichtigen die Häufigkeit der gesuchten Wörter im Dokument (je häufiger, desto höher die Relevanz) und die Häufigkeit der gesuchten Wörter im Index (je häufiger, desto geringer die Relevanz). Eine kleine Verbreitung der russischen Sprache in einem englischen Dokument, wenn die englischen Dokumente überwiegend im Index enthalten sind, hat ein hohes Gewicht, es lohnt sich jedoch, die englischen und russischen Dokumente im Index zu mischen, und das Gewicht nimmt ab.

Das erste Problem kann für den Fall gelöst werden, dass verschiedene Sprachen unterschiedliche Zeichensätze verwenden (russisch-englische Dokumente verwenden kyrillische und lateinische Buchstaben) - Sprachstemmer verarbeiten nur "ihre" Zeichen.


Um das zweite Problem zu lösen, haben wir den Ansatz mit einem eigenen Index für jede Sprache verwendet.


Wenn wir beide Ansätze kombinieren, erhalten wir Sprachindizes, die dennoch Analysatoren für mehrere Sprachen enthalten, die sich nicht in jedem Zeichensatz überschneiden: Russisch-Englisch (und separat Englisch-Russisch), Polnisch-Russisch, Deutsch-Russisch, Ukrainisch-Englisch usw. .


Um nicht alle möglichen Indizes im Voraus zu erstellen, haben wir Indexvorlagen verwendet. Mit Elasticsearch können Sie eine Vorlage angeben, die Einstellungen und Zuordnungen enthält, und ein Indexnamenmuster angeben. Wenn Sie versuchen, ein Dokument in einen nicht vorhandenen Index zu indizieren, dessen Name mit einem der Muster der Vorlage übereinstimmt, wird nicht nur ein neuer Index erstellt, sondern auch Einstellungen und Zuordnungen aus der entsprechenden Vorlage werden darauf angewendet.


Indexstruktur


Für die Indizierung verwenden wir zwei Analysatoren gleichzeitig (über mehrere Felder): Standard für die Suche nach exakten Phrasen und benutzerdefiniert für alles andere:


"ru_en_analyzer": { "filter": [ "lowercase", "russian_morphology", "english_morphology", "word_delimiter", "ru_en_stopwords" ], "char_filter": [ "yo_filter" ], "type": "custom", "tokenizer": "standard"} 

Mit dem Kleinbuchstabenfilter ist alles klar, ich erzähle Ihnen von dem Rest.


Die Filter russian_morphology und english_morphology dienen zur morphologischen Analyse von russischem bzw. englischem Text. Sie sind nicht Teil von Elasticsearch und Teil eines separaten Analyse-Morphologie-Plugins. Dies sind Lemmatisierer, die den Vokabularansatz in Kombination mit einigen Heuristiken verwenden und wesentlich besser funktionieren als die eingebauten Filter für die entsprechenden Sprachen.


 POST _analyze { "analyzer": "russian", "text": "   " } >>    

Und:


 POST _analyze { "analyzer": "ru_en_analyzer", "text": "   " } >>    

Sehr merkwürdiger word_delimiter Filter. Es hilft beispielsweise, Tippfehler zu beseitigen, wenn nach dem Punkt kein Leerzeichen steht. Wir verwenden die folgende Konfiguration:


 "word_delimiter": { "catenate_all": "true", "type": "word_delimiter", "preserve_original": "true" } 

Mit yo_filter können Sie den Unterschied zwischen E und E ignorieren:


 "yo_filter": { "type": "mapping", "mappings": [ " => ", " => " ] } 

ru_en_stopwords Filtertyp stop - unser Wörterbuch der Stoppwörter.


Indizierungsprozess


Bei den Dokumenten in ECM handelt es sich in der Regel um Dateien mit Büroformaten: .docx, .pdf usw. Um den Text zu extrahieren, wird das Ingest-Attachment-Plugin mit der folgenden Pipeline verwendet:


 { "document_version": { "processors": [ { "attachment": { "field": "content", "target_field": "attachment", "properties": [ "content", "content_length", "content_type", "language" ], "indexed_chars": -1, "ignore_failure": true } }, { "remove": { "field": "content", "ignore_failure": true } }, { "script": { "lang": "painless", "params": { "languages": ["ru", "en" ], "language_delimeter": "_" }, "source": "..." } }, { "remove": { "field": "attachment", "ignore_failure": true } } ] } } 

Aus dem Ungewöhnlichen in der Pipeline, Ignorieren von Fehlern der Abwesenheit des Körpers (dies geschieht bei verschlüsselten Dokumenten) und Bestimmen des Zielindex basierend auf der Sprache des Textes. Letzteres geschieht in einer schmerzlosen Schrift, deren Körper ich separat geben werde, weil Aufgrund von JSON-Einschränkungen muss es in eine Zeile geschrieben werden. Zusammen mit Debugging-Schwierigkeiten (der empfohlene Weg ist, hier und da Ausnahmen auszulösen) wird es zu einer schmerzhaften.


 if (ctx.attachment != null) { if (params.languages.contains(ctx.attachment.language)) ctx._index = ctx._index + params.language_delimeter + ctx.attachment.language; if (ctx.attachment.content != null) ctx.content = ctx.attachment.content; if (ctx.attachment.content_length != null) ctx.content_length = ctx.attachment.content_length; if (ctx.attachment.content_type != null) ctx.content_type = ctx.attachment.content_type; if (ctx.attachment.language != null) ctx.language = ctx.attachment.language; } 

Daher senden wir das Dokument immer an index_name . Wenn die Sprache nicht definiert ist oder nicht unterstützt wird, wird das Dokument in diesem Index abgelegt , andernfalls fällt es in die Indexsprache .


Wir speichern nicht den ursprünglichen Hauptteil der Datei, aber das Feld _source ist aktiviert, weil Es ist erforderlich, das Dokument teilweise zu aktualisieren und das gefundene zu markieren.


Wenn sich nur die Karte seit der letzten Indizierung geändert hat, verwenden wir die Update By Query-API ohne Pipeline, um sie zu aktualisieren. Dies ermöglicht es erstens, potenziell schwere Dokumentkörper nicht aus ECM zu ziehen, und zweitens beschleunigt es die Aktualisierung auf der Elasticsearch-Seite erheblich - Sie müssen den Text von Dokumenten nicht aus Office-Formaten extrahieren, was sehr ressourcenintensiv ist.


Daher gibt es in Elasticsearch überhaupt keine Aktualisierung des Dokuments. Technisch gesehen wird beim Aktualisieren aus dem Index das alte Dokument herausgenommen, geändert und wieder vollständig indiziert.

Wenn sich der Text jedoch ändert, wird das alte Dokument im Allgemeinen gelöscht und von Grund auf neu indiziert. Dadurch können Dokumente von einem Sprachindex in einen anderen verschoben werden .


Suche


Um die Beschreibung zu vereinfachen, werde ich einen Screenshot des Endergebnisses geben



Volltext


Der Haupttyp der Abfrage ist Simple Query String Query :


 "simple_query_string": { "fields": [ "card.d*.*_text", "card.d*.*_text.exact", "card.name^2", "card.name.exact^2", "content", "content.exact" ], "query": " ", "default_operator": "or", "analyze_wildcard": true, "minimum_should_match": "-35%", "quote_field_suffix": ".exact" } 

Dabei sind .exact die vom Standardparser indizierten Felder. Die Wichtigkeit des Namens des Dokuments ist doppelt so hoch wie in den anderen Feldern. Mit der Kombination von "default_operator": "or" und "minimum_should_match": "-35%" können Sie Dokumente finden, die nicht bis zu 35% der gesuchten Wörter enthalten.


Synonyme


Im Allgemeinen werden verschiedene Analysatoren für die Indizierung und Suche verwendet. Der einzige Unterschied besteht darin, dass ein Filter hinzugefügt wird, um der Suchabfrage Synonyme hinzuzufügen:


 "search_analyzer": { "filter": [ "lowercase", "russian_morphology", "english_morphology", "synonym_filter", "word_delimiter", "ru_en_stopwords" ], "char_filter": [ "yo_filter" ], "tokenizer": "standard" } 

 "synonym_filter": { "type": "synonym_graph", "synonyms_path": "synonyms.txt" } 

Buchhaltungsrechte


Bei rechtsbasierten Suchvorgängen ist die Hauptabfrage mit einem zusätzlichen Filter in Bool Query eingebettet:


 "bool": { "must": [ { "simple_query_string": {...} } ], "filter": [ { "terms": { "rights": [           ] } } ] } 

Wie wir uns aus dem Abschnitt über die Indizierung erinnern, enthält der Index ein Feld mit der ID von Benutzern und Gruppen, die Rechte an dem Dokument haben. Wenn es einen Schnittpunkt dieses Feldes mit dem übergebenen Array gibt, gibt es Rechte.


Relevanz-Tuning


Standardmäßig bewertet Elasticsearch die Relevanz der Ergebnisse mithilfe des BM25- Algorithmus anhand der Abfrage und des Textes des Dokuments. Wir haben beschlossen, dass drei weitere Faktoren die Bewertung der Einhaltung des gewünschten und tatsächlichen Ergebnisses beeinflussen sollten:


  • der Zeitpunkt der letzten Bearbeitung des Dokuments - je weiter es in der Vergangenheit war, desto weniger wahrscheinlich ist es, dass dieses Dokument benötigt wird;
  • die Anzahl der Aufrufe des Dokuments - je mehr, desto wahrscheinlicher ist es, dass dieses Dokument benötigt wird;
  • ECM-Karosserieversionen haben mehrere mögliche Zustände: entwickelt, betriebsbereit und veraltet. Es ist logisch, dass das Handeln wichtiger ist als die anderen.


    Sie können diesen Effekt mit Hilfe der Function Score Query erzielen:


     "function_score": { "functions": [ { "gauss": { "modified_date": { "origin": "now", "scale": "1095d", "offset": "31d", "decay": 0.5 } } }, { "field_value_factor": { "field": "access_count", "missing": 1, "modifier": "log2p" } }, { "filter": { "term": { "life_stage_value_id": { "value": "" } } }, "weight": 1.1 } ], "query": { "bool": {...} } } 

    Als Ergebnis, ceteris paribus, erhalten wir ungefähr die folgende Abhängigkeit des Ergebnisbewertungsmodifikators vom Datum seiner letzten Änderung X und der Anzahl der Treffer Y:




Externe Intelligenz


Für einen Teil der Funktionalität der intelligenten Suche müssen wir verschiedene Fakten aus der Suchabfrage extrahieren: Daten mit ihrer Anwendung (Erstellung, Änderung, Genehmigung usw.), Namen von Organisationen, Arten von gesuchten Dokumenten usw.


Es ist auch wünschenswert, die Anfrage in eine bestimmte Kategorie einzuteilen, z. B. Dokumente nach Organisation, Mitarbeiter, Aufsichtsbehörden usw.


Diese beiden Vorgänge werden vom ECM Intelligent Module - DIRECTUM Ario ausgeführt .


Intelligenter Suchprozess


Es ist an der Zeit, genauer zu überlegen, welche Mechanismen als Elemente der Intelligenz implementiert sind.


Benutzerfehlerkorrektur


Die Richtigkeit des Layouts wird anhand des Trigramm-Sprachmodells bestimmt. Für eine Zeile wird berechnet, wie wahrscheinlich es ist, dass die dreistelligen Sequenzen in Texten in Englisch und Russisch erfüllt werden. Wenn das aktuelle Layout als weniger wahrscheinlich angesehen wird, wird zunächst ein Hinweis mit einem korrekten Layout angezeigt:



und zweitens werden die weiteren Schritte der Suche mit dem richtigen Layout ausgeführt:



Und wenn mit dem korrigierten Layout nichts gefunden werden kann, beginnt die Suche mit der ursprünglichen Zeile.


Die Tippfehlerkorrektur wird mit Phrase Suggester implementiert. Es liegt ein Problem vor: Wenn Sie eine Abfrage für mehrere Indizes gleichzeitig ausführen, wird vorgeschlagen, dass möglicherweise nichts zurückgegeben wird. Wenn Sie nur für einen Index ausführen, werden Ergebnisse angezeigt. Dies wird behandelt, indem das Vertrauen auf 0 gesetzt wird. Dann wird jedoch vorgeschlagen, Wörter durch ihre normale Form zu ersetzen. Stimmen Sie zu, es wird seltsam sein, wenn Sie nach "Buchstabe a " suchen, um eine Antwort im Geiste zu erhalten: Vielleicht haben Sie nach einem Brief über gesucht?


Dies kann umgangen werden, indem zwei Eingabeaufforderungen in der Anforderung verwendet werden:


 "suggest": { "content_suggest": { "text": " ", "phrase": { "collate": { "query": {         {{suggestion}} } }, } }, "check_suggest": { "text": "", "phrase": { "collate": { "query": {         {{suggestion}} - ({{source_query}}) }, "params": { "source_query": " " } }, } } } 

Von den gebräuchlichen Parametern


 "confidence": 0.0, "max_errors": 3.0, "size": 1 

Wenn der erste Opinester das Ergebnis zurückgegeben hat, der zweite jedoch nicht, ist dieses Ergebnis die ursprüngliche Zeichenfolge selbst, möglicherweise mit Wörtern in anderen Formen, und es besteht keine Notwendigkeit, einen Hinweis anzuzeigen. Wenn der Hinweis weiterhin benötigt wird, wird der ursprüngliche Suchbegriff mit dem Hinweis zusammengeführt. Dies geschieht, indem nur die korrigierten Wörter ersetzt werden und nur diejenigen, die die Rechtschreibprüfung (mit Hunspell) als falsch erachtet.


Wenn die Suche in der Quellzeichenfolge 0 Ergebnisse ergab, wird sie durch die durch die Zusammenführung erhaltene Zeichenfolge ersetzt und die Suche wird erneut ausgeführt:



Andernfalls wird die resultierende Eingabeaufforderungszeichenfolge nur als Eingabeaufforderung für die Suche zurückgegeben:



Abfrageklassifizierung und Faktenextraktion


Wie bereits erwähnt, verwenden wir DIRECTUM Ario, nämlich den Textklassifizierungsdienst und den Faktenextraktionsdienst. Zu diesem Zweck haben wir Analysten anonyme Suchanfragen und eine Liste mit Fakten gestellt, an denen wir interessiert sind. Basierend auf Abfragen und dem Wissen darüber, welche Dokumente sich im System befinden, identifizierten die Analysten mehrere Kategorien und schulten den Klassifizierungsdienst, um die Kategorie gemäß dem Abfragetext zu bestimmen. Basierend auf den resultierenden Kategorien und der Liste der Fakten haben wir die Regeln für die Verwendung dieser Fakten formuliert. Beispielsweise wird der Ausdruck für das letzte Jahr in der Kategorie Jeder als Erstellungsdatum des Dokuments und in der Kategorie Nach Organisation als Registrierungsdatum betrachtet. Gleichzeitig sollten die im letzten Jahr erstellten in jeder Kategorie auf das Erstellungsdatum fallen.


Von der Suchseite aus haben sie eine Konfiguration erstellt, in der sie die Kategorien registriert haben, welche Fakten auf welche Facettenfilter angewendet werden.


Eingabe abgeschlossen


Zusätzlich zu den bereits erwähnten Layoutkorrekturen werden frühere Suchanfragen des Benutzers und öffentliche Dokumente automatisch vervollständigt.



Sie werden mit einem anderen Suggestertyp implementiert - Completion Suggester , aber jeder hat seine eigenen Nuancen.


Autovervollständigung: Suchverlauf

ECM enthält weit weniger Benutzer als Suchmaschinen und weist ihnen genügend allgemeine Abfragen zu warum Lenin Pilz nicht möglich. Alles in einer Reihe zu zeigen, lohnt sich aus Datenschutzgründen ebenfalls nicht. Der übliche Vervollständigungsvorschlag kann nur den gesamten Satz von Dokumenten im Index durchsuchen, aber der Kontextvorschlag hilft dabei - eine Möglichkeit, einen Kontext für jeden Hinweis festzulegen und nach diesen Kontexten zu filtern. Wenn Benutzernamen als Kontexte verwendet werden, kann jedem nur sein Verlauf angezeigt werden.


Sie müssen dem Benutzer auch die Möglichkeit geben, die Eingabeaufforderung zu entfernen, für die er sich schämt. Als Schlüssel zum Löschen haben wir den Benutzernamen und den QuickInfo-Text verwendet. Als Ergebnis haben wir für den Index mit Hinweisen eine so leicht duplizierte Zuordnung erhalten:


 "mappings": { "document": { "properties": { "input": { "type": "keyword" }, "suggest": { "type": "completion", "analyzer": "simple", "preserve_separators": true, "preserve_position_increments": true, "max_input_length": 50, "contexts": [ { "name": "user", "type": "CATEGORY" } ] }, "user": { "type": "keyword" } } } } 

Die Gewichtung für jeden neuen Hinweis wird auf eins festgelegt und erhöht sich jedes Mal, wenn Sie ihn mithilfe der Update By Query-API mit einem sehr einfachen Skript ctx._source.suggest.weight++ .


Autovervollständigung: Dokumente

Es kann jedoch viele Dokumente und mögliche Kombinationen von Rechten geben. Im Gegenteil, wir haben uns hier entschieden, beim automatischen Ausfüllen nicht nach Rechten zu filtern, sondern nur öffentliche Dokumente zu indizieren. Ja, und Sie müssen keine einzelnen Tipps aus diesem Index entfernen. Es scheint, dass die Implementierung in allem einfacher ist als in der vorherigen, wenn nicht in zwei Punkten:


Der erste - Completion Suggester unterstützt nur die Präfixsuche, und Kunden lieben es, .01.01 Artikelnummern und einigen .01.01 beim .01.01 einer Abfrage zuzuweisen. Es gibt .01.01 . Hier können Sie neben dem vollständigen Namen auch davon abgeleitete n-Gramm indizieren:


 { "extension": "pdf", "name": ".01.01   ", "suggest": [ { "input": "", "weight": 70 }, { "input": " ", "weight": 80 }, { "input": "  ", "weight": 90 }, { "input": ".01.01   ", "weight": 100 } ] } 

Dies war bei der Geschichte nicht so kritisch, dennoch gibt derselbe Benutzer ungefähr dieselbe Zeile ein, wenn er erneut nach etwas sucht. Wahrscheinlich .



Die zweite - standardmäßig sind alle Tipps gleich, aber wir möchten einige davon gleich und vorzugsweise so gestalten, dass dies mit der Rangfolge der Suchergebnisse übereinstimmt. Wiederholen Sie dazu grob die in der Funktions-Score-Abfrage verwendeten Funktionen gauss und field_value_factor.


Es stellt sich heraus, dass hier eine solche Pipeline ist:


 { "dir_public_documents_pipeline": { "processors": [ ... { "set": { "field": "terms_array", "value": "{{name}}" } }, { "split": { "field": "terms_array", "separator": "\\s+|$" } }, { "script": { "source": "..." } } ] } } 

mit folgendem Skript:


 Date modified = new Date(0); if (ctx.modified_date != null) modified = new SimpleDateFormat('dd.MM.yyyy').parse(ctx.modified_date); long dayCount = (System.currentTimeMillis() - modified.getTime())/(1000*60*60*24); double score = Math.exp((-0.7*Math.max(0, dayCount - 31))/1095) * Math.log10(ctx.access_count + 2); int count = ctx.terms_array.length; ctx.suggest = new ArrayList(); ctx.suggest.add([ 'input': ctx.terms_array[count - 1], 'weight': Math.round(score * (255 - count + 1)) ]); for (int i = count - 2; i >= 0 ; --i) { if (ctx.terms_array[i].trim() != "") { ctx.suggest.add([ "input": ctx.terms_array[i] + " " + ctx.suggest[ctx.suggest.length - 1].input, "weight": Math.round(score * (255 - i))]); } } ctx.remove('terms_array'); ctx.remove('access_count'); ctx.remove('modified_date'); 

Warum sich mit einer schmerzlosen Pipeline beschäftigen, anstatt sie in einer bequemeren Sprache zu schreiben? Mit der Reindex-API können Sie jetzt den Inhalt von Suchindizes in Indizes für Hinweise (indem Sie natürlich nur die erforderlichen Felder angeben ) in nur einem Befehl übernehmen.


Die Zusammensetzung der wirklich benötigten öffentlichen Dokumente wird nicht oft aktualisiert, sodass dieser Befehl bei einem manuellen Start belassen werden kann.


Ergebnisse anzeigen


Kategorien


Die Kategorie bestimmt, welche Facetten verfügbar sind und wie das Snippet aussehen wird. Es kann automatisch von externer Intelligenz erkannt oder manuell über der Suchleiste ausgewählt werden.


Facetten


Facetten sind so intuitiv für jeden, dessen Verhalten jedoch durch sehr nicht triviale Regeln beschrieben wird. Hier sind einige davon:


  1. Facettenwerte hängen von den Suchergebnissen ab, ABER und die Suchergebnisse hängen von den ausgewählten Facetten ab. Wie vermeide ich eine Rekursion?


  2. Das Auswählen von Werten innerhalb einer Facette wirkt sich nicht auf andere Werte dieser Facette aus, wirkt sich jedoch auf Werte in anderen Facetten aus:




  1. Vom Benutzer ausgewählte Facettenwerte sollten nicht verschwinden, selbst wenn eine Auswahl in einer anderen Facette sie auf 0 vernichtet oder sie nicht mehr oben stehen:


In Bezug auf die Elastizität werden Facetten durch den Aggregationsmechanismus realisiert. Um jedoch den beschriebenen Regeln zu entsprechen, müssen diese Aggregationen ineinander investiert und voneinander gefiltert werden.



Betrachten Sie die dafür verantwortlichen Anforderungsfragmente:


Code zu groß
 { ... "post_filter": { "bool": { "must": [ { "terms": { "card.author_value_id": [ "1951063" ] } }, { "terms": { "editor_value_id": [ "2337706", "300643" ] } } ] } }, "query": {...} "aggs": { "card.author_value_id": { "filter": { "terms": { "editor_value_id": [ "2337706", "300643" ] } }, "aggs": { "card.author_value_id": { "terms": { "field": "card.author_value_id", "size": 11, "exclude": [ "1951063" ], "missing": "" } }, "card.author_value_id_selected": { "terms": { "field": "card.author_value_id", "size": 1, "include": [ "1951063" ], "missing": "" } } } }, ... "editor_value_id": { "filter": { "terms": { "card.author_value_id": [ "1951063" ] } }, "aggs": { "editor_value_id": { "terms": { "field": "editor_value_id", "size": 11, "exclude": [ "2337706", "300643" ], "missing": "" } }, "editor_value_id_selected": { "terms": { "field": "editor_value_id", "size": 2, "include": [ "2337706", "300643" ], "missing": "" } } } }, ... } } 

Was ist hier das:


  • Mit post_filter können Sie den Ergebnissen einer bereits abgeschlossenen Abfrage eine zusätzliche Bedingung auferlegen, ohne die Ergebnisse von Aggregationen zu beeinflussen. Dieselbe Rekursionslücke. Beinhaltet alle ausgewählten Werte aller Facetten.
  • Aggregationen der obersten Ebene im Beispiel card.author_value_id und editor_value_id . Jeder hat:
    • Filtern Sie nach den Werten aller anderen Facetten mit Ausnahme Ihrer eigenen.
    • verschachtelte Aggregation für ausgewählte Facettenwerte - Schutz vor Vernichtung ;
    • verschachtelte Aggregation für andere Facettenwerte. Wir zeigen die Top 10 an und fordern die Top 11 an, um zu bestimmen, ob die Schaltfläche Alle anzeigen angezeigt werden soll.

Schnipsel


Abhängig von der ausgewählten Kategorie kann das Snippet bei der Suche in einer Kategorie unterschiedlich aussehen, z. B. dasselbe Dokument


Alle :



und Mitarbeiter :



Oder erinnern Sie sich, wir wollten das Thema eines kommerziellen Angebots sehen und von wem es kam?



Um nicht die gesamte Karte aus dem Gummiband zu ziehen (dies verlangsamt die Suche), wird die Quellfilterung verwendet :


 { ... "_source": { "includes": [ "id", "card.name", "card.card_type_value_id", "card.life_stage_value_id", "extension", ... ] }, "query": {...} ... } 

Um die im Text des Dokuments enthaltenen Wörter hervorzuheben, wird der Textmarker Fast Vector verwendet, um die am besten geeigneten Snippets für große Texte zu generieren, und der Name Unified Highlighter als am wenigsten anspruchsvoll für Ressourcen und Indexstruktur:


 "highlight": { "pre_tags": [ "<strong>" ], "post_tags": [ "</strong>" ], "encoder": "html", "fields": { "card.name": { "number_of_fragments": 0 }, "content": { "fragment_size": 300, "number_of_fragments": 3, "type": "fvh" } } }, 

In diesem Fall wird der Name vollständig hervorgehoben, und aus dem Text erhalten wir bis zu 3 Fragmente mit einer Länge von 300 Zeichen. Der vom Fast Vector-Textmarker zurückgegebene Text wird durch einen provisorischen Algorithmus weiter komprimiert, um einen minimierten Snippet-Status zu erhalten.


Zusammenbruch


In der Vergangenheit sind Benutzer dieses ECM daran gewöhnt, dass die Suche Dokumente an sie zurückgibt. Tatsächlich sucht Elasticsearch jedoch zwischen Dokumentversionen . Es kann sich herausstellen, dass mehrere nahezu identische Versionen in derselben Abfrage gefunden werden. Dies wird die Ergebnisse durcheinander bringen und den Benutzer verwirren. Glücklicherweise kann dieses Verhalten vermieden werden, indem der Field Collapsing- Mechanismus verwendet wird - eine leichtgewichtige Version von Aggregationen, die bereits mit den fertigen Ergebnissen arbeitet (in dieser ähnelt es post_filter, zwei Krücken sind ein Paar ). Der Zusammenbruch führt zu dem relevantesten der zusammenbrechenden Objekte.


 { ... "query": {...} ... "collapse": { "field": "id" } } 

Leider hat der Zusammenbruch eine Reihe unangenehmer Auswirkungen, zum Beispiel kehren verschiedene numerische Merkmale des Suchergebnisses weiter zurück, als ob es keinen Zusammenbruch gegeben hätte. Das heißt, die Anzahl der Ergebnisse, die Anzahl der Facettenwerte - alle sind leicht falsch, aber der Benutzer bemerkt dies normalerweise nicht, ebenso wie der müde Leser, der diesen Vorschlag wahrscheinlich noch nicht gelesen hat.


Das Ende.

Source: https://habr.com/ru/post/de460263/


All Articles