Search

Invertovaný index, tokenizace, relevance, autocomplete.

„Vyhledávací políčko" vypadá jako maličkost, ale udělat ho dobře je celá disciplína. Když uživatel napíše „leveny telefon", chceš najít i „levné telefony", seřadit výsledky podle relevance a odpovědět do pár milisekund nad miliony záznamů. Obyčejný databázový dotaz na tohle nestačí. Tahle kapitola vysvětlí, jak fulltextové vyhledávání funguje uvnitř.


Pár pojmů na úvod

  • Fulltextové vyhledávání = hledání slov uvnitř textu (ne přesná shoda, ale „obsahuje").
  • Token = jedno slovo, na které se text rozseká (tokenizace).
  • Index = struktura, díky které je hledání rychlé (znáš z Databází).
  • Relevance = jak moc výsledek odpovídá dotazu (podle toho se řadí).

Proč nestačí WHERE text LIKE '%slovo%'

Naivně bys hledal databázovým dotazem ... LIKE '%telefon%'. Má to tři problémy:

  1. Je to pomalé — takový dotaz neumí použít obyčejný index, takže projíždí celou tabulku.
  2. Je to hloupé — najde jen přesný řetězec. Nenajde „telefony" (množné číslo) ani nepřehlédne překlepy a velikost písmen.
  3. Neumí řadit podle relevance — nepozná, který výsledek je „lepší".

Na pořádné vyhledávání se proto používá speciální struktura: invertovaný index.


Invertovaný index — srdce vyhledávání

Představ si rejstřík na konci knihy: u každého slova je seznam stránek, kde se vyskytuje. Invertovaný index dělá přesně tohle pro tvoje data — ke každému slovu si drží seznam dokumentů, které ho obsahují:

Když hledáš „levný telefon", systém si z indexu vytáhne dokumenty pro „levný" a pro „telefon" a najde jejich průnik — to je bleskové, protože nemusí číst žádný text, jen seznamy. Tak funguje vyhledávání nad miliony záznamů v milisekundách.


Jak se text připravuje (proč najde i „telefony")

Než se text uloží do indexu, projde úpravami, aby hledání bylo „chytré":

  • Tokenizace — text se rozseká na jednotlivá slova.
  • Normalizace — sjednotí se velikost písmen, případně se odstraní diakritika. Odstranění diakritiky je ale trade-off závislý na jazyce: u češtiny může sloučit slova s různým významem („byt" vs „být") — není to automatický krok, zvaž to.
  • Stemming / lemmatizace — slova se převedou na základní tvar („telefony", „telefonu" → „telefon"). Stemming hrubě usekává konce a u flektivních jazyků jako čeština často selhává; lemmatizace (převod na slovníkový tvar) je pro češtinu výrazně lepší, i když dražší.
  • Stop words — vyhodí se nicneříkající slova („a", „the"), ať nezabírají místo.

Díky tomu dotaz „levny telefon" najde i „Levné telefony".


Řazení podle relevance

Najít dokumenty nestačí — musíš je seřadit od nejlepšího. Relevance se počítá z toho, jak dobře dokument odpovídá dotazu (zhruba: čím vzácnější slovo a čím častěji se v dokumentu vyskytuje, tím výš). K tomu se přidávají vlastní pravidla („novější výš", „populárnější výš").


Autocomplete (našeptávač)

Napovídání během psaní je trochu jiný problém — hledáš podle začátku slova (prefixu) a musíš odpovědět opravdu rychle (na každé písmeno). Řeší se to prefixovými strukturami a agresivním cachováním populárních dotazů.


Čím to postavit

  • Vyhledávání přímo v Postgresu (má vestavěný fulltext) — stačí pro spoustu aplikací, žádný další systém navíc.
  • Elasticsearch / OpenSearch — specializovaný vyhledávač pro velkou škálu, pokročilé řazení a analýzu. Ne jako hlavní databáze — je to doplněk vedle ní (viz Tech Choices).

Pravidlo: začni fulltextem v Postgresu. Po samostatném vyhledávači sáhni, až ti přestane stačit.

Invertovaný index hledá podle slov. Vedle něj existuje sémantické (vektorové) vyhledávání, které hledá podle významu (najde „štěně" na dotaz „pes") — staví na embeddingech, viz AI / LLM. Produkční systémy dnes často kombinují obojí (hybrid search = klíčová slova

  • vektory) plus rerank krok. Invertovaný index tedy není poslední slovo, jen základ.

Failure modes — jak to v praxi praská

  • LIKE '%…%' jako vyhledávání → pomalé (projíždí celou tabulku) a hloupé (nenajde tvary slov).
  • Index zaostává za databází → vyhledávací index je vůči databázi obvykle eventually consistent (reindexuje se asynchronně) — malé zpoždění je normální, ne bug. Problém je, až když se reindex rozbije nebo zasekne a index ukazuje neexistující/staré záznamy. Měj tu sync pipeline pod monitoringem.
  • Žádné řazení podle relevance → uživatel dostane správné výsledky ve špatném pořadí a nenajde to.
  • Pomalý autocomplete → napovídání musí být bleskové, jinak ruší; bez cache to nedáš.

🛠️ Cvičení

  1. Proč ne LIKE. Vysvětli na konkrétním příkladu tři důvody, proč WHERE name LIKE '%telefon%' není dobré vyhledávání.
  2. Postav invertovaný index. Pro tři krátké věty ručně vytvoř invertovaný index (slovo → čísla vět) a ukaž, jak najdeš větu obsahující dvě konkrétní slova.
  3. Příprava textu. Pro dotaz „nejlevnejsi MOBILY" popiš, co s ním udělá normalizace a stemming, aby našel „nejlevnější mobil".
  4. Relevance. Dva dokumenty obsahují hledané slovo. Vymysli dvě pravidla, podle kterých rozhodneš, který ukázat výš.
  5. Postgres, nebo Elasticsearch? Pro malý e-shop s 5000 produkty rozhodni a zdůvodni.
Náčrt řešení — rozbal, až si cvičení zkusíš sám
  1. Proč ne LIKE — pointa: LIKE '%telefon%' je pomalé (neumí použít běžný index, projíždí celou tabulku), hloupé (najde jen přesný řetězec, ne „telefony" ani jiné tvary, neřeší velikost písmen) a neumí řadit podle relevance. Pozor: ukaž to na konkrétním dotazu — na pořádné vyhledávání se používá invertovaný index.
  2. Postav invertovaný index — pointa: ke každému slovu sepíšeš seznam čísel vět, kde se vyskytuje, a větu se dvěma slovy najdeš jako průnik jejich seznamů. Pozor: nečteš žádný text, jen porovnáváš seznamy — proto je to bleskové i nad miliony záznamů.
  3. Příprava textu — pointa: normalizace sjednotí velikost písmen a (volitelně, viz past) sloučí diakritiku („nejlevnejsi" = „nejlevnější"), stemming/lemmatizace převede slova na základní tvar („MOBILY" → „mobil"); stejně se upraví dotaz i indexovaný text, takže se trefí. Pozor: odstranění diakritiky a stemming jsou u češtiny trade-off (může splést „byt"/„být", stemming často selhává) — lepší je lemmatizace.
  4. Relevance — pointa: výš dej dokument, kde je hledané slovo vzácnější a vyskytuje se častěji, a přidej vlastní pravidlo jako „novější výš" nebo „populárnější výš". Pozor: najít oba dokumenty nestačí — uživatel kouká hlavně na první výsledky, špatné pořadí = nenajde to.
  5. Postgres, nebo Elasticsearch — pointa: pro 5000 produktů zvol vestavěný fulltext v Postgresu, žádný systém navíc nepotřebuješ. Pozor: po Elasticsearch sáhni, až ti Postgres přestane stačit (velká škála, pokročilé řazení) — a i tak jen jako doplněk vedle databáze, ne jako hlavní úložiště.

🧠 Otázky & odpovědi

Proč nestačí na vyhledávání WHERE text LIKE '%slovo%'?

Tři důvody: je to pomalé (takový dotaz neumí použít běžný index a projíždí celou tabulku), je to hloupé (najde jen přesný řetězec, ne tvary slov jako množné číslo, neřeší velikost písmen ani diakritiku) a neumí řadit podle relevance. Na pořádné vyhledávání se používá invertovaný index.

Co je invertovaný index a proč je rychlý?

Je to jako rejstřík v knize: ke každému slovu si drží seznam dokumentů, které ho obsahují. Při hledání „levný telefon" systém vezme seznamy pro obě slova a udělá jejich průnik — nemusí číst žádný text, jen porovnat seznamy, což je bleskové i nad miliony záznamů. To je důvod, proč vyhledávač odpoví v milisekundách.

Proč dotaz levny telefon najde i tvar Levné telefony?

Protože se text před uložením do indexu upravuje: normalizací se sjednotí velikost písmen a odstraní diakritika („levný" = „levny"), stemmingem se slova zkrátí na základ („telefony" → „telefon"). Stejné úpravy se udělají i s dotazem, takže se trefí bez ohledu na tvar slova nebo háčky a čárky.

Proč je řazení podle relevance důležité?

Najít dokumenty obsahující slovo nestačí — uživatel se dívá hlavně na první výsledky. Když je neseřadíš podle toho, jak dobře odpovídají (a podle vlastních pravidel jako novost nebo popularita), ten nejlepší výsledek může skončit na desáté stránce a uživatel ho nenajde, i když tam je.

Kdy stačí fulltext v Postgresu a kdy sáhnout po Elasticsearch?

Začni fulltextem v Postgresu — má ho vestavěný a pokryje spoustu aplikací bez dalšího systému navíc. Po Elasticsearch (samostatný vyhledávač) sáhni, až potřebuješ velkou škálu, pokročilé řazení nebo analýzu, kterou Postgres neuveze. A i tak ho ber jako doplněk vedle databáze, ne jako hlavní úložiště.