adesso Blog

In diesem Blog-Beitrag zeige ich, wie man auf Basis der Open Source Software Elasticsearch textbasierte Daten speichern, indexieren und für menschliche Nutzer einfach durchsuchbar machen kann. So entwickeln wir mit wenigen Mitteln eine performante und funktionsreiche Volltextsuche. Dazu deployen wir eine Instanz des Elasticsearch Webservice, indizieren Beispieldaten und entwickeln mit den Bordmitteln von Elasticsearch eine überall wiederverwendbare Suche. Benötigt werden lediglich ein Browser und ein GitHub-Account:

Den gesamten Code findet ihr in GitHub und ihr könnt alles schnell bei GitPod deployen und ausprobiere.

Volltextsuchen mit Elasticsearch

Jedes Mal, wenn ich meinen Browser öffne, sehe ich als erstes eine Suchmaschine meiner Wahl, und das aus gutem Grund: Schließlich ist das Internet sehr groß, und die Informationen, die ich täglich brauche, finde ich in der Regel nicht allein auf den wenigen Seiten, deren URLs ich selbst aufrufen kann. Stattdessen verlasse ich mich auf Suchmaschinen, um die für meine Fragen relevanten Ergebnisse zu finden. Dabei bedienen sich moderne Suchmaschinen einer Vielzahl von Strategien und Algorithmen: Diese reichen vom einfachen Zählen einiger Schlüsselwörter im Quelltext statischer Seiten über die Gewichtung von Verlinkungen zu anderen Online-Ressourcen bis hin zu KI-gestützten Methoden, um beispielsweise aufgrund meines bisherigen Nutzerverhaltens häufig genutzte Seiten höher zu gewichten. Dies alles mit dem Ziel, mir innerhalb weniger Millisekunden so zufriedenstellende Suchergebnisse zu liefern, dass ich auch beim nächsten Mal die gleiche Suchmaske öffne.

Nun muss man nicht in jedem Fall mit Kanonen auf Spatzen schießen und KI-gestützte Verfahren einführen, wo clevere Algorithmen und Datenhaltung ausreichen. Hier spielt Elasticsearch seine Stärken aus, denn die Suche in großen Datenmengen aus strukturiertem und unstrukturiertem Text wird durch die Verwendung des Inverted Index-Konzepts gelöst: Neu zu speichernder Text wird in der Ingest-Phase nach konfigurierten Prinzipien analysiert, um in der Query-Phase direkt die zu den Sucheingaben passenden Ergebnisse liefern zu können. Standardmäßig werden Texte/Strings sowohl als den Typ text als auch als keyword indiziert. Texte werden in Tokens umgewandelt und diese pro zugehöriger Dokument-ID für die Suche hinterlegt, was für allgemeine Anwendungsfälle und Aggregationen gut funktioniert. Die Standardfunktionen stoßen jedoch an ihre Grenzen, sobald Tippfehler, ein Google-ähnliches Sucherlebnis oder eine domänenspezifische Normalisierung ins Spiel kommen. Um diese Anforderungen zu erfüllen, werden wir nach und nach weitere Funktionen entwickeln.

Analytische Features

Um einen Anwendungsfall für eine Volltextsuche zu adressieren, die Tippfehler toleriert, linguistische Standards verwendet und eine Google-ähnliche Autovervollständigung nutzt, bietet Elasticsearch eine Reihe von Werkzeugen, die einzeln oder in Kombination verwendet werden können, um funktionale Anforderungen zu erfüllen und die Genauigkeit der Suchergebnisse zu verbessern. Als Beispiel betrachten wir den Fall, dass ein Benutzer einen Dreher anstelle von “Michael” verwendet und stattdessen nach “Micheal” sucht. Als nächstes werden einige Funktionen betrachtet.

Ngrams

Ngramme sind ein bekanntes Konzept in der Linguistik und der natürlichen Sprachverarbeitung (NLP). Die Idee besteht darin, einzelne Wörter in eine Anzahl von Buchstaben-Token mit einer definierten Minimal- und Maximallänge zu zerlegen, zum Beispiel 2 und 3. Ein Wort wie Länge würde dann in Token mit einer maximalen Länge von 3 zerlegt:

