Terug

Integratie van Elasticsearch in ons e-learning platform via een GraphQL API

Auteur: Bart Van Gennep

Bij Nerds & Company bouwen we al jaren aan een e-learning platform. Een belangrijk onderdeel daarvan is de bibliotheek, waar gebruikers snel en efficiënt naar content kunnen zoeken. Het platform draait op een Ruby-on-Rails GraphQL API met een Angular frontend. In eerste instantie hielden we het zoeken simpel: filteren op titel, omschrijving, tags, categorieën en deelname-status. Dit werkten we uit met de Ransack-gem, wat aanvankelijk prima functioneerde.

Toch liepen we tegen beperkingen aan. We wilden relevantere zoekresultaten door bepaalde contentonderdelen meer gewicht te geven. Ook wilden we leerpaden beter doorzoekbaar maken en de prestaties verbeteren naarmate het platform groeide. Tijd voor een slimmere aanpak.

De oplossing: Elasticsearch

Na grondig onderzoek kozen we voor Elasticsearch. Deze zoekmachine is gebaseerd op Lucene en biedt krachtige, schaalbare zoekmogelijkheden. We overwogen ook SOLR, maar de verouderde Ruby SDK’s en ontbrekende features maakten die optie minder geschikt.

We stonden voor de keuze: bouwen we een losse zoekapplicatie of integreren we alles binnen het platform? Een aparte app zou te veel overhead opleveren, dus bouwden we een wrapper-gem bovenop elasticsearch-ruby. Zo konden we Elasticsearch naadloos integreren en direct hergebruiken in andere Rails-projecten binnen Nerds.

Hoe werkt het?

We hebben een index opgezet met alle relevante contentdata. Bij elke wijziging in het platform wordt deze index via een achtergrondproces geüpdatet. Real-time updates zijn niet altijd mogelijk, maar de winst in snelheid was het meer dan waard.

Onze wrapper vertaalt GraphQL-queries naar Elasticsearch-queries. GraphQL-inputobjecten worden gegenereerd op basis van de indexmapping en voorgedefinieerde aggregaties. Dit zorgt voor een soepele zoekervaring zonder extra complexiteit voor de gebruiker.

Technische uitdagingen en oplossingen

1. Autorisatie van zoekresultaten

Elasticsearch weet niet welke rechten een gebruiker heeft. Achteraf autoriseren kan paginatie verstoren, dus lossen we dit andˆers op: we sturen een lijst met ID’s van toegankelijke content mee in de zoekquery. Dit vereist een extra databasequery, maar met een impact van ongeveer 100ms vonden we dit acceptabel.

2. Gebruikersspecifieke data filteren

Sommige filters, zoals deelname-status, zijn gebruikersspecifiek. Eerst probeerden we runtime-fields, maar die presteerden slecht. De betere oplossing? Gebruiker-ID’s indexeren per status (behaald, verlopen, niet behaald, etc.). Zo blijft de zoekfunctie snel en efficiënt.

3. Snelheid van indexeren

We gebruiken Postgres-database triggers om leercontent te indexeren. Elke relevante wijziging triggert een data change record, dat vervolgens door een achtergrondproces wordt verwerkt. Dit werkt goed, maar voor beheerders – die snellere updates verwachten – updaten we bij sommige wijzigingen direct de index. Dit voorkomt vertragingen, al moeten we soms in de frontend een paar seconden wachten voordat we redirecten naar de bibliotheek.

4. Filtering en aggregatie

Voor elke filter hebben we een Elasticsearch-aggregatie gedefinieerd. Dit geeft direct inzicht in het aantal resultaten per filterwaarde. Bij sommige filters leidt het selecteren van meerdere waarden echter tot een OR-conditie, waardoor je meer resultaten krijgt dan verwacht. We lossen dit op met multi-search: voor elk filter doen we een aparte zoekopdracht met dezelfde parameters als de hoofdquery. Dit lijkt complex, maar blijft binnen één GraphQL-query.

5. Fuzzy search: omgaan met typfouten

Niemand typt perfect, dus gebruiken we fuzzy search met een standaard tokenizer van lengte 5. Dit werkt goed, al levert het soms verrassende resultaten op. Voor nu laten we dit zo en evalueren we de gebruikerservaring voordat we verdere tweaks doorvoeren.

Het resultaat: een zoekfunctie die wél werkt

De zoekprestaties zijn flink verbeterd. Pagina’s laden sneller, en gebruikers vinden makkelijker relevante content. Toch krijgen we nog feedback dat niet altijd duidelijk is waarom bepaalde resultaten verschijnen. Dit willen we in de UI beter visualiseren. Op termijn overwegen we semantic search om de zoekervaring nóg slimmer te maken.

Werken bij Nerds & Company: Zo lossen wij problemen op

Deze case laat precies zien hoe wij bij Nerds werken. Onze developers krijgen de vrijheid en verantwoordelijkheid om slimme, effectieve oplossingen te bouwen. Geen standaardoplossingen, maar maatwerk dat écht werkt.

Lijkt dit je tof? We zoeken nieuwe Nerds! Bij ons werk je aan uitdagende projecten waarbij je de nieuwste technieken en tools toepast. Zie jij jezelf hier tussen passen? Check onze vacatures en kom kennismaken!