Elasticsearch

Fulltextové vyhledávání a analýza dat

Filip Majerík  |  2026

Typy databází

Typ Příklady Vhodné použití
Relační MySQL, PostgreSQL, OracleDB Transakční systémy, vazby mezi daty, konzistence
Key-Value Redis, DynamoDB Cache, session, velmi rychlý přístup k datům
Dokumentové MongoDB, Couchbase Flexibilní struktura dat, JSON dokumenty
Sloupcové Cassandra, HBase Velké objemy dat, horizontální škálování, vysoká dostupnost, rychlé zápisy
Search engine Elasticsearch, OpenSearch Fulltextové vyhledávání, relevance, agregace

A spousta dalších...

Alternativný typy databází

Existuje ideální databáze?

rozhodování no

Existuje ideální databáze? Ne.

Proč?

  • Nelze splnit všechny vlastnosti distribuovaných systémů (CAP teorém).
  • Různé use-casy řeší různé (často protichůdné) požadavky.
  • Výkon, konzistence a flexibilita jsou vždy kompromis.
  • Optimalizace na konkrétní typ zátěže zhoršuje jiný (např. zápis vs. čtení).
  • Různé datové modely se hodí pro různé typy dat a dotazů.

→ DBS vždy volíme podle konkrétního use-casu a požadavků.

Reálný problém?

Hledání v databázích

  • Uživatel zadá dotaz: sta wrs
  • Očekává:
    • relevantní výsledky (Star Wars)
    • rychlou odezvu
    • toleranci chyb (překlepy: sta wrsstar wars)
  • Data:
    • miliony záznamů
    • různé formy textu
    • více polí (název, popis, herci...)

→ Jak tohle efektivně vyřešit?

Jak bychom to řešili v ...?

  • Relačních databázích
  • Key-Value databázích
  • Dokumentových databázích

Relační databáze - LIKE


        SELECT *
        FROM movies
            WHERE title LIKE '%sta wrs%';
            
  • ❌ nefunguje (překlep)
  • ❌ žádná relevance
  • ❌ pomalé na velkých datech

Relační databáze - FULLTEXT


        SELECT *
        FROM movies
            WHERE MATCH(title) AGAINST ('sta wrs');
                    
  • ✔️ lepší než LIKE
  • ⚠️ základní relevance
  • ⚠️ omezené možnosti ladění
  • ⚠️ slabší práce s překlepy
  • ⚠️ není optimalizovaný pro velký search load
  • ❌️ není standardizovaný
  • 🔥 různá implementace & dotazování
  • ⚠️ potřeba extensions / pluginů
  • ⚠️ většinou hard-core konfigurace
  • ❌ některé RDBMS ho vůbec nepodporují
Použili jste někdy FULLTEXT v RDBMS?

Key-Value databáze - Redis (8+)


        FT.CREATE movies_idx ON HASH PREFIX 1 "movie:"
        SCHEMA
            title TEXT
            description TEXT
	
  • ✔️ fulltext search dostupný přímo v Redis
  • ⚠️ nutnost explicitního indexu
  • ⚠️ jiný přístup než běžný key-value model

Key-Value databáze - Redis


        FT.SEARCH movies_idx "sta wrs"
	
  • ✔️ základní fulltext funguje
  • ⚠️ omezené možnosti relevance
  • ⚠️ méně flexibilní než specializovaný nástroj
  • ⚠️ není primárně určený pro komplexní search
→ není to hlavní use-case Redisu

Dokumentová databáze - MongoDB


        db.movies.createIndex({
          title: "text",
          description: "text"
        });

        db.movies.find({
          $text: { $search: "sta wrs" }
        });
    
  • ✔️ základní fulltext existuje
  • ✔️ přirozená práce s dokumenty / JSON
  • ⚠️ nutnost text indexu
  • ⚠️ omezenější ladění relevance
  • ⚠️ méně specializované než search engine
→ funguje to, ale search není hlavní specializace MongoDB

Dok. db - MongoDB Atlas Search


        db.movies.aggregate([
          {
            $search: {
              text: {
                query: "sta wrs",
                path: ["title", "description"]
              }
            }
          }
        ]);
    
  • ✔️ pokročilejší fulltext než klasický $text
  • ✔️ search index mimo běžný DB index
  • ⚠️ blízké specializovanému search řešení
  • ⚠️ vyšší komplexita než obyčejný find()
→ čím lepší search chceme, tím víc se blížíme specializovanému nástroji

Co zatím víme?

  • Vyhledávání je komplexní problém.
  • Uživatelé očekávají:
    • relevantní výsledky
    • rychlost
    • toleranci chyb
  • Běžné databáze to zvládnou…
              …ale většinou s kompromisy.
  • Search není jejich primární use-case.