['lä', 'län', 'äng', 'nge', 'ge']

Die Ergebnisse werden aber sicher noch nicht das sein, was wir wollen. Ngramm-Tokenizer tun nichts anderes, als Wörter in Token zu zerlegen, also sollten wir uns nicht wundern, wenn die Ergebnisse etwas zufällig aussehen. Werfen wir einen Blick auf die von “Micheal” abgeleiteten Ngramme:

['mi', 'mic', 'ic', 'ich', 'ch', 'che', 'he', 'hea', 'ea', 'eal', 'al']

Obwohl einige Ngramme auch in der Tokenisierung von “Michael” auftauchen würden, gibt es nichts Besonderes an ihnen - eine Suche mit Elasticsearch wird einfach die Dokumente mit den meisten Übereinstimmungen in der Tokenliste zurückgeben. Im Allgemeinen ist ein wenig Testen und Ausprobieren erforderlich, um die besten Minimal- und Maximalwerte für die Ngrammlänge zu finden (je länger, desto spezifischer die Treffer, aber desto weniger fehlertolerant).

Search-as-you-type

Die “search-as-you-type”-Funktionalität nutzt Ngramme auf eine etwas andere Weise als bisher gezeigt. Anstatt das gesamte Wort für die Tokenisierung zu betrachten, wird der Schwerpunkt auf den Wortanfang gelegt, um eine schnelle Suchfunktion zu bieten, die Ergebnisse liefert, während der Benutzer die ersten Buchstaben eingibt.

	
	input = 'micheal'
		for i in range(2, len(input)):
		    response = client.search(index='logstash-articles', size=100, query={
		        "multi_match": {
		            "query": input[:i],
		            "type": "bool_prefix",
		            "fields": [
		                "title.search_as_you_type",
		                "title.search_as_you_type._2gram",
		                "title.search_as_you_type._3gram",
		                "title.search_as_you_type._index_prefix"
		            ]
		        }},
		        source=['title'],
		    ).body
		    print(f"Input "{input[:i]}" yields a total {response['hits']['total']['value']} results with titles {[r['_source']['title'] for r in response['hits']['hits']]}")
	

Während des Tippens wird die Ergebnismenge bereits eingegrenzt und sie könnte schon verwendet werden, um User zum gewünschten Suchergebnis zu leiten.

	
	Input "mi" yields a total 33 results with titles ['1974 United States Senate election in Missouri', '103 Mile Lake', 'Peter Milliman', 'Micropterix lambesiella', 'Middle nasal concha', 'Middletown, Indiana', 'Diving at the 2018 European Aquatics Championships – Mixed 3 m springboard synchro', 'Spring Fork, Missouri', '1968–69 Midland Football League', '1922 Minneapolis Marines season', 'Federico Millacet', 'Federal Ministry of Health (Germany)', 'Grand Haven, Michigan', 'Smock mill, Wolin', 'Kendriya Vidyalaya 9th Mile', '246th Mixed Brigade', 'Micellar solubilization', 'Michael Jordan', 'Mike Gallagher (political commentator)', 'Stephen V. R. Trowbridge (Michigan legislator)', 'The Dazzling Miss Davison', 'Ministry Trax! Box', 'Highway 25 Bridge (Minnesota)', 'Michael Paul Fleischer', 'Mikhail Makagonov', 'Mildred Ratcliffe', 'Jefferson County School District (Mississippi)', 'Michiyoshi', 'Midnattsrocken', 'Miguel Tavares (footballer)', 'Palfrey, West Midlands', 'John Miles (fl. 1404)', 'Marion, Mississippi']
		Input "mic" yields a total 7 results with titles ['Micropterix lambesiella', 'Grand Haven, Michigan', 'Micellar solubilization', 'Michael Jordan', 'Stephen V. R. Trowbridge (Michigan legislator)', 'Michael Paul Fleischer', 'Michiyoshi']
		Input "mich" yields a total 5 results with titles ['Grand Haven, Michigan', 'Michael Jordan', 'Stephen V. R. Trowbridge (Michigan legislator)', 'Michael Paul Fleischer', 'Michiyoshi']
		Input "miche" yields a total 0 results with titles []
	

