Tout d'abord, vous devez réaliser que la prise en charge par le SGBDR de l'indexation de texte intégral est un hack pour forcer une technologie conçue pour permettre un accès efficace aux données structurées à traiter du texte non structuré. (Oui, c'est juste mon opinion. Si nécessaire, je peux le défendre car je comprends extrêmement bien les deux technologies.;)
Alors, que peut-on faire pour améliorer les performances de recherche ?
Option 1 - "Le meilleur outil pour la tâche"
La meilleure façon de gérer la recherche en texte intégral dans un corpus de documents est d'utiliser une technologie spécialement conçue à cet effet, telle que SOLR (Lucene) d'Apache ou Sphinx de l'erreur, Sphinx.
Pour des raisons qui deviendront claires ci-dessous, je recommande fortement cette approche.
Option 2 - Précharger vos résultats
Lors de la construction de solutions de recherche textuelles, l'approche habituelle consiste à indexer tous les documents dans un seul index de recherche et bien que cela puisse être le plus rapide, ce n'est pas la seule approche.
En supposant que ce que vous recherchez peut être facilement quantifié dans un ensemble de règles connues, vous pouvez proposer un style de recherche plus "guidé" qu'un simple texte intégral non qualifié. Ce que je veux dire par là, c'est que si votre application peut bénéficier de l'association des utilisateurs aux résultats, vous pouvez précharger divers ensembles de résultats basés sur un ensemble connu de règles dans leurs propres tables, et ainsi réduire le volume de données à rechercher.
Si vous pensez qu'une majorité de vos utilisateurs bénéficieront d'un ensemble connu de termes de recherche dans un ordre connu, vous pouvez créer votre interface de recherche pour favoriser ces termes.
Donc, en supposant qu'une majorité d'utilisateurs recherchent une variété d'automobiles, vous pouvez proposer des recherches prédéfinies basées sur le modèle, l'année, l'état, etc. Votre interface de recherche serait conçue comme une série de menus déroulants pour "guider" les utilisateurs vers des résultats spécifiques.
Ou si la majorité des recherches portent sur un sujet principal spécifique (par exemple, "automobiles"), vous pouvez prédéfinir un tableau contenant uniquement les enregistrements que vous avez précédemment identifiés comme étant liés aux automobiles.
Ces deux approches réduiraient le nombre d'enregistrements à rechercher et augmenteraient ainsi les temps de réponse.
Option 3 - « Roulez vous-même »
Si vous ne pouvez pas intégrer une technologie de recherche externe dans votre projet et que le préchargement n'est pas une option, il existe encore des moyens d'améliorer considérablement les temps de réponse aux requêtes de recherche, mais ils diffèrent en fonction de ce que vous devez accomplir et de la manière dont vous vous attendez à ce que les recherches soient effectuées. .
Si vous vous attendez à ce que les utilisateurs effectuent des recherches à l'aide de mots clés ou d'expressions uniques et de relations booléennes entre eux, vous pouvez envisager de créer votre propre 'index inversé ' de votre corpus. (C'est ce que fait déjà la recherche booléenne en texte intégral de MySQL, mais le faire vous-même permet de mieux contrôler à la fois la vitesse et la précision de la recherche.)
Pour créer un index inversé à partir de vos données existantes :
Étape 1. Créez trois tableaux
// dict - a dictionary containing one row per unique word in corpus create table dict ( id int primary key, word varchar ) // invert - an inverted_index to map words to records in corpus create table invert ( id int primary key, rec_id int, word_id int ) // stopwords - to contain words to ignore when indexing (like a, an, the, etc) create table stopwords ( id int primary key, word varchar )
Remarque :ceci n'est qu'un croquis. Vous voudrez ajouter des index et des contraintes, etc. lorsque vous créerez réellement ces tables.
Le tableau des mots vides est utilisé pour réduire la taille de votre index aux seuls mots importants pour les requêtes attendues des utilisateurs. Par exemple, il est rarement utile d'indexer des articles en anglais, comme 'a', 'an', 'the', car ils n'apportent pas de sens utile aux recherches par mots-clés.
En règle générale, vous aurez besoin d'une liste de mots vides conçue spécifiquement aux besoins de votre application. Si vous ne vous attendez jamais à ce que les utilisateurs incluent les termes "rouge", "blanc" ou "bleu" dans leurs requêtes ou si ces termes apparaissent dans chaque enregistrement consultable, vous voudriez les ajouter à votre liste de mots vides.
Consultez la note à la fin de ce message pour obtenir des instructions sur l'utilisation de votre propre liste de mots vides dans MySQL.
Voir aussi :
Étape 2. Créer l'index inversé
Pour construire un index inversé à partir de vos enregistrements existants, vous aurez besoin de (pseudo-code) :
foreach( word(w) in record(r) ) { if(w is not in stopwords) { if( w does not exist in dictionary) { insert w to dictionary at w.id } insert (r.id, w.id) into inverted_index } }En savoir plus sur les mots vides :
Au lieu d'utiliser une liste de mots vides spécifique, le test "si (w n'est pas dans les mots vides)" pourrait prendre d'autres décisions soit à la place, soit en complément de votre liste de mots inacceptables.
Votre application peut souhaiter filtrer tous les mots de moins de 4 caractères ou seulement inclure mots d'un ensemble prédéfini.
En créant votre propre index inversé, vous bénéficiez d'un contrôle beaucoup plus important et plus précis sur la recherche.
Étape 3. Interroger l'index inversé à l'aide de SQL
Cette étape dépend vraiment de la façon dont vous vous attendez à ce que les requêtes soient soumises à votre index.
Si les requêtes doivent être "codées en dur", vous pouvez simplement créer vous-même l'instruction select ou si vous devez prendre en charge les requêtes entrées par l'utilisateur, vous devrez convertir le langage de requête que vous choisissez en une instruction SQL (généralement effectuée à l'aide d'un analyseur simple).
En supposant que vous souhaitiez récupérer tous les documents correspondant à la requête logique '(mot1 ET mot2) OU mot3', une approche possible pourrait être :
CREATE TEMPORARY TABLE temp_results ( rec_id int, count int ) AS
( SELECT rec_id, COUNT(rec_id) AS count
FROM invert AS I, dict AS D
WHERE I.word_id=D.id AND (D.word='word1' OR D.word='word2')
GROUP BY I.rec_id
HAVING count=2
)
UNION (
SELECT rec_id, 1 AS count
FROM invert AS I, dict AS D
WHERE I.word_id=D.id AND D.word='word3'
);
SELECT DISTINCT rec_id FROM temp_results;
DROP TABLE temp_results;
REMARQUE :ce n'est qu'un premier passage du haut de ma tête. Je suis convaincu qu'il existe des moyens plus efficaces de convertir une expression de requête booléenne en une instruction SQL efficace et j'accueille toutes les suggestions d'amélioration.
Pour rechercher des expressions, vous devrez ajouter un champ à l'index inversé pour représenter la position du mot dans son enregistrement et en tenir compte dans votre SELECT.
Et enfin, vous devrez mettre à jour votre index inversé lorsque vous ajoutez de nouveaux enregistrements ou supprimez les anciens.
Le dernier mot
La "recherche en texte intégral" relève d'un très vaste domaine de recherche connu sous le nom de "Recherche d'informations" ou IR et il existe de nombreux livres sur le sujet, y compris
-
Récupération d'informations :mise en œuvre et évaluation des moteurs de recherche par Stefan Büttcher, Charles L. A. Clarke et Gordon V. Cormack (23 juillet 2010)
-
Moteurs de recherche :récupération d'informations en pratique par Bruce Croft, Donald Metzler et Trevor Strohman (16 février 2009)
-
Construire des applications de recherche :Lucene, LingPipe et Gate par Manu Konchady (juin 2008)
Consultez Amazon pour en savoir plus.
Remarques
Comment utiliser votre propre liste de mots vides dans MySQL
Pour utiliser votre propre liste de mots vides dans MySQL :
- Créez votre propre liste de mots vides, un mot par ligne, et enregistrez-la dans un emplacement connu sur votre serveur, par exemple :/usr/local/lib/IR/stopwords.txt
- Modifiez mon.cnf pour ajouter ou mettre à jour les lignes suivantes :
[mysqld] ft_min_word_len=1 ft_max_word_len=40 ft_stopword_file=/usr/local/lib/IR/stopwords.txt
qui fixera la longueur minimale et maximale des mots légaux à 1 et 40, respectivement, et indiquera à mysqld où trouver votre liste personnalisée de mots vides.
(Remarque :la valeur par défaut ft_max_word_len est 84, ce qui, à mon avis, est assez excessif et peut entraîner l'indexation de séries de chaînes qui ne sont pas de vrais mots.)
- Redémarrer mysqld
- Supprimer et recréer tous les index liés au texte intégral