Autocomplete php avec 36000 résultats possible

WRInaute impliqué
Bonjour,

j'ai un petit problème et je ne connais pas la meilleure solution à adopter.

Je souhaite créer un autocomplète (php/mysql/javascript). J'ai crée un code qui fonctionne parfaitement, mais dans celui ci je n'ai que 6 résultats possible. Comment faire pour passer de 6 à 36 000 résultats possible. De plus les 36 000 résultats se trouve dans une bdd.

Voici le code qui fonctionne :

PHP:
$query = $_GET['query'];
 
$values = ['Mickael',
            'Julie',
            'Francis',
            'Jonathan',
            'Stephen',
            'Alonso'];
 
if ($query) {
    foreach ($values as $key => $value) {
        if (stripos($value, $query) === false) {
            unset($values[$key]);
        }
    }
}
 
echo json_encode(array_values($values));

Voila le code que je souhaite mettre en place : Est ce la meilleure solution ?

PHP:
// Récupérer les 36 000 communes
 
$sql = "SELECT name, zipcode, server FROM cities";
 
$requete = $bdd -> prepare($sql);
$requete->execute();
 
 
// ICI JE NE SAIS PAS COMMENT FAIRE
 
 
 
if ($query) {
    foreach ($values as $key => $value) {
        if (stripos($value, $query) === false) {
            unset($values[$key]);
        }
    }
}
 
echo json_encode(array_values($values));

Merci d'avance
 
WRInaute passionné
Eh bien, ton résultat, tu le crées simplement avec les résultats d'une requête qui a un LIKE pour faire la recherche du genre :
PHP:
$sql = "SELECT name, zipcode, server FROM cities WHERE name LIKE '%" . addslashes($query) . "%'";

C'est la BD qui va faire la recherche, pas le PHP, évidemment plus efficace que de sortir d'abord les 36000 résultats pour que PHP les traite.
 
Dernière édition:
WRInaute accro
$sql = "SELECT name, zipcode, server FROM cities WHERE name LIKE '%" . addslashes($query) . "%'";
Attention qu'un LIKE qui commence par % n'utilise pas l'index.
Et que ce n'est pas avec addslashes() qu'on escape les paramètres d'une requête (faille d'injection SQL).
 
WRInaute passionné
Si c'est une ville qu'on cherche, c'est vrai que de toute façon inutile de commencer avec un % puisque le début est sûr.
 
WRInaute passionné
Et que ce n'est pas avec addslashes() qu'on escape les paramètres d'une requête (faille d'injection SQL).

Je crois qu'avec un champ UTF8 (je ne mets que de l'utf8 partout) il n'y a pas de faille.
Mais bon, faut mieux des requêtes préparées paramétrées c'est sûr.
 
WRInaute impliqué
Comme il a été dit plus haut, un bon autocomplete doit faire la recherche au niveau de la base de données.
Mais un bon auto-complete ne fait pas de recherche sur un champ de la base de données qui n'est pas préparé pour ça, c'est beaucoup trop naïf et lent.
Par exemple ton champ Cities comporte :
Manneville-ès-Plains
Avec un simple like, si l'utilisateur recherche sans tiret ni accents, le Like ne trouvera rien (à moins, pour les accents, d'utiliser une champ avec un interclassement insensible à la casse, ce qui se paye au niveau des perfs).

Une technique simple à mettre en place, qui offre de bonnes perfs pour le genre de cas évoqué, et qui renvoie de bons résultats :
- créer un champ supplémentaire insensible à la casse (utf8_bin), avec un index, qui contient le nom de la ville "préparé" : tout en minuscules, pas d'accents, pas d'espaces, pas de tirets, pas d'apostrophes : que des lettres sans accents et des chiffres (car il peut y en avoir si ta liste des villes contient les arrondissements de Paris, Lyon, Marseille). Pour l'exemple de Manneville-ès-Plains, ça donne donc mannevilleesplains
- quand une recherche arrive, faire subir le même traitement aux termes recherchés.
- matcher les deux avec BINARY LIKE, et un % uniquement à la fin, sinon, comme l'a indiqué Spout, l'index n'est pas utilisé
- ne pas oublier de mettre un header expires dans le résultat pour mettre dans le cache du navigateur les résultats. Peut éviter de nombreuses requêtes, si l'utilisateur refait la même recherche, ou efface sa recherche caractère par caractère avec backspace.

Bonus :
- coté javascript, au minimum, envoyer le paramètre de recherche en minuscules, pour qu'une recherche sur PARIS appelle la même URL que Paris ou que paris, et donc améliorer l'utilisation du cache si l'utilisateur refait les mêmes recherches avec une casse différente.
- dans le code d'appel, vérifier si ça sert à quelque chose de lancer une recherche. Par exemple si l'utilisateur en est à "Pon" et appuie sur "t", avant de lancer la recherche, vérifier si tous les résultats affichés ne commencent pas par "Pont", auquel cas ça ne sert à rien d'envoyer une requête au serveur : on va récupérer les mêmes résultats.
- éventuellement, renvoyer d'abord les résultats les plus courts, ou les plus pertinents, ou un mix des deux
 
Dernière édition:
WRInaute impliqué
Afin de correspondre au premier code et de me faciliter les choses j'ai fais ceci mais ca ne fonctionne pas à cause des doubles apostrophes en début de chaine.

PHP:
$sql = "SELECT name, zipcode, server FROM cities";

$requete = $bdd -> prepare($sql);
$requete->execute();

while ($donnees = $requete->fetch()) {

     $ar[] = "'".$donnees['name']."'";
}

$values = [implode(',', $ar)];



if ($query) {
    foreach ($values as $key => $value) {
        if (stripos($value, $query) === false) {
            unset($values[$key]);
        }
    }
}

echo json_encode(array_values($values));

£values me donne ceci : ["'mot 1','mot 2','mot 3'"] et je souhaite avoir cela : ['mot 1','mot 2','mot 3'] comme sur le premier code.
 
Discussions similaires
Haut