Mit dieser Funktion werden Tippfehler zwar nicht behoben, aber bei aufmerksamer Eingabe des Users eventuell vermieden oder eine schnellere Korrektur ermöglicht.

Phonetische Analyse

Da Elasticsearch ein Open-Source-Projekt ist, ist es nicht verwunderlich, dass Erweiterungen auf dem Projekt aufbauen, um Anwendungsfälle zu lösen. Erweiterungen für Elasticsearch können die Form von Plugins annehmen, die relativ einfach zu installieren sind. Hier betrachten wir das phonetische Analyse-Plugin, das es uns ermöglicht, phonetische Darstellungen von Eingabetoken zu erhalten.

	
	client.indices.put_settings(
		    index='logstash-articles',
		    settings={
		        'analysis': {
		            'analyzer': {
		                'phonetic_analyzer': {
		                    'tokenizer': 'standard',
		                    'filter': [
		                        'lowercase',
		                        'beider_morse'
		                    ]
		                }
		            },
		            'filter': {
		                'beider_morse': {
		                    'type': 'phonetic',
		                    'encoder': 'beider_morse',
		                    'replace': False
		                }
		            }
		        }
		    }
		)
	

Nach der Definition eines Analysators, der den phonetischen Tokenfilter verwendet, kann die natürliche Sprache in eine phonetische Darstellung umgewandelt werden. Diese hängt vom gewählten Algorithmus und der Ausgangssprache ab, kann aber auch von Elastisearch empfohlen werden. Um den Analyzer zu testen, vergleichen wir die Token, die sich aus der Analyse von “Michael” und “Micheal” ergeben.

	
	michael_phonetic_tokens = [t['token'] for t in client.indices.analyze(
		    index='logstash-articles',
		    text=['michael'],
		    analyzer='phonetic_analyzer'
		).body['tokens']]
		print('"Michael" yields:', michael_phonetic_tokens)
		"Michael" yields: ['mQxYl', 'mQxail', 'mQxoil', 'mitsDl', 'mitsail', 'mitsoil', 'mixDl', 'mixYl', 'mixail', 'mixoil']
		micheal_phonetic_tokens = [t['token'] for t in client.indices.analyze(
		    index='logstash-articles',
		    text=['micheal'],
		    analyzer='phonetic_analyzer'
		).body['tokens']]
		print('"Micheal" yields:', micheal_phonetic_tokens)
		"Micheal" yields: ['mDxDl', 'mDxal', 'mDxil', 'mQxDl', 'mQxal', 'mQxil', 'miDl', 'mikDl', 'mikal', 'mikial', 'mikil', 'mikiol', 'misDl', 'misal', 'misil', 'mitsDl', 'mitsal', 'mitsil', 'mixDl', 'mixal', 'mixial', 'mixil', 'mixiol']
		print('Overlap:', [t for t in michael_phonetic_tokens if t in micheal_phonetic_tokens])
		Overlap: ['mitsDl', 'mixDl']
	

Durch Zufall können wir bereits feststellen, dass es eine Überlappung in der phonetischen Darstellung zwischen “Michael” und “Micheal” gibt. In diesem Fall würde die phonetische Umwandlung ausreichen, um den Tippfehler in der Benutzereingabe zu korrigieren. Auf diese Weise sollten wir bereits einige Ergebnisse erhalten, die für eine Testnutzerbasis einigermaßen akzeptabel sein könnten. Bisher haben wir uns jedoch darauf konzentriert, gute Datentypen zu finden, um die Daten, die wir abfragen wollen, vorzubereiten. Die Abfragetypen, die wir bisher untersucht haben, sind jedoch recht einfach und nutzen die Query DSL von Elasticsearch nicht aus.

Fuzziness

