Fulltextové vyhľadávanie v MySQL – prax
V predchádzajúcom článku sme si vysvetlili teoretické základy používania fulltextu v MySQL. Tentoraz si ukážeme, ako takýto spôsob vyhľadávania uplatniť v praxi. No a na záver si zhodnotíme klady a zápory fulltextového vyhľadávania v MySQL.
Pýtate sa, kde využiť fulltext? Dá sa povedať, že všade, kde sú v databáze uložené rozsiahlejšie textové informácie. Určite ste sa už stretli s fulltextovým vyhľadávaním pri používaní rôznych vyhľadávačov alebo hľadaní príspevkov v diskusných fórach. A práve to bude našou hlavnou témou.
Vytvorenie databázy
Predpokladajme, že máme web podobný Intervalu. To znamená, že uverejňujeme články a chceme našim návštevníkom ponúknuť možnosť vyhľadávania. Články máme uložené v databáze a zadelené do kategórií. Najprv je potrebné takúto databázu vytvoriť. Nasledujúca časť kódu v SQL ukazuje, ako vytvoriť tabuľky.
# Vytvorenie tabuľky článkov
CREATE TABLE clanky
(
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
title varchar(255),
body text,
author varchar(100),
id_category int(11)
)
# Vytvorenie tabuľky kategórií
CREATE TABLE category
(
id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
name varchar(50)
)
V tabuľke clanky máme stĺpce id (jednoznačný identifikátor článku), title (titulok článku), body (text celého článku), author (meno autora) a id_category, ktoré nám ukazuje na meno kategórie v tabuľke category. Tabuľka category obsahuje id (jednoznačný identifikátor kategórie) a name (názov kategórie). Takéto rozdelenie údajov nám pre náš ukážkový skript bude úplne stačiť.
Skript vyhľadávania
Teraz sa pustíme do tvorby skriptu, ktorý nám zabezpečí vyhľadávanie. Nazveme ho index.php. Najprv sa musíme pripojiť k databáze. Tu myslím netreba nič vysvetľovať, nasledujúce funkcie sú notoricky známe.
<?
$db_server=“localhost“; // názov servra
$db_database=“fulltext_search“; // názov databázy
$db_login=“root“; // login do databázy
$db_password=““; // heslo do databázy
// pripojenie na databázu
$db=mysql_connect($db_server,$db_login,$db_password)
or die(„Pripojenie na server zlyhalo!“);
mysql_select_db($db_database)
or die(„Pripojenie k tabulke zlyhalo!“);
?>
Po pripojení k databáze vytvoríme v HTML formulár na vyhľadávanie. Bude pozostávať z textového poľa, v ktorom sa bude zadávať hľadaný výraz, z troch radiobuttonov na voľbu vyhľadávania (AND, OR, presne ten istý reťazec), z troch checkboxov, kde sa má vyhľadávať (v mene autora, v titulku článku a v celom článku), a z jedného selectu na určenie kategórie. Všimnite si, ako je select vytváraný. Napevno v HTML vytvárame iba položku (
) Vsetky s hodnotou 0. Ostatné položky sú generované pomocou PHP tak, že ako názov uvádzame meno kategórie (category.name) a ako hodnotu id (category.id). To nám zabezpečí jednoznačne určiť kategóriu, v ktorej vyhľadávať. <!– Vytvorenie formuláru –>
<html>
<head>
<title>Fulltext search</title>
</head>
<body>
<h1>Vyhľadávanie v databáze článkov</h1>
<form method=“post“>
Hľadaný reťazec: <input type=“text“ name=“searchtext“><br><br>
Slova spájať ako:<br>
<input type=“radio“ name=“operators“ value=“and“> AND<br>
<input type=“radio“ name=“operators“ value=“or“ checked> OR<br>
<input type=“radio“ name=“operators“ value=“quotes“> Hľadať presne taký istý reťazec<br><br>
Hľadat:<br>
<input type=“checkbox“ name=“options[1]“ value=“yes“ checked>
v mene autora<br>
<input type=“checkbox“ name=“options[2]“ value=“yes“ checked>
v titulku článku<br>
<input type=“checkbox“ name=“options[3]“ value=“yes“ checked>
v celom článku<br>
<!– Výpis kategórií –>
v kategórií:
<select name=“category“>
<option value=“0″>Všetky
<?
$result=mysql_query(„SELECT * FROM category“);
while($pole=mysql_fetch_array($result))
echo „<option value=\““.$pole[„id“].“\“> „.$pole[„name“];
?>
</select><br><br>
<input type=“submit“>
</form>
Teraz prejdeme na výpis výsledkov. Zistíme, či bol formulár odoslaný, to znamená, či je registrované superglobálne pole $_POST. Ak sa tak stalo, zistíme, v akých položkách máme vyhľadávať a na ktorých vytvoriť FULLTEXT index. Udáva nám to pole $_POST[„options“][]. Ak je tých položiek viac, musíme ich zapísať ako reťazec stĺpcov oddelených čiarkou. Ak nebola zadaná žiadna položka, vypíšeme chybu.
<? // ak už bol formulár poslany (sú registrované premenne $_POST)
if(isset($_POST[„searchtext“]))
{
// zisťujeme, ktoré checkboxy boli zaškrtnuté
if($_POST[„options“][1])
$indexes=“author“;
if($_POST[„options“][2])
$indexes.=($indexes!=““ ? „, title“ : „title“);
if($_POST[„options“][3])
$indexes.=($indexes!=““ ? „, body“ : „body“);
// ak nebol ani jeden žaškrtnutý vypíše chybu
if($indexes==““)
die(„<b>Chyba pri vyhľadávaní:<br>Nebola zvolená ani jedna voľba, v ktorej hľadať!</b>“);
Ďalej musíme vyselektovať z hľadaného výrazu operátory vyhľadávania. Takto dostaneme reťazec slov oddelených medzerou. Funkcia quotemeta(string)
pridáva pred všetky metaznaky regulárnych výrazov v reťazci string spätné lomítka. Otestujeme, či reťazec po vyselektovaní obsahuje aspoň jedno slovo dlhšie ako tri znaky. Ak nie, vypíšeme chybu. Robíme to kvôli tomu, že MySQL parser považuje za slová iba reťazce dlhšie ako tri znaky.
// vyselektovanie metaznakov z hľadaného reťazca
$_POST[„searchtext“]=ereg_replace(quotemeta(„+|-|*|~|\“|\\|<|>|(|)“),““,$_POST[„searchtext“]);
// ak nie je zadaný hľadaný reťazec, vypíše chybu
if($_POST[„searchtext“]==““)
die(„<b>Chyba pri vyhľadávaní:<br>Nebol zadaný žiaden reťazec, ktorý treba hľadať!</b>“);
else
{
// rozdelenie reťazca na slova a uloženie do poľa
$searchtext=explode(“ „,$_POST[„searchtext“]);
// premenná, do ktorej sa bude ukladať maximalna dĺžka slova
$maximum=0;
for($i=0;$i<count($searchtext);$i++)
{
$pocet=strlen($searchtext[$i]);
// ak je dĺžka slova dlhšia ako $maximum, tak sa do
// premennej $maximum uloží dĺžka tohto slova
$maximum=($maximum < $pocet ? $pocet : $maximum);
}
// ak žiadne slovo nie je dlhšie ako 3 znaky, tak vypíše chybu
if($maximum<3)
die(„<b>Chyba pri vyhľadávaní:<br>Aspoň jedno slovo v reťazci musí byť dlhšie ako 3 znaky</b>“);
}
Podľa toho, aká voľba bola zadaná vo formulári, pridáme operátory. Ak bolo zadané AND, musíme hľadaný reťazec rozdeliť na slová a pred každé pridať operátor „+“, ak bolo zadané hľadať presne taký istý reťazec, pridáme pred a za reťazec úvodzovky, no a napokon ak bolo zadané OR, nemusíme s reťazcom nič vykonávať, pretože pre OR nie je žiaden operátor.
switch($_POST[„operators“])
{
// ak sa má hľadať presne daný výraz, pridáme úvodzovky na začiatok a koniec reťazca
case „quotes“:
$_POST[„searchtext“]=“\““.$_POST[„searchtext“].“\““;
break;
// ak je zadané AND, pridáme operátor + pred každé slovo
case „and“:
// rozdelenie reťazca na slová
$words=explode(“ „,$_POST[„searchtext“]);
//pridanie pred každé slovo operátor +
for($i=0;$i<count($words);$i++)
$words[$i]=“+“.$words[$i];
//spojenie reťazca
$_POST[„searchtext“]=implode(“ „,$words);
break;
// ak je zadané OR nemusíme nič robiť
}
Vytvoríme FULLTEXT index na položkách, ktoré boli zadané vo formulári. Vytvoríme požiadavku $query
pre MySQL server, ktorá vyberie všetky záznamy, vyhovujúce podmienke hľadania. Zistíme, či bola zadaná špecifická kategória. Ak áno, pridáme požiadavke ešte podmienku WHERE
, kde špecifikujeme id kategórie, v ktorej sa má hľadať. Nakoniec doplníme požiadavku o príkaz ORDER BY
, ktorý nám zabezpečí radenie záznamov podľa score. Teraz môžeme požiadavku poslať.
// ak je všetko zadané, potom vytvoríme fulltextový index tabuľky
mysql_query(„ALTER TABLE clanky ADD FULLTEXT search („.$indexes.“)“);
// zapíšeme požiadavku pre MySQL;
$query=“SELECT *,MATCH(„.$indexes.“) AGAINST(‚“.$_POST[„searchtext“].“‚ IN BOOLEAN MODE) as score FROM clanky WHERE MATCH(„.$indexes.“) AGAINST(‚“.$_POST[„searchtext“].“‚ IN BOOLEAN MODE)“;
// ak bola vybraná špecifická kategória, tak pribudne ešte jedna podmienka v požiadavke
if($_POST[„category“]!=0)
{
$query.=“ AND id_category=“.$_POST[„category“];
// výpis, v akej kategórií vyhľadávame
$pole=mysql_fetch_array(mysql_query(„SELECT * FROM category where id=“.$_POST[„category“]));
echo „Vyhladavame v kategorii: <b>“.$pole[„name“].“</b><br>“;
}
// doplnenie požiadavky o zostupné radenie záznamov podľa score
$query.=“ ORDER BY score DESC“;
// poslanie požiadavky
$result=mysql_query($query);
Nakoniec vypíšeme počet vrátených záznamov, vypíšeme ich a zrušíme FULLTEXT index.
echo „Počet nájdených vyhovujúcich výsledkov: <b>“.mysql_num_rows($result).“</b><br>“;
// výpis výsledku
echo „<table width=\“100%\“ border=\“1\“>
<caption>Výsledky vyhľadávania</caption>
<thead>
<tr>
<th>SCORE</th>
<th>AUTOR</th>
<th>TITULOK</th>
<th>TEXT</th>
<th>KATEGÓRIA</th>
</tr>
</thead>
<tbody>“;
while($pole=mysql_fetch_array($result))
{
echo „<tr>
<td>“.$pole[„score“].“</td>
<td>“.$pole[„author“].“</td>
<td>“.$pole[„title“].“</td>
<td>“.$pole[„body“].“</td>“;
// zistenie názvu kategórie
$pole_category=mysql_fetch_array(mysql_query(„SELECT * FROM category WHERE id=“.$pole[„id_category“]));
echo „<td>“.$pole_category[„name“].“</td>
</tr>“;
}
echo „</tbody>
</table>“;
// zrušenie indexu
mysql_query(„ALTER TABLE clanky DROP INDEX search“);
}
?>
</body>
</html>
A ešte jedná dobrá rada. V našom príklade sme pomocou radiobuttonov menili podmienky vyhľadávania (AND, OR, alebo presne taký istý výraz). Ak chceme poskytnúť plnú silu fulltextového vyhľadávania v MySQL, nemali by sme filtrovať operátory vyhľadávania ale poskytnúť nápovedu, ako používať operátory a čo znamenajú (napríklad nejaké také príklady, aké som uviedol v predchádzajúcom článku). S niečím podobným sa môžete stretnúť napríklad aj u Google. Je už len na vás, pre aký štýl sa rozhodnete a čo ponúknete svojim návštevníkom.
Samozrejme, zdrojový kód príkladu, popísaného v tomto článku, si môžete stiahnuť.
Klady a zápory fulltextu v MySQL
Určite veľa z vás ocení jednoduchosť zápisu hľadaných výrazov a triedenie záznamov podľa frekvencie výskytu slov. To všetko za nás vykoná MySQL. Ale pozor! Jednou nevýhodou je to, že FULLTEXT index môže byť vytvorený iba nad stĺpcami patriacich jednej tabuľke. Keby sme v našom príklade mali mená autorov článkov uvedené v inej tabuľke a odkazovali sa na nich pomocou id, nemohli by sme index vytvoriť. No asi najväčšiu nevýhodu zistíme pri jazykoch, ktoré používajú diakritiku (smola, že k ním patrí ako čeština, tak aj slovenčina), pretože veľká časť užívateľov internetu zadáva hľadané výrazy bez diakritiky. Poviete si, veď MySQL vie pracovať s regulárnymi výrazmi, tak potom kde je problém? Ach len keby to tak bolo. Je pravda, že MySQL pozná regulárne výrazy (viď článok od Roberta Bisoma Jak na regulární výrazy v SQL), ale nie je možné ich použitie vo funkcii AGAINST()
. Keby to tak autori MySQL vyriešili, mali by sme po problémoch.
Starší komentáře ke článku
Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.
Mohlo by vás také zajímat
-
Nepodceňte UX na vašem webu: Proč na něm záleží?
10. dubna 2024 -
Optimalizace a zlepšení výkonu kódu: tipy a triky
14. srpna 2023 -
10 nejpopulárnějších programovacích jazyků a jejich využití
9. listopadu 2023 -
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024
Nejnovější
-
Jak rozšířit úložiště Macu za pětinovou cenu?
16. prosince 2024 -
Nové trendy v doménách pro osobní projekty – DIY, LIVING a LIFESTYLE
9. prosince 2024 -
Jak chránit webové stránky před Web/AI Scrapingem
27. listopadu 2024 -
Jaký monitor je nejlepší k novému Macu Mini?
25. listopadu 2024