

new!








|
mySQL - Soundex, ou comment faire des recherches en souplesse !


Cet article a pour but de vous présenter la fonction mySQL Soundex, qui va vous permettre de comparer la sonorité des mots. Très utile pour faire un petit moteur de recherche !
Exposé du problème
 
Nous avons une table SQL que nous nommerons "table_ville", classant des villes de France sous cette forme :
| id | ville |
| 1 | Amiens |
| 2 | Bordeaux |
| 3 | Lille |
| 4 | Lyon |
| 5 | Paris |
| 6 | Marseille |
Nous voulons, via un formulaire sur notre site web, y effectuer une recherche par nom. Le code du formulaire :
<form action="page.php">
Rechercher le ville :<br />
<input type="text" name="ville" /> <input type="submit" value="OK" />
</form>
Voici la page page.php telle qu'elle aurait pu exister :
<html>
<head>
<title>Recherche de ville</title>
</head>
<body>
<?
$result = mysql_query("SELECT id, ville FROM table_ville WHERE ville='".$_GET["ville"]."'");
if(mysql_num_rows($result)>0)
{
list($id, $nom_ville) = mysql_fetch_row($result);
echo "La ville $nom_ville porte le numero d'ID : $id";
}
else
echo "Pas de résultat";
?>
</body>
</html>
Limite de ce système :
 
Le problème avec ce script est que si votre visiteur fait une petite faute ("bordaux", "Lion", "Lile", "Parris"), la requete ci-dessus ne sortira aucun résultat ! Nous allons découvrir comment SOUNDEX va vous sauver la vie !
SOUNDEX ?
 
la fonction s'utilise de cette façon :
SOUNDEX(CHAINE)
La fonction SOUNDEX retourne un code correspondant à la sonorité de la chaine en question. Par exemple:
SOUNDEX('Javascript') = J12613
SOUNDEX('Javaskripte') = J12613
En gros, Javascript et Javaskripte, pour SOUNDEX, ca sonne exactement pareil. De même :
SOUNDEX('bordeaux') = B632
SOUNDEX('bordaux') = B632
Utilisons SOUNDEX dans notre requete SQL
 
Reprenons notre page par y integrer la fonction SOUNDEX :
<html>
<head>
<title>Recherche de ville</title>
</head>
<body>
<?
$result = mysql_query("SELECT id, ville FROM table_ville WHERE SOUNDEX(ville)=SOUNDEX('".$_GET["ville"]."')");
if(mysql_num_rows($result)>0)
{
list($id, $nom_ville) = mysql_fetch_row($result);
echo "La ville $nom_ville porte le numero d'ID : $id";
}
else
echo "Pas de résultat";
?>
</body>
</html>
Et voila, mySQL ne recherche plus suivant la chaine exacte, mais suivant sa sonorité ! Vous visiteurs trouveront toujours plus de résultats maintenant ! :)
Annotations des visiteurs :
  |

De robinjulie38 - le 21-02-2007
  bonjour,
je viens de tester tout ce jolie code et j'ai quelques remarques :
1 : j'ai testé le soundex sur une recherche de pays (donc un seul mot)
2 : j'ai fais 3 types de recherche
_recherche simple
| select * from pays where lib_pays='$pays_saisie' |
|
_recherche avec soundex simple
| select * from pays where soundex(lib_pays)=soundex('".$pays_saisie."') |
|
_recherche avec soundex amélioré (code de lpicard)
$pays=son2( $_saisie);
select * from pays where soundex(lib_pays)=soundex('".$pays_pays."')
|
|
3 : mes conclusions :
_quand le pays est bien orthographié il est préférable d'utiliser la recherche simple. sinon le soundex amélioré retourne parfois plusieurs résultats par exemple pour maroc il me retourne maroc et maurice (île maurice)
_si le soundex amélioré retourne plusieurs résultat il faut s'en remettre au soundex simple qui retourne bien maroc pour maroc
_enfin je ne comprends pourquoi un reduire le résultat de la fonction pour le soundex amélioré à 4 caractère.
par exemple pour l'Afghanistan avec 4 caractères le soundex amélioré ne trouve rien mais avec tous les caractère j'ai un résultat
_il faut donc combiner les trois recherches
cordialement | De lpiquard - le 07-06-2006
  |
 Voici une petite fonction d'un Soundex amélioré ET pour la langue française !