Fuzziness ist ein recht einfaches Konzept, das in vielen Arten von Abfragen, die in der Elasticsearch Query DSLdefiniert sind, verfügbar ist. Angewandt auf unser vorheriges Beispiel löst es das Problem, indem es die gesuchten Abfragebegriffe auf ähnliche Token ausweitet, beispielsweise durch Ändern oder Entfernen eines Zeichens oder durch Vertauschen benachbarter Zeichen.

	
	client.search(index='logstash-articles', query={
		    'match': {
		        'title': {
		            'query': 'micheal',
		            'fuzziness': 1,
		            'fuzzy_transpositions': True
		        }
		    }}
		).body
	

Ein Nachteil von Fuzzy-Abfragen, auch wenn sie verlockend sind, sind ihre relativ hohen Rechenkosten, die die Ausführungszeit von Abfragen in größeren Datensätzen beeinträchtigen können und die Größe der Ergebnismenge erhöhen3.

Zusammengesetzte Abfragen

Es ist an der Zeit, mehrere Abfragen zu einer komplexeren Abfrage zusammenzufassen, die eine feinere Kontrolle über unsere Ergebnismenge und deren Reihenfolge ermöglicht. Ein sehr beliebter Abfragetyp ist die Boolesche Abfrage, die genau das tut, was ihr Name sagt: Sie kombiniert mehrere Abfragen zu einem booleschen Konstrukt (also und, oder, und nicht).

Jede boolesche Abfrage kann aus bis zu vier Teilen bestehen:

	
	"bool": {
		    "must": {}, // definieren, wie ein Ergebnis aussehen _muss_
		    "filter": {}, // festlegen, wie ein Ergebnis aussehen _muss_ - aber keine positiven Ergebnisse bewerten (daher schneller und für die Zwischenspeicherung geeignet)
		    "should": {}, // festlegen, wie ein Ergebnis aussehen _soll_ - wenn mehrere Abfragen definiert sind, reicht es aus, wenn eine übereinstimmt (es sei denn, das Minimum wird überschrieben)
		    "must_not": {} // definieren, wie ein Ergebnis _nicht_ aussehen darf
		}
	

must und filter bilden also den und-Teil einer booleschen Abfrage, should den oder-Teil und must_not den Nichtteil. Diesen mehrschichtigen Ansatz wenden wir nun auf unsere Abfrage an. Die einzelnen Teile werden von Elasticsearch direkt nacheinander in der folgenden Reihenfolge ausgeführt:

  • Zuerst filtern wir nach allen Artikeln, die Ngramme enthalten, die mit dem Suchbegriff in einem der bisher untersuchten relevanten Felder in Verbindung stehen. Dies reduziert die Anzahl der Dokumente, die Elasticsearch während der Scoring-Phase berücksichtigen muss, und beschleunigt die Ausführungszeit der Suchanfrage;
  • Zweitens setzen wir einen Basis-Score für alle Dokumente, die eine Fuzzy-Transposition des Suchbegriffs in denselben Feldern enthalten. Da wir die Anzahl der Kandidaten bereits reduziert haben, können wir uns einen ziemlich gierigen Ansatz mit einem erlaubten Verarbeitungsabstand von zwei leisten (“gierig” bedeutet hier, dass die Abfrage tendenziell viele Treffer erzeugen würde, da wir ein hohes Maß an Flexibilität zulassen - die Umwandlung in ähnliche Token ist zudem ressourcenintensiv, da Elasticsearch nach möglichen ähnlichen Token in allen bis hierher zugelassenen Dokumenten sucht);

