Mango Query – es muss nicht immer Solr sein

Ich brauchte für ein Projekt eine Volltextsuche, die in meiner CouchDB größere Mengen Text schnell und effizient durchsuchen kann. Mit einfachen Mitteln kann man in CouchDB nur nach Key und Value Werten suchen und auch der Einsatz von Wildcards (also * oder %, je nach Programmiersprache) ist stark eingeschränkt.

Nach einigen Recherchen habe ich mich dann für Solr entschieden, einen Docker Container dafür aufgesetzt und die Datenbank bzw. die Abfragen in mein Projekt integriert. Ich habe dazu einfach den zu durchsuchenden Text an CouchDB als auch an Solr gesendet. In Solr speicherte ich dann zusätzliche die _id des CouchDB Dokuments. Damit konnte ich in Solr per Volltext suchen und über die in Solr gespeicherte _id das Dokument in der CouchDB finden. Funktioniert hat das gut.

Diese Methode, zwei NoSQL Datenbanken gleichzeitig zu nutzen, ist nicht unüblich und Solr ist unfassbar schnell und bietet nette zusätzliche Funktionen, wie z.B. Text-Highlighting. Trotzdem war ich irgendwie unglücklich mit diesem Ansatz und hatte Angst im Bezug auf Skalierbarkeit und Verwaltbarkeit. Immerhin hätte ich mich um die Administration von zwei Datenbanken kümmern müssen.

mit Mango Query wird es einfacher

Ich weiß nicht, warum ich bei meinen Recherchen nicht darauf gestoßen bin, denn CouchDB kann mithilfe von Mango Query auch Volltextsuchen ausführen. Die CouchDB Dokumentation ist teilweise sehr verwirrend.

Mango Query basiert ebenfalls auf der Apache Lucene Bibliothek, bietet aber nicht den hohen Funktionsumfang von Solr. Für mein Projekt war das aber nicht wichtig. Wichtiger war, dass ich dadurch einen Docker Container einsparen konnte und die Komplexität senken konnte.

Standardmäßig ist Mango Query sogar schon aktiviert und ihr könnt direkt mit dem Suchen loslegen. Im folgenden Beispiel gehe ich davon aus, dass es schon Dokumente in der CouchDB gibt.

const fetchData = async () => {
  try {
    const response = await fetch('http://localhost:5984/mydatabase/_find', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        selector: {
          'SUCHFELD': { $eq: 'hello' },
        },
        fields: ['FELD1', 'FELD2'],
        limit: 10,
      }),
    });

    if (!response.ok) {
      throw new Error('An error occurred while fetching data.');
    }

    const data = await response.json();
    console.log(data.docs);
  } catch (error) {
    console.error(error);
  }
};

fetchData();

Letzte Aktualisierung am 28.02.2024 / Affiliate Links / Bilder von der Amazon Product Advertising API

Wir haben hier eine “klassische” fetch Abfrage, wie ich sie ständig in meinen React Projekten benutze. Die wichtigen Stellen im Beispiel sind:

  • der POST geht auf die URL http://localhost:5984/mydatabase/_find wobei mydatabase natürlich ein Platzhalter für eure Datenbank ist
  • im body übergeben wir einen JSON-String
  • innerhalb von selector des JSON-Strings definieren wir das zu durchsuchende Feld (im Beispiel SUCHFELD)
  • wir wollen alle Dokumente finden, die im SUCHFELD den Text hello enthalten. $eq steht für equal, also “gleich”
  • innerhalb von fields legen wir fest, welche Felder der gefundenen Dokumente zurückgegeben werden sollen, also z.B. _id oder _rev des Dokuments. Gebt ihr hier nichts an, wird das gesamte Dokument zurückgegeben
  • innerhalb von limit legen wir fest, wie viele Dokumente maximal zurückgegeben werden

Wildcards und weitere Optionen

Im vorangegangenen Beispiel haben wir nach dem exakten Begriff hello gesucht. Die Abfrage findet den Text helloWorld nicht, obwohl dort das Wort hello enthalten ist. Auch ganze Sätze werden nicht nach dem Wort hello durchsucht. Ein Dokument mit dem SUCHEFLD: “welcome and hello my friends” wird nicht gefunden.

Hierfür benötigt ihr nicht den Operator $eq, hierfür benötigt ihr $regex. Das entspricht am ehesten dem aus relationalen SQL-Datenbanken bekannten wehere SUCHFELD like '%hello%'

Und schon wieder ein wichtiger und entscheidender Hinweis: die Suche ist case sensitive, unterscheidet also Groß- und Kleinschreibung. hello entspricht nicht Hello und wird dementsprechend nicht gefunden. Aber auch hierfür gibt es eine Lösung: stellt dem Suchbegriff einfach ein (?i) voran. Der JSON-String aus dem Beispiel könnte also wie folgt aussehen und würde dann hello oder Helo oder HeLO finden.

{
   'selector': {
      'SUCHFELD': {
         '$regex': '(?i)helo'
      }
   }
}

Spannende Optionen die ihr im JSON-String benutzen könnt sind sort, um die Ergebnisse in einer bestimmten Reihenfolge zu erhalten, und bookmark, wenn Ihr die Ergebnisse auf mehreren Seiten darstellen wollt.

Einstieg in SQL: Für alle wichtigen Datenbanksysteme:…*
  • Größe: ca. 7 ‘x5’ (203 x 148 cm x, 203,2 x 147,3 cm)
  • Material: Plüsch, 70% Schwamm, 10% Vlies Stoff 20%

Letzte Aktualisierung am 28.02.2024 / Affiliate Links / Bilder von der Amazon Product Advertising API

Die Option bookmark ist etwas umfangreicher. Ihr bekommt bei jeder Abfrage einen bookmark zurück, der widerspiegelt, bis zu welchem Datensatz Ihr gesucht habe.

Beispiel: Wenn eure Suche 20 Dokumente zurückgibt und ihr ein limit von 10 Dokumenten setzt, könntet ihr eine erneute Suche mit einem limit von 10 und dem bookmark aus der ersten Abfrage durchführen, um die nächsten 10 Dokumente zu erhalten.

Weitere Optionen, auf die ich hier nicht eingegangen bin, findet ihr in der offiziellen Dokumentation unter:

https://docs.couchdb.org/en/stable/api/database/find.html

Mango Query per Weboberfläche

Eine schöne Möglichkeit zum experimentieren bietet die Weboberfläche von CouchDB – Project Fauxton. Hier könnt ihr den JSON-String erstmal ausprobieren, erweitern und verbessern bevor ihr ihn in euer Projekt übernehmt

ein Mango Query in der Weboberfläche von CouchDB

Ähnliche Beiträge

Beitrag teilen

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Cookie Consent Banner von Real Cookie Banner