J'ai testé plusieurs type d'algorithme phonétique celui-ci me parait le mieux : il ne filtre ni trop ni pas assez...
function son2( $sIn ) /// SOUNDEX 2 V FRANCAISE
{
/// Si il n'y a pas de mot, on sort immédiatement
if ( $sIn === '' ) return ' ';
/// On met tout en minuscule
$sIn = strtoupper( $sIn );
/// On supprime les accents
$sIn = strtr( $sIn, 'ÂÄÀÇÈÉÊËŒÎÏÔÖÙÛÜ', 'AAASEEEEEIIOOUUU' );
/// On supprime tout ce qui n'est pas une lettre
$sIn = preg_replace( '`[^A-Z]`', '', $sIn );
/// Si la chaîne ne fait qu'un seul caractère, on sort avec.
if ( strlen( $sIn ) === 1 ) return $sIn . ' ';
/// on remplace les consonnances primaires
$convIn = array( 'GUI', 'GUE', 'GA', 'GO', 'GU', 'CA', 'CO', 'CU', 'Q', 'CC', 'CK' );
$convOut = array( 'KI', 'KE', 'KA', 'KO', 'K', 'KA', 'KO', 'KU', 'K','K', 'K' );
$sIn = str_replace( $convIn, $convOut, $sIn );
/// on remplace les voyelles sauf le Y et sauf la première par A
$sIn = preg_replace( '`(?<!^)[EIOU]`', 'A', $sIn );
/// on remplace les préfixes puis on conserve la première lettre
/// et on fait les remplacements complémentaires
$convIn = array( '`^KN`', '`^(PH|PF)`', '`^MAC`', '`^SCH`', '`^ASA`', '`(?<!^)KN`', '`(?<!^)(PH|PF)`', '`(?<!^)MAC`',
'`(?<!^)SCH`','`(?<!^)ASA`' );
$convOut = array( 'NN', 'FF', 'MCC', 'SSS', 'AZA', 'NN', 'FF', 'MCC', 'SSS', 'AZA' );
$sIn = preg_replace( $convIn, $convOut, $sIn );
/// suppression des H sauf CH ou SH
$sIn = preg_replace( '`(?<![CS])H`', '', $sIn );
/// suppression des Y sauf précédés d'un A
$sIn = preg_replace( '`(?<!A)Y`', '', $sIn );
/// on supprime les terminaisons A, T, D, S
$sIn = preg_replace( '`[ATDS]$`', '', $sIn );
/// suppression de tous les A sauf en tête
$sIn = preg_replace( '`(?!^)A`', '', $sIn );
/// on supprime les lettres répétitives
$sIn = preg_replace( '`(.)\1`', '$1', $sIn );
/// on ne retient que 4 caractères ou on complète avec des blancs
return substr( $sIn . ' ', 0, 4);
}
|
|
| De jugar - le 10-10-2005
  Soundex... c'est pas que bien !!!
Il faut aussi donner ses quelques points négatifs :
* Cette fonction tourne avec les règles phonétiques anglaises ("âne" et "ânes" ne "snoneront" pas pareil)
* N'importe quel mot est résumé en une clef de 5 chiffre commençant par la preière lettre du mot.
Donc
SOUNDEX('Javascript') = J12613
SOUNDEX('Javaskripte') = J12613
Mais
SOUNDEX('casque') = C12345
SOUNDEX('kasque') = K12345 ... Hmmm :(
* Ensuite il faut séparer les mots d'une phrase
SOUNDEX('Javascript') = J12613
SOUNDEX('Javascript rulez') = J12613
soundex('Javascript') + ' ' + soundex('rulez') = 'J12613 R13245'
A part ça, c'est bien | De KevBrok - le 24-08-2005
  Pour faire une requête plus rapide, on aurait pu ajouter un champ "soundex_code" avec la clée soundex(). Ensuite, on fait, en PHP:
if ( isset($_GET['ville'] )
{
$word_sound = soundex($_GET['ville']);
mysql_query('SELECT ville FROM table_ville WHERE ville = \'' . addslashes($_GET['ville']) . '\' OR soundex_code = \'' . $word_sound . '\'');
// Le reste du code ici...
} |
|
C'est plus rapide et en plus ça nous permet d'être plus précis: on recherche aussi le terme exact. (Un peux comme sur la recherche EJS: il y a, par exemple, "4 mots sur 4" quand on trouvé exactement ce qu'on cherchait. | De riphper - le 22-08-2005
  Très bonne démonstration. (Temps de la requête un chouilla plus lent, mais en régle générale, très fonctionnel) |
|
>> Poster une annotation sur cette astuce
  Retour à la liste des trucs et astuces
|

|