→ potřebujeme nástroj navržený přímo pro vyhledávání

Co je na tohle
dělané od začátku?

Drum rolls

Elasticsearch

  • distribuovaný search engine
  • ukládá data jako JSON dokumenty
  • používá invertovaný index
  • optimalizovaný pro fulltextové vyhledávání
  • výsledky řadí podle relevance (score)

Moment...

Co že je ten distribuovaný systém?

wait a moment?

Distribuovaný systém

  • systém běžící na více uzlech (nodes)
  • uzly spolu komunikují a sdílí práci
  • navenek se chová jako jeden celek
  • cílem je škálování a odolnost
  • běží jako skupina spolupracujících node
  • navenek se tváří jako jeden celek = cluster
  • data i dotazy se mezi nody rozdělují
  • díky tomu umí škálovat výkon i odolnost
  • cluster = skupina (např. Elasticsearch) node
  • sdílí data, stav a zodpovědnost za vyhledávání
  • uživatel obvykle komunikuje s clusterem jako s jednou službou
  • uvnitř se ale práce rozděluje mezi více strojů
  • master-eligible node – může se stát masterem (účastní se voleb)
  • elected master node – aktuálně zvolený master, řídí cluster (metadata, shard allocation)
  • data node – drží data a obsluhuje dotazy
  • ingest node – zpracovává data při zápisu (pipelines, transformace)
  • v demo prostředích může jeden node dělat více rolí najednou
  • ve větším nasazení role často oddělujeme (master / data / ingest)
  • index se dělí na primární shardy
  • každý shard může mít svou replicu
  • shardy rozkládají data i zátěž
  • repliky pomáhají s dostupností a často i čtením
  • primární shard a jeho replica nikdy neběží na stejném node

        PUT /program
        {
          "settings": {
            "number_of_shards": 3,
            "number_of_replicas": 1
          }
        }
    
  • number_of_shards: 3 → index se rozdělí na 3 primární shardy
  • number_of_replicas: 1 → každý primární shard bude mít 1 repliku
  • celkem tedy vznikne 6 shardů
  • celkem shardů = primární shardy × (1 + počet replik)
  • 6× Elasticsearch node
  • 3× master + 3× data node
  • Nginx jako SSL reverse proxy a load balancer
  • Kibana pro vizualizaci a práci s clusterem
  • Filebeat pro sběr a posílání dat
  • Logstash pro zpracování a transformaci dat
  • Filebeat sbírá data a posílá je do Logstash
  • Logstash data zpracuje a předá do Elasticsearch
  • Elasticsearch je ukládá do indexů a shardů
  • Kibana nad clusterem dělá správu, dotazy a vizualizaci
  • Nginx sjednocuje přístup zvenku a rozděluje požadavky mezi node
  • ukončuje TLS/SSL
  • funguje jako load balancer pro všechny ES node
  • při chybě umí zkusit další upstream
  • do hlavičky přidává, který node požadavek obsloužil
  • má vlastní health endpoint pro kontrolu dostupnosti
  • !! v našem demu se jedná o SPOF !!

Elastic Workshop demo

docker loading

... co je distribuovaný systém už víme.

A co to vyhledávání?

  • vyhledávání není jen filtrace dat
  • uživatel zadává nepřesné dotazy
  • potřebujeme řešit relevanci, ne jen shodu
  • jazyk ≠ data (tvary, překlepy, synonyma, skloňování, časování)
  • práce s nepřesným dotazem
  • řazení podle relevance
  • analýza textu (tvary slov, tokenizace, stemming...)
  • tolerance k překlepům
  • rychlé hledání i nad velkým objemem dat
  • nevyhledává přímo v datech
  • nejdřív si je připraví do indexu
  • používá tzv. invertovaný index
  • hledání pak probíhá nad tokeny, ne nad celým textem
    Star Wars        → star, wars
    War of Worlds    → war, worlds
    Star Trek        → star, trek

    ----------------------------

    star   → doc1, doc3
    wars   → doc1
    war    → doc2
    worlds → doc2
    trek   → doc3
    

Inverted Index (příklad)

Vstupní dokumenty

  1. Kočka sedí na střeše domu.
  2. Malá kočka seděla na střeše.
  3. Kočky sedí na střechách domů.
  4. Na střeše domu sedí černá kočka.
  5. Kočka právě sedí na střeše starého domu.

Tokenizace

        1 → [kočka, sedí, na, střeše, domu]
        2 → [malá, kočka, seděla, na, střeše]
        3 → [kočky, sedí, na, střechách, domů]
        4 → [na, střeše, domu, sedí, černá, kočka]
        5 → [kočka, právě, sedí, na, střeše, starého, domu]
    

