Tutorials

Fulltext Index in MySQL

Database optimalisatie met een full-text index voor het zoeken in teksten

Pagina 1

Inleiding

In een eerdere tutorial over het gebruik van indexen in MySQL heb ik een laatste beschikbare index nog niet besproken. Deze index, de FULLTEXT index, zal dan ook het onderwerp zijn van deze tutorial.

Tegenwoordig wordt er bij de ontwikkeling van de meeste website wel gebruik gemaakt van een database om gegevens in op te slaan. Teksten van webpaginas, blogs of berichten in een forum of gastenboek, de database wordt gebruikt om al dit soort gegevens in op te slaan.

In het begin is dit allemaal geen probleem, maar wat nu als de site begint te groeien? Op een gegeven moment zul je misschien een interne zoekfunctie nodig hebben zodat bezoekers snel relevante artikelen, topics of paginas kunnen vinden. Dit is het punt waar de FULLTEXT index van MySQL van pas komt om het database gebruik te optimaliseren.

In deze tutorial zal ik aan de hand van voorbeelden van verschillende situaties laten zien wat de grote kracht is van een full-text zoekopdracht t.o.v andere zoekopdrachten. Ik zal verder ook ingaan op de werking van de full-text index en hoe deze gebruikt kan worden om queries te optimaliseren.

Benodigde voorkennis
[li]Basiskennis SQL[/li]
Pagina 2

Zoeken in een MySQL database

Voordat ik de full-text index introduceer in deze tutorial, zal ik eerst een overzicht geven van de meest gebruikelijke methode om te zoeken naar records in een tabel. Laten we eerst eens kijken naar de brongegevens die ik in alle voorbeelden in deze tutorial zal gebruiken.

Gebruikte brongegevens
Om het voorbeeld eenvoudig te houden gebruiken we een tabel waarin we artikelen van een weblog opslaan. De tabel bestaat in eerste instantie uit drie kolommen waarbij enkel een Primary Key index aangemaakt is:

artikelen
---------
id     (INT)
titel  (VARCHAR)
inhoud (TEXT)

Aangezien de full-text functionaliteit voor alsnog alleen beschikbaar is met de MyISAM storage engine van MySQL, gebruiken we een tabel van dat type.

De inhoud van de tabel ziet er als volgt uit:

+----+-------------------------------------+------------------------------------------+
| id | titel                               | inhoud                                   |
+----+-------------------------------------+------------------------------------------+
|  1 | MySQL Tutorial                      | DBMS staat voor DataBase ...             |
|  2 | MySQL op een goede manier gebruiken | Nadat je de volgende stappen ...         |
|  3 | MySQL Optimaliseren                 | In deze tutorial zal ik laten zien ...   |
|  4 | 1001 MySQL tips                     | 1. Start MySQL nooit als root 2. ...     |
|  5 | MySQL vs. YourSQL                   | In de volgende database vergelijking ... |
|  6 | MySQL veiligheid                    | Als je MySQL goed geinstalleerd hebt ... |
+----+-------------------------------------+------------------------------------------+

Zoeken in een tabel met LIKE
De meest gebruikte manier om records in een tabel te zoeken aan de hand van een door de gebruiker ingevulde zoekterm. Zo'n query zal er dan als volgt uitzien:
<?php
$sql = "SELECT * FROM artikelen WHERE inhoud LIKE '%".$zoekwoord."%'";
?>
Als de gebruiker als zoekwoord 'database' zou invullen, zou de query er als volgt uitzien:

SELECT * FROM artikelen WHERE inhoud LIKE '%database%'

En het resultaat van deze query ziet er dan zo uit:

+----+-------------------+------------------------------------------+
| id | titel             | inhoud                                   |
+----+-------------------+------------------------------------------+
|  1 | MySQL Tutorial    | DBMS staat voor DataBase ...             |
|  5 | MySQL vs. YourSQL | In de volgende database vergelijking ... |
+----+-------------------+------------------------------------------+

Waarschijnlijk heb je al eerder gebruik gemaakt van LIKE in je queries, dus dit zal je vrij bekend voorkomen. Hoewel dit een eenvoudige manier is om te zoeken naar records in een tabel levert deze zeker niet altijd de gewenste resultaten. Bovendien zorgen deze queries met LIKE voor een zeker performance verlies zodra de database groter wordt of als je meerdere tabellen in je queries gaat gebruiken.

