Tech talk: zoeken in een groot tekstveld met Elasticsearch-highlighting en Kibana (deel 2)

In deel 1 van deze artikelreeks bespraken we opgeslagen velden en hoe u de standaardconfiguratie van Elasticsearch aanpast. Voor onze dataset leverde die aanpassing geen betere prestaties op. Hier bespreken we de highlightingfunctie, de configuratie ervan en de mogelijke prestatiewinst in Elasticsearch.
Vaak is het nuttig te weten welk woord of token in een document met onze zoekopdracht overeenkomt. In Elasticsearch heet het markeren van zo'n token, u raadt het al, highlighting. In bepaalde gevallen vraagt die functie veel rekencapaciteit en tijd. Een daarvan is highlighting in een groot tekstveld. We bekijken de verschillende methoden zonder diep op technische details in te gaan. Daarna vergelijken we hun prestaties voor onze toepassingen en dataset.
Ter herinnering: onze dataset bestaat uit JSON-documenten met metadata zoals 'title' en 'author'. Een extra veld bevat de tekst uit de pdf. Dat veld telt gemiddeld 200K tekens (200 KB).
Highlighting met Elasticsearch
We willen weten of we highlighting in Elasticsearch voor onze dataset kunnen optimaliseren. Volgens de officiële documentatie kunnen we instellen hoe de zoekresultaten worden gemarkeerd. We proberen de prestaties te verbeteren met twee verschillende parameters:
1. Offsetstrategie: Postings: voegt voor elke term een positie-offset toe aan de geïnverteerde index. Daardoor kan Elasticsearch snel de plaats van een term bepalen zonder analyse.
Term vector met with_positions_offsets: een extra datastructuur met geavanceerde mogelijkheden om resultaten te scoren. Volgens de officiële documentatie zou dit het efficiëntst zijn bij zeer grote velden (> 1 mb). Het neemt waarschijnlijk ook veel meer schijfruimte in.
Opmerking: Elasticsearch indexeert documenten standaard zonder offsets te berekenen.
2. Highlighter: Unified: gebruikt het BM25-algoritme om resultaten te scoren. Dit is de standaardhighlighter.
FVH (Fact vector highlighter): gebruikt het tf–idf-algoritme en vereist een term vector met with_positions_offsets.
Plain: bouwt bij elke zoekopdracht voor elk document en veld opnieuw een volledige kleine index in het geheugen.
Standaard bouwt Elasticsearch geen postings of term vectors op. De highlightingfunctie gebruikt dus de Unified-highlighter zonder offsetstrategie.
Bij de keuze voor een bepaalde highlighter zijn sommige functies niet meer beschikbaar. We raden aan de officiële documentatie te lezen.
Prestaties meten met Elasticsearch
We maten de prestaties van verschillende highlightingconfiguraties. Het doel was een ruwe inschatting van de beste configuratie voor een proof of concept. Er kunnen vertekeningen in die metingen zitten. Onze testomgeving staat namelijk niet onder een constante, productieachtige belasting, maar dient uitsluitend om een eerste inschatting te maken.
We gebruikten de resultaateigenschap 'took' als indicatie van de tijd in milliseconden die een zoekopdracht nodig had. We voerden 100 zoekopdrachten met telkens 1000 gevraagde documenten uit op drie verschillende indices, elk met een andere offsetstrategie.

Het is geen verrassing dat de plain-highlighter zonder offsetstrategie minder goed presteert door zijn technische implementatie. Voor onze dataset lijkt de standaard unified-highlighter met postings het efficiëntst. Hij lijkt ook beter te presteren dan FVH met de term-vectorstrategie. Volgens ons past FVH met term vectors beter bij grotere tekstvelden, zoals de officiële documentatie aangeeft (> 1 MB).
Term vectors gebruiken duidelijk de meeste schijfruimte door hun extra datastructuur. Postings verhogen het schijfgebruik met ongeveer 20%. Dat blijft volgens ons vanuit bedrijfsoogpunt betaalbaar.

Als we prestaties en schijfgebruik samen bekijken, zijn postings met een unified-highlighter duidelijk een goede kandidaat voor onze implementatie.
De data doorzoeken met Kibana
Als u de data probeert te doorzoeken met Kibana, de dashboardsoftware voor datavisualisatie van Elasticsearch, merkt u dat dit erg traag gaat. Het probleem zit niet bij Elasticsearch, maar bij de frontend van Kibana. Die probeert alle grote tekstvelden twee keer op de pagina te laden.
Ten eerste maakt het grote tekstveld deel uit van het source_-veld. Om Kibana sneller te maken, moet u het grote tekstveld uit de source uitsluiten. Dat kan in de configuratie van het indexpatroon onder het tabblad Field filtering_ in de nieuwere versie van Elasticsearch.
Ten tweede bevat het gemarkeerde deel van het zoekresultaat het volledige grote tekstveld in plaats van fragmenten. Een fragment is een deel van de tekst met de gemarkeerde waarde. Bekijk het highlightingdeel van de gegenereerde query bij een zoekopdracht in het tabblad discovery:
"highlight": {
"pre_tags": [
"@kibana-highlighted-field@"
],
"post_tags": [
"@/kibana-highlighted-field@"
],
"fields": {
"*": {}
},
"fragment_size": 2147483647
}
Het probleem is de fragmentgrootte: die is ingesteld op de maximale waarde van een integer. Kibana vraagt het grootst mogelijke gemarkeerde fragment op en laadt zo het volledige grote tekstveld. Volgens ons doet Kibana dit omdat het momenteel geen meerdere gemarkeerde fragmenten kan tonen. De enige oplossing is de highlightingfunctie uitschakelen in de geavanceerde instellingen van Kibana.
Conclusie
We stelden vast dat Kibana niet werkt met grote tekstvelden, vooral voor highlighting. In aansluiting op het vorige artikel, deel 1, kan het zinvol zijn grote tekst niet op te slaan om mogelijk een factor 2 aan schijfruimte te besparen. Voor onze specifieke toepassingen zijn we ervan overtuigd dat momenteel een aparte frontend nodig is om highlighting met grote tekstvelden te implementeren.