Blog der SHI GmbH

Dokumentverteilung in der SolrCloud

Dokumentverteilung in der SolrCloud – Optimale Verteilung für optimale Suchperformance

In einer SolrCloud werden die Dokumente auf alle verfügbaren Shards einer Collection verteilt. Dies geschieht mehr oder minder automatisch. Mit diesem Verteilen der Dokumente wird sichergestellt, dass die einzelnen Indexe nicht zu groß werden und die Suche somit performant bleibt. Bei einer Suche muss man dann jedoch alle Shards durchsuchen um ein valides Trefferergebnis zu bekommen.
Es gibt jedoch oft Situationen, da möchte man nur einen speziellen Teil der Dokumente – Beispielsweise nur die eines speziellen Mandanten – durchsuchen. Dies lässt sich natürlich mit FilterQueries umsetzen, aber es gibt noch eine andere Art.
Wenn die Dokumente eines Mandanten in einem einzelnen Shard einer Collection liegen, dann kann man mit Solr nur in diesem Shard suchen. Dies bedeutet einen Performancegewinn, denn alle anderen Shards müssen nicht durchsucht werden.
In diesem Blog werde ich kurz die eingebauten Konzepte vorstellen, Dokumente in der SolrCloud verteilt werden und wie es sich beeinflussen lässt.

Apache Solr Document-Routing

In Apache Solr gibt es zwei grundlegende Arten, wie die Dokumente in der SolrCloud verteilt werden. Zum einem gibt es den „compositeId“ Routing Mechanismus und zum anderen den „implicit“ Routing Mechanismus. Der Routing Mechanismus muss bei der Erstellung einer Collection angegeben werden und gilt somit auch nur für diese Collection. Dies bedeutet im Umkehrschluss, dass man innerhalb einer SolrCloud mit mehreren Collections beide Routing Mechanismen einsetzen kann.
Bei der Variante „implicit“ gibt es keine automatische Dokumentverteilung. Der Shard der einen Indexierungs-Request erhält, der wird das Dokument auch „speichern“. Beim Anlegen einer Implicit Collection gibt man namentlich an, welche Shards man haben möchte und muss entsprechend seine Indexierungsstrategie anpassen. Bei dieser Variante können jedoch später bei Bedarf weitere Shards zur Collection hinzugefügt werden.
Beim „compositeId“ Dokument Routing wird beim Anlegen der Collection ein sogenannter Hash-Ring über alle Shards gebildet, d.h. es wird für jeden Shard festgelegt welchen Hashbereich er abdeckt. Beim Indexieren der Dokumente wird für jedes Dokument ein Hashwert basierend auf der Id generiert und anschließend das Dokument zu dem entsprechenden Shard weitergeleitet. Die Berechnung des Hashwertes kann auch auf ein sogenanntes ID-Präfix angewendet werden. Somit landen dann immer alle Dokumente mit dem gleichen Präfix, was beispielsweise eine Mandanten Nummer sein könnte, im gleichen Shard.

ID–Manipulation um Dokumente gezielt auf einzelne Shards zu verteilen

Die automatische Verteilung der Dokumente ist zwar gut und schön aber wir sind oft in der Situation, dass wir Dokumente mehr oder minder gezielt ablegen wollen. Dazu nutzen wir den bereits erwähnten Präfix Mechanismus mit dem compositeId Routing-Mechanismus.
Dies bedeutet jedoch wiederrum, dass die ID des Dokumentes ein entsprechendes Format haben muss. Eine Manipulation der ID lässt sich jedoch nicht immer im Quell-System durchführen. Eine zentrale Manipulation ist aber möglich. Mit den UpdateProcessoren kann dies relativ leicht umgesetzt werden, wie folgendes Beispiel zeigen wird.
Zur Vereinfachung nutze ich im folgenden Beispiel einen ScriptUpdateProcessor. Selbstverständlich kann man dies auch in Java implementieren. Den Processor bindet man einfach am Anfang der ProcessorChain ein, wie man im folgenden Ausschnitt der der solrconfig.xml sehen kann.

<updateRequestProcessorChain name="add_mandant_to_id">
     <processor class="solr.StatelessScriptUpdateProcessorFactory">
                 <str name="script">manipulate_id.js</str>
        </processor>
        <processor class="solr.LogUpdateProcessorFactory" />
        <processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>

Um die Verteilung der Dokumente zu beeinflussen wollen wir alle Dokumente, die zu einem Mandanten gehören im selben Shard ablegen. In meinem fiktiven Beispiel haben wir eine Mandanten-ID bereits in unseren Daten und müssen nur zwei Felder mit dem „!“ miteinander verbinden. Die Funktion „processAdd“ in einem Java Script (manipulate_id.js) könnte wie folgt aussehen:

function processAdd(cmd) {
          // get solr document
          doc = cmd.solrDoc;

          // get document id
          id = doc.getFieldValue("id");

          // manipulate document id based on field „mandant“
          mandant = doc.getFieldValue("mandant");
      id = mandant + '!' + id;

      // overwrite existing id with new id
      doc.setField("id", id);
}

Eine Manipulation mit UpdateProcessoren funktioniert solange der RunUpdateProcessor als letztes in der Chain kommt, denn dieser ist für die Verteilung der in der SolrCloud verantwortlich.

Fazit

Ob nun mit oder ohne automatischer Dokumentverteilung beider Varianten haben ihre Vorteile und können individualisiert werden. Nachfolgend fasse ich die Vorteile noch einmal kurz zusammen.

implicit:

  • Dokumentverteilung kann durch dediziertes „Ansprechen“ von einzelnen Shards beeinflusst werden.
  • Skalierung durch Hinzufügen weiterer Shards bei Bedarf

compositeId:

  • Dokumente werden automatisch verteilt
  • Automatische Verteilung der Dokumente kann durch einen Präfix Mechanismus beeinflusst werden
  • Skalierung durch Shard-Splitting im laufenden Betrieb

Weiterführende Links

Markus Klose