Als we naar de EXPLAIN van deze query kijken zien we namelijk dat er geen gebruik gemaakt wordt van indexen:

+----+-------------+-----------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table     | type | possible_keys | key  | key_len | ref  | rows | Extra       |
+----+-------------+-----------+------+---------------+------+---------+------+------+-------------+
|  1 | SIMPLE      | artikelen | ALL  | NULL          | NULL | NULL    | NULL |    6 | Using where |
+----+-------------+-----------+------+---------------+------+---------+------+------+-------------+

De genoemde performance problemen kun je voorkomen door gebruik te maken van de full-text index van MySQL. Op de volgende pagina zal ik ingaan op de werking van deze index.
Pagina 3

Werking van de FULLTEXT index

Een full-text index is een index net als alle andere. Het is vergelijkbaar met bijvoorbeeld de index achter in een boek en biedt de database zo de mogelijkheid om gegevens sneller op te zoeken. Het grote voordeel van een index is namelijk dat niet de hele tabel doorzocht hoeft te worden op zoek naar een bepaald woord of combinatie van woorden.

De werking van een FULLTEXT index
Zoals al eerder gezegd wordt een full-text index dus gebruikt om kolommen waarin stukken tekst opgeslagen zijn te indexeren. Om die reden is een full-text index dus enkel aan te brengen op kolommen van het type CHAR, VARCHAR of TEXT.

Het indexeren van de gegevens verloopt anders dan bij andere indexen. In plaats van het indexeren van de hele waarde uit een veld, worden bij een full-text index alle woorden uit een tekst apart geindexeerd. Als voorwaarde voor het indexeren van een woord wordt een minimale lengte van 4 tekens gehanteerd.

Als er nu een full-text zoekopdracht uitgevoerd wordt, wordt deze index gebruikt om te kijken of er overeenkomende woorden te vinden zijn en zo ja, in welk record deze woorden dan te vinden zijn. Deze manier van zoeken voorkomt dus dat elk record uit de hele tabel doorzocht moet worden en levert een grote snelheidswinst op.

Een tweede reden waarom snelheidswinst geboekt kan worden is het feit dat enkel woorden van 4 tekens of langer geindexeerd worden. In een full-text zoekopdracht worden woorden van 3 of minder tekens dan ook genegeerd en wordt het proces zo versneld.

Het aanbrengen van een full-text index
Zoals ik hierboven al vermelde is een full-text enkel aan te brengen op een CHAR, VARCHAR of TEXT kolom in een tabel met de MyISAM storage engine. De volgende query gebruik je om een FULLTEXT index aan te brengen op de 'inhoud' kolom:

ALTER TABLE artikelen ADD FULLTEXT (inhoud)

Omdat we straks ook in de titel willen zoeken, brengen we ook een full-text index aan op de titel kolom. Het is daarnaast ook mogelijk om een full-text index op meerdere kolommen aan te brengen.

ALTER TABEL artikelen ADD FULLTEXT (titel, inhoud)

Let er in dit geval wel op dat MySQL gebruik maakt van left-most prefixing en je deze index dus niet kunt gebruiken voor een zoekopdracht op enkel de 'inhoud' kolom. Kijk voor meer informatie hierover in mijn tutorial over MySQL Indexes.

Via phpMyAdmin kun je een full-text index op een kolom aanbrengen door op het knopje achter de betreffende kolom te klikken.

Zoeken met behulp van de FULLTEXT index
Om de full-text index te gebruiken bij het zoeken in de database maken we gebruik van een aparte syntax die er als volgt uit ziet:

SELECT kolom 
FROM tabel 
WHERE MATCH(kolom) AGAINST('zoekwoord')

Deze query doorzoekt de full-text index van de kolom genoemd in MATCH() naar het voorkomen van het zoekwoord gegeven in AGAINST().

Laten we eens zien wat voor resultaten we krijgen als we de LIKE query van de vorige pagina omschrijven naar een full-text zoekopdracht.

