Unterstützung von 2BIT bei einem Spring Boot Projekt
16.04.2021, Mirco Widmer

2BIT benötigte personelle Ressourcen, um einen ihrer Kunden bei der Entwicklung einer Spring Boot Applikation zu unterstützen. Das Ziel bestand darin, das REST-Interface von Apache Solr für Clients zu abstrahieren und eine vereinfachte Schnittstelle anzubieten.

Ausgangslage

Ein Kunde von 2BIT hatte das Ziel, interne Informationen verschiedenen Applikationen zugänglich zu machen. Die Daten sollten durchsuchbar sein. Dafür bot sich Apache Solr an:

Solr is the popular, blazing-fast, open source enterprise search platform built on Apache Lucene™.

Damit nicht alle künftigen Applikationen mit der REST-Schnittstelle von Apache Solr kommunizieren müssen, sollte mit einer Search-Applikation eine vereinfachte REST-Schnittstelle angeboten werden. In diesem Projekt verwendeten wir folgenden Technologien:

Apache Solr

Apache Solr ist eine freie, open-source Suchmaschine, die auf der Apache Lucene-Bibliothek basiert. Sie gehört zu den beliebtesten Suchmaschinen-Bibliotheken, die heute verfügbar sind.

Solr nimmt strukturierte, halbstrukturierte und unstrukturierte Daten aus verschiedenen Quellen an, speichert und indiziert sie und macht sie nahezu sofort für die Suche verfügbar.

Spring Boot

Das Spring Framework ist ein open-source Framework für die Java-Plattform, welches oft für Web-Anwendungen verwendet wird. Ziel des Spring Frameworks ist es, die Entwicklung mit Java zu vereinfachen und gute Programmierpraktiken zu fördern. Spring bietet mit einem breiten Spektrum an Funktionalität eine ganzheitliche Lösung zur Entwicklung von Anwendungen und deren Geschäftslogiken; dabei steht die Entkopplung der Applikationskomponenten im Vordergrund.

Spring Boot bietet eine vereinfachte Konfiguration einer Spring-Applikation. Mithilfe des sogenannten Spring Initializers können die benötigten Teilkomponenten ausgewählt werden, welche weitestgehend automatisch konfiguriert werden, sodass die manuelle Konfiguration dieser grösstenteils entfällt. Dadurch eignet sich Spring Boot auch für die Entwicklung von Microservices.

Spring Data

Spring Data hat es sich zur Aufgabe gemacht, ein vertrautes und konsistentes, Spring-basiertes Programmiermodell für den Datenzugriff bereitzustellen. Gleichzeitig behält es die besonderen Eigenschaften des zugrunde liegenden Datenspeichers bei. Es erleichtert den Einsatz von Datenzugriffstechnologien, relationalen und nicht-relationalen Datenbanken, Map-Reduce-Frameworks und Cloud-basierten Datendiensten. Es handelt sich um ein Dachprojekt, das viele datenbankspezifische Unterprojekte enthält. Die Projekte werden durch die Zusammenarbeit mit vielen der Unternehmen und Entwickler entwickelt, die hinter diesen spannenden Technologien stehen.

Spring Data Solr

Spring Data Solr ermöglicht den Zugriff auf Solr über die bekannte Schnittstellen von Spring Data. Entwickler, die sich mit Spring Data auskennen, sind so auch mit Solr sehr schnell produktiv, da die Konzepte für Datenzugriffe sehr ähnlich sind. Spring Data Solr wird künftig leider nicht weiter entwickelt, siehe Details.

Einsatz

Wir setzten die Search-Applikation als Spring Boot Projekt von Grund auf und teilten die Applikation in diese Komponenten auf:

  • REST-Schnittstelle (API)
  • Service Schicht für alle REST-Calls
  • Zugriff auf Apache Solr (Repository)

REST-Schnittstelle (API)

Wir definieren ein GET-Mapping, welches die Suche nach Firmen anbietet. Speziell ist dabei, dass wir den Firmennamen nur ungefähr kennen, beispielsweise könnte man nach next Enginering GmbH suchen. (Man beachte, dass next und Enginering falsch geschrieben sind.)

