Tech talk: Zoeken in een groot tekstveld met Elasticsearch opgeslagen velden (deel 1)
Elasticsearch wordt in de loop der jaren steeds populairder en helpt klanten om hun gegevens op een andere manier te verkennen en te analyseren. Recentelijk is het opgenomen in het Gartner-kwadrant. Met Elasticsearch is het ongelofelijk hoe eenvoudig het is om een cluster op te starten en aan de slag te gaan. Maar als je je cluster niet goed configureert, kom je vroeg of laat in de problemen.
In dit artikel richten we ons op het aanpassen van het standaardgedrag van Elasticsearch om originele velden op te slaan. We zullen ook aandacht besteden aan de potentiële prestatievoordelen en nadelen die kunnen optreden.
Wat we probeerden te doen
In een vorig artikel over de Functie App schrijf ik over het extraheren en verwerken van tekst uit PDF-documenten. Nu vertel ik hoe we alle berekeningsresultaten beschikbaar hebben gemaakt voor zoekopdrachten door de prestaties te optimaliseren.
Onze dataset bestaat uit JSON-documenten die tekst en attributen uit PDF's combineren. De tekstgrootte is gemiddeld 200K tekens. De gebruikerservaring moet hetzelfde zijn als bij een bekende zoekmachine zoals Google. Wanneer een gebruiker een zoekopdracht intypt, moet hij bovendien snel een antwoord krijgen. Een resultaat na 1 minuut heeft geen zin in onze use cases.
Onze dataset bestaat uit 32 TB geïndexeerde gegevens. Bovendien weten we dat Elasticsearch scale-out veel beter is dan scale-up en dat het de gegevens en de werklast gemakkelijk aankan. Het is een kwestie van architectuur en het aantal nodes.
We beginnen met een cluster van 21 knooppunten als schatting. Er zijn enkele optimalisaties en configuraties die het vermelden en het experimenteren waard zijn, bijvoorbeeld opgeslagen velden en markeren. We zullen ons in dit eerste deel richten op de configuratie voor opgeslagen velden.
Het opgeslagen veld in Elasticsearch
In Elasticsearch kun je met een opgeslagen veld de originele waarde ophalen in een queryresultaat. Het originele document wordt opgeslagen in een veld genaamd source_ dat wordt geretourneerd. In de meeste gevallen is dit de manier waarop u het originele document van uw zoekopdracht krijgt. Standaard bevat source_ alle velden, inclusief de grote, tenzij je velden expliciet uitsluit of insluit.
Elasticsearch leest de _source van de schijf elke keer dat je een query uitvoert, parseert het als JSON en retourneert. Het lezen van zo'n opgeslagen veld met uitgebreide tekst kan een prestatieprobleem zijn, zowel op CPU (parseren van grote JSON-structuur) als op schijf I/O (lezen van veel gegevens). Bovendien zal het lezen van een onnodig grote hoeveelheid gegevens van schijf de cache van het bestandssysteem opblazen, waardoor het minder effectief wordt. Afhankelijk van de grootte van het grote tekstveld en de gebruikssituaties, zou het een goed idee zijn om het standaard gedrag aan te passen om betere prestaties te bereiken.
De _source in Elasticsearch aanpassen
Elasticsearch biedt de mogelijkheid om velden van deze specifieke _bron uit te sluiten. Het geeft je ook de mogelijkheid om een specifiek veld apart op te slaan, los van de _bron. Op deze manier kun je waardevolle informatie zoals "titel" en andere metagegevens over het document teruggeven zonder dat je uitgebreide tekst hoeft te parseren en te lezen.
Om je veld apart op te slaan, moet je je index mapping configureren: - Sluit het uit van de _source. - Geef store: true op om het veld apart op te slaan.
{
"mappings": {
"_source": {
"excludes": ["content"]
},
"properties": {
"content": {
"type": "text",
"store": true
},
"author": {
"type": "keyword"
},
"title": {
"type": "keyword"
}
}
}
}
Zelfs als de oplossing wordt geleverd met een potentieel grote prestatieverbetering, brengt het ook ernstige nadelen met zich mee die je moet weten.
Zoals uitgelegd in de officiële documentatie, zal het uitsluiten van velden van _sourceook enkele nuttige functies uitschakelen:
Update, update_by_query en reindex API's.
De markeerfunctie van niet-opgeslagen velden. Voor het markeren van zoekresultaten moet het veld op de een of andere manier zijn opgeslagen.
Een index bijwerken naar een hoofdversie. Op een gegeven moment kun je niet meer verder upgraden.
Mogelijkheid om query's te debuggen door het originele document te bekijken.
Alle mogelijke toekomstige functies die de originele _bron met alle velden nodig hebben.
Wat we aanraden in Elasticsearch
Het is nu duidelijk dat dit soort prestatieverbetering een hoge prijs heeft. Er komen enkele scenario's in ons op:
Als je de grote tekst uitsluitend gebruikt om de omgekeerde index op te bouwen voor zoeken in de volledige tekst, dan is het zinvol om deze tekst uit te sluiten van de _source. Je zult mogelijk je I/O en CPU werkbelasting verlagen, maar ook het schijfgebruik.
Als we zeldzame randgevallen hebben waarbij we de grote tekst moeten ophalen, zal het zinvol zijn om deze apart van het _bron-veld op te slaan.
Volgens onze use-cases (groot veld van 200 KB), zagen we geen merkbare verbetering van het apart opslaan van het grote tekstveld die zulke nadelen zou rechtvaardigen. We denken dat de cache van het bestandssysteem het verschil heeft gemaakt.
Zoals vermeld in dit artikel over het goed laten presteren van Elasticsearch, zou het zinvol zijn om het veld expliciet uit te sluiten van de _source als de grote veldgrootte (100 MB) groot genoeg is om de prestatieverbetering te laten opwegen tegen de nadelen. In dit specifieke geval raden we sterk aan om de gegevens in een aparte gegevensopslag te bewaren:
Documenten bijwerken door handmatig verwijderen en opnieuw indexeren.
Indexen bijwerken naar een grote versie.
Bij een upgrade moet je opnieuw beginnen met een leeg cluster en alle documenten handmatig opnieuw indexeren. In sommige gevallen kan dit vanuit zakelijk oogpunt onaanvaardbaar zijn en dan moet je met twee afzonderlijke clusters werken om de downtime te minimaliseren. Je kunt ook met één cluster werken als dat groot genoeg is om je gegevens twee keer te indexeren.
Conclusie
In eerste instantie dachten we dat onze dataset een groot tekstveld zou bevatten. We realiseerden ons al snel dat ons veld niet zo groot was en dat Elasticsearch een veel groter tekstveld aankan dan we dachten. Het idee om het grote tekstveld apart op te slaan lijkt op het eerste gezicht intrigerend, maar het biedt geen waardevol prestatievoordeel in onze dataset. We zijn er nog steeds van overtuigd dat het de prestaties in bepaalde randgevallen zou kunnen verbeteren.
Al met al moet het uitsluiten van velden van de _source een weloverwogen beslissing zijn. In de meeste gevallen raden we niet aan om de _source aan te passen, tenzij een veld groot genoeg is om de nadelen te rechtvaardigen. Om meer te weten te komen over dit onderwerp, nodig ik je uit om deze discussie te lezen.