SELECT *
FROM artikelen
WHERE MATCH(inhoud) AGAINST('database')

Dit geeft het volgende resultaat:

+----+-------------------+------------------------------------------+
| id | titel             | inhoud                                   |
+----+-------------------+------------------------------------------+
|  5 | MySQL vs. YourSQL | In de volgende database vergelijking ... |
|  1 | MySQL Tutorial    | DBMS staat voor DataBase ...             |
+----+-------------------+------------------------------------------+

Precies hetzelfde resultaat als bij de query met LIKE dus. Als we echter kijken naar de EXPLAIN van deze query zien we dat er inderdaad gebruik is gemaakt van de index:

+----+-------------+-----------+----------+---------------+--------+---------+------+------+-------------+
| id | select_type | table     | type     | possible_keys | key    | key_len | ref  | rows | Extra       |
+----+-------------+-----------+----------+---------------+--------+---------+------+------+-------------+
|  1 | SIMPLE      | artikelen | fulltext | inhoud        | inhoud | 0       |      |    1 | Using where |
+----+-------------+-----------+----------+---------------+--------+---------+------+------+-------------+


Eigenschappen van een full-text zoekopdracht
Full-text indexen worden over het algemeen gebruikt om grotere stukken tekst, zoals bijvoorbeeld kranten artikelen of content van webpaginas. Om dit soort zoekopdrachten te optimaliseren heeft de full-text functionaliteit van MySQL een aantal belangrijke eigenschappen:

[li]Gedeeltelijke woorden worden uitgesloten van de zoekopdracht.[/li]
[li]Woorden van 3 tekens of korter worden uitgesloten van de zoekopdracht.[/li]
[li]Woorden die in meer dan de helft van alle rijen in een tabel voorkomen, worden uitgesloten.[/li]
[li]Woorden met daarin een - worden behandeld als 2 aparte woorden.[/li]
[li]Rijen worden gesorteerd op relevantie. Hoe vaker een zoekwoord voorkomt, hoe hoger de relevantie.[/li]
[li]Woorden in de lijst met stopwoorden, zijn uitgesloten van een zoekopdracht.[/li]
[li]Full-text zoekopdrachten zijn standaard niet hoofdletter gevoelig.[/li]

Een aantal van deze eigenschappen heb ik al eerder genoemd, enkele echter nog niet. Dat woorden die in meer dan 50% van de rijen in een tabel voorkomen genegeerd worden tijdens een full-text zoekopdracht heeft te maken met het feit dat je die records dan waarschijnlijk helemaal niet wilt zien. Als de meeste records in de database 'MySQL' bevatten en je enkel geinteresseerd bent in 'MySQL veiligheid' wil je al die andere records met 'MySQL' erin waarschijnlijk niet zien.

Het voorbeeld is te zien in deze query:

SELECT *
FROM artikelen
WHERE MATCH(titel) AGAINST('MySQL')

Deze geeft namelijk een lege resultaat-set terug.

Resultaten van een full-text zoekopdracht worden automatisch gesorteerd op aflopende relevantie. Hoe deze relevantie precies bepaald wordt en wat je ermee kunt doen, zal ik later in deze tutorial bespreken.

Tenslotte is er nog de lijst met stopwoorden die uitgesloten worden van een full-text zoekopdracht. Deze lijst is gebasseerd op de Engelse taal en zal dus niet veel invloed hebben op Nederlandse teksten. Voor de volledigheid is de lijst hier te vinden.

FULLTEXT index op meerdere kolommen
Zoals ik eerder al vertelde is het ook mogelijk om een full-text index aan te brengen op meerdere kolommen. De inhoud van deze kolommen zal dan geindexeerd worden in dezelfde index en kan dus gebruikt worden om in beide kolommen tegelijk te zoeken.

Stel dat we een index (titel, inhoud) hebben, dan zouden we met de volgende query van die index gebruik kunnen maken:

SELECT *
FROM artikelen
WHERE MATCH(titel, inhoud) AGAINST('tutorial')

Het resultaat van deze query is als volgt:

+----+---------------------+----------------------------------------+
| id | titel               | inhoud                                 |
+----+---------------------+----------------------------------------+
|  1 | MySQL Tutorial      | DBMS staat voor DataBase ...           |
|  3 | MySQL Optimaliseren | In deze tutorial zal ik laten zien ... |
+----+---------------------+----------------------------------------+