@GetMapping("/fuzzy/company-name")
List<CompanySolr> fuzzyCompanyName(@RequestParam String companyName,
                                   @RequestParam(defaultValue = "0") int page,
                                   @RequestParam(defaultValue = "20") int size) {
    try {
        return tenantService.findFuzzyByCompanyName(companyName, PageRequest.of(page, size))
                            .getContent();
    } catch (DataAccessException e) {
        LOGGER.error("Error while communicating with Solr", e);
        return List.of();
    }
}

Die REST-Schnittstelle weiss nichts von Spring Data oder Apache Solr, sie kennt lediglich einen TenantService.

Service Schicht für alle REST-Calls

Der TenantService bietet eine Suche nach Firmennamen an:

public Page<CompanySolr> findFuzzyByCompanyName(String companyName, Pageable pageable) {
    return companyRepository.findFuzzyByCompanyName(escapeQueryChars(companyName), pageable);
}

Der Service kennt das CompanyRepository und leitet die Anfrage an dieses weiter.

Zugriff auf Apache Solr (Repository)

Um nun konkret auf die abgelegten Informationen zuzugreifen, die in Apache Solr vorhanden sind, existiert das Konzept von Repositories. Dieses Konzept stammt aus Spring Data und Spring Data Solr implementiert es ebenfalls. Wir definieren ein Interface und implementieren dort verschiedene Zugriffs-Methoden auf die Daten.

public interface CompanyRepository extends SolrRepository<CompanySolr, String> {
    Page<CompanySolr> findByCompanyName(String companyName, Pageable pageable);

    @Query(value = "companyName:?0~")
    Page<CompanySolr> findFuzzyByCompanyName(String companyName, Pageable pageable);
}

Die Methode findByCompanyName() funktioniert so, dass nach Objekten gesucht wird, bei welchen das Attribut CompanyName übereinstimmt. Also alle Attribute, die im Methodennamen nach findBy aufgezählt sind, werden automatisch verglichen und nur Objekte bei welchen alle Attribute überein stimmen werden gefunden. Dies ist sehr praktisch für einfache Abfragen, weil man sich um die Implementation nicht kümmern muss.

Bei etwas komplexeren Abfragen, wie beispielsweise einer Fuzzy-Suche, muss man Spring Data Solr noch weitere Informationen mitgeben. Dies geschieht mit der Query-Annotation. Man hat innerhalb der Annotation Zugriff auf die einzelnen Parameter, ?0 beispielsweise ist ein Platzhalter für das erste Argument der Methode. Wir wollen das Attribut companyName fuzzy vergleichen, dafür verwenden wir den Operator ~. Solr wendet den Damerau-Levenshtein-Distanz Algorithmus an, um herauszufinden, wie ähnlich zwei Begriffe zueinander sind. In unserem Beispiel haben wir die Firma nxt Engineering GmbH im Solr-Index und wir suchen nach next Enginering GmbH. Solr führt nun verschiedene Modifikationen am gesuchten Text durch und schaut, wie viele Modifikationen nötig sind, bis die Texte identisch sind. Es sind zwei Modifikationen nötig, um den Text next Enginering GmbH nach nxt Engineering GmbH zu überführen:

  1. nxt Enginering GmbH (e entfernt)
  2. nxt Engineering GmbH (e hinzugefügt)

Wir definieren, dass Texte als ähnlich gelten, wenn weniger als drei solcher Modifikationen nötig sind. In unserem Beispiel wird die Firma gefunden, obwohl sie nicht ganz korrekt geschrieben wurde.

Apache Solr unterstützt viele verschiedene Arten von Suchen. Weitere Informationen dazu gibt es in der Apache Solr Dokumentation.

Fazit

In kurzer Zeit konnten wir mithilfe eines Spring Boot Microservices verschiedenen Applikationen eine Schnittstelle anbieten, um Informationen über Firmen zu finden. Diese Clients müssen sich nicht um die Abfrage-Details von Apache Solr kümmern, das übernimmt die neue Search-Applikation.