Hallo Freunde! Es gibt Leute mit unterschiedlichem Erfahrungsstand, die in unseren Foren mitmachen - und das ist toll! Aber im Moment bin ich auf der Suche nach echten Ruby-Titanen!
Elasticsearch ist eine Suchmaschine, die auf einer bewährten und ausgereiften Bibliothek basiert - Apache Lucene. Enorme Aktivität in Git Projekt Repository und die Implementierung in Projekten wie GitHub, SoundCloud, Stack Overflow und LinkedIn zeugen von seiner großen Beliebtheit. Der Teil "Elastic" sagt alles über die Natur des Systems, dessen Fähigkeiten enorm sind: von einer einfachen Dateisuche in kleinem Maßstab über Wissensentdeckung bis hin zu Big-Data-Analysen in Echtzeit... Was Elastic leistungsfähiger als die Konkurrenz macht, ist die Reihe von Standardkonfigurationen und Verhaltensweisen, die es ermöglichen, einen Cluster zu erstellen und in wenigen Minuten mit dem Hinzufügen von Dokumenten zum Index zu beginnen. Elastic konfiguriert einen Cluster für Sie, definiert einen Index und legt die Feldtypen für das erste erhaltene Dokument fest, und wenn Sie einen weiteren Server hinzufügen, kümmert es sich automatisch um die Aufteilung der Indexdaten zwischen den Servern.Leider macht die oben erwähnte Automatisierung es für uns unklar, was die Standardeinstellungen bedeuten, und es stellt sich oft als irreführend heraus. Dieser Artikel ist der Beginn einer Serie, in der ich mich mit den häufigsten Problemen befassen werde, die bei der Erstellung einer Elastic-basierten App auftreten können.
Die Anzahl der Scherben kann nicht geändert werden.
Indizieren wir das erste Dokument mit Index-API:
$ curl -XPUT 'http://localhost:9200/myindex/employee/1' -d '{
"first_name" : "Jane",
"last_name" : "Smith",
"steet_number": 12
}'
In diesem Moment erstellt Elastic einen Index für uns mit dem Namen myindex. Was hier nicht sichtbar ist, ist die Anzahl der Shards, die dem Index zugewiesen sind. Shards können als individuelle Prozesse verstanden werden, die für die Indizierung, Speicherung und Suche eines Teils der Dokumente eines gesamten Indexes verantwortlich sind. Bei der Indizierung von Dokumenten entscheidet elastic, in welchem Shard ein Dokument gefunden werden soll. Dies geschieht nach der folgenden Formel:
shard = hash(document_id) % number_of_primary_shards
Es ist nun klar, dass die Anzahl der primären Shards für einen Index, der Dokumente enthält, nicht geändert werden kann. Legen Sie also vor der Indizierung des ersten Dokuments immer manuell einen Index an und geben Sie dabei die Anzahl der Shards an, die Sie für ein indiziertes Datenvolumen für ausreichend halten:
$ curl -XPUT 'http://localhost:9200/myindex/' -d '{
"settings" : {
"number_of_shards" : 10
}
}'
Standardwert für Anzahl_der_Scherben
Dies bedeutet, dass der Index auf bis zu 5 Server skaliert werden kann, die während der Indizierung Daten sammeln. Für die Produktionsumgebung sollte der Wert der Shards in Abhängigkeit von der erwarteten Häufigkeit der Indizierung und der Größe der Dokumente festgelegt werden. Für Entwicklungs- und Testumgebungen empfehle ich, den Wert auf 1 zu setzen - warum? Das wird im nächsten Abschnitt dieses Artikels erklärt.
Sortierung der Textsuchergebnisse bei einer relativ kleinen Anzahl von Dokumenten
Wenn wir nach einem Dokument mit einer Phrase suchen:
$ curl -XGET 'http://localhost:9200/myindex/my_type/_search' -d
'{
"query": {
"match": {
"title": "Der schlaue braune Fuchs"
}
}
}'
Elastic verarbeitet die Textsuche in wenigen Schritten, einfach gesagt:
- Die Phrase aus der Anfrage wird in dieselbe identische Form umgewandelt, in der das Dokument indiziert wurde, in unserem Fall ist es eine Reihe von Begriffen:
["quick", "brown", "fox"]
("der" wurde gestrichen, weil es unbedeutend ist),
- der Index wird durchsucht, um die Dokumente zu finden, die mindestens eines der gesuchten Wörter enthalten,
- Jedes übereinstimmende Dokument wird im Hinblick auf seine Relevanz für den Suchbegriff bewertet,
- werden die Ergebnisse nach der berechneten Relevanz sortiert und die erste Ergebnisseite wird dem Benutzer angezeigt.
Im dritten Schritt werden unter anderem die folgenden Werte berücksichtigt:
- wie viele Wörter der Suchphrase im Dokument enthalten sind
- wie oft ein bestimmtes Wort in einem Dokument vorkommt (TF - Termfrequenz)
- ob und wie oft die übereinstimmenden Wörter in anderen Dokumenten vorkommen (IDF - inverse document frequency) - je häufiger das Wort in anderen Dokumenten vorkommt, desto weniger bedeutend
- Wie lang ist das Dokument?
Die Funktionsweise von IDF ist für uns wichtig. Elastic berechnet diesen Wert aus Leistungsgründen nicht für jedes Dokument im Index - stattdessen berechnet jeder Shard (Index Worker) seine lokale IDF und verwendet sie für die Sortierung. Daher können wir bei der Indexsuche mit einer geringen Anzahl von Dokumenten je nach Anzahl der Shards in einem Index und der Dokumentenverteilung sehr unterschiedliche Ergebnisse erhalten.
Nehmen wir an, wir haben 2 Shards in einem Index; im ersten sind 8 Dokumente mit dem Wort "fox" indiziert, im zweiten nur 2 Dokumente mit demselben Wort. Infolgedessen wird sich das Wort "fox" in beiden Shards deutlich unterscheiden, was zu falschen Ergebnissen führen kann. Daher sollte für Entwicklungszwecke ein Index erstellt werden, der nur aus einem primären Shard besteht:
$ curl -XPUT 'http://localhost:9200/myindex/' -d
'{"settings" : { "number_of_shards" : 1 } }'
Die Anzeige der Ergebnisse von "fernen" Suchseiten tötet Ihren Cluster
Wie ich bereits in den vorangegangenen Abschnitten geschrieben habe, werden die Dokumente in einem Index auf ganz individuelle Indexprozesse - Shards - verteilt. Jeder Prozess ist völlig unabhängig und befasst sich nur mit den Dokumenten, die ihm zugewiesen sind.
Wenn wir einen Index mit Millionen von Dokumenten durchsuchen und darauf warten, die 10 besten Ergebnisse zu erhalten, muss jeder Shard seine 10 am besten übereinstimmenden Ergebnisse an den Cluster zurückgeben Knotender die Suche eingeleitet hat. Dann werden die Antworten von jedem Shard zusammengeführt und die 10 besten Suchergebnisse (innerhalb des gesamten Index) ausgewählt. Ein solcher Ansatz ermöglicht eine effiziente Verteilung des Suchprozesses auf viele Server.
Nehmen wir an, dass unsere Anwendung die Anzeige von 50 Ergebnissen pro Seite ermöglicht, ohne dass die Anzahl der Seiten, die von einem Benutzer angezeigt werden können, eingeschränkt ist. Denken Sie daran, dass unser Index aus 10 primären Scherben besteht (1 pro Server).
Schauen wir uns an, wie die Gewinnung von Suchergebnissen für die 1. und die 100. Seite aussehen wird:
Seite Nr. 1 der Suchergebnisse:
- Der Knoten, der eine Anfrage erhält (Controller), leitet sie an 10 Shards weiter.
- Jeder Shard liefert seine 50 besten übereinstimmenden Dokumente, sortiert nach Relevanz.
- Nachdem die Antworten von jedem Shard eingegangen sind, führt der Controller die Ergebnisse zusammen (500 Dokumente).
- Unsere Ergebnisse sind die 50 besten Dokumente aus dem vorherigen Schritt.
Seite Nr. 100 der Suchergebnisse:
- Der Knoten, der eine Anfrage erhält (Controller), leitet sie an 10 Shards weiter.
- Jeder Shard liefert seine 5000 besten übereinstimmenden Dokumente, sortiert nach Relevanz.
- Nach Erhalt der Antworten von jedem Shard führt der Controller die Ergebnisse zusammen (50000 Dokumente).
- Unsere Ergebnisse sind die Dokumente aus dem vorangegangenen Schritt mit den Positionen 4901 - 5000.
Wenn man davon ausgeht, dass ein Dokument 1 KB groß ist, bedeutet dies im zweiten Fall, dass ~50 MB an Daten an den Cluster gesendet und verarbeitet werden müssen, um 100 Ergebnisse für einen Benutzer anzuzeigen.
Es ist unschwer zu erkennen, dass der Netzwerkverkehr und die Indexlast mit jeder weiteren Ergebnisseite erheblich zunehmen. Aus diesem Grund ist es nicht empfehlenswert, dem Nutzer die "fernen" Suchseiten zur Verfügung zu stellen. Wenn unser Index gut konfiguriert ist, dann sollte der Benutzer das gewünschte Ergebnis auf den ersten Suchergebnisseiten finden, und wir schützen uns vor unnötiger Belastung unseres Clusters. Um diese Regel zu bestätigen, prüfen Sie, bis zu welcher Anzahl von Suchergebnisseiten die beliebtesten Web-Suchmaschinen die Anzeige erlauben.
Interessant ist auch die Beobachtung der Antwortzeit des Browsers für aufeinanderfolgende Suchergebnisseiten. Nachfolgend finden Sie zum Beispiel die Antwortzeiten für einzelne Suchergebnisseiten in der Google-Suche (der Suchbegriff war "Suchmaschine"):
| Suchergebnisseite (10 Dokumente pro Seite) | Antwortzeit |
|——————————————–|—————|
| 1 | 250ms |
| 10 | 290ms |
| 20 | 350ms |
| 30 | 380ms |
| 38 (letzte verfügbare) | |
Im nächsten Teil werde ich näher auf die Probleme bei der Indexierung von Dokumenten eingehen.