Onlangs introduceerde Textkernel versie 3 van haar producten Search! en Match! met Elasticsearch als de nieuwe onderliggende zoekmachine. Ruben Geerlings, lead developer van Search!, vertelt over deze beslissing, maar ook over de uitdagingen en oplossingen bij de overgang naar Elasticsearch.
door Ruben Geerlings
Lancering van versie 3 van Search!
Laat mij allereerst een korte introductie geven van het product. Search! is onze semantische zoeksoftware die onze klanten helpt om de juiste kandidaten en vacatures in hun eigen database en externe bronnen te vinden. We hebben een uitgebreide interface ontwikkeld met unieke functionaliteiten zoals de nice-to-have, should-have en must-have selectie en de widget voor synoniemen en gerelateerde termen om op een gebruiksvriendelijke manier complexe zoekopdrachten uit te voeren. Search! gebruikt semantische technologie, gebaseerd op natural language understanding, om de intentie van de gebruiker te begrijpen en deze om te zetten naar een voor de zoekmachine begrijpelijke query.
Onlangs hebben wij versie 3 van Search! gelanceerd; tevens de introductie van Elasticsearch als onze nieuwe onderliggende zoekmachine die out-of-the-box-oplossingen biedt voor schaalbaarheid en hoge beschikbaarheid.
Beperkingen van Search! 2
Omdat steeds meer bedrijven gebruikmaken van Search! en de vraag naar schaalbaarheid toenam, realiseerden wij dat we onze onderliggende zoekmachine moesten veranderen om flexibele schaalmogelijkheden te kunnen ondersteunen. Search! 2 ondersteunt tot 15 miljoen cv’s of vacatures. Wij wilden meer. Veel meer. Na gesprekken met verschillende klanten over hun toekomstige behoeftes ten aanzien van schaalbaarheid hebben we besloten een nieuwe versie van Search! te ontwikkelen, versie 3, om zo op te kunnen schalen naar honderden miljoenen cv’s en vacatures.
Van single node naar clusters met Elasticsearch
De vorige versie van Search! vormde een uitdaging vanwege de vereenvoudigde structuur. Een index (verzameling van doorzoekbare documenten) was beperkt tot het bezetten van een enkele machine. Elasticsearch is een open source zoekmachine die gebouwd is boven op Apache Lucene. Waar Lucene een high performance-zoekmachine biedt voor het doorzoeken van een enkele schijf biedt Elasticsearch een distributed zoekmachine die op basis van een cluster van machines opereert waarbij gebruikgemaakt wordt van een techniek genaamd sharding.
Sharding deelt een grote index op in kleinere indexes (genaamd shards) die elk worden aangestuurd door een Lucene index. De shards kunnen naast elkaar bestaan in dezelfde machine of verdeeld over verschillende machines (zogeheten cluster nodes). Een zoekopdracht wordt tegelijkertijd naar alle shards verzonden en de resultaten worden gecombineerd om tot een totaal zoekresultaat te komen.
Voorbeeld: stel dat we in een verzameling van 100 miljoen cv’s willen zoeken. Eén machine bezit niet de capaciteit om alle gegevens te bevatten en snelle queries uit te voeren. Door de index op te delen in 10 shards van elk 10 miljoen cv’s kunnen de cv’s verdeeld worden over een Elasticsearch-cluster van 10 machines die gelijktijdig kunnen worden aangestuurd om zo tot snelle zoekresultaten te komen. Bovendien kunnen we Elasticsearch de opdracht geven om replicas van de shards te creëren, daarmee is de beschikbaarheid van data gegarandeerd, zelfs als meerdere machines in de cluster uitvallen.
De keuze voor Elasticsearch
Elasticsearch als zoekmachine is in populariteit toegenomen door de eenvoudige implementatie en ontwikkelaarsvriendelijke API. De actieve ontwikkelingscommunity lanceert regelmatig nieuwe versies. Gecombineerd met het gemak waarmee klanten kunnen opschalen (een klant kan beginnen met een cluster van drie Elasticsearch-nodes en vervolgens stapsgewijs nodes hieraan toevoegen, zodat de capaciteit toeneemt) gaf de doorslag om te kiezen voor Elasticsearch als onze nieuwe backend.
Porting semantische zoekfunctionaliteiten
De keuze voor Elasticsearch bleek het gemakkelijke gedeelte. Het porten van alle semantische zoekfuncties bleek niet zo eenvoudig. Wat in eerste instantie ingeschat was als twee maanden werk, bleek uiteindelijk zes maanden te kosten. De meeste tijd ging zitten in het omzetten van de semantische query. Waar een typische Elasticsearch zoekopdracht bestaat uit één keyword-zoekveld, bestaan de zoekopdrachten bij Search! uit een combinatie van velden (zoals locatie, werkervaring, opleiding en vaardigheden), met verschillende niveaus (nice-to-have of must-have), waarbij rekening wordt gehouden met fuzzy overeenkomsten (zoals zoeken met gerelateerde woorden of zoeken in de buurt van een locatie) en daarbij nog het toepassen van verschillende filters en scoremogelijkheden. Om dit te bereiken maakten we veel gebruik van de Elasticsearch-queryconstructies (bool en dis-max) die in diverse lagen genesteld waren.
“Je kunt niet verwachten dat een zoekopdracht die goede resultaten oplevert voor algemene webpagina’s, ook de beste resultaten oplevert wanneer specifiek naar cv’s en vacatures wordt gezocht.”
Ranking en evaluatie
Veel van het onderzoek is gaan zitten in het afstemmen van de ranking-formule. We moesten er zeker van zijn dat alle aspecten van de query in de juiste mate bijdragen aan de uiteindelijke matching-score. Het kostte veel iteraties totdat we alles juist hadden. Elasticsearch heeft geen domeinkennis. Je kunt niet verwachten dat een query die goede resultaten oplevert voor algemene webpagina’s ook de beste resultaten oplevert wanneer specifiek naar cv’s en vacatures wordt gezocht.
Om zeker te zijn dat de ranking in Search! 3 gelijk of beter is dan in Search! 2 vergeleken we de zoekresultaten via de wetenschappelijke methode. Een panel van ervaren gebruikers evalueerde een groot aantal zoekresultaten en beoordeelden deze als relevant of niet-relevant zonder te weten van welke versie de resultaten kwamen. De evaluatie liet zien welke versie beter scoorde op welke queries.
Op maat gemaakte score-plugin voor Elasticsearch
Om de gewenste scoreformule in Elasticsearch te implementeren, ontwikkelden we een op maat gemaakte Elasticsearch-plugin. De plugin wordt geleverd bij Search! en kan worden geïnstalleerd in elke Elasticsearch-node. De Elasticsearch-plugin kan elk aspect van de onderliggende Lucene index aanpassen, wat in dit geval wordt gebruikt om de speciaal voor Search! ontwikkelde scoreformule te implementeren.
Search! 3 en verder
Elasticsearch heeft ons geholpen ons doel van schaalbaarheid en hoge beschikbaarheid in Search! 3 te bereiken. Daarnaast heeft het porten van de ranking-formule zelfs de algehele kwaliteit van zoekresultaten verbeterd. De mogelijkheid van op maat gemaakte Elasticsearch-plugins zorgen ervoor dat wij onze specifieke scoreformule kunnen implementeren. We zijn erg enthousiast over de toekomstige mogelijkheden van Search! We zijn al bezig met het bouwen van nieuwe semantische functies bovenop Elasticsearch, die we begin dit jaar hopen uit te brengen. Ik heb er alle vertrouwen in dat we met Elasticsearch kunnen meeschalen met de groei van onze klanten en dit nog vele Search!-versies zal ondersteunen.
Over de auteur
Ruben Geerlings is lead developer van Search! en werkt zes jaar bij Textkernel. Hij begon te werken aan Sourcebox en is daar overgegaan naar de Search!- en Match!-producten. Drie jaar geleden initieerde hij de Textkernel Innovation Week en was vervolgens elk jaar betrokken bij de organisatie van het evenement. Onder meer “virtual agent voor online toepassingen” en “crowdsourced job recommendation engine” behoren tot zijn innovaties. Ruben is geboren en getogen in Amsterdam en is afgestudeerd in Computer Science bij de Universiteit van Amsterdam, gespecialiseerd in Software Engineering. In zijn vrije tijd probeert hij zijn één jaar oude zoontje Nederlands en Mandarijn bij te brengen.
Nieuwsgierig naar Textkernel? We groeien en zijn op zoek naar nieuwe collega’s!