28. září 2007

Fulltextové vyhledávání (Lucene, Compass)

V dnešní době je celkem běžný požadavek na fulltextové vyhledávání v aplikaci. Uživatel aplikace si již nechce pamatovat všechny ty možné atributy a vybírat možné hodnoty - on se prostě potřebuje dostat k cíli na základě toho co zná a už bez ohledu na vlastní uložení dat.
Pokud se někdo rozhodne zahrnout fulltextové vyhledávání do své aplikace, tak první co bude muset vyřešit je, zda použít vestavěnou podporu fulltextu v databázi či vybrat nějakou knihovnu, která bude fulltext implementovat. Pro obě volby existují určité výhody a nevýhody.
Mezi výhodami řešení pomocí knihoven se často uvádí:

  • výkonnější než databázové řešení

  • plně konfigurovatelné

  • plně pod kontrolou

  • databázové řešení lze použít pouze pro omezený doménový model, kdežto knihovna v tomto ohledu žádné omezení nemá


Mezi výhody databázového řešení patří:
  • většinou automaticky součástí databázových serverů

  • snadné a lehké použití bez nějakého velkého nastavování

  • někdy i lepší vlastnosti než řešení pomocí knihovny, např. podpora češtiny


Pro vysvětlení posledního bodu bych rád dodal některá fakta: já osobně používám knihovnu Apache Lucene (verze 2.0). K hodnocení této knihovny se dostanu dále v článku, ale co už bych chtěl uvést již zde, je horší podpora češtiny. Není problém samozřejmě ukládat český text s diakritikou a i vyhledávat s diakritikou, ale již není možné počítat s ohýbáním slov. To je možné ve většině případů řešit pomocí zástupného znaku *, ale není to úplně stoprocentní. Na druhou stranu např. Microsoft nabízí český a slovenský jazykový modul do svého SQL serveru, který tuto funkcionalitu nabízí. Žádnou osobní zkušenost s tím ale nemám.

Apache Lucene a Spring modules

Jak už jsem zmínil, tak ve svém projektu používám knihovnu Apache Lucene. Nejsem odborník přes fulltextové techniky, ale myslím si, že Lucene nabízí jedno z nejlepších (možná i nejlepší) řešení pro fulltextové vyhledávání na platformě Java. Další důvod, proč jsem toto řešení kdysi vybral bylo množství dokumentace a informací na webu a také podpora ve Spring modules, což zase posouvá práci s touto knihovnou o úroveň výše. S knihovnou Lucene resp. Spring modules jsem naprosto spokojený - co se týče nastavení datového modelu, co se týče použití (ale to hlavně díky Spring modules) a také výkonnost se ukazuje jako velice dobrý. Aplikaci teď budeme nasazovat do pilotního provozu u zákazníka, takže na závěrečné zhodnocení je ještě čas.

Compass

Apache Lucene a Spring modules bude znát asi většina lidí, ale již méně je známý Compass - Java Search Engine Framework. Já osobně jsem si této knihovny všimnul na konferenci Spring One a dokonce jsem našel ke stažení vlastní prezentaci.
Nemám s tímto frameworkem zatím žádnou osobní zkušenost, ale některé klíčové vlastnosti jsou velice zajímavé:
  • Framework je postaven nad Apache Lucene. Compass lze používat nejen jako nástavbu nad Lucene, která řeší některé jeho nedostatky jako např. chybějící podpora transakcí, příliš nízkoúrovňové API, nepříliš rychlá aktualizace indexů a možnost ukládání indexů pouze na souborový systém (pozn. nízkoúrovňové API a ukládání indexů řeší již Spring modules).

  • Integrace se Springem a Hibernate

  • Compass umožňuje si stávající datový model (nebo jeho část) napamovat pro účely fulltextového vyhledávání. K tomuto je možné použít konfiguraci pomocí XML nebo anotací.

  • Změna datového modelu se může automaticky promítat v indexech.


Pokud někdo máte zkušenost s jazykovým modulem do MS SQL nebo jiných databází či přímo s Compassem, budu jedině rád, když se podělíte o vaši zkušenost.

10 komentářů:

Anonymní řekl(a)...

Já osobně mám zkušenost s Lucene jen dobrou. Na nějaké sklonování v češtině ale komerčně zapomeňte -- dostat se ke kvalitním korpusům je možné jen na akademické půdě. Lze to ale řešit i jinak -- já třeba použil metodu "odsekávání přípon", která sice zhorší sémantiku slov (semi-kořenů), ale výsledků je víc a v praxi to funguje dobře.

Petr Jůza řekl(a)...

Tak to mě teď o to více zajímá zkušenost s tím modulem od MS, protože dle stránek MS by vše mělo chodit (ale to oni vlastně píšou vždycky :) ).

Jan Novotný řekl(a)...

Taky používáme Lucene - nedáme na něj dopustit. Češtinu řešíme tak, že veškeré texty určené pro indexování zbavíme diakritiky a výsledek je uspokojující.

Co mám zkušenosti s fulltextovým vyhledáváním na úrovni db, tak všude jsem vždycky narazil na problémy s výkonností (Informix, MySQL a myslím, že i Oracle). Lucene naprosto skvěle škáluje a i při milionech záznamů a gigabajtech indexovaných dat máte výsledky ve zlomku vteřiny.

