Comment utiliser la recherche de texte intégral dans PostgreSQL sur Ubuntu 16.04

introduction

La recherche en texte intégral est une technique utilisée par les moteurs de recherche pour trouver des résultats dans une base de données. Il peut être utilisé pour optimiser les résultats de recherche sur des sites Web tels que des magasins, des moteurs de recherche, des journaux, etc.

Plus précisément, FTS récupère les documents, qui sont des entités de base de données contenant des données textuelles, qui ne correspondent pas parfaitement aux critères de recherche. Cela signifie que lorsqu’un utilisateur recherche «chats et chiens», par exemple, une application appuyée par FTS peut renvoyer des résultats contenant les mots séparément (uniquement «chats» ou «chiens»), dans un ordre différent. (“Chiens et chats”), ou contiennent des variantes des mots (“chat” ou “chien”). Cela donne aux applications un avantage à deviner ce que l’utilisateur veut dire et à obtenir plus rapidement des résultats plus pertinents.

Techniquement parlant, les systèmes de gestion de base de données (SGBD) tels que PostgreSQL permettent généralement des recherches de texte partielles à l’aide de clauses LIKE. Cependant, ces demandes ont tendance à sous-performer sur des jeux de données volumineux. Ils sont également limités à faire correspondre les entrées exactes de l’utilisateur, ce qui signifie qu’une requête peut ne produire aucun résultat, même s’il existe des documents contenant des informations pertinentes.

En utilisant FTS, vous pouvez créer un moteur de recherche de texte plus puissant sans introduire de dépendances supplémentaires sur des outils plus avancés. Dans ce didacticiel, nous utiliserons PostgreSQL pour stocker des données contenant des articles pour un site Web d’actualités hypothétiques, puis pour apprendre à interroger la base de données à l’aide de FTS et à sélectionner uniquement les meilleures correspondances. Enfin, nous améliorerons les performances des requêtes de recherche en texte intégral.

Conditions préalables

Avant de commencer ce guide, vous aurez besoin des éléments suivants:

Si vous configurez un serveur PostgreSQL sans suivre le tutoriel ci-dessus, assurez-vous de disposer du paquetage + postgresql-contrib + utilisant + sudo apt-get list postgresql-contrib +.

Étape 1 - Création de données d’exemple

Pour commencer, nous aurons besoin de certaines données pour tester le plug-in de recherche en texte intégral. Nous allons donc créer des exemples de données. Si vous avez déjà votre propre tableau avec des valeurs de texte, vous pouvez passer à l’étape 2 et effectuer les substitutions appropriées en suivant.

Sinon, la première étape consiste à se connecter à la base de données PostgreSQL à partir de son serveur. Comme vous vous connectez à partir du même hôte, vous n’avez pas besoin d’entrer votre mot de passe par défaut.

sudo -u postgres psql sammy

Ceci établira une session interactive PostgreSQL indiquant le nom de la base de données sur laquelle vous travaillez, qui dans notre cas est ++. Vous devriez voir une invite de commande + sammy = # + database.

Ensuite, créez un exemple de table dans la base de données appelée + news +. Chaque entrée de ce tableau représente un article d’actualité avec un titre, du contenu, le nom de l’auteur et un identifiant unique.

CREATE TABLE news (
  id SERIAL PRIMARY KEY,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  author TEXT NOT NULL
);

+ id + est l’index principal de la table avec le type spécial + SERIAL +, qui crée un compteur à incrémentation automatique pour la table. C’est un identifiant unique qui va automatiquement à l’index de la base de données. Nous parlerons davantage de cet indice à l’étape 3 lorsque nous examinerons les améliorations de performances.

Ajoutez ensuite quelques exemples de données à la table à l’aide de la commande + INSERT +. Cet exemple de données dans la commande ci-dessous représente des exemples d’articles de presse.

