Deprecated: Function ereg() is deprecated in /users/zalohovane/kaviarovetoasty.com/kaviarovetoasty.com/index.php on line 29

Kaviárové toasty

Fulltextové vyhledávání řazené podle relevance

Už delší dobu jsem přemýšlel o fulltextovém vyhledávání na svém blogu. Hned z počátku jsem zavrhnul variantu

SELECT * FROM tabulka WHERE sloupec
LIKE '%hledané slovo%'

Přestože to umí hledat jednoduše i varianty slova neumí to řadit podle relevance.

Nechtěl jsem stavět žádné složité vyhledávací systémy (jednak sem byl línej a připadlo mi to na moji malinkatou databázi jako jít s kulometem lovit motýli). Rozhodl jsem se proto využít schopnosti MySQL pomocí syntaxe

SELECT * FROM tabulka
WHERE MATCH (sloupec)
AGAINST ('hledaný výraz');

Toto je celkem vyhovující, vypíše to výsledky seřazené podle relevance. Problém je při hledání více slov, vrátí totiž všechno, kde je alespoň jedno slovo a nedá se to změnit. Nejde taky hledat jen části slov. Řešením by mohlo být:

SELECT * FROM tabulka
WHERE MATCH (sloupec)
AGAINST ('hledaný výraz' in boolean mode);

Díky „in boolean mode“ nyní můžeme používat booleovské operátory v MySQL.

Booleovský fulltext ale neumí řadit podle relevance.

SELECT *, MATCH (sloupec)
AGAINST ('hledaný výraz')
FROM tabulka;

Ukáže krásně čísla reprezentující relevanci jednotlivých výsledků. (0 – nenalezeno a desetinná čísla, čím větší, tím relevantnější. Při výpočtu se bere v úvahu počet slov v prohledávaném vzorku, počet unikátních slov ve vzorku, počet nalezených slov ve vzorku a počet dokumentů (řádků) obsahující hledaný výraz)

Při použití „in boolean mode“

SELECT *, MATCH (sloupec)
AGAINST ('hledaný výraz' in boolean mode)
FROM tabulka;

ukáže 0 – nenalezeno, 1 – nalezeno (nezáleží na tom kolikrát!), 2 – pokud byli hledány dvě slova a obě byly nalezeny (když najde jen jedno z požadovaných, hodnota je 1)

Po dlouhém a usilovném přemýšlení a hledání v nekonečných končinách internetu jsem dospěl k následujícímu řešení.

SELECT *,
MATCH (sloupec)
AGAINST('hledaný výraz' IN BOOLEAN MODE) AS skore1,
AGAINST('hledaný výraz') AS skore2,
FROM tabulka
HAVING skore1 > 0
ORDER BY skore1  DESC, skore2 DESC;

Vytvořím si dva imaginární sloupce, skore1 a skore2.

Skore1 obsahuje relevanci v booleovském vyhledávání.

Skore2 obsahuje relevanci v normálním (ne booleovském) vyhledávání.

Při hledání jednoho výrazu bez booleovských operátorů je skore1 u všech najitých položek 1, výsledky se tedy seřadí ještě podle skore2, které vrací správné hodnoty.

Při hledání více výrazů bez booleovských operátorů skore1 určí kolik z hledaných výrazů daný výsledek obsahuje, položky se stejným skore1 se mezi sebou (pouze mezi sebou, ne všechny) seřadí podle skore2.

Při použití booleovských operátorů je skore2 = 0, proto se výsledky řadí jen podle skore1, což způsobuje jejich menší relevanci.

Zde používám ještě trochu vylepšené řešení, které dává větší váhu (dvojnásobnou) na slova v nadpisu.

SELECT *,
MATCH (nadpis, pispevek)
AGAINST('hledaný výraz' IN BOOLEAN MODE)
AS skore1,
(
  (2*(MATCH(nadpis)AGAINST('hledaný výraz')))
   +
  (MATCH(prispevek)AGAINST('hledaný výraz'))
) AS skore2
FROM tabulka
HAVING skore1 > 0
ORDER BY skore1  DESC, skore2 DESC;

Moje řešení je použitelné jen na malých objemech dat, s velkým množstvím řádků v databázi by bylo nejspíš pomalé. Na tak malé databázi jako je zde se žádné zpomalení neprojeví, můžete vyzkoušet sami.

Pro správnou funkčnost je nutné nejprve vytvořit fulltextové indexy sloupců ve kterých budeme vyhledávat, například SQL dotazem

ALTER TABLE tabulka
ADD FULLTEXT nazev_indexu(sloupec, sloupec);

Já používám název indexu stejnej jako název sloupce.

Také to umí hledat jen slova s minimálně 4 znaky.

Rubrika:   11. března 2006, 17.04 • Přidej do Linkuj.cz

Komentáře:

[1] Acci   http://rssad.mazlo.org/ 23. dubna 2006, 12.57

Perfekt! Díky, něco takového jsem dlouhou dobu hledal. Sice používám Fulltextové vyhledávání v MySQL, ale nenapadlo mě obě metody zkombinovat

Reaguj na tento komentář

[2] peCan   http://pecan.cz 12. prosince 2006, 16.20gravatar

Třeba pomocí UNION spojíš tabulky a pak je to brnkačka:-)

Jinak fakt super návod. 10/10.

Reaguj na tento komentář

RSS komentářů k tomuto článku   RSS všech komentářů












Tohle všechno má na svědomí Béďa   ICQ: 233479341   Béďa CMS   Mapa webu   GeoURL