7 votes

Requêtes de recherche PHP mysql

J'essaie de créer un moteur de recherche pour un site basé sur l'inventaire. Le problème est que j'ai des informations à l'intérieur de bbtags (comme dans [b]test[/b] sentence le test devrait être évalué à 3 alors que sentence devrait être évalué à 1 ).

Voici un exemple d'index :
My test sentence, my my (a une UGS de TST-DFS )
La base de données :

|Product|  word  |relevancy|
|   1   |   my   |    3    |
|   1   |  test  |    1    |
|   1   |sentence|    1    |
|   1   | TST-DFS|    10   |

Mais comment pourrais-je faire correspondre TST-DFS si l'utilisateur a tapé TST DFS ? Je voudrais que cet UGS ait une pertinence de disons 8 au lieu de la version complète 10 ..

J'ai entendu dire que la fonction de recherche FULL TEXT de MySQL serait utile, mais je n'arrive pas à trouver une bonne façon de procéder. J'aimerais éviter des choses comme les UNIONS, et garder la requête aussi optimisée que possible.

Toute aide pour trouver un bon système à cet effet serait la bienvenue.

Merci, Max

5voto

ZJR Points 3342

Mais comment puis-je faire correspondre TST-DFS si l'utilisateur a tapé TST DFS ?
J'aimerais que cette UGS ait une pertinence de disons 8, au lieu des 10

Si j'ai bien compris la question, la réponse est en fait facile.
Eh bien, si vous forgez votre requête un peu avant de l'envoyer à mysql.

Ok, disons que nous avons $query et il contient TST-DFS .

Est-ce qu'on va se concentrer sur portées des mots ? Je suppose que nous devrions, comme le font la plupart des moteurs de recherche donc :

$ok=preg_match_all('#\w+#',$query,$m);

Maintenant si ce modèle correspondait ... $m[0] contient le liste de mots en $query .
Vous pouvez l'adapter à votre UGS, mais la correspondance avec les mots complets de manière ET est à peu près ce que l'utilisateur présume. (comme cela se passe sur google et yahoo)

Ensuite, nous devons préparer un $expr expression qui sera injecté dans notre requête finale.

if(!$ok) { // the search string is non-alphanumeric
  $expr="false";
} else {   // the search contains words that are no in $m[0]
  $expr='';
  foreach($m[0] as $word) {
    if($expr)
      $expr.=" AND ";  // put an AND inbetween "LIKE" subexpressions
    $s_word=addslashes($word); // I put a s_ to remind me the variable
                                 // is safe to include in a SQL statement, that's me 
    $expr.="word LIKE '%$s_word%'"; 
  }
}

Maintenant $expr devrait ressembler à "words LIKE '%TST%' AND words LIKE '%DFS%'"

Avec cette valeur, nous pouvons construire la requête finale :

$s_expr="($expr)";
$s_query=addslashes($query);

$s_fullquery=
"SELECT (Product,word,if((word LIKE '$s_query'),relevancy,relevancy-2) as relevancy) ".
"FROM some_index ".
"WHERE word LIKE '$s_query' OR $s_expr";

Qui se lit, pour "TST-DFS" :

SELECT (Product,word,if((word LIKE 'TST-DFS'),relevancy,relevancy-2) as relevancy)
FROM some_index
WHERE word LIKE 'TST-DFS' OR (word LIKE '%TST%' AND word LIKE '%DFS%')

Comme vous pouvez le voir, dans le premier SELECT ligne, si la correspondance est partielle, mysql retournera relevancy-2

Dans le troisième, le WHERE clause, si la correspondance complète échoue, $s_expr , la requête de correspondance partielle que nous avons préparée à l'avance est essayé à la place.

2voto

Mindfulgeek Points 141

J'aime mettre tout en minuscules et supprimer les caractères spéciaux (comme dans un numéro de téléphone ou une carte de crédit, je supprime tout ce qui n'est pas un chiffre des deux côtés).

1voto

Kibbee Points 36474

Plutôt que d'essayer de créer votre propre solution FTS, vous pourriez essayer d'adapter le moteur FTS de MySQL à vos besoins. Ce que j'ai vu faire est de créer une nouvelle table pour stocker vos données FTS. Créez une colonne pour chaque élément de données dont vous voulez qu'il ait une pertinence différente. Pour votre champ sku, vous pourriez stocker le sku brut, avec les espaces, les traits de soulignement, les traits d'union et tout autre caractère spécial intact. Vous pouvez ensuite stocker une version dépouillée, sans tous ces éléments. Vous pouvez également stocker une version sans les zéros de tête, car les gens oublient souvent ce genre de choses. Vous pouvez stocker toutes ces variantes dans la même colonne. Stockez le nom de votre produit dans une autre colonne, et la description du produit dans une autre colonne. Créez un index distinct pour chaque colonne. Ensuite, lorsque vous effectuez votre recherche, vous pouvez rechercher chaque colonne individuellement et multiplier le rang des résultats en fonction de l'importance que vous accordez à cette colonne. Ainsi, vous pouvez multiplier les résultats du sku par 10, le titre par 5 et laisser les résultats de la description tels quels. Il se peut que vous deviez expérimenter un peu pour obtenir les résultats que vous souhaitez, mais cela peut s'avérer plus simple que de créer votre propre index.

1voto

ajacian81 Points 2925

Créez un tableau de mots-clés. Quelque chose du genre :

integer keywordId (autoincrement) | varchar keyword | int pointValue

Attribuez tous les mots-clés, skus, etc. possibles dans ce tableau. Créez une autre table, un pont post-keywords, (en supposant que postId est l'identifiant que vous avez assigné dans votre table originale) selon le modèle suivant :

integer keywordId | integer postId

Une fois que vous l'avez, vous pouvez facilement ajouter des mots-clés à chaque message au fur et à mesure qu'il est intéressé. Pour calculer la valeur totale des points pour un post donné, une requête telle que la suivante devrait faire l'affaire :

SELECT sum(pointValue) FROM keywordPostsBridge kpb 
JOIN keywords k ON k.keywordId = kpb.keywordId
WHERE kpb.postId = YOUR_INTENDED_POST

1voto

Richard Zhang Points 101

Je pense que la solution est assez simple, à moins que j'aie manqué quelque chose.

En fait, vous lancez deux recherches, l'une est une correspondance exacte, l'autre est une correspondance similaire ou une correspondance regex.

Joignez deux ensembles de résultats ensemble, comme match left join exact match. Ensuite, par exemple :

final_relevancy = (IFNULL(like_relevancy, 0) + IFNULL(exact_relevancy, 0) * 3) / 4

Je n'ai pas essayé moi-même. C'est juste une idée.

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