Anschließend werden die Dokumente höher bewertet, die mit einer oder beiden Suchanfragen übereinstimmen, entweder durch phonetische Äquivalenz oder durch direkte lexikalische Treffer.

	
	client.search(index='logstash-articles', query={
		    'bool': {
		        'filter': [
		            {
		                "multi_match": {
		                    "query": "micheal",
		                    'fields': [
		                        'title.ngram',
		                        'summary.ngram',
		                        'content.ngram'
		                    ]
		                }
		            }
		        ],
		        'must': [
		            {
		                "multi_match": {
		                    "query": "micheal",
		                    'fuzziness': 2,
		                    'fuzzy_transpositions': True,
		                    'fields': [
		                        'title',
		                        'summary',
		                        'content'
		                    ]
		                }
		            }
		        ],
		        'should': [
		            {
		                'match': {
		                    'title.phonetic': {
		                        'query': 'micheal'
		                    }
		                }
		            },
		            {
		                'match': {
		                    'title': {
		                        'query': 'micheal'
		                    }
		                }
		            }
		        ]
		    }},
		    highlight={'fields': {'title': {}, 'summary': {}, 'content': {}}},
		    source=['title'],
		).body
	

Wir haben nun eine Abfrage, die mehrere Textanalysefunktionen nutzt, bis zu einem gewissen Grad tolerant gegenüber Tippfehlern ist und mehrere relevante Felder durchsucht. Um die Benutzerfreundlichkeit durch Vorschläge während der Eingabe zu verbessern, könnten wir die zuvor verwendeten “search-as-you-type”-Felder weiter integrieren.

Development und Advanced Features

Obwohl wir jetzt einen guten Ausgangspunkt haben, haben wir nur ein wenig an der Oberfläche der Textanalysewerkzeuge von Elasticsearch gekratzt. Um das Ganze abzurunden, werfen wir einen kurzen Blick auf einige weitere Funktionen, die wir verwenden können, um unsere Abfragen nach und nach zu verbessern.

Regression & Testing