Normalizace (zjednodušeně)

        kočka / kočky → kočk
        sedí / seděla → sed
        střeše / střechách → střech
        domu / domů → dom
    

Inverted Index


        kočk   → [1, 2, 3, 4, 5]
        sed    → [1, 2, 3, 4, 5]
        střech → [1, 2, 3, 4, 5]
        dom    → [1, 3, 4, 5]
        malá   → [2]
        černá  → [4]
        starý  → [5]
        právě  → [5]
    
  • Star Wars v indexu neznamená, že najdeme i str wrs.
  • Samotný invertovaný index hledá jen to, co v něm opravdu je.
  • Bez další úpravy dotazu nebo dat může být výsledek stále [].
  • Search kvalita stojí i na správné analýze textu.
        Star Wars  → star, wars
        str wrs    → str, wrs

        --------------------

        str  → ?
        wrs  → ?

            → Výsledek: nic
    
  • Analyzerem
  • Hunspell (slovníky)
  • n-gram / autocomplete
  • Analyzer pipeline
  • analyzery upravují text → tokeny
  • řeší jazyk (tvary slov, stemming…)
  • pomáhají sjednotit data a dotaz
  • standard – základní tokenizace + lowercase
  • simple – ponechává znaky + lowercase
  • language analyzers – např. czech, english
  • whitespace – dělí jen podle mezer
  • custom analyzers – vlastní tokenizer + filtry
  • slova, která ignorujeme při vyhledávání
  • např. a, the, je, to
  • pomáhají snížit „šum“ v datech
  • zkusíme různé analyzéry…
  • str wrs → pořád str, wrs
  • výsledek: stále nic
  • slovníková kontrola nad tvary slov
  • užitečné hlavně pro morfologii jazyka
  • typicky pro skloňování, časování, odvozování tvarů
  • ale str wrs stále není validní slovo
  • Hunspell zlepšuje práci se slovními tvary
  • neřeší ale zkrácené nebo rozbité tokeny
  • str wrs → stále nic
  • text se rozdělí na menší části
  • neindexujeme jen celé slovo, ale i jeho fragmenty
  • to pomáhá při našeptávání a neúplném vstupu
  • starst, sta, star
  • str wrs už se může částečně potkat s indexem
  • funguje dobře pro prefixy a části slov
  • je skvělé pro autocomplete
  • ale není to univerzální řešení relevance
  • str wrss velkou pravděpodobností nic
  • pipeline kombinuje více kroků zpracování textu
  • např. tokenizer + lowercase + stop words + stemming
  • umožní si analyzaci textu přesně přizpůsobit
  • ale pořád pracujeme jen s tím, co z textu dokážeme odvodit
  • pipeline zlepší konzistenci analyzace
  • pomůže zkombinovat více technik najednou
  • ale str wrs stále nemusí stačit na star wars
  • samotná pipeline také problém nevyřešila
  • Analyzery - pomáhají s jazykem
  • Hunspell - pomáhá se slovními tvary
  • n-gram - pomáhá s fragmenty a autocomplete
  • pipeline - pomáhá tyto kroky kombinovat
  • kvalitní search je vždy kombinace přístupů
  • Analyzerem
  • Hunspell (slovníky)
  • n-gram / autocomplete
  • Analyzer pipeline
  • nepíše přesně → str wrs
  • netrefí klávesu → sqtr wsrs
  • tokeny se neshodují
  • klasické analyzéry nepomohly
  • potřebujeme hledat „přibližně“
  • umožňuje hledat i nepřesné shody
  • počítá Levenshteinovu vzdálenost mezi slovy
  • str → blízko star → vzdálenost 1 (doplní a)
  • wrs → blízko wars → vzdálenost 1 (doplní a)
  • sqtr → blízko star→ vzdálenost 2 (odebere q, přidá a)
  • wsrs → blízko wars→ vzdálenost 1 (prohodí s a a)
  • str wrsstar wars
  • uživatel píše nepřesně
  • my přesto najdeme správný výsledek
  • ale má své limity
  • Analyzer
  • Hunspell
  • n-gram / autocomplete
  • Analyzer pipeline
  • Fuzziness
  • Analyzer pipeline (index-time) → fuzziness (query-time)
  • tokenizer určuje, kde se text rozdělí
  • různé typy → různé tokeny
  • např. standard, whitespace, pattern
  • výběr tokenizeru ovlivňuje kvalitu search
  • standard (UAX) – chytré dělení textu
  • (UAX) URL Email – speciální varianta standard (UAX) pro URL a e-maily
  • whitespace – dělí jen podle mezer
  • letter – jen písmena
  • pattern – vlastní pravidla (regex)
  • path – pro cesty / URL
Zdrojová data JSON / CSV / logy / dump
ETL + datová pumpa transformace, čištění, validace
Elasticsearch indexace dokumentů