We zien dat er nu zowel in de titel als in de inhoud gezocht wordt naar het trefwoord 'tutorial'. Ook laat het resultaat van EXPLAIN ons zien dat inderdaad de index (titel, inhoud) gebruikt wordt.
Pagina 4

Relevantie bij een FULLTEXT zoekopdracht.

Nu we weten hoe de full-text index op een kolom werkt en op welke manier we deze index kunnen gebruiken, is het tijd om eens wat dieper in te gaan op full-text zoekopdrachten.

Een groot voorbeeld van dit soort zoekopdrachten is namelijk dat de resultaten gesorteerd worden op relevantie. In tegenstelling tot queries met LIKE waarbij gewoon alle resultaten teruggegeven worden, krijg je nu de rijen in volgorde van relevantie terug. Hoe vaker het zoekwoord in een rij voorkomt, hoe hoger de relevantie van die rij.

De relevatie is een niet-negatieve waarde die van de volgende factoren afhankelijk is:
[li]Het aantal woorden in de gevonden rij[/li]
[li]Het aantal unieke woorden in die rij[/li]
[li]Het totaal aantal woorden in alle gevonden rijen[/li]
[li]Het aantal rijen dat een bepaald woord bevat[/li]
Voor het bepalen van de zoekscore wordt elk woord gewaardeerd aan de hand van zijn significatien in de tabel en de query. Een woord dat vaak voorkomt in een tabel heeft een lager gewicht dan een wordt dat maar enkele keren voorkomt. Deze gewichten worden vervolgens gecombineerd om de relevantie van een rij te bepalen.

Weergeven van de relevantie
Hoewel deze zoekscores eigenlijk helemaal geen nuttige waarde hebben en enkel gebruikt worden om de resultaten op relevantie te sorteren, is het soms leuk om deze waarden toch eens weer te geven.

Laten we eens kijken wat een full-text zoekopdracht op de inhoud naar het trefwoord 'database' voor zoekscores oplevert:

SELECT 
    id,
    MATCH(inhoud) AGAINST('database') AS score
FROM 
    artikelen

Het resultaat van deze query is als volgt:

+----+------------------+
| id | score            |
+----+------------------+
|  1 | 0.66266459031789 |
|  2 |                0 |
|  3 |                0 |
|  4 |                0 |
|  5 | 0.67003110026735 |
|  6 |                0 |
+----+------------------+

We zien dat blijkbaar alleen de rijen met id 1 en 5 een resultaat opleveren bij deze zoekopdracht. Dat is ook duidelijk te zien als we de WHERE clausule toevoegen:

SELECT 
    *,
    MATCH(inhoud) AGAINST('database') AS score
FROM 
    artikelen
WHERE
    MATCH(inhoud) AGAINST('database')

Het resultaat is dan als volgt:

+----+-------------------+------------------------------------------+------------------+
| id | titel             | inhoud                                   | score            |
+----+-------------------+------------------------------------------+------------------+
|  5 | MySQL vs. YourSQL | In de volgende database vergelijking ... | 0.67003110026735 |
|  1 | MySQL Tutorial    | DBMS staat voor DataBase ...             | 0.66266459031789 |
+----+-------------------+------------------------------------------+------------------+

Zoals je ziet wordt het gevonden resultaat met de hoogste relevantie als eerste getoond. Daarna volgt de rest van de resultaten op aflopende relevantie.

We zien dat de resultaten met een relevantie van 0 niet weergegeven worden zodra je de WHERE clausule in de query opneemt. Een relevatien van 0 betekent dat er geen overeenkomsten zijn gevonden en dus worden deze rijen niet opgenomen in het resultaat van de zoekopdracht.

Het twee keer toepassen van de MATCH(...) AGAINST(...) combinatie in de query veroorzaakt geen extra overhead. De MySQL optimizer herkent namelijk dat deze twee bewerkingen identiek zijn en zal de full-text zoekopdracht daarom maar een keer uitvoeren.

Een string als zoekopdracht
Met de full-text zoekfunctie is het ook mogelijk om een string al zoekopdracht op te geven. Laten we eens kijken naar de volgende query:

SELECT *
FROM artikelen
WHERE MATCH(inhoud) AGAINST('start mysql nooit')

Het resultaat van deze query is het volgende:

+----+------------------+------------------------------------------+
| id | titel            | inhoud                                   |
+----+------------------+------------------------------------------+
|  4 | 1001 MySQL tips  | 1. Start MySQL nooit als root 2. ...     |
|  6 | MySQL veiligheid | Als je MySQL goed geinstalleerd hebt ... |
+----+------------------+------------------------------------------+

Misschien is dit niet helemaal wat je zou verwachten, aangezien je gezocht hebt naar 'start mysql nooit' en die string helemaal niet voorkomt in het tweede record.

Dit heeft echter te maken met de manier waarop MySQL full-text zoekopdrachten uitvoert. MySQL behandeld elke combinatie van tekens die een woord kunnen voorkomen (letters, cijfers en underscores) als een woord. Elk woord wordt apart opgezocht in de index en vervolgens wordt de zoekscore bepaald. Vervolgens wordt met behulp van al deze zoekscores de relevantie van een rij bepaald.

Dit heeft dus als gevolg dat ook rijen weergegeven worden waarin maar 1 woord uit de zoekopdracht in voorkomt. En dit is precies het punt waarom zoekresultaten gesorteerd worden op relevantie. Deze waarde zal namelijk voor het eerste record vele malen hoger zijn, dan voor het tweede gevonden record. Dat blijkt ook als we die relevantie tonen:

+----+------------------+------------------------------------------+------------------+
| id | titel            | inhoud                                   | score            |
+----+------------------+------------------------------------------+------------------+
|  4 | 1001 MySQL tips  | 1. Start MySQL nooit als root 2. ...     |  3.7399836498101 |
|  6 | MySQL veiligheid | Als je MySQL goed geinstalleerd hebt ... | 0.66266459031789 |
+----+------------------+------------------------------------------+------------------+

MySQL bepaalt waar woorden beginnen en eindigen door te zoeken naar bepaalde tekens, zoals spaties, kommas en punten. Een apostrof in een zoekopdracht is ook geen probleem, zodra het er maar niet meer worden. Een woord als data'base wordt beschouwt als 1 woord, terwijl data''base als 2 woorden beschouwd wordt. Een apostrof aan het begin of eind van een woord, wordt tijdens een full-text zoekopdracht genegeerd: 'data'base' wordt dus geinterpreteerd als data'base.
Pagina 5

Boolean FULLTEXT zoekopdrachten

Eerder in deze tutorial hebben we gezien hoe we een full-text zoekopdracht kunnen uitvoeren, wat relevantie is en hoe dat principe gebruikt wordt bij full-text zoekopdrachten. Nu is het tijd om wat dieper in te gaan op de zoekopdrachten zelf.

We hebben al enkele voorbeelden gezien van full-text zoekopdrachten waarin we hebben gezocht naar een bepaald woord of naar een gedeelte van een zin. Uit die voorbeelden is gebleken dat MySQL elk woord uit de zoekopdracht apart beoordeeld en uiteindelijk een bepaalde relevantie aan een rij koppelt. Afhankelijk van die relevantie wordt een resultaat wel of niet weergegeven.

Boolean full-text zoekopdrachten
Alle zoekopdrachten die we tot nu toe gezien hebben waren heel algemeen. Echter kunnen we met behulp van de IN BOOLEAN MODE modifier onze zoekopdrachten verder specificeren. Zo kunnen we bijvoorbeeld bepalen welke zoekwoorden wel of niet in het resultaat voor mogen komen en kunnen we bepalen welke gevonden woorden belangrijker zijn dan andere.

Laten we beginnen met een voorbeeld waarin we op zoek gaan naar titels waarin wel 'MySQL' voorkomt maar geen 'YourSQL':

SELECT *
FROM artikelen
WHERE MATCH (titel)
AGAINST ('+MySQL -YourSQL' IN BOOLEAN MODE)

Deze query levert het volgende resultaat:

+----+-------------------------------------+------------------------------------------+
| id | titel                               | inhoud                                   |
+----+-------------------------------------+------------------------------------------+
|  1 | MySQL Tutorial                      | DBMS staat voor DataBase ...             |
|  2 | MySQL op een goede manier gebruiken | Nadat je de volgende stappen ...         |
|  3 | MySQL Optimaliseren                 | In deze tutorial zal ik laten zien ...   |
|  4 | 1001 MySQL tips                     | 1. Start MySQL nooit als root 2. ...     |
|  6 | MySQL veiligheid                    | Als je MySQL goed geinstalleerd hebt ... |
+----+-------------------------------------+------------------------------------------+

Zoals we zien ontbreekt de rij met de titel 'MySQL vs. YourSQL' uit de resultaat-set. We hebben immers aangegeven geen resultaten te willen zien waarin 'YourSQL' voorkomt.

Eigenschappen van boolean full-text zoekopdrachten
De boolean full-text zoekopdrachten hebben andere eigenschappen dan normale full-text zoekopdrachten. Deze eigenschappen zijn de volgende:
[li]De 50% grens wordt niet gebruikt.[/li]
[li]De resultaten worden niet automatisch gesorteerd op relevantie.[/li]
[li]Deze zoekopdrachten werken ook als er geen FULLTEXT index bestaat. Ze zijn dan wel vrij traag.[/li]
[li]De minimale woordlengte van 4 tekens wordt gehanteerd.[/li]
[li]Woorden uit de stopwoordenlijst worden genegeerd.[/li]

Operators
Er zijn verschillende operators die je kunt gebruiken in een boolean full-text zoekopdracht. Met deze operators kun je je zoekopdracht op allerlei wijzen specificeren:
[li]+ Het woord moet aanwezig zijn in elke gevonden rij.[/li]
[li]- Het woord mag niet voorkomen in een gevonden resultaat.[/li]
[li]> Het volgende woord krijgt een hogere zoekscore als het gevonden wordt.[/li]
[li]< Het volgende woord krijgt een lagere zoekscore als het gevonden wordt.[/li]
[li]() Groeperen woorden in een subexpressie.[/li]
[li]~ Het volgende woord krijgt een negatieve zoekscore en draagt dus negatief bij aan de relevantie.[/li]
[li]" Een zinsdeel tussen dubbel quotes moet letterlijk in het resultaat voorkomen.[/li]
[li]* Fungeert als wildcard. Een resultaat wordt gevonden als een woord begint met het woord voorafgaand aan deze operator.[/li]

Voorbeelden
Veel meer valt er eigenlijk niet uit te leggen over de boolean full-text zoekfunctie. Om verder te verduidelijke hoe deze zoekfunctie werkt zal ik een aantal voorbeelden geven.

Ik zal in deze voorbeelden verder alleen de WHERE clausule van de queries tonen, de rest van de query blijft toch telkens hetzelfde. Van elk voorbeeld zal ik ook het resultaat tonen die de query terug geeft.

Voorbeeld 1: geen operators

MATCH (inhoud)
AGAINST ('mysql root' IN BOOLEAN MODE)

Deze query vindt rijen die op z'n minst een van beide woorden bevatten:

+----+------------------+------------------------------------------+
| id | titel            | inhoud                                   |
+----+------------------+------------------------------------------+
|  4 | 1001 MySQL tips  | 1. Start MySQL nooit als root 2. ...     |
|  6 | MySQL veiligheid | Als je MySQL goed geinstalleerd hebt ... |
+----+------------------+------------------------------------------+

Voorbeeld 2: +mysql +root

MATCH (inhoud)
AGAINST ('+mysql +root' IN BOOLEAN MODE)

Deze query vindt rijen waarin beide woorden voorkomen.

+----+-----------------+--------------------------------------+
| id | titel           | inhoud                               |
+----+-----------------+--------------------------------------+
|  4 | 1001 MySQL tips | 1. Start MySQL nooit als root 2. ... |
+----+-----------------+--------------------------------------+

Voorbeeld 3: +mysql root

MATCH (inhoud)
AGAINST ('+mysql root' IN BOOLEAN MODE)

Deze query vindt alle rijen waarin 'mysql' voorkomt. Rijen met daarnaast ook 'root' krijgen een hogere relevantie:

+----+------------------+------------------------------------------+-----------------+
| id | titel            | inhoud                                   | score           |
+----+------------------+------------------------------------------+-----------------+
|  4 | 1001 MySQL tips  | 1. Start MySQL nooit als root 2. ...     | 1.3333333730698 |
|  6 | MySQL veiligheid | Als je MySQL goed geinstalleerd hebt ... |               1 |
+----+------------------+------------------------------------------+-----------------+

Voorbeeld 4: +mysql -root

MATCH (inhoud)
AGAINST ('+mysql -root' IN BOOLEAN MODE)

Vindt alle rijen met 'mysql' maar zonder 'root':

+----+------------------+------------------------------------------+
| id | titel            | inhoud                                   |
+----+------------------+------------------------------------------+
|  6 | MySQL veiligheid | Als je MySQL goed geinstalleerd hebt ... |
+----+------------------+------------------------------------------+

Voorbeeld 5: +mysql ~root

MATCH (inhoud)
AGAINST ('+mysql ~root' IN BOOLEAN MODE)

Vindt alle rijen met 'mysql'. Rijen waarin ook 'root' voorkomt worden lager gewaardeerd:

+----+------------------+------------------------------------------+------------------+
| id | titel            | inhoud                                   | score            |
+----+------------------+------------------------------------------+------------------+
|  4 | 1001 MySQL tips  | 1. Start MySQL nooit als root 2. ...     | 0.83333331346512 |
|  6 | MySQL veiligheid | Als je MySQL goed geinstalleerd hebt ... |                1 |
+----+------------------+------------------------------------------+------------------+

Voorbeeld 6: +mysql +(>goed <nooit)

MATCH (inhoud)
AGAINST ('+mysql +(>goed <nooit)' IN BOOLEAN MODE)

Vindt alle rijen met 'mysql' en ofwel 'goed' of 'nooit'. Rijen met 'goed' worden hoger gewaardeerd en rijen met 'nooit' lager:

+----+------------------+------------------------------------------+------------------+
| id | titel            | inhoud                                   | score            |
+----+------------------+------------------------------------------+------------------+
|  4 | 1001 MySQL tips  | 1. Start MySQL nooit als root 2. ...     | 0.83333337306976 |
|  6 | MySQL veiligheid | Als je MySQL goed geinstalleerd hebt ... |             1.25 |
+----+------------------+------------------------------------------+------------------+

Voorbeeld 7: data*

MATCH (inhoud)
AGAINST ('data*' IN BOOLEAN MODE)

Vindt alle rijen met woorden die beginnen met 'data':

+----+-------------------+------------------------------------------+
| id | titel             | inhoud                                   |
+----+-------------------+------------------------------------------+
|  1 | MySQL Tutorial    | DBMS staat voor DataBase ...             |
|  5 | MySQL vs. YourSQL | In de volgende database vergelijking ... |
+----+-------------------+------------------------------------------+

Voorbeeld 8: "staat voor database"

MATCH (inhoud)
AGAINST ('"staat voor database"' IN BOOLEAN MODE)

Vindt alle rijen waarin letterlijk 'staat voor database' voorkomt:

+----+----------------+------------------------------+
| id | titel          | inhoud                       |
+----+----------------+------------------------------+
|  1 | MySQL Tutorial | DBMS staat voor DataBase ... |
+----+----------------+------------------------------+
Pagina 6

FULLTEXT Query Expansion

Een laatste onderwerp dat ik in deze tutorial wil bespreken zijn full-text zoekopdrachten die gebruik maken van Query Expansion (vertaald: query uitbreiding).

Deze methode is over het algemeen handig als een zoekstring te kort is doordat de gebruiker niet precies weet waar hij op moet zoeken (bijv. de 'Ik doe een gok' optie van Google). Stel dat een gebruiker bijvoorbeeld zoekt op 'database' kan hij best wel eens 'MySQL', 'PostgreSQL' of 'Oracle' bedoelen. In dat geval zouden artikelen waarin deze trefwoorden voorkomen ook als gevonden resultaat terug gegeven moeten worden.