Na informixu například, jsme dosahovali časů kolem 10 - 15 vteřin a níž jsme se prostě nemohli dostat ať jsme dělali, co jsme dělali (a to nemluvím o zatížení db serveru). A jestli si dobře vzpomínám, problémy s češtinou tam byly taky :).

Lukáš Vlček řekl(a)...

Co se týká knihovny Compass, tak ji mohu jedině doporučit. Zkušenost s ní mám velmi dobrou. Používáme ji ve spojení Spring - JPA (Hibernate) - Oracle. Výhodou oproti internímu DB řešení vidím především v tom, že lze do indexování snadno zahrnout i ta doménová data, která nejsou uložena v databázi (např. soubory z CVS), navíc nabízí vše, co nabízí Lucene (nevím jak vaše MS databáze, ale oracle před nějakou dobou neměl moc dobře vyřešeno vracení fragmentů textu s vyznačenými slovy, které byly v uživatelově dotazu). Navíc není velký problém do zdrojáků Compassu něco dopsat. Shay Banon má na vše důsledně napsané testy a rád udělá revizi tvého kódu, pokud se rozhodneš pro nějakou kontribuci (tví kolegové na to s největší pravděpodobností nebudou mít ani čas ani takovou motivaci jako on).

S čím jsem měl potíže je mapování objektů do indexu. Pokud persistuješ data do DB a chceš je i prohledávat, tak je třeba být velmi opatrný při návrhu mapování do databáze. Především je třeba dbát na to, aby prvky kompozitních objektů měly vždy vazbu na předka (tedy udělat mapování do DB tak, aby prvek obsahoval ID svého rodiče, pakliže tento prvek je do indexu mapovaný jako @Searchable(root = false)), jinak nebude snadné zajistit jejich přeindexování při změně v databázi. To ale není asi specifický problém Compassu, jedná se spíše o obecný problém.

Unknown řekl(a)...

zdravim,

mam otazocku k vyhladavacu lucene.
Rozmyslame u nas vo firme nasadit lucene, nie sme si vsak isti, ci dokaze lucene pracovat s dynamickymi datami. Mame totiz velke tabulky radovo 100tis az milionmi zaznamov, ktore su dynamicke t.j. menia sa dost casto, napr. take vyhladanie poloziek v objednavkach

Ako sa vie lucene s tymto vyrovnat?

Zatial sme sa hrali len so statickymi datami, ale regenrovanie indexu nam robi trosku vrasky na cele.

//milan

Petr Jůza řekl(a)...

Já zatím bohužel nemůžu dát nějakou zkušenost, protože aplikace se teprve bude nasazovat, ale také počítáme s dynamickými daty v řádu statisíců až miliónů záznamů.
Reindexaci změněných záznamů řešíme pomocí scheduleru, který se automaticky spouští v určitou dobu a provádí reindexaci. Nebojíme se toho, že by si s tím Lucene snad neporadil...

Lukáš Vlček řekl(a)...

Lucene přece automatické přeindexování neřeší! Umí pouze smazat nějaký dokument (označit za smazaný, k fyzickému výmazu dojde třeba později při optimizaci indexu) a jinak umí dokumenty pouze přidávat (takže update dokumentu znamená výmaz a nové zaindexování).

Co se týká výkonosti Compassu, tak důležité bude, jak uděláte mapování. Při vyhledávání se totiž typicky pracuje s jednotlivými dokumenty (pro určité slovo [term] získáte seznam dokumentů, ve kterých je obsaženo). To znamená, že je třeba provést mapování hierarchií doménovývh objektů (stromových struktur) do "jednorozměrného" dokumentu. Toto mapování nemusí být jednoduché a má velký vliv na dvě zásadní věci:
1) rychlost indexování
2) automatické přeindexování objektů, pokud se změní některé z jeho (pod)součástí. Viz můj předchozí comment.

Myslim, že Lucene by neměl mít problem při zpracování několika miliónů objektů. Fyzický limit Lucene je popsán zde: http://lucene.apache.org/java/docs/fileformats.html (viz konec dokumentu). Compass si interně data ukládá do nezávislých indexů, takže tam je teoreticky limit posunut ještě mnohem dál (podle toho, jak je uděláno mapování - http://www.opensymphony.com/compass/versions/1.2RC1/html/core-searchengine.html#core-searchengine-subindexhash).

Co se mi na Compassu líbí je to, že automatické přeindexování a optimalizace indexů se děje na pozadí a skutečný index je nahrazen novým, jakmile jsou nová data k dispozici. Compass nabízí několik build-in algoritmů, které lze konfigurovat: http://www.opensymphony.com/compass/versions/1.2RC1/html/core-searchengine.html#core-searchengine-optimizers
Pokud potřebuje nějaký jiný, určitě nebude problém ho dopsat.

Petr Jůza řekl(a)...

Ano, Lucene automatické přeindexování neřeší, musí se to řešit vlastním algoritmem. Pro vrácený seznam změněných dat kontrolujeme, zda již data nejsou v indexu - pokud jsou, tak se index nejdříve smaže před vlastním přidáním. Po těchto změnách se provede optimalizace indexů.

Petr Jůza řekl(a)...

Zajímavá polemika na téma, zda je Lucene dobrý.

jumar řekl(a)...

Môže mi, prosím, niekto poradiť, kde si môžem stiahnuť český a slovenský jazykový modul pre MSSQL?
Vyššie uvedený odkaz nefunguje a vygoogliť sa mi ho nepodarilo.