Wie bereits erwähnt, bietet der Query Designer von Elasticsearch verschiedene Möglichkeiten, das Design der Abfrage an die Erwartungen des Benutzers anzupassen. Um zu testen, ob eine angepasste Abfrage die erwarteten Ergebnisse liefert oder nicht, ist es eine gute Idee, eine Test-Suite zu erstellen, zum Beispiel mit dem Ranking Evaluation API: Damit kann eine Reihe von Dokumenten definiert werden, die abhängig von der Abfrage und ihren Parametern in der Suchergebnisliste erscheinen oder nicht. Dies ist besonders nützlich, wenn wir im ständigen Dialog mit unseren Testern stehen und unser Abfragedesign weiterentwickeln, aber auch das beibehalten wollen, was bisher gut funktioniert hat.

	
	POST logstash-articles/_rank_eval
		{
		"requests": [
		    {
		    "id": "micheal_query",
		    "request": { // the request to be tested
		    "query": { "match": { "title.phonetic": "micheal" } }
		    },    "ratings": [
		        { "_inde
		x": "logstash-articles", "_id": "https://en.wikipedia.org/wiki/Michael_Jordan", "rating": 3 },
		        { "_index": "logstash-articles", "_id": "https://en.wikipedia.org/wiki/Michael_Paul_Fleischer", "rating": 1 },
		        { "_index": "logstash-articles", "_id": "https://en.wikipedia.org/wiki/Scheldeprijs", "rating": 0 }
		        ]
		    },
		    {
		    "id": "michael_query",
		    "request": {
		        "query": { "match": { "title": "michael" } }
		    },
		    "ratings": [
		        { "_index": "logstash-articles", "_id": "https://en.wikipedia.org/wiki/Michael_Jordan", "rating": 3 }
		        ]
		    }
		    ],
		    "metric": {
		    "precision": {
		        "k": 20,
		        "relevant_rating_threshold": 1,
		        "ignore_unlabeled": false
		    }    }
		}
	

Runtime fields

Ein weiteres sehr nützliches Feature für die Entwicklung ist runtime_fields. Normalerweise sollten die Felder eines Indexes deklariert werden, bevor Daten in Elasticsearch geladen werden, wie wir es bisher getan haben. Alternativ können Felder zu einem bestehenden Index hinzugefügt werden, der dann aktualisiert wird, um die definierte Analyse auf den Dokumenten durchzuführen, bis zu der das Feld nicht verwendet werden kann. runtime_fields erlauben einen anderen Ansatz: Der Wert des Feldes wird zur Laufzeit bestimmt, d.h. wenn die Daten bereits abgefragt oder analysiert werden. Der Wert des runtime_fields kann durch die Bereitstellung eines Skripts über die Such-API oder durch manuelles Hinzufügen über Kibana bestimmt werden.

	
	GET logstash-articles/_search
		{
		    "runtime_mappings": {
		        "#links": {
		            "type": "long",
		            "script": "emit(doc['links.keyword'].length);"
		        }
		    },
		    "query": {
		        "range": {
		            "#links": {
		                "gte": 1000
		            }
		        }
		    },
		    "_source": ["title"]
		}
	

runtime_fields sind während der Entwicklung oder für periphere Anwendungen nützlich. Sobald feststeht, dass ein Feld für den betrachteten Anwendungsfall nützlich ist, muss entschieden werden, ob die Funktionalität während der Laufzeit gekapselt bleiben oder in eine dauerhaftere gespeicherte Lösung umgewandelt werden soll.

NLP

Zum Schluss wollen wir uns etwas ungewöhnlicherem zuwenden. Wie bereits erwähnt, sind auch Plugins und Erweiterungen Teil des Elastic Stacks. OpenNLP ist ein auf maschinellem Lernen (ML) basierendes Framework für die Verarbeitung von natürlichem Text und kann für verschiedene Aufgaben eingesetzt werden, unter anderem für die Erkennung von benannten Entitäten (NER). Elasticsearch kann so konfiguriert werden, dass trainierte ML-Modelle geladen werden, um den gelesenen Text zu analysieren. Dazu müssen zunächst das Plugin und die benötigten ML-Modelle in Elasticsearch geladen werden, um anschließend eine Ingest-Pipeline zu definieren, die den zu indexierenden Text mit den gewünschten Annotationen anreichert.

	
	client.ingest.put_pipeline(
		    id='opennlp-pipeline',
		    processors=[
		    {
		        "opennlp" : {
		        "field" : "text",
		        "annotated_text_field" : "annotated_text"
		        }
		    }
		    ]
		)
	

Die Einrichtungsschritte sind im oben genannten Gitpod-Workspace verfügbar und die NER-Modelle können mit dem beschriebenen Code ausprobiert werden. Hier als Beispiel die Liste der erkannten Personen im Wikipedia-Artikel zu Michael Jordan:

	
	'Condor', 'Sandro Miller', 'Marv Albert', 'Chris Mullin', 'Simon', 'Michael', 'Karl Malone', 'Jason Kidd', 'Story', 'Bryant', 'Harper San Francisco', 'Charles Oakley', 'Mark Vancil', 'Mike', 'James R . Jordan Sr .', 'Bob Knight', 'Russell Westbrook', 'Minor League Baseball', 'Ed Bradley', 'Jordan', 'John R . Wooden', 'Daniel Green', 'Ben', 'Rodman', 'Kobe Bryant', 'With Scottie Pippen', 'Ron Harper', 'Rod Strickland', 'After Jordan', 'Nick Anderson', "Shaquille O ' Neal", 'Stu Inman', 'Jordan Brand', 'Brand', 'Marcus', 'Sam Perkins', 'Wade', 'Babe Ruth', 'Rip " Hamilton', 'David L .', 'Kwame Brown', 'Jerry West', 'Jordan "', 'Abe Pollin', 'James Harden', 'Dean Smith', 'Abdul - Jabbar', 'Steve Alford', 'Jordan Rules', 'Derek Jeter', 'Richard Esquinas', 'Michael Jordan Celebrity Invitational', 'Bugs Bunny', 'Victoria', 'Jason Hehir', 'Travis Scott', 'David Steward', 'Larry Hughes', 'Johnson', 'James', 'David Thompson', 'George Shinn', 'Barack Obama', 'Jerry Reinsdorf', 'Dan Devine', 'Bob', 'Roy S . Johnson', 'Larry Martin Demery', 'Clyde Drexler', 'Knafel', 'David', 'Michael Jordan', 'Jordan Motorsports', 'Robert L . Johnson', 'Muhammad Ali', 'Citing Bowie', 'Spike Lee', 'Lee', 'Charles Barkley', 'Walter Iooss', 'Phil Jackson', 'Don Nelson', 'Gary Payton', 'Jason Whitlock', 'Ron Shelton', 'Larry Bird', 'Kevin Garnett', 'Vince Carter', 'Horace Grant', 'Michael Jackson', 'Russell', 'Clyde "', 'Daniel Sundheim', 'Isiah Thomas', 'George Floyd', 'Scottie Pippen', 'Mitchell', 'W . W . Norton', 'Sam Bowie', 'Kareem Abdul - Jabbar', 'Allen Iverson', 'Robert F . Smith', 'Sportswriter Wright Thompson', 'Larry Jordan', 'Patrick Ewing', 'James Jordan', 'Steve Kerr', 'George Postolos', 'Dwyane Wade', 'Thompson', 'LeBron James', 'Magic Johnson', 'Toni Kukoč', 'David Stern', 'Michael Jordan Career Retrospective', 'Irving J .', 'Malone', 'Brown', 'Sam Vincent', 'Doug Brady', 'Jordan Drive', 'Jack Hartman', 'Justin Jordan', 'Jasmine', 'Grant Hill', 'Adam Morrison', 'Dunk Contest', 'Glen Rice', 'Jerry Stackhouse', 'Mario Lemieux', 'Wayne Gretzky', 'Loyola Academy', 'Bryon Russell', 'John Paxson', 'Deloris', 'Penny Hardaway', 'James R . Jordan Jr .', 'Bill Russell', 'Bobby Simmons', 'Family Clinics', 'His', 'Willis Reed', 'Broadcaster Al Michaels', 'Despite Jordan', 'John Salmons', 'Luka Dončić', 'Gatorade', 'Subsequently', 'James Worthy', 'Mike "', 'Andrei S', 'Walter Davis', 'Doug Collins', 'Julius Erving . Larry Bird', 'David Falk', 'Doug Colling', 'Porter', 'Jeffrey', 'Walter', 'Jeffrey Jordan OLY', 'Roland', 'Dennis Rodman', 'Doc Rivers', 'Oprah Winfrey'
	

Fazit

In diesem Blog-Beitrag wurde gezeigt, wie mit wenigen Mitteln eine Suchheuristik auf Basis von Textanalyse und Query DSL innerhalb von Elasticsearch realisiert werden kann. Eingaben können mit Hilfe von Ngrammen und phonetischer Transformation fehlertoleranter gemacht werden, außerdem können bereits während der Benutzereingabe (also bei unvollständigen Suchparametern) Vorschläge für Suchtreffer geliefert werden. Mit Fuzzy Search und der Kombination der entwickelten Suchheuristiken wird eine mehrschichtige Suche entworfen, die sowohl schnell als auch fehlertolerant ist.

  • 1. Ihr könnt einfach das verlinkte Repo-Template „elasticsearch-demo“ benutzen, um ein eigenes Repo auf GitHub zu erstellen. Benutzt dann den Link zu eurem Repo, um einen Workspace über das GitPod Dashboard zu erstellen und zu öffnen. Das Setup des Workspace wird für euch automatisch ausgeführt und die Codebeispiele funktionieren out-of-the-box. ↩
  • 2. Das Geschäftsmodell der Firmen, die ihre Suchmaschinen kostenlos zur Verfügung stellen, ist nicht Gegenstand dieses Beitrags.
  • 3. Für weitere Informationen lest euch gern den Wikipedia-Artikel zum Thema "Präzisions- und Recall-Problem" durch.
Bild Simon Stemper

Autor Simon Stemper

Simon Stemper arbeitet seit 2019 als Cloud Data Engineer bei adesso in Dortmund. Im Bereich Data & Analytics berät er Kunden zu Einsatz und Betrieb von Big-Data-Technologien.

Kategorie:

Softwareentwicklung

Schlagwörter:

Open Source

REST

Diese Seite speichern. Diese Seite entfernen.