Kam se data budou plnit?

index #1 program-raw (atuo mapping)
index #2 program-basic (minimal mapping)
index #3 program-search (search mapping)
  • ovlivňuje relevanci výsledků
  • některá pole jsou důležitější než jiná
  • výsledky se řadí podle score
  • boost = zvýšení váhy

    // varianta 1 — inline (caret ^)
    {
      "multi_match": {
        "query": "ulice",
        "fields": [
          "title^3",
          "description"
        ]
      }
    }


    // varianta 2 — explicitní boost
    {
      "match": {
        "title": {
          "query": "ulice",
          "boost": 3
        }
      }
    }

    
  • neboostujeme jen pole
  • vážíme více signálů
  • text (název, popis…)
  • metadata (žánr, země, jazyk)
  • uživatelský kontext (filtry)
  • Název vs. popis
  • Jazyk názvu (cz / en / original)
  • Žánr (drama, komedie…)
  • Země
  • Fulltext vs. přesná shoda
play!
  • neexistuje univerzální správné nastavení
  • ladí se podle use-case
  • často iterativně (test → úprava → test)
  • malé změny → velký dopad
  • overboosting problém - ladění na malých/chybných datech
  • Significant terms – statisticky neobvyklá slova
  • Collapse – nejlepší výsledek za skupinu
  • Aggregations – souhrny a analýza dat
  • More like this – podobný obsah
  • hledají statisticky neobvyklá slova
  • porovnávají subset vs celý dataset
  • počítají se při dotazu (query-time)
  • využívají frekvenci výskytu (TF / DF)
  • neukládají se jako data → jsou odvozené
    Celý index: 1000 filmů
    Subset: 100 akčních filmů

    'exploze':
        → v celém indexu: 50×
        → v subsetu: 40×

        => nečekaně vysoký výskyt (80% dokumentů)significant
    
    Celý index: 1000 filmů

    'film':
        → v celém indexu: 900×
        → v subsetu: 10×

        => normální výskyt (~1% dokumentů)non-significant
    
  • seskupí výsledky podle pole vybraného fieldu
  • z každé skupiny vrátí jen jeden dokument
  • např. jeden pořad za každý rok
  • výběr může být podle score nebo řazení
    Dotaz: Chci znát pro každý rok film,
           který nejlépe odpovídá výrazu: 'terminator'
                
            Výsledky:

            * 1984 - Terminátor - 87 %
            * 1991 - Terminátor 2: Den zúčtování - 91 %
            * 2003 - Terminátor 3: Vzpoura strojů - 74 %
            * 2007 - Hra s časem - 20 %
            * 2009 - Terminator Salvation - 67 %
            * 2015 - Terminator Genesys - 66 %
            * 2019 - Terminátor: Temný osud - 67 %
                
  • seskupují data do bucketů
  • nevrací primárně dokumenty, ale statistiku
  • typicky: kolik filmů je v žánrech, letech, zemích…
  • fungují jako analytická vrstva nad indexem
  • buckety můžeme zanořovat
  • např. žánrrokzemě
  • dostaneme strukturovaný pohled na data
  • něco jako hierarchická analytika
        Dotaz: Chci znát počet filmů
               dle žánru a následně dle let v kterých vyšly.
                
        1000 filmů
            ├─ Akční: 500
            │  ├─ 1980s: 120
            │  ├─ 1990s: 180
            │  └─ 2000s: 200
            │
            ├─ Sci-fi: 300
            │  └─ ...
            └─ Komedie: 200
               └─ ...
    
  • najde podobné dokumenty
  • porovnává jejich textový obsah
  • vybírá důležité termy ze zdrojového dokumentu
  • hodí se pro „co dalšího by se mi mohlo líbit?“
  • vezmeme jeden dokument
  • z něj se vyberou významné termy
  • podle nich se hledají podobné dokumenty
  • není to AI magie, ale práce s textem a relevancí
  • nejedná se o použití signifikantních termů, ale výpočet relevance
Hledání začíná dotazem , More like this začíná dokumentem.
  • uživatel otevře film Terminátor 2
  • chceme nabídnout podobné filmy
  • Elasticsearch vezme: popis / názvy / tagy
  • → vrátí obsah, který je textově podobný
  • kNN – vektorové vyhledávání (AI, embeddingy)
  • LTR – Learning to Rank (ML pro relevanci)
  • Percolator – dotazy jako data
  • Suggesters – našeptávače
  • Geo search – hledání podle polohy
  • vyhledávání není jen filtrace dat
  • pracujeme s jazykem, chybami a relevancí
  • mapping + analyzery + query = výsledek
  • relevance je konfigurace

Děkuji za pozornost.

Otázky?