2 votes

Comment obtenir et ordonner les entrées les plus pertinentes de la base de données avec plusieurs mots-clés Laravel 5

J'ai des difficultés à gérer des mots-clés multiples et à interroger la base de données en fonction de la pertinence. Je veux effectuer une recherche dans chaque ligne et, s'il y a plus d'un mot clé par ligne qui correspond à mes colonnes sélectionnées, trier ces entrées en premier.

J'ai quelque chose qui fonctionne, mais il s'agit simplement de tirer toutes les entrées avec un mot-clé présent dans une colonne, sans ordre spécifique ou pertinence.

Prenez cet exemple concret :

$search_terms = array('York', 'North Yorkshire');

$properties = Property::where(function ($q) use ($search_terms) {
            foreach ($search_terms as $value) {
                $q->orWhere('address1', 'like', "%{$value}%");
                $q->orWhere('address2', 'like', "%{$value}%");
                $q->orWhere('postcode', 'like', "%{$value}%");
                $q->orWhere('city_town', 'like', "%{$value}%");
                $q->orWhere('county', 'like', "%{$value}%");
            }
        })->paginate(25);

Cela fonctionne et permet d'extraire toutes les entrées dont les mots-clés sont présents dans l'une des colonnes sélectionnées. Dans ce cas York de la city_town et North Yorkshire de la county colonne.

J'ai besoin que la requête vérifie chaque rangée individuelle pour ces mots-clés et ramène les entrées dans lesquelles TOUTES de ces mots-clés sont présents, suivi par où un ou plusieurs sont présents ensuite (mon exemple fait cela maintenant).

Merci d'avance à toute personne susceptible de m'aider.

4voto

devk Points 5775

Ok, peut-être qu'un magicien SQL pourrait vous donner une meilleure solution SQL. Mais en attendant...

Voici comment je procéderais avec Laravel collections (tri avec php) :

$search_terms = array('York', 'North Yorkshire');

$properties = Property::where(function ($q) use ($search_terms) {
            foreach ($search_terms as $value) {
                $q->orWhere('address1', 'like', "%{$value}%");
                $q->orWhere('address2', 'like', "%{$value}%");
                $q->orWhere('postcode', 'like', "%{$value}%");
                $q->orWhere('city_town', 'like', "%{$value}%");
                $q->orWhere('county', 'like', "%{$value}%");
            }
        })->paginate(25);

$props = ['address1', 'address2', 'postcode', 'city_town', 'county'];

$properties = $properties->sortByDesc(function($i, $k) use ($search_terms, $props) {
    // The bigger the weight, the higher the record
    $weight = 0;
    // Iterate through search terms
    foreach($search_terms as $searchTerm) {
        // Iterate through properties (address1, address2...)
        foreach($props as $prop) { 
            // Use strpos instead of %value% (cause php)
            if(strpos($i->{$prop}, $searchTerm) !== false)
                $weight += 1; // Increase weight if the search term is found
        }
    }

    return $weight;
});

$properties = $properties->values()->all();

0voto

TiDJ Points 186

J'espère vraiment que vous avez résolu votre problème en un an, mais je pense avoir été confronté au même genre de problème et voici comment je l'ai géré. (je pense que la solution de devk est un peu trop gourmande en terme de performance). J'utilise Laravel 5.6.

J'obtiens des expertises sous forme de chaîne de caractères dans ma base de données, voici un exemple de la valeur que pourrait avoir une expertise :

user->expertises = "SAP, ERP, team management"

Je veux mettre quelques expertises dans mon champ de recherche et obtenir le résultat le plus pertinent :

$input = "SAP, nagement" // Expertises searched, volontary 'nagement' uncompleted word
$keywords = explode(", ", $input); // Array of keyword

$raw = "(";
foreach($keywords as $key) {
    $raw .= "(user.expertises LIKE '%".$key."%')+";
}
$raw = substr($raw, 0, -1); // Remove the last "+"
$raw .= ") as weight";
// End result :
// ((user.expertises LIKE '%SAP%')+(user.expertises LIKE '%nagement%')) 
// as weight

// It will do smtg like '(0+1+1) as weight' for example, for each user

$request = User::select('*')->addSelect(DB::raw($raw));
return $request->orderBy('weight', 'DESC')->paginate(10);

L'utilisateur de mon exemple aura 2 poids. Et sera en tête des résultats (car le poids est ici compris entre 0 et 2, en fonction du nombre de mots-clés).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X