2009-12-14 9 views
5

J'ai un site qui doit rechercher par le biais de 20-30k enregistrements, qui sont principalement des films et des séries TV. Le site exécute php/mysql avec memcache. Je cherche à remplacer le FULLTEXT par soundex() recherche que j'ai actuellement, qui fonctionne ... un peu, mais n'est pas très bon dans de nombreuses situations.Quelle est l'application de recherche de site la plus simple à mettre en œuvre, qui prend en charge la recherche floue?

Existe-t-il des scripts de recherche décents qui soient simples à implémenter et qui fournissent une capacité de recherche correcte (de 3 colonnes dans une table).

Répondre

6

La réponse de ewemli est dans la bonne direction, mais vous devriez combiner le mapping FULLTEXT et soundex, sans remplacer le fulltext, sinon vos requêtes LIKE sont probablement très lentes.

create table with_soundex (
    id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, 
    original TEXT, 
    soundex TEXT, 
    FULLTEXT (soundex) 
); 

insert into with_soundex (original, soundex) values 

('add some test cases', CONCAT_WS(' ', soundex('add'), soundex('some'), soundex('test'), soundex('cases'))), 
('this is some text', CONCAT_WS(' ', soundex('this'), soundex('is'), soundex('some'), soundex('text'))), 
('one more test case', CONCAT_WS(' ', soundex('one'), soundex('more'), soundex('test'), soundex('case'))), 
('just filling the index', CONCAT_WS(' ', soundex('just'), soundex('filling'), soundex('the'), soundex('index'))), 
('need one more example', CONCAT_WS(' ', soundex('need'), soundex('one'), soundex('more'), soundex('example'))), 
('seems to need more', CONCAT_WS(' ', soundex('seems'), soundex('to'), soundex('need'), soundex('more'))) 
('some helpful cases to consider', CONCAT_WS(' ', soundex('some'), soundex('helpful'), soundex('cases'), soundex('to'), soundex('consider'))) 

select * from with_soundex where match(soundex) against (soundex('test')); 
+----+---------------------+---------------------+ 
| id | original   | soundex    | 
+----+---------------------+---------------------+ 
| 1 | add some test cases | A300 S500 T230 C000 | 
| 2 | this is some text | T200 I200 S500 T230 | 
| 3 | one more test case | O500 M600 T230 C000 | 
+----+---------------------+---------------------+ 

select * from with_soundex where match(soundex) against (CONCAT_WS(' ', soundex('test'), soundex('some'))); 
+----+--------------------------------+---------------------------+ 
| id | original      | soundex     | 
+----+--------------------------------+---------------------------+ 
| 1 | add some test cases   | A300 S500 T230 C000  | 
| 2 | this is some text    | T200 I200 S500 T230  | 
| 3 | one more test case    | O500 M600 T230 C000  | 
| 7 | some helpful cases to consider | S500 H414 C000 T000 C5236 | 
+----+--------------------------------+---------------------------+ 

Cela donne assez bons résultats (dans les limites du algo soundex) tout en profitant au maximum d'un indice (une requête LIKE « % foo » doit balayer toutes les lignes de la table).

Notez l'importance d'exécuter soundex sur chaque mot, pas sur toute la phrase. Vous pouvez également exécuter votre propre version de soundex sur chaque mot plutôt que de le faire, mais dans ce cas assurez-vous de le faire à la fois lors du stockage et de la récupération en cas de différences entre les algorithmes (par exemple, l'algo de MySQL ne limite pas lui-même à la norme 4 chars)

0

Il existe une fonction SOUNDEX dans mysql. Si vous souhaitez rechercher un titre de film:

select * from movie where soundex(title) = soundex('the title'); 

Bien sûr, il ne fonctionne pas à la recherche dans le texte, comme film ou résumé de l'intrigue.


Soundex est un modèle relativement simple algo. Vous pouvez également décider de gérer tout ce qui, au niveau applicatif, il peut être plus facile:

  • lorsque le texte est stocké, tokenize et appliquer soundex sur tous les mots
  • magasin le texte original et la version soundex en deux colonnes
  • lorsque vous effectuez une recherche, calculer le soundex à l'application. niveau, puis utilisez un LIKE régulier au niveau db.
+0

Je suis intrigué. Si film.title est "Apocalypse Now" mais que l'utilisateur recherche "Apocalypse Cow", alors le soundex pourrait bien trouver une correspondance en faisant '... où film.title = "$ user_title" OU soundex (film.title) = soundex ($ user_title) '; Mais cela ne fonctionnerait pas en disant, film.intro var (255) qui contenait "Martin Sheen" et l'utilisateur recherché "Martin Shean" ai-je compris? Désolé si ce commentaire Q/est dans le mauvais endroit, s'il vous plaît mettez-moi bien si c'est le cas. – Cups

+0

soundex ('Un film avec Martin Sheen') -> A513563525, sélectionnez soundex ('A'), soundex ('film'), soundex ('avec'), soundex ('Martin'), soundex ('Sheen') -> A000, M100, W300, M635, S500 Donc, si vous stockez la version soundex du texte 'A000 M100 W300 M635 S500' et recherchez avec LIKE '% M635% S500%' cela pourrait être ok. Ceci n'est cependant toujours pas optimal. La recherche de "Mart Insheen" (malentendu possible du nom) donne "% M630% I525%" et ne fonctionnerait pas. – ewernli

1

Si vous cherchez une solution simple existant au lieu de créer votre propre solution consulter

0

Soundex a des limites pour faire face à la recherche floue. Une meilleure fonction est la distance d'édition, qui peut être intégrée dans MySQL en utilisant UDF. Vérifiez http://flamingo.ics.uci.edu/toolkit/ pour une implémentation C++ pour MySQL sous Linux.