INSERT INTO news (id, title, content, author) VALUES
   (1, 'Pacific Northwest high-speed rail line', 'Currently there are only a few options for traveling the 140 miles between Seattle and Vancouver and none of them are ideal.', 'Greg'),
   (2, 'Hitting the beach was voted the best part of life in the region', 'Exploring tracks and trails was second most popular, followed by visiting the shops and then checking out local parks.', 'Ethan'),
   (3, 'Machine Learning from scratch', 'Bare bones implementations of some of the foundational models and algorithms.', 'Jo');

Maintenant que la base de données contient des données à rechercher, nous pouvons essayer d’écrire des requêtes.

Étape 2 - Préparation et recherche de documents

La première étape consiste ici à créer un document avec plusieurs colonnes de texte à partir de la table de base de données. Ensuite, nous pouvons transformer la chaîne résultante en un vecteur de mots, ce que nous allons utiliser dans les requêtes.

Tout d’abord, nous devrons rassembler toutes les colonnes en utilisant la fonction de concaténation PostgreSQL + || + et en transformant la fonction + to_tsvector () +.

SELECT title || '. ' || content as document, to_tsvector(title || '. ' || content) as metadata FROM news WHERE id = 1;

Cela renvoie le premier enregistrement en tant que document complet, ainsi que sa version transformée à utiliser pour la recherche.

Output-[ RECORD 1 ]-----------------------------------------------------
document    | Pacific Northwest high-speed rail line. Currently there are only a few options for traveling the 140 miles between Seattle and Vancouver and none of them are ideal.

metadata    | '140':18 'current':8 'high':4 'high-spe':3 'ideal':29 'line':7 'mile':19 'none':25 'northwest':2 'option':14 'pacif':1 'rail':6 'seattl':21 'speed':5 'travel':16 'vancouv':23