Door de WITH QUERY EXPANSION modifier aan de zoekopdracht mee te geven, kunnen we dit waarschijnlijk deels voor elkaar krijgen. Dit principe werkt namelijk door de zoekopdracht twee keer uit te voeren waarbij de zoekstring voor de tweede opdracht uitgebreid wordt met woorden uit de meest relevante resultaten uit de eerste opdracht.

Stel dus dat we zoeken naar 'database' en in de gevonden resultaten komt 'MySQL' veelvuldig voor. De tweede zoekopdracht zal dan ook rijen vinden waarin 'MySQL' voorkomt ook al bevatten deze rijen het woord 'database' niet.

Ik zal dit hele verhaal maar eens verduidelijken met een tweetal voorbeelden. Allereerst maar eens een normale zoekopdracht:

SELECT *
FROM artikelen
WHERE MATCH(inhoud) AGAINST('database')

Het resultaat van deze query:

+----+-------------------+------------------------------------------+
| id | titel             | inhoud                                   |
+----+-------------------+------------------------------------------+
|  5 | MySQL vs. YourSQL | In de volgende database vergelijking ... |
|  1 | MySQL Tutorial    | DBMS staat voor DataBase ...             |
+----+-------------------+------------------------------------------+

Als we nu het Query Expansion principe toepassen ziet de query er als volgt uit:

SELECT *
FROM artikelen
WHERE MATCH(inhoud) AGAINST('database' WITH QUERY EXPANSION)

En het resultaat wordt dan:

+----+-------------------------------------+------------------------------------------+
| id | titel                               | inhoud                                   |
+----+-------------------------------------+------------------------------------------+
|  1 | MySQL Tutorial                      | DBMS staat voor DataBase ...             |
|  5 | MySQL vs. YourSQL                   | In de volgende database vergelijking ... |
|  2 | MySQL op een goede manier gebruiken | Nadat je de volgende stappen ...         |
+----+-------------------------------------+------------------------------------------+

We zien dat er nu een extra rij gevonden is. Als je de resultaten gaat vergelijken zie je dat er nu twee records gevonden zijn met 'volgende' erin terwijl dat er eerst maar 1 was. Blijkbaar is het woord 'volgende' dus door MySQL als zeer relevant woord beoordeeld en gebruikt in de tweede zoekopdracht.
Pagina 7

Slotwoord en referenties

Dit is het einde van deze tutorial over de full-text index in MySQL. Ik heb in deze tutorial geprobeerd om een zo duidelijk mogelijk overzicht te geven van de werking van de full-text index en de mogelijkheden die deze index met zich meebrengt.

Laat ik nogmaals opmerken dat de full-text index alleen beschikbaar is met de MyISAM storage engine van MySQL en eigenlijk alleen nuttig is als je een zoekfunctie op wilt zetten waarbij je door teksten wilt zoeken. In dat geval zal deze index namelijk een grote snelheidswinst op kunnen leveren t.o.v. andere methoden om de database te doorzoeken. Bovendien biedt de full-text index de mogelijkheid om te sorteren op relevantie, iets dat in dit soort gevallen zeer handig blijkt te zijn.

Tenslotte zijn de boolean zoekopdrachten ook een fijne bijkomstigheid. Dit geeft jou of de gebruiker van je zoekfunctie zoveel meer mogelijkheden om zoekopdrachten te specificeren. Bovendien kun je zoekopdrachten op die manier nog enorm versnellen waardoor de efficientie toeneemt.

Kortom, de full-text index van MySQL is een uitermate handige index om je database te optimaliseren als je bezig bent met het ontwikkelen van een zoekfunctie.

Opmerkingen of suggesties over deze tutorial zijn natuurlijk altijd welkom!

Deze tutorial is ook hier te vinden: Fulltext Index in MySQL.

Bronvermelding
[li]MySQL handleiding[/li]
[li]Using Fulltext Indexes in MySQL - Part 1[/li]
[li]Using Fulltext Indexes in MySQL - Part 2[/li]
[li]Performing Full-text and Boolean Searches with MySQL[/li]
[li]Using Relevance Rankings for Full Text and Boolean Searches with MySQL[/li]
[li]Using Boolean Operators for Full Text and Boolean Searches with MySQL[/li]

Reacties

0
Nog geen reacties.