Vous remarquerez peut-être qu’il y a moins de mots dans la version transformée, + métadonnées + dans le résultat ci-dessus, que dans l’original + document + . Certains mots sont différents et chaque mot est accompagné d’un point-virgule et d’un numéro. En effet, la fonction `+ to_tsvector () + normalise chaque mot pour nous permettre de rechercher des variantes du même mot, puis trie le résultat par ordre alphabétique. Le nombre est la position du monde dans le + document. Il peut y avoir des positions supplémentaires séparées par des virgules si le mot normalisé apparaît plusieurs fois.

Nous pouvons maintenant utiliser ce document converti pour tirer parti des fonctionnalités de FTS en recherchant le terme «Explorations».

SELECT * FROM news WHERE to_tsvector(title || '. ' || content) @@ to_tsquery('Explorations');

Examinons les fonctions et les opérateurs que nous avons utilisés ici.

La fonction + to_tsquery () + traduit le paramètre, qui peut être une recherche utilisateur directe ou légèrement ajustée, en un critère de recherche de texte qui réduira l’entrée de la même manière que + to_tsvector () +. En outre, la fonction vous permet de spécifier la langue à utiliser et de déterminer si tous les mots doivent figurer dans le résultat ou un seul d’entre eux.

L’opérateur + @@ + identifie si le + tsvector + correspond au + tsquery + ou à un autre + tsvector +. Il retourne + true ou` + false`, ce qui facilite son utilisation dans le cadre des critères + WHERE.

Output-[ RECORD 1 ]-----------------------------------------------------
id      | 2
title   | Hitting the beach was voted the best part of life in the region
content | Exploring tracks and trails was second most popular, followed by visiting the shops and then checking out local parks.
author  | Ethan

La requête a renvoyé le document contenant le mot «Exploring», même si le mot que nous utilisions pour la recherche était «Explorations». L’utilisation d’un opérateur + LIKE + à la place de FTS aurait donné un résultat vide.

Maintenant que nous savons comment préparer les documents pour FTS et comment structurer les requêtes, voyons comment améliorer les performances de FTS.

Étape 3 - Améliorer les performances du FTS

Générer un document chaque fois que nous utilisons une requête FTS peut devenir un problème de performances lorsque vous utilisez de grands ensembles de données ou des serveurs plus petits. Une bonne solution à ce problème, que nous allons implémenter ici, consiste à générer le document transformé lors de l’insertion de la ligne et à le stocker avec les autres données. De cette façon, nous pouvons simplement le récupérer avec une requête au lieu de le générer à chaque fois.

Commencez par créer une colonne supplémentaire appelée ++ dans la table + news + existante.

ALTER TABLE news ADD "document" tsvector;

Nous devons maintenant utiliser une requête différente pour insérer des données dans la table. Contrairement à l’étape 2, nous devrons également préparer le document transformé et l’ajouter à la nouvelle colonne + document +, comme suit:

INSERT INTO news (id, title, content, author, document)
VALUES (4, 'Sleep deprivation curing depression', 'Clinicians have long known that there is a strong link between sleep, sunlight and mood.', 'Patel', to_tsvector('Sleep deprivation curing depression' || '. ' || 'Clinicians have long known that there is a strong link between sleep, sunlight and mood.'));

Pour ajouter une nouvelle colonne à la table existante, nous devons d’abord ajouter des valeurs vides pour la colonne + document +. Nous devons maintenant le mettre à jour avec les valeurs générées.

Utilisez la commande + UPDATE + pour ajouter les données manquantes.

UPDATE news SET document = to_tsvector(title || '. ' || content) WHERE document IS NULL;

L’ajout de ces lignes à notre table constitue une bonne amélioration des performances, mais dans les grands ensembles de données, des problèmes peuvent subsister, car la base de données devra toujours analyser l’ensemble de la table pour rechercher les lignes correspondant aux critères de recherche. Une solution simple consiste à utiliser des index.

Database index est une structure de données qui stocke les données séparément des données principales, ce qui améliore les performances des opérations de récupération de données. Il est mis à jour après toute modification du contenu de la table, au détriment des écritures supplémentaires et de l’espace de stockage comparativement réduit. Sa petite taille et sa structure de données sur mesure permettent aux index de fonctionner beaucoup plus efficacement que d’utiliser l’espace table principal pour la sélection de requêtes.

En fin de compte, les index aident la base de données à trouver plus rapidement les lignes en effectuant une recherche à l’aide de structures de données et d’algorithmes spéciaux. PostgreSQL a ververal types d’index qui conviennent à des types particuliers de requêtes. Les plus pertinents pour ce cas d’utilisation sont les index GiST et les index GIN. La principale différence entre eux réside dans la rapidité avec laquelle ils peuvent extraire des documents de la table. La création de GIN est plus lente lors de l’ajout de nouvelles données, mais plus rapide pour les requêtes. GIST construit plus rapidement, mais nécessite des lectures de données supplémentaires.

Parce que GiST est environ trois fois plus lent à récupérer des données que GIN, nous allons créer un index GIN ici.

CREATE INDEX idx_fts_search ON news USING gin(document);

En utilisant la colonne indexée + document, une requête` + SELECT` est également devenue un peu plus simple.

SELECT title, content FROM news WHERE document @@ to_tsquery('Travel | Cure');

La sortie ressemblera à ceci:

Output-[ RECORD 1 ]-----------------------------------------------------
title   | Sleep deprivation curing depression
content | Clinicians have long known that there is a strong link between sleep, sunlight and mood.
-[ RECORD 2 ]-----------------------------------------------------
title   | Pacific Northwest high-speed rail line
content | Currently there are only a few options for traveling the 140 miles between Seattle and Vancouver and none of them are ideal.

Lorsque vous avez terminé, vous pouvez quitter la console de la base de données avec + \ q +.

Conclusion

Ce guide explique comment utiliser la recherche en texte intégral dans PostgreSQL, y compris la préparation et le stockage du document de métadonnées et l’utilisation d’un index pour améliorer les performances. Si vous souhaitez en savoir plus sur FTS dans PostgreSQL, consultez la https://www.postgresql.org/docs/9.5/static/textsearch-intro.html la documentation officielle de PostgreSQL sur la recherche en texte intégral].

Related