L'Agenda du Libre

Logiciels, Arts, Données, Matériels, Contenus, Communs, Internet...

À proximité

Loxodata

Actualités des organisations

Loxodata

PostgreSQL Extension Day 2025


Bourgogne-Franche-Comté
Publié le
lundi 17 mars 2025 09h30
Importé le
lundi 17 mars 2025 13h04

PostgreSQL Extension Day 2025

Le 12 mai 2025 se tiendra l’événement gratuit PostgreSQL Extension Day à Montréal, soit la veille de la conférence PostgreSQL PGConf.dev qui se tiendra pour sa part du 13 au 15 mai. Cette conférence n’est toutefois pas affiliée à la PGConf.dev.

Ce rassemblement a pour but de réunir tous les acteurs qui contribuent et utilisent les extensions de PostgreSQL constituant un écosystème de plusieurs centaines de projets: près de 400 actuellement. Le PostgreSQL Extension Day est organisé par le groupe Postgres Extension Developers Coalition.

Le CFP est ouvert jusqu’au 1er avril 2025, et les inscriptions sont ouvertes par ici.

Loxodata

L'extension pg_trgm


Bourgogne-Franche-Comté
Publié le
vendredi 07 mars 2025 09h20
Importé le
vendredi 07 mars 2025 13h04

L’extension pg_trgm

Présentation

L’extension pg_trgm (trigrammes) est fournie dans la distribution standard de PostgreSQL. Elle est présente dans /contrib et s’installe simplement dans une base de données:

loxodata_text=# CREATE EXTENSION IF NOT EXISTS pg_trgm; CREATE EXTENSION

Cette extension permet de décomposer une chaîne de caractères en succession de sous-chaînes de 3 caractères (trigrammes), afin de permettre des recherches sur une sous-chaîne, ou bien des recherches de similarité entre chaînes de caractères.

Fonctionnement

Jeu d’essai

Dans le cadre de cette présentation, je me suis constitué une table d’un million de lignes, laquelle contient un champ family contenant un nom de famille parmi les 1000 plus fréquent en France, et dont la fréquence dans la table est semblable à celle de la population française:

loxodata_text=# \dS my_datas Table "public.my_datas" Column | Type | Collation | Nullable | Default -------------+--------+-----------+----------+-------------------------------------- id | bigint | | not null | nextval('my_datas_id_seq'::regclass) random_text | text | | | family | text | | | Indexes: "idx_test_id" btree (id) loxodata_text=# SELECT count(1) FROM my_datas; count --------- 1000204 (1 row) loxodata_text=# SELECT * FROM my_datas LIMIT 5; id | random_text | family --------+--------------------------------------+--------- 211685 | 94376bb6-3655-4a65-b61a-8dbec927c5e5 | GRANGER 211686 | 7f9f8a34-13f2-4459-bd2c-e4b90a7eca9b | LE ROUX 211687 | 526549b3-13fe-4aae-87c1-4a5480cf6898 | FUCHS 211688 | 1acbdde8-b4cd-4bf8-957c-84adf1c6cf1c | BRUNET 211689 | 77cd8645-bfe8-471c-a118-3dbe507d8e8f | LAMBERT (5 rows)

Décomposition

On peut visualiser la décomposition en trigrammes avec la fonction show_trgm() :

loxodata_text=# SELECT show_trgm('GRANGER'); show_trgm ----------------------------------------- {" g"," gr",ang,"er ",ger,gra,nge,ran} (1 row)

Similarité

La fonction similarity() permet de tester la similarité entre deux chaînes de caractères. Le résultat est un score entre 0 et 1. Zéro indique qu’il n’y a aucun trigramme en commun entre les deux chaînes, tandis que 1 indique que les deux chaînes sont identiques. On peut ainsi tester la similarité entre deux noms de famille:

loxodata_text=# select similarity('GRANGER','BRUNET'); similarity ------------ 0 (1 row) loxodata_text=# select similarity('GRANGER','GRANGE'); similarity ------------ 0.6666667 (1 row) loxodata_text=# select similarity('GRANGER','GRANIER'); similarity ------------ 0.45454547 (1 row) loxodata_text=# select similarity('GRANGER','LEGRAND'); similarity ------------ 0.14285715 (1 row)

L’opérateur booléen de similarité entre deux chaînes est% :

loxodata_text=# select 'GRANGER' % 'GRANIER'; ?column? ---------- t (1 row) loxodata_text=# select 'GRANGER' % 'LEGRAND'; ?column? ---------- f (1 row)

L’opérateur booléen retourne True si le score de similarité excède une limite fixée par défaut à 0.3. La limite courante peut être consultée avec la fonction show_limit() :

loxodata_text=# select show_limit(); show_limit ------------ 0.3 (1 row)

Et cette limite peut être modifiée au niveau de la session avec la fonction set_limit(). Ainsi, si on passe le seuil à 0.1, ‘GRANGER’ et ‘LEGRAND’ sont désormais considérés comme similaires:

loxodata_text=# select set_limit(0.1); set_limit ----------- 0.1 (1 row) loxodata_text=# select 'GRANGER' % 'LEGRAND'; ?column? ---------- t (1 row)

Cette limite peut être configurée au niveau du cluster avec le paramètre pg_trgm.similarity_threshold.

Indexation et performances

L’indexation BTREE classique

Les champs TEXT peuvent être indexés classiquement avec un index BTREE:

loxodata_text=# CREATE INDEX idx_test ON my_datas(family text_pattern_ops); CREATE INDEX

Cela permet de trouver rapidement des chaînes de caractères ou des débuts de chaînes de caractères:

loxodata_text=# EXPLAIN ANALYZE SELECT id FROM my_datas WHERE family = 'GRANGER'; QUERY PLAN --------------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on my_datas (cost=10.09..2289.04 rows=731 width=8) (actual time=0.101..0.584 rows=658 loops=1) Recheck Cond: (family = 'GRANGER'::text) Heap Blocks: exact=637 -> Bitmap Index Scan on idx_test (cost=0.00..9.91 rows=731 width=0) (actual time=0.047..0.047 rows=658 loops=1) Index Cond: (family = 'GRANGER'::text) Planning Time: 0.120 ms Execution Time: 0.612 ms (7 rows) loxodata_text=# EXPLAIN ANALYZE SELECT id FROM my_datas WHERE family like 'GRAN%'; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------- Index Scan using idx_test on my_datas (cost=0.42..8.45 rows=66 width=8) (actual time=0.024..2.121 rows=3692 loops=1) Index Cond: ((family ~>=~ 'GRAN'::text) AND (family ~<~ 'GRAO'::text)) Filter: (family ~~ 'GRAN%'::text) Planning Time: 0.137 ms Execution Time: 2.234 ms (5 rows)

Cependant un tel index se révèle inutile lorsqu’on ne connaît pas le début de la chaîne recherchée. Dance ce cas on bascule sur un Seq Scan malgré la présence de l’index:

loxodata_text=# EXPLAIN ANALYZE SELECT id FROM my_datas WHERE family like '%ANGER'; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------- Gather (cost=1000.00..17185.70 rows=6643 width=8) (actual time=0.196..36.796 rows=2585 loops=1) Workers Planned: 2 Workers Launched: 2 -> Parallel Seq Scan on my_datas (cost=0.00..15521.40 rows=2768 width=8) (actual time=0.027..33.117 rows=862 loops=3) Filter: (family ~~ '%ANGER'::text) Rows Removed by Filter: 332540 Planning Time: 0.071 ms Execution Time: 36.894 ms (8 rows)

Indexation des trigrammes

Il est possible d’indexer les vecteurs de trigrammes avec un index GIN:

loxodata_text=# CREATE INDEX idx_test_trgm ON my_datas USING GIN(family gin_trgm_ops); CREATE INDEX

La recherche sur la fin de chaîne de caractères se fait maintenant en utilisant l’index nouvellement créé:

loxodata_text=# EXPLAIN ANALYZE SELECT id FROM my_datas WHERE family like '%ANGER'; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on my_datas (cost=94.35..9754.04 rows=6643 width=8) (actual time=1.422..3.197 rows=2585 loops=1) Recheck Cond: (family ~~ '%ANGER'::text) Heap Blocks: exact=2292 -> Bitmap Index Scan on idx_test_trgm (cost=0.00..92.69 rows=6643 width=0) (actual time=1.193..1.194 rows=2585 loops=1) Index Cond: (family ~~ '%ANGER'::text) Planning Time: 0.085 ms Execution Time: 3.282 ms (7 rows)

Nous pouvons maintenant effectuer une recherche de similarité:

loxodata_text=# EXPLAIN ANALYZE SELECT DISTINCT family FROM my_datas WHERE family% 'GRANGER'; QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------------- Unique (cost=370.28..370.61 rows=64 width=7) (actual time=19.476..19.867 rows=6 loops=1) -> Sort (cost=370.28..370.45 rows=66 width=7) (actual time=19.474..19.632 rows=4284 loops=1) Sort Key: family Sort Method: quicksort Memory: 264kB -> Bitmap Heap Scan on my_datas (cost=119.31..368.29 rows=66 width=7) (actual time=7.737..18.771 rows=4284 loops=1) Recheck Cond: (family% 'GRANGER'::text) Rows Removed by Index Recheck: 3468 Heap Blocks: exact=5458 -> Bitmap Index Scan on idx_test_trgm (cost=0.00..119.29 rows=66 width=0) (actual time=7.173..7.173 rows=7752 loops=1) Index Cond: (family% 'GRANGER'::text) Planning Time: 0.297 ms Execution Time: 19.887 ms (12 rows) loxodata_text=# SELECT DISTINCT family FROM my_datas WHERE family% 'GRANGER'; family ---------- GRAND GRANGE GRANGER GRANIER GRAS LAGRANGE (6 rows)

Cette recherche par similarité peut être utile, votre serviteur en sait quelque chose avec son patronyme qui comporte un ‘B’ muet et qui entraîne souvent moultes confusions lorsque je dois épeler mon nom, et qui est donc écrit souvent approximativement:

loxodata_text=# SELECT DISTINCT family FROM my_datas WHERE family% 'LEFEBVRE'; family ---------- LEFEBVRE LEFEVRE LEFEUVRE (3 rows)

Performances

On peut voir que sur une recherche d’égalité, ou bien sur une recherche de début de chaîne, c’est l’index B-Tree qui est préféré par le planner:

loxodata_text=# EXPLAIN ANALYZE SELECT family FROM my_datas WHERE family = 'LEFEBVRE'; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- Index Only Scan using idx_test on my_datas (cost=0.42..1370.94 rows=3801 width=7) (actual time=0.018..0.488 rows=4312 loops=1) Index Cond: (family = 'LEFEBVRE'::text) Heap Fetches: 399 Planning Time: 0.340 ms Execution Time: 0.615 ms (5 rows) loxodata_text=# EXPLAIN ANALYZE SELECT family FROM my_datas WHERE family like 'LEFEBVRE%'; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- Index Only Scan using idx_test on my_datas (cost=0.42..1389.95 rows=3867 width=7) (actual time=0.010..0.729 rows=4312 loops=1) Index Cond: ((family ~>=~ 'LEFEBVRE'::text) AND (family ~<~ 'LEFEBVRF'::text)) Filter: (family ~~ 'LEFEBVRE%'::text) Heap Fetches: 399 Planning Time: 0.165 ms Execution Time: 0.877 ms (6 rows) loxodata_text=# drop index idx_test; DROP INDEX

Il est cependant important de noter que si l’index B-Tree est préféré sur la recherche en début de chaîne ( LIKE 'xxxx%' ) c’est parce que la classe d’opérateurs text_pattern_ops a été utilisée lors de la création de l’index. Si nous créons un index B-Tree sans cette classe d’opérateurs, il sera préféré pour une recherche d’égalité, mais pas pour une recherche de début de chaîne du fait des problèmes complexes liés aux LOCALES des différentes langues:

loxodata_text=# CREATE INDEX idx_test ON my_datas(family); CREATE INDEX loxodata_text=# EXPLAIN ANALYZE SELECT family FROM my_datas WHERE family like 'LEFEBVRE%'; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ Bitmap Heap Scan on my_datas (cost=139.26..7724.28 rows=3867 width=7) (actual time=2.370..5.048 rows=4312 loops=1) Recheck Cond: (family ~~ 'LEFEBVRE%'::text) Heap Blocks: exact=3544 -> Bitmap Index Scan on idx_test_trgm (cost=0.00..138.29 rows=3867 width=0) (actual time=2.000..2.000 rows=4312 loops=1) Index Cond: (family ~~ 'LEFEBVRE%'::text) Planning Time: 0.162 ms Execution Time: 5.179 ms (7 rows)

Si nous supprimons définitivement l’index B-Tree, on voit que l’index sur les trigrammes est utilisé efficacement pour une recherche d’égalité (seulement après PG v13) mais pas aussi efficacement qu’avec l’index B-Tree (coût estimé 7666 vs 1370). Cependant ce coût est remarquablement constant que la recherche se fasse sur une égalité, un début de chaîne (LIKE 'xxx%') ou une recherche sur une sous-chaîne (LIKE '%xxx%').

loxodata_text=# EXPLAIN ANALYZE SELECT family FROM my_datas WHERE family = 'LEFEBVRE'; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ Bitmap Heap Scan on my_datas (cost=151.72..7666.35 rows=3801 width=7) (actual time=3.331..6.085 rows=4312 loops=1) Recheck Cond: (family = 'LEFEBVRE'::text) Heap Blocks: exact=3544 -> Bitmap Index Scan on idx_test_trgm (cost=0.00..150.77 rows=3801 width=0) (actual time=2.961..2.962 rows=4312 loops=1) Index Cond: (family = 'LEFEBVRE'::text) Planning Time: 0.095 ms Execution Time: 6.298 ms (7 rows) loxodata_text=# EXPLAIN ANALYZE SELECT family FROM my_datas WHERE family like 'LEFEBVRE%'; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ Bitmap Heap Scan on my_datas (cost=139.26..7724.28 rows=3867 width=7) (actual time=2.632..5.366 rows=4312 loops=1) Recheck Cond: (family ~~ 'LEFEBVRE%'::text) Heap Blocks: exact=3544 -> Bitmap Index Scan on idx_test_trgm (cost=0.00..138.29 rows=3867 width=0) (actual time=2.263..2.263 rows=4312 loops=1) Index Cond: (family ~~ 'LEFEBVRE%'::text) Planning Time: 0.075 ms Execution Time: 5.584 ms (7 rows) loxodata_text=# EXPLAIN ANALYZE SELECT family FROM my_datas WHERE family like '%LEFEBVRE%'; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------ Bitmap Heap Scan on my_datas (cost=109.52..7694.54 rows=3867 width=7) (actual time=1.628..4.402 rows=4312 loops=1) Recheck Cond: (family ~~ '%LEFEBVRE%'::text) Heap Blocks: exact=3544 -> Bitmap Index Scan on idx_test_trgm (cost=0.00..108.55 rows=3867 width=0) (actual time=1.260..1.260 rows=4312 loops=1) Index Cond: (family ~~ '%LEFEBVRE%'::text) Planning Time: 0.078 ms Execution Time: 4.603 ms (7 rows)

Conclusion

  • Si un champ texte fait l’objet d’une recherche d’égalité dans une clause WHERE, un index B-Tree est parfaitement adéquat.
  • Si un champ texte fait l’objet d’une recherche sur un début de chaîne de type WHERE champ LIKE 'ABC%' , un index B-Tree est là encore adéquat, à condition de lui spécifier la classe d’opérateurs text_pattern_ops.
  • Si un champ texte fait l’objet d’une recherche sur une sous-chaîne de type WHERE champ LIKE '%ABC%' , seul un index GIN ou GiST sur les trigrammes sera utile.
  • Lorsqu’un index sur les trigrammes a été créé, dans la plupart des cas l’index B-Tree peut être supprimé. Cependant, du fait de la meilleure efficacité du B-Tree, il peut être pertinent dans de rares occasions de conserver également l’index B-Tree.
Loxodata

Retour sur la PG Conf Europe 2024


Bourgogne-Franche-Comté
Publié le
lundi 24 février 2025 15h10
Importé le
lundi 24 février 2025 21h06

Retour sur la PG Conf Europe 2024

Cette année, la PostgreSQL Conference Europe 2024 s’est déroulée à Athènes, en Grèce, à quelques hectomètres de l’acropole. À nouveau, un record d’affluence est battu cette année avec 779 participants, ce qui en fait l’évènement PostgreSQL le plus important au monde.

La liste des conférences est disponible sur le site de l’évènement: https://2024.pgconf.eu/. Les supports de présentations, ainsi que les enregistrements vidéos sont également mis à disposition.

La conférence d’ouverture est donnée par Stacey Haysler. Le sujet abordé est celui du coût de la licence PostgreSQL. Cette dernière étant gratuite, elle demande une implication des différents acteurs pour que le projet puisse fonctionner et demeurer robuste et pérenne.

Les conférences sont ensuite réparties dans différentes salles, avec 4 conférences simultanées, dont une réservée aux sponsors. Nous résumons ici nos notes à propos des présentations auxquelles nous avons assisté.

Performance

Andres Freund nous explique les particularités de NUMA, qui est une architecture d’accès à la mémoire, ce qui a des conséquences pour les processeurs, et donc les logiciels qui s’en servent. Quels sont les problèmes rencontrés dans le contexte de l’utilisation de PostgreSQL? Cette présentation est complexe, mais détaillée et permet à l’auditoire de mieux comprendre le comportement global des systèmes, tout en ouvrant vers des optimisations possibles de PostgreSQL.

Les orateurs Thomas Munro & Nazir Bilal Yavuz détaillent un point important concernant les performances des lectures et écritures de données (I/O) : après un historique des solutions, ils expliquent ce que sont les solutions modernes telles que les Streaming I/O et que peut apporter le patch AIO qui est en cours de développement.

Rafael Thofehrn Castro nous présente des extensions et patchs pour suivre les plans d’exécutions à la volée dans une instance PostgreSQL. C’est bluffant, malheureusement rien n’est disponible publiquement.

Louise Leinweber détaille de façon claire et précise ce que sont les statistiques sur les données dans PostgreSQL, comment elles sont utilisées dans PostgreSQL et quels leviers nous avons pour agir.

Denzil Ribeiro évoque l’outillage nécessaire à la supervision d’une instance PostgreSQL dans le cloud, en particulier tout ce qui est spécifique aux environnements clouds, très utile lorsqu’on vient d’environnements dits “on-premise”.

Stacey Haysler et Karen Jex utilisent quelques points emblématiques des problèmes souvent rencontrés par les utilisateurs de PostgreSQL pour évoquer les bonnes ou mauvaises pratiques et certains anti-patterns connus.

Robert Treat évoque avec humour ses mésaventures avec les vacuums et les ID de transactions, et les améliorations apportées depuis dans PostgreSQL 17.

Ryan Booz évoque un outil très utile en ce qui concerne la gestion de la performance: le partitionnement des tables, ses différentes possibilités et cas d’usage, jusqu’aux extensions que sont TimescaleDB et Citus.

High availibility

Boriss Mejías détaille le fonctionnement d’une réplication active-active, avec toutes les notions, plus ou moins complexes, qui permettent de bien comprendre les contraintes qu’imposent ce type de réplication.

Michael Banck expose de façon pratique et claire le fonctionnement de Patroni, avec quelques éléments pertinents à retenir, correspondant à son expérience.

Julian Markwort compare les différents gestionnaires de connexions entre eux. Quelles sont les différentes questions qui se posent pour adopter un tel outil, et pourquoi faut-il choisir pgBouncer?

Euler Taveira présente le développement qu’il a mené dans PostgreSQL pour intégré l’outil pg_createsubscriber qui permet de convertir une réplication physique en réplication logique, accélérant ainsi la création d’un réplica logique.

Kubernetes

Karen Jex explique le fonctionnement de Kubernetes et l’utilisation de l’opérateur Crunchy Postgres, et comment son fonctionnement s’articule avec le rôle et les responsabilités d’un administrateur de bases de données.

Adam Wright évoque le lien entre Kubernetes et PostgreSQL: les opérateurs! Différents opérateurs pour PostgreSQL existent et ne sont pas strictement équivalents, ce qui nécessite une compréhension de chacun d’entre eux de la part de l’administrateur de bases de données pour les adopter: sécurité, réseau, sauvegarde, stockage, extension.

David Pech fait le retour d’expérience d’une migration d’instance PostgreSQL depuis des machines virtuelles vers un cluster Kubernetes. Le choix de l’opérateur Kubernetes est un point important de la démarche. Après avoir fait tomber quelques mythes autour de Kubernetes, l’orateur détaille de plan de travail pour adopter la solution.

Dave Pitts et Derk Van Veen introduisent les concepts de haute disponibilité de PostgreSQL par le jeu, ce qui est toujours une bonne manière d’apprendre.

Intelligence artificielle

Jonathan Katz parle de l’extension pgvector, qui est une possibilité offerte aux utilisateurs de PostgreSQL de vectoriser des données et de faire des recherches par approximation.

Grant Fritchey se demande si les prompts d’IA sont de bons outils pour les DBA? Quelles sont les différentes tâches du DBA qui pourraient bénéficier de l’aide d’un assistant conversationnel?

Sécurité

Lætitia Avrot évoque l’ensemble des fonctionnalités liées aux permissions dans PostgreSQL: rôle, groupe, privilèges, Row Level Security, privilèges par défaut.

Taras Kloba détaille un sujet très important, quoique parfois trop négligé: comment protéger PostgreSQL contre les attaques. Des mises à jour de sécurité à la gestion de l’authentification en passant par la protection des données, cette présentation fait la liste des points à retenir en termes de sécurité.

Peter Eisentraut fait le tour des besoins et solutions de chiffrement de données disponibles avec PostgreSQL.

Autres

Le modèle actuel de snapshot, qui autorise la visibilité des enregistrements, est maintenant vieux de plus de vingt ans: quel modèle peut-il le remplacer, en prenant en compte la croissance de la concurrence d’accès. L’orateur évoque alors les notions de Commit Sequence Number ou d’un modèle hybride.

Christoph Berg explique en détail le fonctionnement de PostgreSQL lorsqu’on lui demande de supprimer un enregistrement, et ce qu’il est possible de faire pour retrouver cet enregistrement avec l’extension pg_dirtyread ou la commande pg_waldump. Dans tous les cas, faites des sauvegardes!

Yugo Nagata présente l’extension pg_ivm qui permet de créer des vues matérialisées incrémentales, qui sont donc mises à jour rapidement, contrairement aux vues matérialisées existantes dans PostgreSQL qui nécessitent une régénération entière.

Loxodata

PostgreSQL 17.4 et autres correctifs


Bourgogne-Franche-Comté
Publié le
jeudi 20 février 2025 15h30
Importé le
jeudi 20 février 2025 21h07

Le PGDG (PostgreSQL Global Development Group) a publié une mise à jour de toutes les versions supportées de PostgreSQL, incluant 17.4, 16.8, 15.12, 14.17 et 13.20.

Pour la liste complète des changements, se référer à la note de publication de versions.

Corrections de bogues et améliorations

Les problèmes ci-dessous concernent PostgreSQL 17. Certains de ces problèmes peuvent aussi concerner d’autres versions de PostgreSQL.

Les correctifs sont:

  • Amélioration du comportement des fonctions d’échappement de la bibliothèque libpq. Le correctif de la vulnérabilité CVE-2025-1094 a introduit une régression amenant les fonctions d’échappement à ne pas respecter les tailles des chaînes de caractères fournies en paramètres, entraînant dans certains cas des plantages. Ce problème peut impacter une bibliothèque cliente de PostgreSQL en fonction de son intégration à la bibliothèque libpq;
  • Correction de fuites mémoire dans la commande pg_createsubscriber;

Mise à jour

Toutes les publications de mises à jour de PostgreSQL sont cumulatives. Comme pour les autres mises à jour mineures, il n’est pas nécessaire d’extraire et de recharger les bases de données ni d’utiliser pg_upgrade pour appliquer cette mise à jour; il suffit simplement d’arrêter PostgreSQL et de mettre à jour les binaires.

Les utilisateurs ayant sauté une ou plusieurs mises à jour peuvent avoir besoin d’étapes additionnelles après la mise à jour. Les notes de publication des versions précédentes fournissent les détails.

Pour plus de détails, se référer à la note de publication de versions.

Liens

Si vous avez des corrections ou suggestions sur cette annonce de publication, merci de les envoyer à la mailing liste publique pgsql-www@lists.postgresql.org.

Loxodata

PostgreSQL 17.3 et autres correctifs


Bourgogne-Franche-Comté
Publié le
vendredi 14 février 2025 16h00
Importé le
vendredi 14 février 2025 21h04

Le PGDG (PostgreSQL Global Development Group) a publié une mise à jour de toutes les versions supportées de PostgreSQL, incluant 17.3, 16.7, 15.11, 14.16, 13.19.

Cette publication corrige également une vulnérabilité de sécurité et plus de 70 bogues reportés dans les mois précédents.

Cependant, le PGDG a annoncé mettre à disposition le 20 février prochain un correctif suite à l’introduction d’une régression sur cette mise à jour. Il est recommandé de ne pas procéder à cette mise à jour, mais d’attendre la version 17.4.

Problèmes de sécurité

  • CVE-2025-1094:

    • CVSS v3.1 Base Score: 8.1
    • Supported, Vulnerable Versions: 13 - 17.

Une neutralisation inadéquate d’une syntaxe avec guillemets dans les fonctions de libpq PQescapeLiteral(), PQescapeIdentifier(), PQescapeString() et PQescapeStringConn() permet de faire de l’injection SQL dans certains cas d’usage. Spécifiquement, l’injection SQL requiert à l’application d’utiliser le résultat de fonction pour construite l’entrée de psql, le terminal interactif de PostgreSQL. De même, une neutralisation inadéquate d’une syntaxe avec guillemets dans les programmes utilitaires de PostgreSQL en ligne de commande permet à une source d’arguments à ces commandes en ligne d’effectuer de l’injection SQL lorsque le paramètre client_encoding est BIG5 et server_encoding est soit EUC_TW soit MULE_INTERNAL. Les versions antérieures à PostgreSQL 17.3, 16.7, 15.11, 14.16 et 13.19 sont affectées.

Le projet PostgreSQL remercie Stephen Fewer, Principal Security Researcher, Rapid7 pour avoir signalé ce problème.

 

Corrections de bogues et améliorations

Cette mise à jour corrige plus de 70 bogues ayant été reportés durant les mois précédents. Les problèmes ci-dessous concernent PostgreSQL 17. Certains de ces problèmes peuvent aussi concerner d’autres versions de PostgreSQL.

Les correctifs sont:

  • restauration du comportement d’avant la version 17 concernant la troncature des noms de bases de données de plus de 63 octets et les noms d’utilisateurs dans les requêtes de connexion;
  • ne pas vérifier des privilèges de connexions et limites sur les processus parallèles, mais les hériter du processus principal;
  • suppression du suffixe Lock des noms d’évènements d’attente LWLock;
  • correction de la réutilisation de résultats obsolètes dans les agrégats de fenêtrage qui peuvent conduire à des résultats incorrects;
  • correction de plusieurs conditions de concurrence pour vacuum qui dans le pire des cas peut conduire à une corruption du catalogue système;
  • corrections sur la TRUNCATE de tables et d’index pour prévenir une éventuelle corruption;
  • correction sur le détachement d’une partition lorsque sa propre contrainte de clé étrangère fait référence à une table partitionnée;
  • correction pour les codes de format FFn (par exemple FF1) pour to_timestamp, où un code de format entier avant le FFn consommait tous les chiffres disponibles;
  • corrections pour SQL/JSON et XMLTABLE() pour mettre des entrées spécifiques entre guillemets lorsque cela est nécessaire;
  • inclusion de l’option ldapscheme dans la vue pg_hba_file_rules();
  • corrections pour UNION, y compris le fait de ne pas fusionner des colonnes avec des collations non compatibles;
  • corrections pouvant avoir un impact sur la disponibilité ou la vitesse de démarrage d’une connexion à PostgreSQL;
  • correction de plusieurs fuites mémoire dans la sortie du décodage logique;
  • correction de plusieurs fuites mémoire avec le langage PL/Python;
  • ajout de l’autocomplétion pour la commande COPY (MERGE INTO);
  • rendre pg_controldata plus résilient lors de l’affichage d’informations provenant de fichiers pg_control corrompus;
  • correction d’une fuite mémoire sur la commande pg_restore avec des données compressées via zstd;
  • correction de pg_basebackup pour gérer correctement les fichiers pg_wal.tar de plus de 2GB sur Windows;
  • modification sur le module earthdistance pour utiliser le canevas des fonctions standards SQL pour corriger des problèmes sur des mises à jour majeures vers la version 17 quand l’extension earthdistance est utilisée;
  • corrige des erreurs avec pageinspect dans des instances où la définition de la fonction brin_page_items() n’est pas à jour de la dernière version;
  • corrige des conditions de concurrence lors de tentative d’annulation d’une requête distante avec postgres_fdw;

Cette publication met aussi à jour les fichiers de fuseaux horaires avec la publication de tzdata 2025a pour les changements de lois DST au Paraguay, plus des corrections historiques pour les Philippines.

Mise à jour

Toutes les publications de mises à jour de PostgreSQL sont cumulatives. Comme pour les autres mises à jour mineures, il n’est pas nécessaire d’extraire et de recharger les bases de données ni d’utiliser pg_upgrade pour appliquer cette mise à jour; il suffit simplement d’arrêter PostgreSQL et de mettre à jour les binaires.

Les utilisateurs ayant sauté une ou plusieurs mises à jour peuvent avoir besoin d’étapes additionnelles après la mise à jour. Les notes de publication des versions précédentes fournissent les détails.

Pour plus de détails, se référer à la note de publication de versions.

Liens

Si vous avez des corrections ou suggestions sur cette annonce de publication, merci de les envoyer à la mailing liste publique pgsql-www@lists.postgresql.org.

Loxodata

Correctif hors cycle pour PostgreSQL


Bourgogne-Franche-Comté
Publié le
vendredi 14 février 2025 09h00
Importé le
vendredi 14 février 2025 13h04

Le PGDG prévoit une livraison hors cycle pour le 20 février 2025 afin de corriger une régression introduite sur la mise à jour du 13 février 2025 portant sur les versions mineures: 17.3, 16.7, 15.11, 14.16 et 13.19. Dans cette mise à jour, vous retrouverez des correctifs pour les versions supportées (17.4, 16.8, 15.12, 14.17, 13.20). Bien que ces correctifs puissent ne pas impacter tous les utilisateurs de PostgreSQL, le PGDG a préféré adresser le problème au plus tôt et ne pas attendre la prochaine échéance prévue le 8 mai 2025.

Le correctif de sécurité CVE-2025-1094, traitant d’une vulnérabilité dans la librairie libpq de PostgreSQL, a introduit une régression portant sur la gestion des chaînes de caractères (“C string”) terminée par un caractère non nul. L’erreur pourrait être visible en fonction de comment un client PostgreSQL a implémenté ce comportement, et peut ne pas impacter tous les drivers PostgreSQL. Par précaution, le PGDG a avancé le cycle de mise à jour.

Si vous êtes impacté par ce problème, il est recommandé d’attendre la sortie des versions 17.4, 16.8, 15.12, 14.17 et 13.29 avant de mettre à jour PostgreSQL.

Loxodata

pgwatch 3


Bourgogne-Franche-Comté
Publié le
lundi 03 février 2025 15h30
Importé le
lundi 03 février 2025 21h04

Supervision

L’outil pgwatch est l’un des outils les plus populaires pour la supervision des instances PostgreSQL. Le projet a été initié par la société Cybertec pour ses propres besoins. Initialement en version 2, pgwatch2 a été réécrit récemment en version 3. Pavlo Golub est en charge du projet chez Cybertec.

Cette version 3 propose les mêmes fonctionnalités éprouvées de la version 2 avec quelques nouveautés, notamment le stockage en parallèle vers plusieurs stockages, l’utilisation de l’API v3 de Etcd, factorisation du code et dépréciation de certains types de stockage (InfluxDB par exemple), mise à jour des versions de certains composants tels que Grafana ou les images Docker mis à disposition.

Pour rappel, pgwatch se base sur un collecteur écrit en go qui vient récupérer une liste de métriques prédéfinies, mais extensibles à souhait afin de récupérer des statistiques sur vos instances PostgreSQL et le système (moyennant l’utilisation de l’extension PL/Python) quelque soit leur nombre avec le minimum d’impact. Le stockage des métriques s’effectue sur PostgreSQL, mais il est aussi possible de choisir TimescaleDB, Prometheus ou des fichiers JSON.

Les tableaux de bord fournis sont utilisables dans l’outil Grafana, ce qui permet de les personnaliser finement, de créer des alertes, et de gérer finement les accès aux différents tableaux et données collectées.

pgwatch permet aussi de récupérer les statistiques des outils tels que PgBouncer, Patroni, Pgpool-II, Prometheus, parser les logs de PostgreSQL, ou de récupérer des statistiques depuis des services managés de PostreSQL chez divers fournisseurs de solution cloud (AWS, Azure, Google).

L’architecture de pgwatch est très modulaire et permet de s’adapter à votre infrastructure et à tous vos cas d’usage ou presque.

Quelques nouveautés

Remote Sinks

Une des nouveautés de la version 3 de pgwatch est le découplage de la partie stockage. L’introduction des remote sinks avec la possibilité d’utiliser l’interface (basée sur RPC) mise à disposition pour implémenter un type de stockage particulier pour y pousser les métriques de pgwatch.

Mais aussi, la possibilité de disposer en parallèle de plusieurs stockages des métriques, par exemple vers une base de données et un fichier JSON.

Etcd

Autre grosse nouveauté, c’est le passage à la version 3 de l’API de etcd.

En effet, jusqu’à la version 3.3 de etcd, l’API par défaut était la version 2. Le protocole de la version 2 n’étant pas compatible avec la version 3 de ce dernier. Lors de l’utilisation d’un cluster Patroni et de la découverte automatique des noeuds, pgwatch se base sur le protocole d'etcd.

Pour cette raison, pgwatch en version 3 utilise la version 3.5 de etcd afin d’utiliser le protocole version 3 de l’API etcd. Le protocole version 2 n’étant pas compatible avec le protocole en version 3, les clés/valeurs de la version 2 ne pourront être lues avec la version 3. Il faudra migrer en utilisant la procédure de migration donnée par etcd ici. Côté patroni, la migration repose sur le changement dans le fichier de configuration de la version de etcd en indiquant etcd3.

La documentation de pgwatch est disponible ici pour la version 3.

Migration vers pgwatch3

La question de la migration de pgwatch2 vers pgwatch3 se pose. Dans la documentation actuelle, rien n’y fait référence. Mais après discussion avec Pavlo Golub, il existe un utilitaire de conversion pour convertir des métriques personnalisées au format utilisé par pgwatch2 vers celui de pgwatch3.

Il est ainsi possible de récupérer vos anciennes métriques personnalisées pour les convertir dans le format utilisé par pgwatch avec un unique fichier .yaml:

go run convert_metrics.go --src /home/projects/pgwatch2/pgwatch2/metrics/ --dst /tmp/metrics.yaml

Références

Loxodata

Ecosystème opensource PostgreSQL


Bourgogne-Franche-Comté
Publié le
mardi 28 janvier 2025 11h00
Importé le
mardi 28 janvier 2025 13h04

L’écosystème PostgreSQL

Une collaboration entre ORANGE et LOXODATA a initié le projet libre pg-ecosystem. Ce projet se présente comme un catalogue des outils et extensions libres autour de PostgreSQL afin de répondre à deux questions:

  • Quelles sont les possibilités d’industrialisation de ressources logiciels libres dans l’écosystème PostgreSQL?
  • Comment limiter la dette technique ou la dépendance à un seul fournisseur?

De ces deux questions ont découlé les travaux autour d’une étude sur les outils et extensions libres. Nous avons défini des critères d’évaluation les plus objectifs possibles: vivacité du projet, perennité des contributions, adoption par la communauté…

Le projet s’est structuré en catalogue, proposant une fiche par projet (produit). Chaque fiche décrit le produit succinctement et inclut les attributs suivants:

  • Catégorie
  • Licence
  • Documention
  • Maturité
  • Développement
  • Compatibilité
  • Déploiement

Les attributs du projet pourraient être amenés à évoluer, en fonction des retours que nous aurons.

Le projet pg-ecosystem est publié sous licence CC-BY-SA et est publié en anglais.

Le catalogue est rendu disponible via le portail pg-ecosystem. Les contributions sont acceptées et bienvenues sur Gitlab pg-ecosystem.

Le projet a été présenté à la dernière édition du Capitole du Libre 2024 dont vous pouvez retrouver la présentation: Construction d’un catalogue de l’écosystème Open Source de PostgreSQL.

Loxodata

OpenSource Experience 2024 - Les vidéos sont en ligne


Bourgogne-Franche-Comté
Publié le
vendredi 24 janvier 2025 10h00
Importé le
vendredi 24 janvier 2025 21h04

La présentation de LOXODATA à l’OpenSource Experience 2024 est en ligne

Côté conférences, nous avons parlé de le sécurisation des accès aux bases de données, une présentation très rapide en 20 minutes d’un vaste sujet. Le support est disponible  Sécurisons PostgreSQL .

L’OSXP a publié les vidéos des conférences données pendant les deux jours.

Vous pouvez retrouver la captation de notre présentation «Sécurisons les accès à PostgreSQL» sur la chaîne Youtube de l’événement.

Loxodata

L'extension pgvector


Bourgogne-Franche-Comté
Publié le
vendredi 17 janvier 2025 11h00
Importé le
vendredi 17 janvier 2025 13h05

Ces deux dernières années, on aura noté l’engouement autour de l’IA, du machine learning et de son accessibilité via les plateformes telles que OpenAI. La communauté PostgreSQL s’est penchée dessus aussi afin de rendre PostgreSQL attractif comme moteur de bases de données vectorielles, grâce à son extensibilité, notamment depuis la sortie de l’extension pg_vector.

Introduction

L’extension pgvector créée par Andrew Kane, et initiée en avril 2021, vient de connaître un élan de popularité depuis deux ans, surtout à la vue de l’engouement des travaux autour de l’IA et du machine learning, et de fait des vecteurs.

Pourtant les principes mathématiques et les algorithmes utilisés dans le machine learning et l’IA existent depuis plusieurs décennies. Ce qui a changé c’est l’accessibilité de ces derniers et la mise à disposition des données issues de ces algorithmes très rapidement, ce qui implique de pouvoir stocker les données vectorielles au plus près des applications.

Pour revenir à pgvector, cette extension permet à PostgreSQL de stocker des données vectorielles grâce à un nouveau type de données spécialisé et indexable, et d’effectuer des recherches vectorielles de type K-NN (K nearest-neighbor) ou ANN (aproximate nearest-neighbor) en proposant désormais deux types d’index: IVFFlat et HNSW.

Jonathan Katz a écrit une série d’articles sur pgvector, auquel il contribue activement, et notamment cet article: Vectors are the new JSON in PostgreSQL où il y fait le parallèle entre le support du JSON par PostgreSQL et les vecteurs. Jonathan Katz nous rappelle comment PostgreSQL a fait le pari de supporter le format JSON/JSONB, à la base un format d’échange, pour répondre aux besoins des développeurs d’applications afin de stocker des données au format JSON et de pouvoir les requêter efficacement.

La communauté PostgreSQL continue d’ailleurs d’implémenter le standard SQL/JSON et pousse à son adoption. La version 17 de PostgreSQL fournit par exemple de nouvelles fonctions JSON et un nouveau constructeur JSON_TABLE().

Ce qui s’est passé pour PostgreSQL avec JSON est en train de se reproduire avec les vecteurs: le besoin de stocker et rechercher des vecteurs, donnant l’occasion à PostgreSQL de devenir une base de données vectorielles avec toutes les fonctionnalités que PostgreSQL offre déjà.

Extensibilité

Une des forces de PostgreSQL est son extensibilité éprouvée et permet d’ajouter de nouvelles fonctionnalités sans toucher au code principal. L’écosystème des extensions est immense. Vous pouvez retrouver une liste exhaustive des extensions sur PGXN. Parmi les plus connues, on peut citer pg_stat_statements pour surveiller les statistiques d’exécution des requêtes SQL, postgis pour gérer les données géospatiales ou encore timescaledb pour gérer les séries temporelles.

Parmi les vues disponibles sous PostgreSQL pour lister les extensions, vous pouvez utiliser les vues [pg_available_extensions](https://www.postgresql.org/docs/current/view-pg-available-extensions.html ou [pg_available_extension_versions](https://www.postgresql.org/docs/current/, ou la vue pg_extension.

Bases de données vectorielles

Avant de rentrer dans le détail de l’implémentation de pgvector, nous allons rappeler ce qu’on entend par bases de données vectorielles.

Une base de données vectorielles doit permettre de stocker des vecteurs et rechercher des similarités de manière efficace et précise dans un espace vectoriel à haute dimension, en offrant une indexation performante et des opérations de calcul de distance adaptés selon le cas d’usage envisagé.

Les cas d’usage de ces bases de données pouvant être les suivants:

  • système de recommendation
  • recherche d’images
  • traitement naturel du langage
  • détection d’anomalies
  • bioinformatique
  • chatbots (RAG)

Une base de données vectorielles doit également apporter les fonctionnalités attendues sur les bases de données relationnelles telles que les transactions, la sécurité, la scalabilité, la haute disponibilité et la recherche hybride.

Vecteurs

Les vecteurs produits par plongement vectorielle (embeddings) par les grands modèles de langage (LLM) sont des tableaux de données numériques (réels à virgule flottante, type real stocké sous 4 octects) permettant de représenter des données hétérogènes comme des images, des fichiers audios ou des textes.

[-0.07, -0.53, -0.02, …, -0.61, 0.59]

Les vecteurs sont de dimension finie dont le nombre varie selon les modèles ayant produits ces derniers. Par exemple, le modèle text-embedding-3-small de chez OpenAI produit des vecteurs de 1356 dimensions, alors que le modèle text-embedding-0004 de chez Google est à 768 dimensions. Chaque modèle définit également les types d’opérations de distance acceptées.

pgvector

L’extension pgvector initié par Andrew Kane permet d’apporter à PostgreSQL le stockage et la recherche d’un nouveau type de données, le type vector à n dimensions. Il est possible d’utiliser la recherche exact et approximative (ANN).

Par défaut, le type vector utilise le type real sous quatre octets pour le stockage, mais il est possible de réduire la taille de stockage en utilisant des vecteurs de demi précision, des binaires ou le type sparse.

Pour comparer les vecteurs entre eux et faire des recherches de similarité, l’extension implémente plusieurs type d’opérations de distance en fonction de la nature des données et de l’objectif de la comparaison. On compte pas moins de six opérateurs de distance, les deux derniers opérateurs étant réservés au type vecteur binaire:

  • <-> distance L2 ou Euclidienne (vector_l2_ops)
  • <#> produit scalaire (vector_ip_ops)
  • <=> distance cosinus (vector_cosine_ops)
  • <+> distance L1 ou Manhattan (vector_l1_ops)
  • <~> distance Hamming (bit_hamming_ops)
  • <%> distance Jaccard (bit_jaccard_ops)

L’extension prend en charge également de nombreux langages existants pour les clients PostgreSQL.

Pour démarrer, créons une table avec une colonne de type vecteur (à trois dimensions pour l’exemple), insérons des données et effectuons une recherche de similarité de documents selon la distance Euclidienne (ou L2) avec l’opérateur <-> :

CREATE TABLE documents ( id serial PRIMARY KEY, embedding vector(3) ); INSERT INTO documents (embedding) VALUES ('[1,2,3]'), ('[4,5,6]'); SELECT * FROM documents ORDER BY embedding <-> '[3,1,2]' LIMIT 5;

Indexation

L’extension propose deux types de vecteurs pour la recherche aproximative (ANN) : IVFFlat et HNSW, en plus de la recherche exacte (recherche séquentielle). Le choix de l’un des types d’index est un compromis à faire entre performance et rappel. La performance étant entendue aussi bien en termes de construction de l’index que de recherche via cet index. Le rappel mesure quant à lui le ratio entre les éléments pertinents retournés parmi tous les éléments pertinents. Il est aussi possible de jouer avec les différents paramètres des index afin de placer le curseur selon votre cas d’usage.

HNSW

Le premier index disponible est l’index HNSW, pour Hierarchical Navigable Small World. Cet index est basé sur un graphe multi-couches, chaque couche étant plus ou moins dense. Plus on descend dans les couches, plus il y a de vecteurs. Pour effectuer une recherche ANN, il suffira de traverser le graphe à la recherche de la plus courte distance entre les vecteurs cibles.

© Github @ skyzh

La création de l’index HNSW peut se faire sans aucune données présentes initialement. Le temps de construction de l’index sera plus long et utilisera plus de mémoire que l’index IFVFlat, mais sera plus performant lors des requêtes. Il faudra créer un index par type d’opérateur de distance.

L’index possède deux paramètres lors de la construction de ce dernier:

  • m (par défaut à 16) nombre de connexions entre vecteurs, par couche
  • ef_construction (par défaut à 64) nombre de vecteurs candidats par voisinage pour la construction du graphe

Par exemple:

CREATE INDEX ON documents USING hnsw (embedding vector_cosine_ops) WITH (m = 16, ef_construction = 100);

En augmentant ces paramètres, il est possible d’améliorer la valeur de rappel mais au détriment du temps de construction de l’index et de la mémoire utilisée. Il est aussi possible d’affiner la recherche avec le paramètre ef_search, mais au détriment de la vitesse de requête:

  • ef_search (défaut à 40) nombre de vecteurs candidats par voisinage pour requête
SET hnsw.ef_search = 100; SELECT * FROM documents ORDER BY embedding <=> '[3,1,2]' LIMIT 10;

Il est possible également d’accélérer la création de l’index s’il peut contenir dans la taille définie par le paramètre maintenance_work_mem mais faire attention dans ce cas à ne pas consommer toute la mémoire disponible. On peut enfin rajouter des workers supplémentaires avec max_parallel_maintenance_workers et max_parallel_workers pour accélérer aussi la construction de l’index.

IVFFlat

Le deuxième index est l’index IVFFlat qui se base sur la création de liste (clusters) de vecteurs, et recherche un sous-ensemble de ces listes le plus proche du vecteur cible (avec l’algorithme K-means pour la recherche de centroïde). La construction de l’index ne peut se faire qu’après avoir inséré vos données. Cet index utilise moins de mémoire et est plus rapide à la construction que l’index HNSW mais est moins performant que ce dernier, en terme de vitesse et rappel.

© Github @ skyzh

Il est aussi important de noter que si la distribution des vecteurs change fréquemment, il sera nécessaire de reconstruire l’index (REINDEX CONCURRENTLY).

L’index IVFFlat dispose d’un paramètre pour la construction:

  • lists nombre de listes
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops) WITH (lists = 100);

Plus le nombre de liste est grand, plus la durée de construction sera longue.

Pour la recherche, il est possible de modifier le paramètre:

  • probes (1 par défaut) nombre de listes dans lesquelles rechercher
SET ivfflat_probes = 2; SELECT * FROM documents ORDER BY embedding <=> '[3,1,2]' LIMIT 3;

En augmentant le paramètre probes, il est possible d’améliorer le rappel au détriment de la performance. On peut rajouter aussi des workers supplémentaires avec max_parallel_maintenance_workers et maw_parallel_workers pour accélérer aussi la construction de l’index comme avec l’index HNSW.

Scan d’index itératif

La version 0.8.0 de pgvector a ajouté la possibilité d’activer le scan d’index itératif (désactivé par défaut). Avec cette fonctionnalité, PostgreSQL va scanner les index approximatifs à la recherche des plus proches voisins, appliquer ensuite les filtres additionnels (clause WHERE) puis scanner à nouveau les index si le nombre de voisins retournés n’est pas suffisant jusqu’à obtenir la valeur attendue.

Il est possible de l’activer pour chaque index, et choisir l’ordre du tri par rapport à la distance entre éléments:

SET hnsw.iterative_scan = strict_order|relaxed_order|off; SET ivfflat.iterative_scan = relaxed_order|off;

Vous pouvez configurer le nombre d’éléments scannés pour chaque type d’index:

SET hnsw.max_scan_tuples = 20000; (par défaut) SET ivfflat.max_probes = 100;

Quantification

Par défaut, pgvector stocke le type vecteur sous 32 bits, en nombre à virgule flottante. Depuis la version 0.7.0, il est possible d’optimiser le stockage des vecteurs et la performance des requêtes en réduisant le nombre de bits utilisés pour stocker les vecteurs, et ainsi réduire la taille des index et donc l’empreinte mémoire et disque. On peut désormais utiliser le type halfvec stocké sous 16 bits et le type binaire bit.

Par exemple:

CREATE INDEX ON documents USING hnsw ((embedding::halfvec(1536)) halfvec_l2_ops); CREATE INDEX ON documents USING hnsw ((binary_quantize(embedding)::bit(3072)) bit_hamming_ops); SELECT id FROM documents ORDER BY binary_quantize(embedding)::bit(3072) <~> binary_quantize($1) LIMIT 10;

Le type vecteur halfvec permet de stocker jusqu’à 4096 dimensions lorsque le type vecteur était limité à près de 2000 dimensions et le type binaire pouvant aller jusqu’à 64000 dimensions. L’inconvénient étant la réduction de l’information qui entraîne une diminution du rappel.

Conclusion

Comme vous venez de le voir, PostgreSQL grâce à son extensibilité permet d’adresser différents cas d’usage, et dans cet article l’extension pgvector en est la parfaite illustration tranformant PostgreSQL en une base de données vectorielles tout en fournissant les fonctionnalités de la base de données relationnelles éprouvées depuis de nombreuses années.

pgvector permet de répondre aux besoins issues autour de l’IA et sa popularité ne risque pas de retomber si l’on en croît le dépôt GitHub hébergeant le projet.

Références

Crédits photos: Jerry Kavan

Loxodata

Recherche multilingue en texte intégral avec PostgreSQL (partie 2)


Bourgogne-Franche-Comté
Publié le
jeudi 16 janvier 2025 13h05
Importé le
jeudi 16 janvier 2025 21h04

Utilisation en base de données

Tests en base de données

Création d’une table simple contenant des documents en plusieurs langues

Pour commencer, nous allons créer une table qui va contenir des documents collectés sur le net:

CREATE TABLE pages (id BIGSERIAL PRIMARY KEY, url TEXT UNIQUE, lang CHAR(2) NOT NULL, title TEXT, content TEXT);

La table contiendra simplement un indentifiant, l’url source du document, la langue du document, son titre et son contenu.

Programme python d’alimentation

Pour nous constituer un jeu d’essai, nous allons simplement “scrapper” des pages du site Wikipedia en anglais et en français. Ce script va chercher dans notre table une URL pour lequel le document est absent, va lire l’URL en question, ajouter dans la table les autres URLs présentes dans le document, puis enregister le contenu du document sous forme de texte brut.

Pour scrapper les sites respectivement en anglais et en français, le script se lance simplement:

~/loxodata_text$ python3 get_links.py en ~/loxodata_text$ python3 get_links.py fr

Le script:

from bs4 import BeautifulSoup import requests import psycopg2 import sys def get_links(url,conn,cursor,lang): response = requests.get(url) data = response.text soup = BeautifulSoup(data, 'lxml') page1_html = BeautifulSoup(data, 'html.parser') page1_txt = page1_html.get_text() mots = page1_txt.split() # Supprimer espaces multiples for w in mots: if len(w) > 1024: mots.remove(w) # supprimer les chaines trop longues else: page1_txt = " ".join(mots) titre = soup.title.get_text() query = "UPDATE pages SET content=%s,title=%s WHERE url=%s;" cursor.execute(query,(page1_txt,titre,url)) for link in soup.find_all('a'): link_url = link.get('href') if link_url is not None and \ ('/Talk:' in link_url or \ '/wiki/Discussion' in link_url or \ '/wiki/CSS' in link_url or \ 'wiki/File:' in link_url or \ 'wiki/Fichier:' in link_url or \ '/User:' in link_url or \ '/User_talk:' in link_url): # éliminer les discussions/users, fichiers, ne garder que les articles link_url = None if link_url is not None and link_url.startswith('/wiki'): # traitement des URL relatives link_url='https://'+lang+'.wikipedia.org'+link_url if link_url is not None and link_url.startswith('https://'+lang+'.wikipedia.org/wiki'): query = "INSERT INTO pages (url,lang) VALUES (%s,%s) ON CONFLICT DO NOTHING;" data = (link_url) cursor.execute(query,(data,lang.upper())) conn.commit() return if __name__ == "__main__": if len(sys.argv) < 2: lang='en' else: lang=sys.argv[1] lang=lang.lower() r = 'https://'+lang+'.wikipedia.org/wiki/Main_Page' conn = psycopg2.connect(database='loxodata_text', host='localhost', user='aegir', port=5432) cursor = conn.cursor() # Ajouter l'URL de départ query = "INSERT INTO pages(url,lang) VALUES(%s,%s) ON CONFLICT DO NOTHING;" cursor.execute(query,(r,lang.upper())) conn.commit() stop = False documents=0 max_doc=10000 while not stop: query = "SELECT url FROM pages WHERE lang=%s AND content IS NULL LIMIT 1;" cursor.execute(query,(lang.upper(),)) r = cursor.fetchone() if r is None: stop = True else: documents=documents+1 print(documents,r[0]); get_links(r[0],conn,cursor,lang) if documents > max_doc: stop = True

Après avoir touné “un certain temps”, nous avons un jeu d’essai correct pour nos tests:

loxodata_text=# select count(1) as urls, count(1) filter (where content is not null) as total, count(1) filter (where content is not null and lang='FR') as fr, count(1) filter (where content is not null and lang='EN') as en from pages; urls | total | fr | en ---------+-------+------+------ 1299347 | 14543 | 8393 | 6150 (1 row)

Plus de 14.000 articles ont été chargés, dont 8.000 en français et 6.000 en anglais.

Première recherche simple

Dans cet exemple, je vais effectuer une recherche simple “thé & japonais”. Bien évidemment les résultats dépendent des pages qui auront été “scrappées” sur le wikipédia. La recherche s’effectue sur le contenu de la page. On affiche son titre et son URL. Mais surtout on utilise la fonction ts_rank() qui permet d’obtenir un score de correspondance. Zéro indiquant que le document ne correspond pas du tout, tandis que 1 indique que le document répond à 100%. Ceci permet de limiter la requête aux 10 documents les plus pertinents.

loxodata_text=# select * from (select id,ts_rank(to_tsvector('french_custom',content),to_tsquery('french_custom','thé & japonais') ) , title,url from pages where lang='FR' and to_tsquery('french_custom','thé & japonais') @@ to_tsvector('french',content) order by 2 desc) foo limit 10 ; id | ts_rank | title | url -------+------------+----------------------------------------+------------------------------------------------------------------------- 1716 | 0.99486476 | Thé au Japon Wikipédia | https://fr.wikipedia.org/wiki/Th%C3%A9_au_Japon 13527 | 0.9795128 | Thé vert Wikipédia | https://fr.wikipedia.org/wiki/Th%C3%A9_vert 13056 | 0.8625401 | Cérémonie du thé japonaise Wikipédia | https://fr.wikipedia.org/wiki/C%C3%A9r%C3%A9monie_du_th%C3%A9_japonaise 25315 | 0.8625401 | Cérémonie du thé japonaise Wikipédia | https://fr.wikipedia.org/wiki/Chad%C3%B4 22413 | 0.8625401 | Cérémonie du thé japonaise Wikipédia | https://fr.wikipedia.org/wiki/Chanoyu 13023 | 0.81228346 | Thé Wikipédia | https://fr.wikipedia.org/wiki/Th%C3%A9 13979 | 0.7667292 | Catégorie:Thé au Japon Wikipédia | https://fr.wikipedia.org/wiki/Cat%C3%A9gorie:Th%C3%A9_au_Japon 1745 | 0.73748296 | Bancha (thé) Wikipédia | https://fr.wikipedia.org/wiki/Bancha_(th%C3%A9) 1730 | 0.7290929 | Cérémonie du thé Wikipédia | https://fr.wikipedia.org/wiki/C%C3%A9r%C3%A9monie_du_th%C3%A9 1736 | 0.71149355 | Sencha Wikipédia | https://fr.wikipedia.org/wiki/Sencha (10 rows)

Notre recherche ne s’effectuant que sur le contenu de la page, il pourrait être pertinent d’ajouter le titre de la page au texte dans lequel on fait une recherche, au moins pour calculer le score:

loxodata_text=# select * from (select id,ts_rank(to_tsvector('french_custom',title || ' ' || content),to_tsquery('french_custom','thé & japonais') ) , title,url from pages where lang='FR' and to_tsquery('french_custom','thé & japonais') @@ to_tsvector('french',content) order by 2 desc) foo limit 10 ; id | ts_rank | title | url -------+------------+----------------------------------------+------------------------------------------------------------------------- 1716 | 0.9961827 | Thé au Japon Wikipédia | https://fr.wikipedia.org/wiki/Th%C3%A9_au_Japon 13527 | 0.9795128 | Thé vert Wikipédia | https://fr.wikipedia.org/wiki/Th%C3%A9_vert 13056 | 0.8625401 | Cérémonie du thé japonaise Wikipédia | https://fr.wikipedia.org/wiki/C%C3%A9r%C3%A9monie_du_th%C3%A9_japonaise 25315 | 0.8625401 | Cérémonie du thé japonaise Wikipédia | https://fr.wikipedia.org/wiki/Chad%C3%B4 22413 | 0.8625401 | Cérémonie du thé japonaise Wikipédia | https://fr.wikipedia.org/wiki/Chanoyu 13979 | 0.8246348 | Catégorie:Thé au Japon Wikipédia | https://fr.wikipedia.org/wiki/Cat%C3%A9gorie:Th%C3%A9_au_Japon 13023 | 0.81228346 | Thé Wikipédia | https://fr.wikipedia.org/wiki/Th%C3%A9 1745 | 0.73748296 | Bancha (thé) Wikipédia | https://fr.wikipedia.org/wiki/Bancha_(th%C3%A9) 1730 | 0.7290929 | Cérémonie du thé Wikipédia | https://fr.wikipedia.org/wiki/C%C3%A9r%C3%A9monie_du_th%C3%A9 1736 | 0.71149355 | Sencha Wikipédia | https://fr.wikipedia.org/wiki/Sencha (10 rows)

On peut voir ainsi que le score de la page intitulée “Catégorie:Thé au Japon” a été légèrement amélioré, ce qui permet à ce document d’être classé avant la page générale “Thé”.

Le poids des mots… sans photo

PostgreSQL permet de donner plus d’importance (plus de poids) aux mots d’une certaine partie d’un document. Cela s’effectue avec la fonction setweight(ts_vector,poids). Le poids est une simple lettre A,B,C ou D (par ordre décroissant). Ce poids figure dans les éléments d’un ts_vector. Pour rappel, voici un ts_vector sans poids:

loxodata_text=# select to_tsvector('french_custom','Vive postgres'); to_tsvector -------------------- 'postgr':2 'viv':1 (1 row)

Voici ce même vecteur auquel on a attribué le poids ‘A’ :

loxodata_text=# select setweight(to_tsvector('french_custom','Vive postgres'),'A'); setweight ---------------------- 'postgr':2A 'viv':1A (1 row)

Et voici maintenaant la concaténation de deux vecteurs de poids différents:

loxodata_text=# select setweight(to_tsvector('french_custom','Vive postgres'),'A') || setweight(to_tsvector('french_custom','PostgreSQL est un SGBDR'),'B'); ?column? ------------------------------------ 'postgr':2A,3B 'sgbdr':6B 'viv':1A (1 row)

On peut donc effectuer notre test précédent en attribuant un poids supérieur au titre du document (on affiche cette fois 12 résultats au lieu de 10) :

loxodata_text=# select * from (select id,ts_rank(setweight(to_tsvector('french_custom',title),'A') || setweight(to_tsvector('french_custom',content),'B'), to_tsquery('french_custom','thé & japonais')) , title,url from pages where lang='FR' and to_tsquery('french_custom','thé & japonais') @@ to_tsvector('french',content) order by 2 desc) foo limit 12 ; id | ts_rank | title | url -------+------------+----------------------------------------+------------------------------------------------------------------------- 1716 | 0.99999994 | Thé au Japon Wikipédia | https://fr.wikipedia.org/wiki/Th%C3%A9_au_Japon 13527 | 0.99999994 | Thé vert Wikipédia | https://fr.wikipedia.org/wiki/Th%C3%A9_vert 13979 | 0.99999684 | Catégorie:Thé au Japon Wikipédia | https://fr.wikipedia.org/wiki/Cat%C3%A9gorie:Th%C3%A9_au_Japon 22800 | 0.9999663 | Catégorie:Thé japonais Wikipédia | https://fr.wikipedia.org/wiki/Cat%C3%A9gorie:Th%C3%A9_japonais 13056 | 0.99990284 | Cérémonie du thé japonaise Wikipédia | https://fr.wikipedia.org/wiki/C%C3%A9r%C3%A9monie_du_th%C3%A9_japonaise 25315 | 0.99990284 | Cérémonie du thé japonaise Wikipédia | https://fr.wikipedia.org/wiki/Chad%C3%B4 22413 | 0.99990284 | Cérémonie du thé japonaise Wikipédia | https://fr.wikipedia.org/wiki/Chanoyu 13023 | 0.99958086 | Thé Wikipédia | https://fr.wikipedia.org/wiki/Th%C3%A9 1745 | 0.9980019 | Bancha (thé) Wikipédia | https://fr.wikipedia.org/wiki/Bancha_(th%C3%A9) 1730 | 0.9977101 | Cérémonie du thé Wikipédia | https://fr.wikipedia.org/wiki/C%C3%A9r%C3%A9monie_du_th%C3%A9 1736 | 0.9971023 | Sencha Wikipédia | https://fr.wikipedia.org/wiki/Sencha 13321 | 0.99643356 | Kamairicha Wikipédia | https://fr.wikipedia.org/wiki/Kamairicha (12 rows)

Cela à permis de faire apparaître “Catégorie:Thé japonais” en quatrième position, tandis que l’article sur le Sencha est passé à la onzième place.

Extrait pertinent

Plutôt qu’afficher l’URL, il peut être intéressant d’afficher l’extraît de texte le plus pertinent du document. Cela peut se faire avec la fonction ts_headline que nous pouvons appliquer aux 5 premiers résultats de notre requête:

loxodata_text=# select id,rank,title, ts_headline('french_custom',title||' '||content,to_tsquery('french_custom','thé & japonais')) from (select id,ts_rank(setweight(to_tsvector('french_custom',title),'A') || setweight(to_tsvector('french_custom',content),'B'), to_tsquery('french_custom','thé & japonais')) as rank , title,url,content from pages where lang='FR' and to_tsquery('french_custom','thé & japonais') @@ to_tsvector('french',content) order by 2 desc) foo limit 5 ; id | rank | title | ts_headline -------+------------+----------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------- 13527 | 0.99999994 | Thé vert Wikipédia | <b>Thé</b> au <b>Japon</b>. <b>Thé</b> vert <b>japonais</b> Sencha <b>Thé</b> vert Genmaicha Le <b>Japon</b> produit essentiellement du <b>thé</b> 1716 | 0.99999994 | Thé au Japon Wikipédia | <b>thé</b> au <b>Japon</b>. Le <b>thé</b> de Toganoo est considéré comme le meilleur <b>thé</b> du <b>Japon</b> 13979 | 0.99999684 | Catégorie:Thé au Japon Wikipédia | <b>Thé</b> <b>japonais</b> 20 PM Maître de <b>thé</b> <b>japonais</b> 27 P Pages dans la catégorie « <b>Thé</b> 22800 | 0.9999663 | Catégorie:Thé japonais Wikipédia | <b>Thé</b> <b>japonais</b> Wikipédia Catégorie:<b>Thé</b> <b>japonais</b> Wikipédia Aller au contenu Menu principal Menu principal déplacer 13056 | 0.99990284 | Cérémonie du thé japonaise Wikipédia | <b>thé</b> au <b>Japon</b>, ou « service <b>japonais</b> du <b>thé</b> », appelée chanoyu, ou sadō, ou encore (5 rows)

La taille du ou des extraits retournés est un paramètre de la fonction ts_headline() de même que les balises de mise en évidence (<b></b>). Attention, cette fonction est coûteuse en CPU, c’est pourquoi il est convenable d’être attentif à ne l’appliquer que sur un resultset déjà réduit au maximum.

Performances

Si vous avez essayé, de votre côté, de reproduire les exemples précédents au fur et à mesure de votre lecture, il est probable que vous éprouviez quelques inquiétudes quant aux performances du FTS. Le problème étant que la fonction to_tsvector() est “lente”. Si l’on souhaite effectuer des recherches avec des performances correctes, il est impératif de précalculer ces vecteurs de lexèmes.

On va donc ajouter une colonne de type tsvector à notre table:

loxodata_text=# alter table pages add column vector tsvector; ALTER TABLE

Puis nous allons précalculer nos vecteurs conformément à la langue du document. Dans le cas d’une base de données en exploitation, il serait bien sûr beaucoup plus pertinent de mettre un trigger sur la table afin que le champ vector soit renseigné/mis à jour lors des INSERT ou UPDATE:

loxodata_text=# update pages set vector = to_tsvector('french_custom',title || ' ' || content) where lang = 'FR' and content is not null; UPDATE 8393 Time: 1371518,736 ms (22:51,519) loxodata_text=# update pages set vector = to_tsvector('english_custom',title || ' ' || content) where lang = 'EN' and content is not null; UPDATE 6150 Time: 351283,849 ms (05:51,284)

Si nous effectuons notre recherche originale sur le thé japonais avec un EXPLAIN ANALYZE successivement en calculant le vecteur puis en utilisant le champ vector qui vient d’être créé nous avons les résultats suivants:

loxodata_text=# explain analyze select id, title,url from pages where lang='FR' and to_tsquery('french_custom','thé & japonais') @@ to_tsvector('french_custom',content); QUERY PLAN ---------------------------------------------------------------------------------------------------------------------------------- Gather (cost=1000.00..169567.06 rows=15 width=99) (actual time=373.272..21921.275 rows=3007 loops=1) Workers Planned: 2 Workers Launched: 2 -> Parallel Seq Scan on pages (cost=0.00..168565.56 rows=6 width=99) (actual time=322.930..21800.415 rows=1002 loops=3) Filter: ((lang = 'FR'::bpchar) AND ('''the'' & ''japon'''::tsquery @@ to_tsvector('french_custom'::regconfig, content))) Rows Removed by Filter: 432113 Planning Time: 0.138 ms Execution Time: 21921.710 ms (8 rows) Time: 21922,225 ms (00:21,922) loxodata_text=# explain analyze select id, title,url from pages where lang='FR' and to_tsquery('french_custom','thé & japonais') @@ vector; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------- Gather (cost=1000.00..34297.92 rows=810 width=99) (actual time=0.414..479.358 rows=3007 loops=1) Workers Planned: 2 Workers Launched: 2 -> Parallel Seq Scan on pages (cost=0.00..33216.92 rows=338 width=99) (actual time=0.218..384.590 rows=1002 loops=3) Filter: (('''the'' & ''japon'''::tsquery @@ vector) AND (lang = 'FR'::bpchar)) Rows Removed by Filter: 432113 Planning Time: 0.158 ms Execution Time: 479.523 ms (8 rows) Time: 480,046 ms

Pour le moment, laissons de côté le temps d’éxécution qui est beaucoup lié à l’état des caches. On peut voir que le coût estimé par le planner est déjà divisé par 5 (34297.92 vs 169567.06) en utilisant notre champ précalculé.

On aurait pu être tenté de partitionner notre table pages sur la langue, mais l’intérêt serait limité puisqu’on peut également créer des index partiels. Pour rappel, si un tableau est indexé dans un index BTree, l’index permettra de trouver rapidement exactement ce tableau dans son intégralité. Tandis que des index GiN ou GiST permettront de retrouver les tableaux qui contiennent les éléments recherchés.

Nous allons donc indexer les éléments du champ vector pour chaque langue:

loxodata_text=# create index x_pages_vector_fr ON pages USING GIN(vector) where lang='FR'; CREATE INDEX Time: 10520,209 ms (00:10,520) loxodata_text=# create index x_pages_vector_en ON pages USING GIN(vector) where lang='EN'; CREATE INDEX Time: 11435,435 ms (00:11,435)

Le EXPLAIN ANALYZE de la requête de recherche devient ainsi:

loxodata_text=# explain analyze select id, title,url from pages where lang='FR' and to_tsquery('french_custom','thé & japonais') @@ vector; QUERY PLAN -------------------------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on pages (cost=40.69..2817.94 rows=810 width=99) (actual time=0.446..2.632 rows=3007 loops=1) Recheck Cond: (('''the'' & ''japon'''::tsquery @@ vector) AND (lang = 'FR'::bpchar)) Heap Blocks: exact=606 -> Bitmap Index Scan on x_pages_vector_fr (cost=0.00..40.48 rows=810 width=0) (actual time=0.392..0.392 rows=3007 loops=1) Index Cond: (vector @@ '''the'' & ''japon'''::tsquery) Planning Time: 0.347 ms Execution Time: 2.731 ms (7 rows) Time: 3,329 ms

Comme on peut le voir, cet index permet de diviser par douze le coût estimé par le planner.

Le cas de l’index GiST

Si on compare l’exécution avec un index GiST au lieu de GIN nous avons:

loxodata_text=# drop index x_pages_vector_fr; DROP INDEX Time: 155,098 ms loxodata_text=# drop index x_pages_vector_en; DROP INDEX Time: 45,920 ms loxodata_text=# CREATE INDEX x_pages_vector_fr ON pages USING GIST(vector tsvector_ops) WHERE lang='FR'; CREATE INDEX Time: 1969,569 ms (00:01,970) loxodata_text=# CREATE INDEX x_pages_vector_en ON pages USING GIST(vector tsvector_ops) WHERE lang='EN'; CREATE INDEX Time: 1891,561 ms (00:01,892) loxodata_text=# explain analyze select id, title,url from pages where lang='FR' and to_tsquery('french_custom','thé & japonais') @@ vector; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------- Bitmap Heap Scan on pages (cost=36.59..3608.35 rows=1072 width=99) (actual time=1.882..69.167 rows=3007 loops=1) Recheck Cond: (('''the'' & ''japon'''::tsquery @@ vector) AND (lang = 'FR'::bpchar)) Rows Removed by Index Recheck: 1533 Heap Blocks: exact=750 -> Bitmap Index Scan on x_pages_vector_fr (cost=0.00..36.32 rows=1072 width=0) (actual time=1.724..1.725 rows=4540 loops=1) Index Cond: (vector @@ '''the'' & ''japon'''::tsquery) Planning Time: 0.199 ms Execution Time: 69.357 ms (8 rows)

On peut voir que le coût estimé est supérieur avec un GiST qu’avec un GIN. Le point le plus intéressant c’est que le scan de l’index GiST a ramené plus de lignes (4540) que celui de l’index GIN lequel a ramené exactement le même nombre de lignes (3007) que la requête elle-même. Ce comportement était prévisible car si le GIN indexe des valeurs exactes, le GiST indexe lui des checksums de valeurs, ce qui entraîne de faux positifs et donc nécessite un filtrage après coup des lignes ramenées par le scan de l’index, et donc des lectures superflues, et donc forcément un coût supplémentaire. L’utilisation d’un index GiST peut cependant parfois se justifier, en particulier parce qu’il supporte l’inclusion de valeurs (CREATE INDEX ... INCLUDE (champ)). Donc si votre table de documents comporte d’autres champs quasi-systématiquement utilisés dans la clause WHERE (identifiant de l’auteur, droits d’accès etc.) l’utilisation du GiST peut être pertinente afin de pouvoir inclure cette ou ces donnée(s) à l’index.

Limites

Il faut savoir que lorsque des ts_vector sont indexés, seuls les lexèmes le sont. Le poids éventuellement associé à chaque lexème ne l’est pas. Cela ne pose en soit pas de problème, mais si vous avez précalculé votre champ vector en concaténant des fragments de texte de poids différents, ne soyez pas surpris d’avoir éventuellement 2 champs vector différents qui, selon l’index sont égaux.

Conclusion

Les capacités de recherches en texte intégral de PostgreSQL sont très largement méconnues, surtout en France, alors que quelques simples efforts de configurations permettraient dans bien des cas d’espèce de s’affranchir de coûteux moteurs spécialisés et propriétaires.

Configuration

Si la configuration par défaut de la recherche en texte intégral de PostgreSQL est assez efficace en anglais, il convient pour le français (ou l’espagnol) de compléter le paramétrage par défaut. Pour cela:

  • Copier la configuration ‘french’ dans une nouvelle (french_custom par exemple).
  • Installer l’extension unaccent.
  • Installer éventuellement l’extension DICT_XSYN.
  • Supprimer le mapping des éléments que l’on souhaite exclure de la recherche (emails, URLs, valeurs numériques…)
  • Paramétrer un fichier .stop (non accentué) et attribuer ce fichier au dictionnaire french_stem.
  • Paramétrer un fichier .syn ou .rules et créer le dictionnaire de synonymes.
  • Modifier le mapping des éléments lexicographiques asciiword, hword, hword_part, word vers les dictionnaires unaccent, syn_fr, french_stem (unaccent est inutile pour asciiword).

Modélisation

  • En plus du ou des champ(s) text contenant les textes sur lesquels seront effectués des recherches, il convient d’avoir un champ dans lequel est précalculé le ts_vector. Un trigger pour alimenter ce champ est recommandé.
  • Si les documents sont suceptibles d’être dans plusieurs langues, un champ identifiant la langue du document est nécessaire.
  • Un index GIN ou GiST doit être créé sur le ts_vector précalculé. Si la base est mutilingue, il est recommandé de faire un index séparé par langue. L’index GIN est recommandé, sauf s’il est pertinent, en terme de performances, d’inclure dans l’index des données annexes.

Maintenance

  • Toute modification d’un dictionnaire (ajout de stop-words, de synonymes etc. ) ou modification de la configuration TEXT SEARCH impose évidemment de lancer un recalcul des champs ts_vector précalculés.
  • La modification d’un dictionnaire peut être prise en compte immédiatement à l’aide d’un ALTER. Par exemple, dans le cas de la modification des stop-words:
ALTER TEXT SEARCH DICTIONARY french_stem(STOPWORDS = custom_french );

Volumétries

Pour rappel, j’ai constitué pour rédiger cet article une base contenant 14.543 articles de wikipédia. Cela représente 493 Mo de texte brut:

loxodata_text=# select pg_size_pretty(sum(octet_length(content))) from pages; pg_size_pretty ---------------- 493 MB

Grace au mécanisme de compression intégré à pg_toast, ces textes n’occupent que 264 Mo dans la base:

loxodata_text=# select pg_size_pretty(sum(pg_column_size(content))) from pages; pg_size_pretty ---------------- 264 MB

Notez que j’ai utilisé la compression transparente par défaut pour les champs TOASTed PGLZ (champs TEXT et TS_VECTOR). Depuis la version 14 de PostgreSQL, la compression LZ4 est disponible, paramétrable champ par champ si besoin, laquelle permet une amélioration significative des performances au détriment d’une perte de compression infinitésimale. N’oubliez pas d’explorer ce point dans votre tuning.

Le champ ts_vector précalculé occupe 294 Mo:

loxodata_text=# select pg_size_pretty(sum(pg_column_size(vector))) from pages; pg_size_pretty ---------------- 294 MB

Les index GIN occupent 122 Mo:

loxodata_text=# select pg_size_pretty(pg_relation_size('x_pages_vector_en') + pg_relation_size('x_pages_vector_fr') ); pg_size_pretty ---------------- 122 MB

Il semble donc raisonnable de prévoir au moins 1,4 Mo d’espace de stockage pour chaque Mo de texte brut dans le cadre d’une base conçue pour la recherche en texte intégral.

Loxodata

Recherche multilingue en texte intégral avec PostgreSQL (partie 1)


Bourgogne-Franche-Comté
Publié le
jeudi 16 janvier 2025 13h00
Importé le
jeudi 16 janvier 2025 21h04

Principes et configurations

Historique

En 2000, des développements pour PostgreSQL basés sur OpenFTS ont débuté. Ce projet était alors nommé Tsearch. En 2003 le projet est devenu Tsearch2, utilisant le nouveau type de données tsvector et les index GiN/GiST de PostgreSQL 8.2 ainsi que l’UTF8. La recherche en texte intégral (ou FTS pour Full-Text Search) était proposée dans une contribution séparée nommée tsearch2 et développée par Oleg Bartunov et Teodor Sigaev. La contribution a été pleinement intégrée dans PostgreSQL à partir de la version 8.3. L’objet de ce document est donc de présenter la recherche en plein texte disponible avec la distribution standard de PostgreSQL.

Principe général

Décomposition des documents

La recherche en texte intégral diffère de la simple recherche basée sur les chaînes de caractères. Il s’agit en effet d’effectuer une recherche sémantique et non pas une simple recherche d’expression régulière. PostgreSQL est doté d’outils puissants permettant de travailler sur les chaînes de caractères, évaluer la similarité entre deux chaînes, etc. On peut citer par exemple l’extension pg_trgm (trigrammes) particulièrement utile pour de telles recherches.

On peut résumer la recherche sémantique en quelques étapes simples (on nomme “document” le texte qui fera ultérieurement l’objet d’une recherche) :

  • Décomposition du document en éléments lexicographiques simples (mots, nombres, adresses…);
  • Factorisation des éléments lexicographiques simples en lexèmes;
  • Transformation du document en un vecteur de lexèmes.

Voici un exemple simple de transformation d’un texte en vecteur de lexèmes en guise d’illustration:

loxodata_text=# select to_tsvector('english','I love postgres, but she loves shopping with a $100 banknote'); to_tsvector ------------------------------------------------------ '100':10 'banknot':11 'love':2,6 'postgr':3 'shop':7 (1 row)

On peut voir que le texte a été décomposé en 5 lexèmes, et que le lexème “love” est présent sur deux positions: 2 et 6. La fonction ts_debug() permet d’avoir plus de détails sur cette transformation:

loxodata_text=# select * from ts_debug('english', 'I love postgres, but she loves shopping with a $100 banknote'); alias | description | token | dictionaries | dictionary | lexemes -----------+------------------+----------+----------------+--------------+----------- asciiword | Word, all ASCII | I | {english_stem} | english_stem | {} blank | Space symbols | | {} | | asciiword | Word, all ASCII | love | {english_stem} | english_stem | {love} blank | Space symbols | | {} | | asciiword | Word, all ASCII | postgres | {english_stem} | english_stem | {postgr} blank | Space symbols | , | {} | | asciiword | Word, all ASCII | but | {english_stem} | english_stem | {} blank | Space symbols | | {} | | asciiword | Word, all ASCII | she | {english_stem} | english_stem | {} blank | Space symbols | | {} | | asciiword | Word, all ASCII | loves | {english_stem} | english_stem | {love} blank | Space symbols | | {} | | asciiword | Word, all ASCII | shopping | {english_stem} | english_stem | {shop} blank | Space symbols | | {} | | asciiword | Word, all ASCII | with | {english_stem} | english_stem | {} blank | Space symbols | | {} | | asciiword | Word, all ASCII | a | {english_stem} | english_stem | {} blank | Space symbols | $ | {} | | uint | Unsigned integer | 100 | {simple} | simple | {100} blank | Space symbols | | {} | | asciiword | Word, all ASCII | banknote | {english_stem} | english_stem | {banknot} (21 rows)

La sortie de ts_debug() indique que les caractères virgule et dollar (",$") ont été considérés comme des espaces, «100» est bien détecté comme un entier non signé, et les mots «I,but,she,with,a» n’ont pas été convertis en lexèmes. Ces derniers sont en effet des «stop words», c’est-à-dire des mots trop courants pour être significatifs, ils sont donc éliminés du vecteur de lexèmes.

Requête de recherche

La requête de recherche va suivre le même principe: les éléments recherchés vont être décomposés en lexèmes, et PostgreSQL va chercher des éléments communs entre les deux vecteurs.

loxodata_text=# select to_tsquery('english','shops & banknotes'); to_tsquery -------------------- 'shop' & 'banknot' (1 row)

Comme vous l’aurez deviné, le & est un opérateur logique signifiant ET. Les différents opérateurs logiques pour une requête en plein texte sont:

  • & ET logique
  • | OU logique
  • ! NON logique
  • <-> Précédence

Et enfin, l’opérateur @@ teste la correspondance entre un vecteur et une requête.

On peut ainsi tester, par exemple, une requête shops & (banknotes | credit <-> card), c’est à dire «contient ‘shop’ ET (soit (‘banknotes’) soit (‘credit’ suivi de ‘card’)) » avec différentes phrases:

loxodata_text=# WITH docs as (SELECT unnest(ARRAY['I love postgres, but she loves shopping with a $100 banknote','I love postgres, but she loves shopping with a credit card', 'I love postgres, but she loves shopping with a card for credit', 'I love $100 banknotes']) as sentence) SELECT to_tsquery('english','shops & (banknotes | credit <-> card)') @@ to_tsvector('english',sentence) result, sentence FROM docs; result | sentence --------+---------------------------------------------------------------- t | I love postgres, but she loves shopping with a $100 banknote t | I love postgres, but she loves shopping with a credit card f | I love postgres, but she loves shopping with a card for credit f | I love $100 banknotes (4 rows)

La requête retourne False pour la troisième phrase car le mot ‘card’ ne suit pas immédiatement ‘credit’, et la quatrième phrase retourne également False du fait de l’absence du lexème ‘shop’.

Il faut noter que les positions enregistrées dans le vecteur tiennent compte de la présence de stop words. Ainsi ‘credit for card’ ne correspondra pas à ‘credit <-> card’ bien que ‘for’ soit un stop word.

Configurations

Tout d’abord une précision: les configurations FTS se font base par base, elles ne sont pas globales au cluster (i.e. instance).

Différentes langues

Dans ces premiers exemples, nous avons utilisé uniquement l’anglais pour une raison très simple: PostgreSQL est livré bien configuré pour l’anglais. Cependant pour le français, même si le support est présent, quelques ajustements sont nécessaires.

Commençons par faire une copie de la configuration par défaut:

loxodata_text=# CREATE TEXT SEARCH CONFIGURATION french_custom ( COPY=french ); CREATE TEXT SEARCH CONFIGURATION

Nous pouvons examiner les différents éléments lexicographiques définis dans cette configuration:

loxodata_text=# \dF+ french_custom Text search configuration "public.french_custom" Parser: "pg_catalog.default" Token | Dictionaries -----------------+-------------- asciihword | french_stem asciiword | french_stem email | simple file | simple float | simple host | simple hword | french_stem hword_asciipart | french_stem hword_numpart | simple hword_part | french_stem int | simple numhword | simple numword | simple sfloat | simple uint | simple url | simple url_path | simple version | simple word | french_stem

Un premier test rapide nous montre une difficulté liée à la langue française: les accents.

loxodata_text=# select title,to_tsvector('french',title) from pages where id=186; title | to_tsvector -----------------------+---------------------------- Imprimeur Wikipédia | 'imprimeur':1 'wikipédi':2 (1 row)

Cela poserait un problème, par exemple, avec les participes passés, puisque “mange” et “mangé” seraient des lexèmes différents. On peut donc utiliser l’extension standard UNACCENT et l’ajouter à notre configuration:

loxodata_text=# CREATE EXTENSION IF NOT EXISTS unaccent; NOTICE: extension "unaccent" already exists, skipping CREATE EXTENSION loxodata_text=# ALTER TEXT SEARCH CONFIGURATION french_custom ALTER MAPPING FOR hword, hword_part, word WITH unaccent, french_stem; ALTER TEXT SEARCH CONFIGURATION

Vérifions la prise en compte de unaccent sur notre configuration:

loxodata_text=# \dF+ french_custom Text search configuration "public.french_custom" Parser: "pg_catalog.default" Token | Dictionaries -----------------+---------------------- asciihword | french_stem asciiword | french_stem email | simple file | simple float | simple host | simple hword | unaccent,french_stem hword_asciipart | french_stem hword_numpart | simple hword_part | unaccent,french_stem int | simple numhword | simple numword | simple sfloat | simple uint | simple url | simple url_path | simple version | simple word | unaccent,french_stem

Nous pouvons faire un test rapide avec ts_debug() pour voir le comportement:

loxodata_text=# select ts_debug('french_custom','Cet article est écrit en 2024 pour être publié sur le blog de Loxodata (https://www.loxodata.fr/post/)'); ts_debug ------------------------------------------------------------------------------- (asciiword,"Word, all ASCII",Cet,{french_stem},french_stem,{cet}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",article,{french_stem},french_stem,{articl}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",est,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (word,"Word, all letters",écrit,"{unaccent,french_stem}",unaccent,{ecrit}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",en,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (uint,"Unsigned integer",2024,{simple},simple,{2024}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",pour,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (word,"Word, all letters",être,"{unaccent,french_stem}",unaccent,{etre}) (blank,"Space symbols"," ",{},,) (word,"Word, all letters",publié,"{unaccent,french_stem}",unaccent,{publie}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",sur,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",le,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",blog,{french_stem},french_stem,{blog}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",de,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",Loxodata,{french_stem},french_stem,{loxodat}) (blank,"Space symbols"," (",{},,) (protocol,"Protocol head",https://,{},,) (url,URL,"www.loxodata.fr/post/)",{simple},simple,"{www.loxodata.fr/post/)}") (host,Host,www.loxodata.fr,{simple},simple,{www.loxodata.fr}) (url_path,"URL path","/post/)",{simple},simple,"{/post/)}") (32 rows)

Sur les 32 éléments lexicographiques, 6 ont été éliminés (est, en, pour…) car figurant dans les “stop words”. La plupart des éléments sont des “mots”, nous avons également un nombre entier (2024) et une URL. Les accents ont bien été supprimés des lexèmes (“etre”, “publie”…)

Choix des éléments lexicographiques à traiter

Selon les types de documents que nous souhaitons traiter, nous pouvons éliminer des éléments à traiter. Ainsi nous pouvons éliminer les valeurs numériques, les URLs et les adresses emails de nos configurations français et anglais:

loxodata_text=# ALTER TEXT SEARCH CONFIGURATION french_custom DROP MAPPING FOR email, sfloat, float, int, uint, url, host, url_path; ALTER TEXT SEARCH CONFIGURATION loxodata_text=# ALTER TEXT SEARCH CONFIGURATION english_custom DROP MAPPING FOR email, sfloat, float, int, uint, url, host, url_path; ALTER TEXT SEARCH CONFIGURATION loxodata_text=#

Un nouveau test avec ts_debug() montre que ces éléments lexicographiques (nombre et url) sont désormais ignorés lors de l’utilisation de la configuration french_custom:

loxodata_text=# select ts_debug('french_custom','Cet article est écrit en 2024 pour être publié sur le blog de Loxodata (https://www.loxodata.fr/post/)'); ts_debug ------------------------------------------------------------------------------ (asciiword,"Word, all ASCII",Cet,{french_stem},french_stem,{cet}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",article,{french_stem},french_stem,{articl}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",est,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (word,"Word, all letters",écrit,"{unaccent,french_stem}",unaccent,{ecrit}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",en,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (uint,"Unsigned integer",2024,{},,) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",pour,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (word,"Word, all letters",être,"{unaccent,french_stem}",unaccent,{etre}) (blank,"Space symbols"," ",{},,) (word,"Word, all letters",publié,"{unaccent,french_stem}",unaccent,{publie}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",sur,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",le,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",blog,{french_stem},french_stem,{blog}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",de,{french_stem},french_stem,{}) (blank,"Space symbols"," ",{},,) (asciiword,"Word, all ASCII",Loxodata,{french_stem},french_stem,{loxodat}) (blank,"Space symbols"," (",{},,) (protocol,"Protocol head",https://,{},,) (url,URL,"www.loxodata.fr/post/)",{},,) (host,Host,www.loxodata.fr,{},,) (url_path,"URL path","/post/)",{},,) (32 rows)

Stop-words

On peut constater que le fichier des stop-words français fourni par défaut est très succinct:

loxodata_text=# select to_tsvector('french_custom','le la les ce ça'); to_tsvector --------------- 'ca':5 'le':3 (1 row)

“ça” et “les” n’y figurent pas par exemple.

Mais nous pouvons télécharger un fichier plus complet et le placer dans la configuration tsearch (le fichier doit obligatoirement avoir le suffixe .stop) :

~/loxodata_text$ wget https://raw.githubusercontent.com/stopwords-iso/stopwords-fr/refs/heads/master/stopwords-fr.txt ~/loxodata_text$ sudo cp stopwords-fr.txt /opt/pgsql/16/share/tsearch_data/french_custom.stop

Puis modifier la configuration du dictionnaire français pour utiliser ce nouveau fichier:

loxodata_text=# alter TEXT SEARCH DICTIONARY french_stem(STOPWORDS = french_custom ); ALTER TEXT SEARCH DICTIONARY

Et maintenant, vérifions la prise en compte de cette nouvelle configuration:

loxodata_text=# select to_tsvector('french_custom','le la les ce ça'); to_tsvector ------------- 'ca':5 (1 row)

Si “les” est bien maintenant considéré comme un stop-word, il n’en est pas de même pour “ça” ce qui peut surprendre, car ce mot figure bien dans notre fichier:

~/loxodata_text$ grep -n "ça" stopwords-fr.txt 676:ça

L’explication est simple, les stop-words sont appliqués après le filtre “unaccent”. Il convient donc de modifier ce fichier afin d’en retirer également les accents. Le fichier de stop-words étant un simple fichier texte, il est aisé de le modifier:

~/loxodata_text$ sudo bash -c "sed -i -e 's/ç/c/g' /opt/pgsql/16/share/tsearch_data/french_custom.stop"

Ensuite, il faut refaire notre ALTER TEXT SEARCH DICTIONARY afin de recharger le fichier de stop-words:

loxodata_text=# alter TEXT SEARCH DICTIONARY french_stem(STOPWORDS = french_custom ); ALTER TEXT SEARCH DICTIONARY loxodata_text=# select to_tsvector('french_custom','le la les ce ça'); to_tsvector ------------- (1 row)

“ça” est donc bien maintenant un stop-word. Il faudrait bien évidemment effectuer la substitution pour chaque type de caractère accentué ( ’s/é/e/g' etc. ) la commande tr ne pouvant être utilisée car elle n’est pas compatible avec l’UTF8.

Synonymes

Il peut être utile dans le cadre de la recherche en texte intégral de disposer d’un dictionnaire de synonymes. Là encore, c’est une configuration spécifique à chaque langue qui doit être effectuée. Bien évidemment le dictionnaire à utiliser dépendra beaucoup de la nature des documents à indexer (documentation technique, juridique, etc.).

Comme pour les stop-words, il faut placer un fichier de synonymes dans le répertoire de configuration tsearch_data. Ce dictionnaire doit obligatoirement avoir le suffixe .syn. J’ai donc ainsi créé un fichier french_custom.syn:

~/loxodata_text$ cat /opt/pgsql/16/share/tsearch_data/french_custom.syn FISC DGFIP domicile maison auto voiture aimer adorer bosser travailler copain ami joli beau étudiant élève scrameustache alien

Le principe étant que le mot situé à gauche sera substitué par celui de droite.

Il nous faut donc créer ce dictionnaire de synonymes:

loxodata_text=# create TEXT SEARCH DICTIONARY syn_fr (template=synonym, synonyms='french_custom'); CREATE TEXT SEARCH DICTIONARY

Et dans la foulée, tester le bon fonctionnement de ce dictionnaire:

loxodata_text=# select ts_lexize('syn_fr', 'FISC'); ts_lexize ----------- {dgfip} (1 row) loxodata_text=# select ts_lexize('syn_fr', 'maison'); ts_lexize ----------- (1 row) loxodata_text=# select ts_lexize('syn_fr', 'domicile'); ts_lexize ----------- {maison} (1 row)

Il nous reste à modifier le mapping pour les mots afin d’ajouter ce dictionnaire:

loxodata_text=# ALTER TEXT SEARCH CONFIGURATION french_custom ALTER MAPPING FOR asciiword WITH syn_fr,french_stem; ALTER TEXT SEARCH CONFIGURATION loxodata_text=# ALTER TEXT SEARCH CONFIGURATION french_custom ALTER MAPPING FOR hword, hword_part, word WITH unaccent,syn_fr, french_stem; ALTER TEXT SEARCH CONFIGURATION

Puis à en vérifier la prise en compte:

loxodata_text=# select to_tsvector('french_custom','domicile adoré'); to_tsvector --------------------- 'ador':2 'maison':1 (1 row)

C’est moins musical, mais cela fonctionne bien.

Limites et dict_xsyn

Le problème, c’est que le dictionnaire des synonymes passe AVANT le stemmer. Nous avons donc encore affaire à des chaînes de caractères, et non pas des lexèmes. Par conséquent “domicile” et “domiciles” sont des mots différents. On pourrait être tenté de faire passer d’abord le stemmer, puis ensuite le dictionnaire de synonymes, mais cela ne fonctionne pas. L’extension dict_xsyn est livrée en standard et répond (au moins partiellement) à ce problème en permettant de faire un dictionnaire de synonymes plus élaboré.

Commençons par créer l’extension:

loxodata_text=# create extension if not exists dict_xsyn; CREATE EXTENSION

Ensuite il faut placer un fichier .rules, comme pour le fichier de synonymes:

~/loxodata_text$ cat /opt/pgsql/16/share/tsearch_data/french_custom.rules maison domicile domiciles aimer adore adores adoree adorees adorer adorons adorez adorent DGFIP FISC MINEFI numerique digital ko kb octet byte bytes

L’utilisation habituelle de ce fichier est de mettre à gauche un mot, puis ses synonymes à droite. Mais xsyn permet d’inverser ce fonctionnement (la liste de synonymes est la source, et le premier mot est la cible). Là encore, il faut écrire les mots de manière non accentuée puisque unaccent passera AVANT le dictionnaire xsyn. Il faut donc maintenant créer le dictionnaire:

loxodata_text=# CREATE TEXT SEARCH DICTIONARY xsyn_fr (template=xsyn_template, rules='french_custom');

Faisons un rapide test:

loxodata_text=# SELECT ts_lexize('xsyn_fr', 'domicile'); ts_lexize ----------- (1 row) Time: 0,253 ms loxodata_text=# SELECT ts_lexize('xsyn_fr', 'maison'); ts_lexize ---------------------- {domicile,domiciles} (1 row)

Le résultat est logique vu notre fichier .rules de synonymes, mais c’est en fait exactement l’inverse du but recherché puisque ce que l’on souhaite c’est que “domicile” et “domiciles” soient transformés en “maison”. Mais comme je l’ai dit, des options booléennes sont disponibles pour les dictionnaires xsyn:

  • KEEPORIG: Indique s’il faut mettre en sortie le mot le plus à gauche.
  • MATCHORIG: Indique si la règle est appliquée quand on rencontre le mot le plus à gauche.
  • KEEPSYNONYMS: Indique s’il faut mettre en sortie les synonymes (tous les mots de droite).
  • MATCHSYNONYMS: Indique si la règle est appliquée quand on rencontre un des synonymes (un des mots de droite).

Dans notre cas, nous voulons remplacer par le mot de gauche (original) n’importe quel mot de droite (synonyme), donc:

  • KEEPORIG: True. (Nous voulons garder le mot de gauche).
  • MATCHORIG: False. (Inutile d’appliquer la règle lorsqu’on rencontre le mot de gauche).
  • KEEPSYNONYMS: False. (Nous ne voulons pas garder les mots de droite)
  • MATCHSYNONYMS: True. (La règle est appliquée lorsqu’on rencontre un des mots de droite).
loxodata_text=# ALTER TEXT SEARCH DICTIONARY xsyn_fr (rules='french_custom', KEEPORIG=true, MATCHORIG=false, KEEPSYNONYMS=false, MATCHSYNONYMS=true); ALTER TEXT SEARCH DICTIONARY

Il nous reste à modifier les mappings pour le traitement des éléments lexicographiques:

loxodata_text=# ALTER TEXT SEARCH CONFIGURATION french_custom ALTER MAPPING FOR asciiword WITH xsyn_fr,french_stem; ALTER TEXT SEARCH CONFIGURATION loxodata_text=# ALTER TEXT SEARCH CONFIGURATION french_custom ALTER MAPPING FOR hword, hword_part, word WITH unaccent,xsyn_fr, french_stem; ALTER TEXT SEARCH CONFIGURATION

Et à tester le fonctionnement:

loxodata_text=# select to_tsvector('french_custom','domiciles adorés'); to_tsvector ---------------------- 'aimer':2 'maison':1 (1 row)
Loxodata

OpenSource Experience 2024


Bourgogne-Franche-Comté
Publié le
mercredi 11 décembre 2024 10h00
Importé le
mercredi 11 décembre 2024 13h04

LOXODATA était à l’OpenSource Experience 2024

L’Open Source Experience (OSXP) 2024 s’est achevée la semaine dernière. LOXODATA était présente à la fois sur le stand des partenaires d’Orange, et comme conférenciers.

Nous étions aux côtés d’autres partenaires d’Orange, qui tous proposent leur support et leur expertise autour d’outils open source. Cette présence, en tant que partenaire, nous a permis de communiquer autour de notre expertise PostgreSQL, les prestations, le support ou la formation sur ce fabuleux système de gestion de bases de données et son écosystème.

Outre les différentes visites des divisions d’Orange, du TOSIT (The Open Source I Trust) et de certains membres d’OW2, nous avons eu des échanges très enrichissants avec d’autres partenaires et visiteurs. Les possibilités offertes par PostgreSQL attisent toujours autant d’intérêt.

Nous remercions Orange pour cette invitation et la visibilité que cela donne à notre entreprise et à leurs partenaires.

Côté conférences, nous avons parlé de le sécurisation des accès aux bases de données, une présentation très rapide en 20 minutes d’un vaste sujet. Le support est disponible  Sécurisons PostgreSQL . Nous avons également participé au workshop “Orange et ses partenaires dans l’écosystème open source”.

Loxodata

PostgreSQL 17.2 et autres correctifs


Bourgogne-Franche-Comté
Publié le
vendredi 22 novembre 2024 13h00
Importé le
vendredi 22 novembre 2024 21h04

Le PGDG (PostgreSQL Global Development Group) a publié une mise à jour de toutes les versions supportées de PostgreSQL, incluant 17.2, 16.6, 15.10, 14.15, 13.18.

PostgreSQL 12 est maintenant en fin de vie et ne devait plus recevoir de correctifs, mais étant donné la nature d’un problème présent dans la précédente publication, le PGDG (PostgreSQL Global Development Group) publie aussi la version 12.22 de PostgreSQL 12.

Les versions 17.1, 16.5, 15.9, 14.14, 13.17, et 12.21 publiées précédemment ne doivent pas être utilisées.

Cette publication corrige également 4 vulnérabilités de sécurités et plus de 35 bogues reportés dans les mois précédents.

Pour la liste complète des changements, se référer à la section Notes de publication.

Note: fin de vie de PostgreSQL 12

Il s’agit de la dernière publication de PostgreSQL 12. PostgreSQL 12 est maintenant en fin de vie et ne recevra plus de correctifs de sécurité ou de bogues. Si vous utilisez PostgreSQL 12 en production, nous vous suggérons de planifier une mise à jour vers une version plus récente et supportée de PostgreSQL. Se référer à notre politique de version pour plus d’informations.

Correctifs et améliorations de cette publication

Les problèmes ci-dessous concernent PostgreSQL 17. Certains de ces problèmes peuvent toutefois concerner d’autres versions de PostgreSQL.

Cette publication:

  • rétablit le fonctionnement de ALTER ROLE .. SET ROLE et ALTER DATABASE .. SET ROLE. Le correctif CVE-2024-10978 a accidentellement causé la non-application des rôles lorsqu’elle vient de sources non interactives, incluant les commandes ALTER {ROLE|DATABASE} et la variable d’environnement PGOPTIONS;
  • rétablit la compatibilité de timescaledb et d’autres extensions compilées en utilisant une version de PostgreSQL précédent la publication du 14 novembre (17.0, 16.4, 15.8, 14.13, 13.16, 12.20, et précédents). Ce correctif rétablit la structure ResultRelInfo à sa taille précédente, ainsi les extensions affectées n’ont pas besoin d’être recompilées;
  • corrige un cas où un slot de réplication logique pouvait revenir en arrière;
  • annule la suppression de journaux de transactions (WAL) encore utiles pendant pg_rewind;
  • corrige un problème d’exécution concurrente avec la suppression d’entrée de statistiques partagées, ce qui pouvait entrainer la perte de données statistiques;
  • corrige une défaillance d’ALTER TABLE lors de la vérification du changement d’options de classe d’opérateurs d’un index, si la table dispose d’un index avec une classe d’opérateurs différente de celle par défaut.

Problèmes de sécurité

  • CVE-2024-10976: Les sécurités au niveau ligne (RLS) de PostgreSQL dans une sous-requête ne tiennent pas compte des changements d’identifiant utilisateur.

    • CVSS v3.1 Base Score: 4.2
    • Supported, Vulnerable Versions: 12 - 17.

    Une traçabilité incomplète des tables avec une sécurité niveau ligne (RLS) dans PostgreSQL permet à une requête réutilisée de modifier ou d’afficher des lignes différentes de celles prévues. Les CVE-2023-2455 et CVE-2016-2193 ont fixé la plupart des interactions avec une politique de sécurité au niveau ligne. Il s’agit des mêmes conséquences que ces 2 précédents CVE. En d’autres termes, cela conduit à l’application de politiques RLS potentiellement incorrectes dans les cas où des politiques RLS spécifiques à un rôle sont utilisées et où une requête donnée est planifiée dans le cadre d’un rôle, puis exécutée dans le cadre d’autres rôles. Ce scénario peut se produire dans le cadre des fonctions SECURITY DEFINER ou lorsqu’un utilisateur et une requête communs sont planifiés au départ, puis réutilisés dans le cadre de plusieurs rôles (SET ROLE).

    L’application d’une politique incorrecte peut permettre à un utilisateur d’effectuer des lectures et des modifications qui ne seraient normalement pas autorisées. Ceci n’affecte que les bases de données qui ont utilisé CREATE POLICY pour définir une politique de sécurité des lignes (RLS). Un attaquant doit adapter son attaque au modèle de réutilisation du plan de requête d’une application particulière, aux changements d’identifiant de l’utilisateur, et aux politiques de sécurité des lignes spécifiques aux rôles. Les versions antérieures à PostgreSQL 17.1, 16.5, 15.9, 14.14, 13.17, et 12.21 sont affectées.

    Le projet PostgreSQL remercie Wolfgang Walther pour avoir signalé ce problème.

     

  • CVE-2024-10977: la bibliothèque libpq de PostgreSQL conserve un message d’erreur d’un composant «man-in-the-middle».

    • CVSS v3.1 Base Score: 3.1
    • Supported, Vulnerable Versions: 12 - 17.

    L’utilisation par une application cliente d’un message d’erreur de PostgreSQL permet à un serveur non fiable, selon les réglages SSL ou GSS courants, de fournir des octets arbitraires non-nuls à l’application utilisant la bibliothèque libpq. Par exemple, un attaquant MITM pourrait envoyer un long message d’erreur qu’un humain pourrait prendre par erreur pour le résultat d’une requête. Cela n’est probablement pas un problème pour les applications clientes pour lesquelles l’interface utilisateur indique de façon non ambigüe les limites d’un message d’erreur. Les versions antérieures à PostgreSQL 17.1, 16.5, 15.9, 14.14, 13.17, et 12.21 sont affectées.

    Le projet PostgreSQL remercie Jacob Champion pour avoir signalé ce problème.

     

  • CVE-2024-10978: PostgreSQL SET ROLE, SET SESSION AUTHORIZATION est réinitialisé avec un mauvais identifiant.

    • CVSS v3.1 Base Score: 4.2
    • Supported, Vulnerable Versions: 12 - 17.

    Une mauvaise affectation des privilèges dans PostgreSQL permet à un utilisateur applicatif non privilégié de voir ou de modifier des lignes différentes de celles prévues. Une attaque nécessite que l’application utilise SET ROLE, SET SESSION AUTHORIZATION, ou une fonctionnalité équivalente. Le problème survient lorsqu’une requête de l’application utilise des paramètres de l’attaquant ou transmet les résultats de la requête à l’attaquant. Si cette requête réagit à current_setting('role') ou à l’identifiant de l’utilisateur actuel, elle peut modifier ou renvoyer des données comme si la session n’avait pas utilisé SET ROLE ou SET SESSION AUTHORIZATION. L’attaquant ne contrôle pas quel identifiant incorrect s’applique. Le texte de la requête provenant de sources moins privilégiées n’est pas un problème ici, parce que SET ROLE et SET SESSION AUTHORIZATION ne sont pas des bacs à sable pour les requêtes non vérifiées. Les versions antérieures à PostgreSQL 17.1, 16.5, 15.9, 14.14, 13.17, et 12.21 sont affectées.

    Le projet PostgreSQL remercie Tom Lane pour avoir signalé ce problème.

     

  • CVE-2024-10979: le changement d’une variable d’environnement de PL/Perl exécute arbitrairement du code.

    • CVSS v3.1 Base Score: 8.8
    • Supported, Vulnerable Versions: 12 - 17.

    Un contrôle incorrect des variables d’environnement dans PostgreSQL PL/Perl permet à un utilisateur de base de données non privilégié de modifier des variables d’environnement sensibles (par exemple PATH). Ceci est souvent suffisant pour permettre l’exécution de code arbitraire, même si l’attaquant n’est pas un utilisateur du système d’exploitation du serveur de base de données. Les versions antérieures à PostgreSQL 17.1, 16.5, 15.9, 14.14, 13.17, et 12.21 sont affectées.

    Le projet PostgreSQL remercie Coby Abrams pour avoir signalé ce problème.

     

Corrections de bogues et améliorations

Cette mise à jour corrige plus de 35 bogues ayant été reportés durant les mois précédents. Les problèmes ci-dessous concernent PostgreSQL 17. Certains de ces problèmes peuvent aussi concerner d’autres versions de PostgreSQL.

Les correctifs sont:

  • correction de l’attachement ou du détachement d’une partition de table avec une contrainte de clé étrangère. Après la mise à jour, les utilisateurs impactés par ce problème devront exécuter des étapes manuelles pour terminer la correction. Merci de consulter la section Mise à jour de cette note de publication pour plus d’information;
  • correction de l’utilisation de la libc comme collation par défaut lorsque LC_CTYPE est C alors qu’LC_COLLATE est une localisation différente. Ceci peut amener des résultats de requêtes incorrects. Si vous avez ces réglages dans votre base de données, il est nécessaire de réindexer les index impactés après la mise à jour. Ce problème ne concerne que PostgreSQL 17.0;
  • plusieurs corrections du Planner de requêtes, incluant l’interdiction de joindre des partitions (partitionwise join) si les collations des partitions ne correspondent pas;
  • correction d’une potentielle mauvaise réponse ou mauvaise erreur du planner pour les actions MERGE ... WHEN NOT MATCHED BY SOURCE;
  • corrections de la validation de COPY FORCE_NOT_NULL et FORCE_NULL;
  • correction d’un crash du serveur quand un appel à la fonction json_objectagg() contient une fonction volatile;
  • vérification qu’il y a une dépendance enregistrée entre une table partitionnée et une méthode d’accès non intégrée spécifiée dans CREATE TABLE ... USING. Ce correctif ne s’occupe que des tables partitionnées créées après cette mise à jour;
  • correction d’un problème d’exécution concurrente lors de la validation d’une transaction sérialisable;
  • correction d’un problème d’exécution concurrente dans un COMMIT PREPARED qui pourrait nécessiter la suppression manuelle d’un fichier après la récupération d’un crash;
  • correction de la vue pg_cursors pour se prémunir d’erreur en excluant les curseurs lorsqu’ils ne sont pas complètement configurés;
  • réduction de la consommation mémoire du décodage logique;
  • correction pour empêcher les fonctions stables de recevoir des valeurs de lignes périmées lorsqu’elles sont appelées à partir de la liste d’arguments d’une instruction CALL et que le CALL se trouve dans un bloc d’EXCEPTION PL/pgSQL;
  • correction d’un crash de JIT pour les systèmes ARM (aarch64) ;
  • la commande \watch de psql traite maintenant les valeurs inférieures à 1ms comme un 0 (pas d’attente entre les exécutions) ;
  • correction de l’impossibilité d’utiliser les informations d’identification d’un utilisateur de réplication dans le fichier de mots de passe (pgpass) ;
  • pg_combinebackup remonte maintenant une erreur si un fichier de sauvegarde incrémentale est présent dans un répertoire qui devrait contenir une sauvegarde complète;
  • correction pour éviter de réindexer les tables et index temporaires dans vacuumdb et parallel reindexdb.

Cette publication met aussi à jour les fichiers de fuseau horaire avec la publication de tzdata 2024b. Cette version de tzdata modifie les anciens noms de zones compatibles avec System-V pour dupliquer les zones géographiques correspondantes; par exemple PST8PDT est maintenant un alias pour America/Los_Angeles. La principale conséquence visible est que pour les horodatages antérieurs à l’introduction de fuseaux horaires normalisés, la zone est considérée comme représentant le temps solaire moyen local pour l’emplacement nommé. Par exemple, dans PST8PDT, une entrée timestamptz telle que 1801-01-01 00:00 aurait auparavant été rendue par 1801-01-01 00:00:00-08, mais elle est maintenant rendue par 1801-01-01 00:00:00-07:52:58.

Des corrections historiques ont également été apportées pour le Mexique, la Mongolie et le Portugal. Notamment, Asia/Choibalsan est maintenant un alias pour Asia/Ulaanbaatar au lieu d’être une zone séparée, principalement parce que les différences entre ces zones se sont avérées être basées sur des données peu fiables.

Mise à jour

Toutes les publications de mises à jour de PostgreSQL sont cumulatives. Comme pour les autres mises à jour mineures, il n’est pas nécessaire d’extraire et de recharger les bases de données ni d’utiliser pg_upgrade pour appliquer cette mise à jour; il suffit simplement d’arrêter PostgreSQL et de mettre à jour les binaires.

Si vous utilisez des tables partitionnées avec des contraintes de clés étrangères pour lesquels vous avez fait des commandes ATTACH PARTITION/DETACH PARTITION, vous allez avoir besoin de faire quelques étapes après cette mise à jour. La correction s’obtient en exécutant une commande ALTER TABLE ... DROP CONSTRAINT sur la table désormais autonome pour chaque contrainte défectueuse, et en ajoutant à nouveau la contrainte. Si l’ajout de la contrainte échoue, vous devez alors rétablir manuellement la cohérence entre les tables référentes et référencées, puis créer à nouveau la contrainte.

Cette requête peut être utilisée pour identifier les contraintes défaillantes et construire les commandes pour les recréer:

SELECT conrelid::pg_catalog.regclass AS "constrained table" , conname AS constraint , confrelid::pg_catalog.regclass AS "references" , pg_catalog.format('ALTER TABLE %s DROP CONSTRAINT %I;' , conrelid::pg_catalog.regclass , conname) AS "drop" , pg_catalog.format('ALTER TABLE %s ADD CONSTRAINT %I %s;' , conrelid::pg_catalog.regclass , conname , pg_catalog.pg_get_constraintdef(oid)) AS "add" FROM pg_catalog.pg_constraint c WHERE contype = 'f' AND conparentid = 0 AND ( SELECT count(*) FROM pg_catalog.pg_constraint c2 WHERE c2.conparentid = c.oid) <> ( SELECT count(*) FROM pg_catalog.pg_inherits i WHERE (i.inhparent = c.conrelid OR i.inhparent = c.confrelid) AND EXISTS ( SELECT 1 FROM pg_catalog.pg_partitioned_table WHERE partrelid = i.inhparent));

Étant donné qu’il est possible qu’une ou plusieurs des étapes ADD CONSTRAINT échouent, vous devriez enregistrer la sortie de cette requête dans un fichier puis exécuter chaque étape.

De plus, si vous utilisez PostgreSQL 17.0 et libc comme fournisseur de collation par défaut, et que le paramètre LC_CTYPE vaut C alors que le paramètre LC_COLLATE a une valeur locale différente, vous allez avoir besoin de reconstruire les index basés sur du texte. Vous pouvez faire cela avec la commande REINDEX INDEX CONCURRENTLY.

Les utilisateurs ayant sauté une ou plusieurs mises à jour peuvent avoir besoin d’étapes additionnelles après la mise à jour. Les notes de publication des versions précédentes fournissent les détails.

Pour plus de détails, se référer à la note de publication de versions.

Liens

Si vous avez des corrections ou suggestions sur cette annonce de publication, merci de les envoyer à la mailing liste publique pgsql-www@lists.postgresql.org.

Loxodata

Capitole du Libre 2024


Bourgogne-Franche-Comté
Publié le
mardi 19 novembre 2024 11h12
Importé le
mardi 19 novembre 2024 13h04

Retour sur le week-end du Capitole du Libre

Le week-end du 16 et 17 novembre 2024 s’est tenue l’édition 2024 du Capitole du Libre. Ce rendez-vous incontournable du logiciel libre à Toulouse s’est déroulé au sein de l’ENSEEIHT. LOXODATA a proposé des présentations qui ont été acceptées (merci au comité de sélection) parmi un large panel de conférences et ateliers dont vous retrouverez le programme complet ici. Parmi les propositions de LOXODATA, vous pouviez voir les sujets suivants:

Une captation vidéo a été effectuée et devrait être mise en ligne prochainement.

Merci à l’équipe de bénévoles pour l’organisation et à l’ENSEEIHT pour l’accueil de l’évènement.

Rendez-vous l’année prochaine pour une autre édition.

Loxodata

Capitole du libre 2024


Bourgogne-Franche-Comté
Publié le
lundi 04 novembre 2024 10h45
Importé le
lundi 04 novembre 2024 13h05

Le Capitole du libre 2024 nous offre un weekend d’échanges autour du logiciel libre à Toulouse au sein de l’ENSEEIHT les 16 et 17 novembre prochains.

Le programme

Vous pouvez retrouver le programme complet ici de l’édition de cette année.

Avec une centaine de conférences et près de 25 ateliers, en plus de keynotes et du village associatif, ce weekend s’annonce riche en partage autour du logiciel libre.

Le Capitole du libre est organisé depuis 2009 par l’association Toulibre.

Cette année, LOXODATA s’est porté partenaire Bronze de l’évènement, avec la présentation de quatres conférences, dont une en partenariat avec le groupe Orange:

L’évènement est gratuit mais il est nécessaire de s’inscrire ici.

Crédits photo: Baptiste Buisson, Toulibre, Capitole du Libre

Loxodata

Capitole du libre 2024


Bourgogne-Franche-Comté
Publié le
lundi 04 novembre 2024 10h45
Importé le
mardi 19 novembre 2024 13h04

Le Capitole du libre 2024 nous offre un weekend d’échanges autour du logiciel libre à Toulouse au sein de l’ENSEEIHT les 16 et 17 novembre prochains.

Le programme

Vous pouvez retrouver le programme complet ici de l’édition de cette année.

Avec une centaine de conférences et près de 25 ateliers, en plus de keynotes et du village associatif, ce weekend s’annonce riche en partage autour du logiciel libre.

Le Capitole du libre est organisé depuis 2009 par l’association Toulibre.

Cette année, LOXODATA s’est porté partenaire Bronze de l’évènement, avec la présentation de quatres conférences, dont une en partenariat avec le groupe Orange:

L’évènement est gratuit mais il est nécessaire de s’inscrire ici.

Crédits photo: Baptiste Buisson, Toulibre, Capitole du Libre

Loxodata

PostgreSQL 17


Bourgogne-Franche-Comté
Publié le
vendredi 27 septembre 2024 10h00
Importé le
vendredi 27 septembre 2024 13h05

Sortie de PostgreSQL 17

26 septembre 2024 - Le PostgreSQL Global Development Group annonce aujourd’hui la publication de PostgreSQL 17, dernière version de la base de données open source de référence.

PostgreSQL 17 repose sur plusieurs décennies de développement, améliorant ses performances et sa mise à l'échelle tout en s’adaptant aux modèles émergents d’accès aux données et à leur stockage. Cette version de PostgreSQL amène des gains de performance généralisés, dont une révision complète de l’implantation de la gestion de la mémoire des opérations de vacuum, des optimisations de l’accès au stockage, des améliorations pour les charges de travail fortement concurrentielles, l’accélération des chargements et exports en masse et des améliorations de l’exécution des requêtes utilisant les index. PostgreSQL 17 possède des fonctionnalités qui profitent aussi bien aux nouvelles charges de travail qu’aux systèmes critiques. On peut citer les ajouts à l’expérience développeur avec la commande SQL/JSON JSON_TABLE et les améliorations de réplication logique qui simplifient la gestion de la haute disponibilité et des mises à jour de version majeures.

«PostgreSQL 17 souligne la manière dont la communauté open source mondiale, qui pilote le développement de PostgreSQL, construit les améliorations qui aident les utilisateurs à tous les niveaux de leur expérience avec la base de données» dit Jonathan Katz, un membre de la «core team» de PostgreSQL. «Qu’il s’agisse d’améliorations pour opérer les bases de données à l'échelle ou de nouvelles fonctionnalités qui contribuent à une expérience développeur agréable, PostgreSQL va parfaire votre expérience de la gestion de données. »

PostgreSQL, système innovant de gestion des données, reconnu pour sa fiabilité et sa robustesse, bénéficie depuis plus de 25 ans d’un développement open source par une communauté mondiale de développeurs et développeuses. Il est devenu le système de gestion de bases de données relationnelles de référence pour les organisations de toute taille.

Des gains de performance sur l’ensemble du moteur

Le processus de vacuum de PostgreSQL, critique pour le bon déroulement des opérations, nécessite des ressources du serveur de l’instance pour s’exécuter. PostgreSQL 17 introduit une nouvelle structure interne de la mémoire pour vacuum qui divise par 20 l’utilisation mémoire. PostgreSQL améliore ainsi la vitesse des opérations de vacuum tout en réduisant l’usage des ressources partagées, les rendant disponibles à votre charge de travail.

PostgreSQL 17 poursuit l’amélioration des performances de sa couche d’entrées/sorties. Les charges de travail hautement concurrentes pourront voir leurs performances en écriture doubler grâce à une amélioration sur le traitement du write-ahead log (WAL). De plus, la nouvelle interface d’entrées/sorties par flux accélère les lectures séquentielles (lecture de toutes les données d’une table). Cette même fonctionnalité bénéficie aussi à ANALYZE qui peut ainsi mettre à jour les statistiques du planificateur de requêtes bien plus rapidement.

PostgreSQL 17 étend ses gains de performance à l’exécution de requêtes. Il améliore la performance des requêtes avec des clauses IN utilisant des index de type B-tree, la méthode d’indexation par défaut de PostgreSQL. De plus, il est maintenant possible de paralléliser la construction des index BRIN. PostgreSQL 17 comporte plusieurs améliorations dans la planification des requêtes, dont des optimisations sur les contraintes NOT NULL et des améliorations dans le traitement des common table expressions (les requêtesWITH). Cette version prend en charge plus d’instructions SIMD (Single Instruction/Multiple Data) pour accélérer les calculs, incluant l’usage d’AVX-512 pour la fonction bit_count.

Amélioration pour les développeurs

PostgreSQL a été la première base de données relationnelle à ajouter le support de JSON (2012), et PostgreSQL 17 complète son implantation du standard SQL/JSON. JSON_TABLE est maintenant disponible dans PostgreSQL 17, permettant aux développeurs de convertir des données JSON dans une table standard PostgreSQL. PostgreSQL 17 supporte maintenant les constructeurs SQL/JSON (JSON, JSON_SCALAR, JSON_SERIALIZE) et les fonctions de requêtage (JSON_EXISTS, JSON_QUERY, JSON_VALUE), offrant de nouvelles possibilités aux développeurs d’interagir avec leurs données JSON. Cette version ajoute plus d’expressions jsonpath, avec un accent sur la conversion de données JSON vers des types de données natifs de PostgreSQL comme les types numériques, booléens, chaînes de caractères et date/heure.

PostgreSQL 17 rajoute des fonctionnalités à la commande MERGE, utilisée pour les mises à jour conditionnelles, en incluant une clause RETURNING et la capacité de mettre à jour les vues. En prime, PostgreSQL 17 dispose de nouvelles capacités de chargement et d’export de données en masse pouvant aller jusqu'à doubler la performance lors de l’export de grandes lignes en utilisant la commande COPY. COPY bénéficie d’améliorations de performance, lorsque les encodages de la source et de la destination correspondent et inclut une nouvelle option, ON_ERROR, qui permet la poursuite d’un import même en cas d’erreur d’insertion.

Cette version étend les fonctionnalités de gestion des données à la fois dans les partitions et dans les données distribuées sur des instances PostgreSQL distantes. PostgreSQL 17 supporte l’utilisation de colonnes identité et des contraintes d’exclusions sur des tables partitionnées. Les foreign data wrapper PostgreSQL (postgres_fdw), qui sont utilisés pour exécuter des requêtes sur des instances PostgreSQL distantes, peuvent maintenant transmettre les sous-requêtes EXISTS et IN vers un serveur distant pour un traitement plus efficace.

PostgreSQL 17 inclut un fournisseur de collation interne, indépendant de la plateforme et immutable permettant de garantir l’immutabilité des résultats et fournit une sémantique de tri similaire à la collation C mais avec l’encodage UTF-8 au lieu de SQL_ASCII. L’utilisation de ce nouveau fournisseur de collation garantit que les résultats triés des requêtes basées sur du texte seront identiques, indépendamment de l’environnement.

Améliorations de la réplication logique pour la haute disponibilité et les mises à jour majeures

La réplication logique est utilisée pour transmettre des données en temps réel dans de nombreux cas d’usage. Toutefois, avant cette version, une mise à jour majeure nécessitait de supprimer les slots de réplication logique, ce qui obligeait à resynchroniser les données vers les souscripteurs après la mise à jour. À partir de PostgreSQL 17, les mises à jour utilisant la réplication logique seront simplifiées: elles ne nécessiteront plus de supprimer les slots de réplication logique.

PostgreSQL 17 inclut désormais un contrôle des bascules sur incident pour la réplication logique, ce qui la rend plus résiliente dans les environnements hautement disponibles.

Enfin, PostgreSQL 17 introduit l’outil en ligne de commande pg_createsubscriber pour convertir un réplica physique en réplica logique.

Autres options de gestion de la sécurité et des opérations de maintenance

PostgreSQL 17 étend les possibilités de gestion du cycle de vie des systèmes de bases de données. Une nouvelle option TLS, sslnegotiation, est ajoutée, qui permet aux utilisateurs d’effectuer une négociation TLS directe lors de l’utilisation d’ALPN (enregistrée comme postgresql dans le répertoire ALPN). PostgreSQL 17 ajoute le rôle prédéfini pg_maintain, qui donne les privilèges d’effectuer des opérations de maintenance aux utilisateurs.

pg_basebackup, l’utilitaire de sauvegarde intégré à PostgreSQL, supporte désormais les sauvegardes incrémentales et ajoute l’utilitaire pg_combinebackup pour reconstruire une sauvegarde complète. En complément, pg_dump intègre une nouvelle option, appelée --filter, qui permet de préciser un fichier contenant la liste des objets à intégrer lors de la génération d’un export.

PostgreSQL 17 ajoute des améliorations aux fonctionnalités de supervision et d’analyse. EXPLAIN présente maintenant le temps passé sur les lectures et écritures de blocs et intègre deux nouvelles options: SERIALIZE et MEMORY, utiles pour voir le temps passé dans la conversion de données lors des transmissions réseau, et la quantité de mémoire utilisée. PostgreSQL 17 indique désormais la progression du vacuum des index. Cette version ajoute la vue système pg_wait_events, qui combinée avec pg_stat_activity, donne plus d’informations sur les raisons pour lesquelles une session active est en attente.

Fonctionnalités additionnelles

De nombreuses autres fonctionnalités ont été ajoutées à PostgreSQL 17. Elles peuvent aussi être utiles dans vos cas d’usage. Vous pouvez vous référer aux notes de version (en anglais) pour consulter la liste complète des fonctionnalités modifiées ou ajoutées.

À propos de PostgreSQL

PostgreSQL est le système de gestion de bases de données libre de référence. Sa communauté mondiale est composée de plusieurs milliers d’utilisateurs, utilisatrices, contributeurs, contributrices, entreprises et institutions. Le projet PostgreSQL, démarré il y a plus de 30 ans à l’université de Californie, à Berkeley, a atteint aujourd’hui un rythme de développement sans pareil. L’ensemble des fonctionnalités proposées est mature, et dépasse même celui des systèmes commerciaux leaders sur les fonctionnalités avancées, les extensions, la sécurité et la stabilité.

Liens

En savoir plus sur les fonctionnalités

Pour de plus amples informations sur les fonctionnalités ci-dessus et toutes les autres, vous pouvez consulter les liens suivants:

Où télécharger

Il existe plusieurs façons de télécharger PostgreSQL 17, dont:

D’autres outils et extensions sont disponibles sur le PostgreSQL Extension Network.

Documentation

La documentation au format HTML et les pages de manuel sont installées avec PostgreSQL. La documentation peut également être consultée en ligne ou récupérée au format PDF.

Licence

PostgreSQL utilise la licence PostgreSQL, licence «permissive» de type BSD. Cette licence certifiée OSI est largement appréciée pour sa flexibilité et sa compatibilité avec le monde des affaires, puisqu’elle ne restreint pas l’utilisation de PostgreSQL dans les applications propriétaires ou commerciales. Associée à un support proposé par de multiples sociétés et une propriété publique du code, sa licence rend PostgreSQL très populaire parmi les revendeurs souhaitant embarquer une base de données dans leurs produits sans avoir à se soucier des prix de licence, des verrous commerciaux ou modifications des termes de licence.

Contacts

Site internet

Courriel

Images et logos

Postgres, PostgreSQL et le logo éléphant (Slonik) sont des marques déposées de l’Association de la Communauté PostgreSQL. Si vous souhaitez utiliser ces marques, vous devez vous conformer à la politique de la marque.

Support professionnel et dons

PostgreSQL bénéficie du support de nombreuses sociétés, qui financent des développeurs et développeuses, fournissent l’hébergement ou un support financier. Les plus fervents supporters sont listés sur la page des sponsors.

Il existe également une très grande communauté de sociétés offrant du support PostgreSQL, du consultant indépendant aux entreprises multinationales.

Les dons au PostgreSQL Global Development Group, ou à l’une des associations à but non lucratif, sont acceptés et encouragés.

Crédits photo Richard Jacobs.

Loxodata

PGConf.EU 2024 à Athènes


Bourgogne-Franche-Comté
Publié le
mercredi 18 septembre 2024 15h30
Importé le
mercredi 18 septembre 2024 21h04

Cette année encore, LOXODATA participera à la PGConf Europe 2024 qui se tiendra du 22 au 25 octobre au Divani Caravel Hotel à Athènes. LOXODATA sera partenaire Bronze de l'évènement.

La conférence reprend le format habituel d’une journée de formations, suivi de trois journées de présentations réparties sur trois salles en parallèle. Il est toujours possible de s’inscrire à l'évènement.

Ce sera la quatorzième année consécutive que se déroule la PGConf Europe, hormis les années 2020 et 2021 pour les raisons que l’on connaît tous.

C’est l’occasion pour tous les acteurs du projet PostgreSQL de se rencontrer et partager, quel que soit son niveau et l’utilisation que l’on peut avoir de PostgreSQL.

Le programme

Vous pouvez retrouver le programme de l'évènement sur le site de la conférence.

Magnus Hagander en maître de conférence initiera l'évènement avec un talk de bienvenue, puis laissera place à Stacey Haysler pour une présentation générale sur PostgreSQL, là où l’année dernière Simon Riggs nous faisait la rétrospective des vingt dernières années du projet PostgreSQL et perspectives des vingt prochaines années.

Puis, vous aurez à loisir de choisir parmi une cinquantaine de présentations sur des sujets divers: techniques, communautaires ou grand public.

Nous espérons vous retrouver dans les allées de cette prochaine PGConf Europe 2024 afin de partager cet évènement annuel important pour la communauté PostgreSQL en Europe.

Crédits photo: Kylie Docherty et PostgreSQL Europe

Loxodata

PostgreSQL 17 en RC1


Bourgogne-Franche-Comté
Publié le
vendredi 06 septembre 2024 12h00
Importé le
vendredi 06 septembre 2024 13h04

Le PostgreSQL Global Development Group a annoncé la publication de la première Release Candidate de PostgreSQL 17. En tant que Release Candidate, la version de PostgreSQL 17 RC1 sera quasiment identique à la publication initiale de PostgreSQL 17, cependant, des corrections pourront être appliquées avant la mise à disposition de la version finale de PostgreSQL 17.

La date de publication pour la version finale de PostgreSQL 17 est prévue au 26 septembre 2024. Consulter la section Planning des publications pour plus de détails.

Mise à jour vers la RC1 de PostgreSQL 17

Pour mettre à jour votre version de PostgreSQL depuis une précédente version de PostgreSQL, vous pouvez utiliser la même stratégie que pour mettre à jour vers toute version majeure de PostgreSQL (par exemple avec la commande pg_upgrade ou pg_dump/pg_restore).

Pour plus d’information, consultez la section mise à jour de la documentation officielle: https://www.postgresql.org/docs/17/upgrading.html

Changements depuis la bêta 3

Plusieurs corrections ont été apportées à PostgreSQL 17 suite aux remontées d’utilisateurs ayant testé la bêta 3.

Dont notamment:

  • suppression de la fonctionnalité de MERGE/SPLIT d’une partition
  • amélioration des performances suite à un correctif autour de la réplication logique et des sous-transactions

Pour la liste complète des corrections, veuillez consulter la page des tickets ouverts.

Planning des publications

Il s’agit de la première Release Candidate de la version 17. Sauf à découvrir un problème imposant un nouveau délai ou une nouvelle Release Candidate, PostgreSQL 17 devrait être publiée le 26 septembre 2024.

Pour plus d’information, veuillez consulter la page Beta Testing.

Liens

Loxodata

PostgreSQL 16.4 et autres correctifs


Bourgogne-Franche-Comté
Publié le
vendredi 09 août 2024 10h00
Importé le
vendredi 09 août 2024 13h04

Le PGDG a publié une mise à jour de toutes les versions supportées de PostgreSQL. Il s’agit des versions 16.4, 15.8, 14.13, 13.16 et 12.20, ainsi que la troisième publication Bêta de PostgreSQL 17. Cette publication corrige une vulnérabilité de sécurité et près de 55 bogues repérés durant les derniers mois.

Pour la liste complète des changements, se référer à la section Notes de publication.

Fin de support de PostgreSQL 12

La version 12 de PostgreSQL ne recevra plus aucun correctif à partir du 14 novembre 2024. Si vous utilisez une version 12 de PostgreSQL en production, nous vous recommandons de planifier une mise à jour vers une version plus récente et supportée de PostgreSQL. Se référer à notre politique de versionnement pour plus d’informations.

Problèmes de sécurité

CVE-2024-7348: le remplacement de relations dans PostgreSQL lors de l’utilisation de pg_dump permet d’exécuter du code SQL arbitraire.

CVSS v3.1 Base Score: 8.8

Versions vulnérables et supportées: 12 - 16.

Un assaillant capable de créer et supprimer des objets non-temporaire pourrait injecter du code SQL qui serait exécuté par une session pg_dump concurrente avec les privilèges du rôle exécutant pg_dump (qui est souvent un super-utilisateur). L’attaque implique le remplacement d’une séquence ou d’un objet similaire avec une vue ou une table étrangère qui exécuterait du code malicieux. Pour se prémunir de cela, l’introduction d’un nouveau paramètre restrict_nonsystem_relation_kind permet de désactiver l’expansion de vues autres qu’internes ainsi que l’accès aux tables étrangères et apprend à pg_dump à le définir lorsqu’il est disponible. Notez que l’attaque est bloquée lorsque pg_dump et le serveur sauvegardé sont suffisamment récents pour avoir ce correctif.

Le projet PostgreSQL remercie Noah Misch pour avoir signalé ce problème.

Corrections des bogues et améliorations

Cette mise à jour corrige près de 55 bogues qui ont été signalés depuis ces derniers mois. Les problèmes listés ci-dessous affectent la version 16 de PostgreSQL. Certaines peuvent aussi affecter d’autres versions supportées de PostgreSQL.

  • empêche des résultats incorrects de plans “Merge Right Anti Join”, lorsque la relation interne est connue pour avoir une clé de jointure unique, la fusion pourrait alors se faire quand il y a des clés de jointure dupliquées dans la relation externe;
  • empêche une boucle infinie dans VACUUM;
  • corrige la configuration de l’élagage d’une partition pendant ALTER TABLE DETACH ... PARTITION CONCURRENTLY;
  • corrige le comportement de fonctions stables utilisées comme argument d’un appel CALL;
  • la fonction pg_sequence_last_value() retourne maintenant NULL plutôt que de remonter une erreur quand elle est appelée sur une séquence non tracée dans une instance secondaire et sur séquence temporaire d’une autre session;
  • corrige l’analyse des opérateurs ignorés dans websearch_to_tsquery() ;
  • vérifie correctement la possibilité de mettre à jour les colonnes cibles des vues par INSERT ... DEFAULT;
  • verrouille les séquences détenues lors de ALTER TABLE ... SET LOGGED|UNLOGGED;
  • ne remonte par d’erreurs si un déclencheur AFTER en file d’attente n’existe plus;
  • Corrige la sélection d’un index arbitral pour INSERT ... ON CONFLICT quand l’index souhaité a des expressions ou des prédicats, par exemple à travers une vue actualisable;
  • refuse la modification d’une table temporaire d’une autre session avec ALTER TABLE;
  • corrige la manipulation des statistiques étendues sur expressions dans CREATE TABLE ... LIKE STATISTICS;
  • corrige l’échec du recalcul des sous-requêtes générées par les agrégats MIN() ou MAX() ;
  • désactive le caractère de soulignement dans les paramètres positionnés;
  • empêche une défaillance lorsqu’une fonction JIT en ligne remonte une erreur;
  • corrige la manipulation de sous-transactions d’une transaction préparée lors du démarrage d’une instance secondaire;
  • empêche l’initialisation incorrecte d’un créneau de réplication logique;
  • corrige une fuite mémoire dans le processus d’envoi des WAL de réplication logique quand la publication change pour une table partitionnée pour laquelle les partitions ont des types de données d’enregistrement qui diffèrent physiquement de la table;
  • désactive la création de tickets de sessions TLS avec état avec OpenSSL;
  • corrige la manipulation par PL/pgSQL de plages d’entier contenant des caractères de soulignement (par exemple, FOR i IN 1_001..1_002) ;
  • corrige l’incompatibilité entre PL/Perl et Perl 5.40;
  • plusieurs correctifs liés à des fonctions et déclencheurs récursifs en PL/Python;
  • garantit le fait que pg_restore -l rapporte les tables dépendantes des entrées contenues correctement;
  • pg_stat_statements passe maintenant un identifiant de requête pour les ordres utilitaires apparaissant dans des fonctions en langage SQL;
  • corrige postgres_fdw lors d’une correspondance entre une table étrangère et une vue distante non triviale;
  • postgres_fdw n’envoie plus la clause FETCH FIRST WITH TIES à un serveur distant.

Mise à jour

Toutes les publications de mises à jour de PostgreSQL sont cumulatives. Comme pour les autres mises à jour mineures, il n’est pas nécessaire d’extraire et de recharger les bases de données ni d’utiliser pg_upgrade pour appliquer cette mise à jour; il suffit simplement d’arrêter PostgreSQL et de mettre à jour les binaires.

Les utilisateurs ayant sauté une ou plusieurs mises à jour peuvent avoir besoin d’étapes additionnelles après la mise à jour. Les notes de publication des versions précédentes fournissent les détails.

Pour plus de détails, se référer à la note de publication de versions.

Note à propos de PostgreSQL 17 Bêta

Cette publication marque la troisième publication bêta de PostgreSQL 17 et rapproche d’une étape la communauté de la disponibilité probablement vers la fin du troisième trimestre.

Dans l’esprit de la communauté PostgreSQL «open-source», nous vous encourageons fortement à tester les nouvelles fonctionnalités de PostgreSQL sur vos systèmes pour nous aider à éliminer les bogues et autres problèmes existants. Bien que nous ne recommandons pas l’utilisation de PostgreSQL 17 Bêta 3 dans des environnements de production, nous vous encourageons à trouver des moyens de tester les applications avec cette version.

Vos tests et retours aideront la communauté à s’assurer que la publication de PostgreSQL 17 maintiendra nos standards pour livrer une version fiable et stable de la base de données relationnelle «open-source» la plus avancée du monde. Merci de prendre connaissance du processus de publication et de comment vous pouvez contribuer: (https://www.postgresql.org/developer/beta/).

Mettre à jour vers PostgreSQL 17 Bêta 3

Afin de mettre à jour vers PostgreSQL 17 Bêta 3 à partir d’une publication antérieure de PostgreSQL, vous aurez besoin d’utiliser une stratégie similaire à la mise à jour entre versions majeures de PostgreSQL (par exemple: pg_upgrade ou pg_dump/pg_restore). Pour plus d’information, merci de prendre connaissance de la documentation sur la mise à jour.

Changements depuis la Bêta 2

Les corrections et changements dans PostgreSQL 17 Beta 3 incluent:

  • renommage du paramètre standby_slot_names vers synchronized_standby_slots:
  • plusieurs correctifs sur SQL/JSON;
  • corrections de pg_combinebackup --clone;
  • correction de pg_createsubscriber pour fonctionner avec un nom de base de données contenant un caractère espace;
  • pg_createsubscriber supprime maintenant les souscriptions préexistantes lors de l’exécution sur une base de données cibles;
  • amélioration de l’efficacité lors de la récupération d’information sur une souscription avec pg_upgrade;
  • correction du comportement d’un repli TLS avec sslmode=prefer en erreur quand un serveur envoie une erreur pendant le processus de démarrage;
  • documentation d’un cas d’erreur avec une sauvegarde incrémentale de pg_basebackup sur une instance secondaire lorsqu’il est exécuté immédiatement après la sauvegarde précédente.
  • Correction d’un problème où pg_upgrade --transaction-size peut faire qu’un processus d’arrière-plan (backend) consomme de la mémoire dans un ordre de grandeur de plus;

Merci de se référer aux notes de publication pour la liste complète des nouveautés et changements, ainsi qu’aux items ouverts de PostgreSQL pour plus de détails sur les changements et correctifs.

Liens

Si vous avez des corrections ou suggestions sur cette annonce de publication, merci de les envoyer à la mailing list publique pgsql-www@lists.postgresql.org.

Loxodata

IA et neutralité carbone


Bourgogne-Franche-Comté
Publié le
vendredi 02 août 2024 09h00
Importé le
vendredi 09 août 2024 13h04

Neutralité carbone?

Les géants de la tech américaine comme Google et Microsoft se sont engagés il y a quelques années à tendre vers la neutralité carbone en 2030. Mais qu’est-ce que la neutralité carbone? Selon le Parlement Européen, la neutralité carbone est “l’équilibre entre les émissions de carbone et l’absorption du carbone de l’atmosphère par les puits de carbone”.

L’Union européenne s’est fixé comme objectif de neutralité carbone les années 2050. Plusieurs actions sont visées pour essayer d’atteindre cet objectif, dont notamment:

  • Décarboner totalement la production d’énergie à l’horizon 2050
  • Réduire la consommation d’énergie dans tous les secteurs
  • Diminuer les émissions non liées à la consommation d’énergie
  • Augmenter les puits de carbone (naturels et technologiques)

Or, avec l’avènement de l’IA générative, et des cryptomonnaies encore avant, on voit que l’atteinte de la neutralité carbone risque d’être bousculée.

IA générative et datacenters

On ne peut passer à côté désormais de tous les services d’intelligence artificielle, et notamment l’IA générative, tant les grands groupes se livrent une bataille sans merci, menant à une course à la puissance de calcul. Ce qu’il faut voir derrière ces services, c’est la demande toujours croissante de nouveaux datacenters pour stocker les innombrables données nécessaires aux algorithmes d’IA générative. Ce qui pousse à consommer de plus en plus d’énergie, et donc à émettre plus de gaz à effet de serre.

Cette augmentation s’est élevée à 48% sur cinq ans d’après le rapport de Google, et représentait pour la seule année 2023, près de 17,2 millions de tonnes de CO2.

En plus de mettre en tension les réseaux d’énergie, les ressources en eau sont aussi à surveiller de près, car c’est bien l’eau qui est utilisée pour refroidir ces grands centres de données. On peut aussi noter la demande toujours forte en matières premières pour équiper ces datacenters de puces de dernière génération d’un fabricant taïwanais bien connu.

Depuis l’année dernière, Google comme d’autres sociétés essaye aussi une autre stratégie pour atteindre la neutralité carbone, celle d’investir dans des crédits de suppression carbone en plus de chercher à augmenter l’efficacité énergétique de ces datacenters.

pg_vector

En attendant, PostgreSQL est entré dans la course de l’IA générative afin de proposer des fonctionnalités facilitant son intégration. L’extension pg_vector est une extension créée il y a maintenant trois ans afin de pouvoir stocker des données de type vecteur, et de faire de la recherche de similarité vectorielle efficace en proposant plusieurs types d’index et d’opérations de calcul de distance.

En faisant ce choix, PostgreSQL peut devenir alors une base de données vectorielle offrant ses fonctionnalités éprouvées, avec des requêtes rendues plus efficaces pour ce type de données, à l’image du support du JSON par PostgreSQL.

Le mot de la fin

Les enjeux sont importants et les objectifs ambitieux, mais il est important de s’y pencher, car nous sommes tous acteurs, et face au réchauffement climatique il est urgent d’agir. On peut également espérer rendre cette consommation de l’IA moins énergivore et plus efficiente.

Liens

Loxodata

PostgreSQL 17 bêta 2


Bourgogne-Franche-Comté
Publié le
jeudi 27 juin 2024 16h00
Importé le
jeudi 27 juin 2024 21h04

PostgreSQL 17 Bêta 2 publiée

Le PostgreSQL Global Development Group annonce la disponibilité de la deuxième bêta de PostgreSQL 17 en téléchargement. Cette publication contient un aperçu des fonctionnalités qui seront disponibles dans la version finale de PostgreSQL 17. Des modifications peuvent toutefois intervenir d’ici là.

Vous pouvez trouver des informations sur toutes les fonctionnalités et les changements de PostgreSQL 17 dans les notes de version

Dans l’esprit de la communauté open source PostgreSQL, nous vous encourageons fortement à tester les nouvelles fonctionnalités de PostgreSQL dans vos systèmes de base de données. Ceci afin de nous aider à éliminer les bogues et autres problèmes qui pourraient exister. Bien que nous ne vous conseillions pas de faire fonctionner PostgreSQL 17 Bêta 2 dans vos environnements de production, nous vous encourageons à trouver des moyens de faire fonctionner votre charge applicative typique avec cette publication bêta.

Vos tests et vos commentaires aideront la communauté à s’assurer que PostgreSQL 17 respecte nos standards de stabilité et fiablité. Vous pouvez également vous renseigner sur notre processus de beta testing et comment y contribuer.

Mise à jour vers PostgreSQL 17 Bêta 2

Pour mettre à jour vers PostgreSQL 17 Beta 2 à partir d’une précédente version de PostgreSQL, vous aurez besoin d’utiliser une stratégie similaire à la mise à jour entre versions majeure de PostgreSQL (i.e. pg_upgrade ou pg_dump/pg_restore). Pour plus d’information, merci de consulter la section de la documentation concernant les mises à jour.

Changement depuis la publication Bêta 1

Les corrections et changement depuis la publication PostgreSQL 17 Bêta 2 incluent:

  • Appliquer correctement le comportement par défaut de la clause ON EMPTY lorsqu’elle n’est pas présente dans la requête SQL/JSON;
  • Correction d’un problème avec la fonction pg_logical_slot_get_changes relative à la gestion de la propriété de la ressource;
  • Plusieurs correctifs liés à la nouvelle structure de données pour les données relative à la commande VACUUM.

Veuillez consulter les notes de publication pour une liste complète des nouveautés et changements: https://www.postgresql.org/docs/17/release-17.html

Tests pour le débogage et la compatibilité

La stabilité de chaque publication de PostgreSQL dépend de vous, la communauté. En testant la version à venir avec votre charge et vos outils de tests, vous pourrez nous aider à trouver les bogues et régressions avant la publication de PostgreSQL 17.

Étant donné qu’il s’agit d’une version bêta, des changements mineurs dans le comportement de la base de données, des détails et des APIs sont toujours possibles. Vos retours et tests aideront à déterminer les ajustements finaux des nouvelles fonctionnalités.

La qualité des tests aide à déterminer le moment de la publication finale.

Une liste des problèmes ouverts est publiquement disponible dans le wiki de PostgreSQL. Vous pouvez rapporter des bogues en utilisant le formulaire présent sur le site web de PostgreSQL: https://www.postgresql.org/account/submitbug/.

Planning Bêta

Il s’agit de la deuxième publication bêta de la version 17. Le projet PostgreSQL publiera autant de bêtas que cela est nécessaire pour tester. Celles-ci seront suivies par une ou plusieurs publications de versions candidates, jusqu’à la publication de la version finale autour de septembre ou octobre 2024.

Pour plus d’information, veuillez consulter la page Beta Testing.

Liens

Crédits photo: Carlos Gonzalez

Loxodata

Retour sur POSETTE 2024


Bourgogne-Franche-Comté
Publié le
mardi 25 juin 2024 09h00
Importé le
mardi 25 juin 2024 13h04

POSETTE vous dites?

La semaine passée s’est déroulé l’évènement virtuel et gratuit, “POSETTE: an event for Postgres 2024”, organisé par l’équipe PostgreSQL chez Microsoft. Cette année était la troisième édition de l’évènement, qui s’appelait auparavant Citus Con et organisé par Citus Data, racheté en 2019 par Microsoft.

Que signifie l’acronyme POSETTE? Claire Giordano qui fait partie du comité de sélection de l’évènement chez Microsoft, nous l’explique dans ce post: P.O.S.E.T.T.E - Postgres Open Source Ecosystem Talks Training & Education et a été inspiré par le nom du FOSDEM, un évènement majeur pour les développeurs.

Claire nous partage également le processus de sélection des sujets dans cet article. C’est intéressant de voir également l’envers du décor et ce qui amène les organisateurs d’évènements à sélectionner tel ou tel sujet pour les conférences.

Pour en revenir à l’évènement POSETTE 2024, il s’est déroulé sur trois jours, du 11 au 13 juin, avec pas moins de 42 présentations (dont 4 keynotes), 44 orateurs et quatre diffusions en direct sur deux fuseaux horaires différents.

Le format virtuel de l’évènement a permis à tous de participer, sans les frais inhérents aux autres conférences, les contraintes professionnelles et familliales. Il était possible de rejoindre un serveur Discord pour l’occasion afin de poser des questions aux orateurs et de discuter avec les autres participants.

Le programme 2024

Vous pouvez retrouver la rediffusion des conférences ci-dessous pour les trois journées:

Les sujets des conférences étaient assez équilibrés, et ont embrassé plusieurs thématiques autour du noyau de PostgreSQL (15 sujets), de son écosystème (8 sujets), de la version Azure PostgreSQL de Microsoft (8 sujets), de l’IA (7 sujets) et de sujets plus communautaires (4 sujets).

On voit que les sujets autour de l’IA et de l’adoption de PostgreSQL dans cet écosystème ont été nombreux, mais pas seulement. Les sujets sur PostgreSQL et son écosystème ont été majoritaires, avec beaucoup de sujets techniques intéressants. Pour n’en citer que quelques-uns: présentation du planificateur/optimiseur de requêtes PostgreSQL, les bonnes pratiques sur partionnement, tout savoir sur le RLS (row level security), optimisation de requêtes versus optimisation de configuration, réplication physique et logique, JSONB et schéma.

Le format virtuel de l’évènement peut déplaire à certains, mais pour ma part, je trouve qu’il est tout à fait approprié pour fédérer le plus de monde possible autour de PostgreSQL. Mais si vous avez l’occasion de participer en personne à une des nombreuses conférences autour de PostgreSQL, il ne faut pas hésiter: la prochaine PGConf européenne se tiendra à Athènes du 22 au 25 octobre.

Crédits photo: Citus Data et Microsoft

Loxodata

Réplication logique et Patroni


Bourgogne-Franche-Comté
Publié le
lundi 24 juin 2024 10h55
Importé le
lundi 24 juin 2024 13h04

Dans ce précédent article, nous vous présentions l'évolution des fonctionnalités de la réplication logique apportées par les différentes versions de PostgreSQL et dans cet autre article, nous avions vu la mise en place d’une réplication logique.

Réplication logique et haute disponibilité

Dans le cadre de la haute disponibilité en réplication physique avec un primaire et plusieurs secondaires, la bascule lors d’un incident va bloquer la réplication logique.

Pour rappel, la mise en place de la réplication logique implique de créer un slot de réplication sur le primaire, ce slot permettant de conserver les fichiers WAL requis par les souscriptions (un slot de réplication par souscription).

Lors d’une bascule, le slot de réplication logique créé initialement sur le primaire ne sera pas présent sur le secondaire promu. La souscription abonnée à cette publication se retrouvera alors bloquée car ne recevant plus les changements émis par la publication, le temps de recréer un slot de réplication logique, avec le risque de perdre des données pendant la bascule.

Nativement, PostgreSQL n’offre pas encore de solution intégrée pour la gestion des slots de réplication pendant une bascule. Mais la prochaine version majeure de PostgreSQL, la version 17, va commencer à intégrer des changements pour y pallier.

En attendant, vous pouvez utiliser l’extension pg_failover_slots. Sinon, si vous utilisez Patroni, il est possible de configurer ce dernier pour gérer les slots de réplication. C’est l’objet de la suite de l’article.

Patroni, c’est quoi déjà?

Patroni est un framework de gestion de cluster PostgreSQL pour assurer la haute disponibilité de service, en assurant une bascule automatique et offrant une gestion de la configuration centralisée.

La mise en place d’un cluster Patroni pourra faire l’objet d’un prochain article, mais pour l’instant nous allons considérer que vous possédez déjà un cluster Patroni opérationnel avec une instance primaire, et deux instances secondaires.

Configuration

Première étape à la mise en place d’une réplication logique avec Patroni, il faut passer le paramètre wal_level à logical afin d’ajouter dans les fichiers WAL toutes les informations nécessaires au support du décodage logique.

Nous utiliserons la commande patronictl qui permet de gérer le cluster Patroni et vérifier son état.

Vérifier le statut et la topologie actuelle d’un cluster avec l’option topology:

postgres@pgdeb01:~$ patronictl -c /etc/patroni/patroni.yml topology + Cluster: loxodemo (7382147555638198668) ------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +-----------+-------------+---------+-----------+----+-----------+ | pgdeb01 | 10.200.0.11 | Leader | running | 1 | | | + pgdeb02 | 10.200.0.12 | Replica | streaming | 1 | 0 | | + pgdeb03 | 10.200.0.13 | Replica | streaming | 1 | 0 | +-----------+-------------+---------+-----------+----+-----------+

Consulter la configuration du cluster avec l’option show-config:

postgres@pgdeb01:~$ patronictl -c /etc/patroni/patroni.yml show-config loop_wait: 10 maximum_lag_on_failover: 1048576 postgresql: parameters: archive_command: pgbackrest --stanza=loxodemo archive-push %p archive_mode: 'on' recovery_conf: restore_command: pgbackrest --stanza=loxodemo archive-get %f %p use_pg_rewind: false use_slots: false retry_timeout: 10 ttl: 30

Nous modifions le paramètre PostgreSQL wal_level à logical avec l’option edit-config:

postgres@pgdeb01:~$ patronictl -c /etc/patroni/config.yml edit-config --- +++ @@ -4,6 +4,7 @@ parameters: archive_command: pgbackrest --stanza=loxodemo archive-push %p archive_mode: 'on' + wal_level: 'logical' recovery_conf: restore_command: pgbackrest --stanza=loxodemo archive-get %f %p use_pg_rewind: false Apply these changes? [y/N]: y Configuration changed

Le changement de ce paramètre nécessite un redémarrage des instances PostgreSQL. Le redémarrage est indiqué par Patroni dans la sortie de l’option list, dans la colonne Pending restart:

postgres@pgdeb01:~$ patronictl -c /etc/patroni/config.yml list + Cluster: loxodemo (7382147555638198668) ----+----+-----------+-----------------+-----------------------------+ | Member | Host | Role | State | TL | Lag in MB | Pending restart | Pending restart reason | +---------+-------------+---------+-----------+----+-----------+-----------------+-----------------------------+ | pgdeb01 | 10.200.0.11 | Leader | running | 1 | | * | wal_level: replica->logical | | pgdeb02 | 10.200.0.12 | Replica | streaming | 1 | 0 | * | wal_level: replica->logical | | pgdeb03 | 10.200.0.13 | Replica | streaming | 1 | 0 | * | wal_level: replica->logical | +---------+-------------+---------+-----------+----+-----------+-----------------+-----------------------------+

Il faut alors procéder au redémarrage en utilisant l’option restart:

postgres@pgdeb01:~$ patronictl -c /etc/patroni/config.yml restart --force loxodemo + Cluster: loxodemo (7382147555638198668) ----+----+-----------+-----------------+-----------------------------+ | Member | Host | Role | State | TL | Lag in MB | Pending restart | Pending restart reason | +---------+-------------+---------+-----------+----+-----------+-----------------+-----------------------------+ | pgdeb01 | 10.200.0.11 | Leader | running | 1 | | * | wal_level: replica->logical | | pgdeb02 | 10.200.0.12 | Replica | streaming | 1 | 0 | * | wal_level: replica->logical | | pgdeb03 | 10.200.0.13 | Replica | streaming | 1 | 0 | * | wal_level: replica->logical | +---------+-------------+---------+-----------+----+-----------+-----------------+-----------------------------+ Success: restart on member pgdeb01 Success: restart on member pgdeb02 Success: restart on member pgdeb03

Il peut être intéressant aussi de revoir la configuration des paramètres suivants, qui demandent aussi un redémarrage de PostgreSQL:

max_replication_slots: 10 max_wal_senders: 10 max_worker_processes: 10
  • max_replication_slots (défaut à 10) indiquant le nombre de slots de réplication maximum (réplication logique et physique). Doit être au moins égal au nombre de réplica et de souscription (pour chaque souscription, un apply worker et plusieurs tablesync worker);
  • max_wal_senders (défaut à 10) doit être équivalent ou plus au nombre de slots de réplication, plus le nombre de réplica présents;
  • max_worker_processes (défaut à 8) doit être supérieur aux valeurs précédentes, et supérieures sur les réplicas;

Du côté des souscriptions, il peut aussi être utile de modifier les paramètres suivants propre aux souscriptions:

max_logical_replication_workers: 4 max_sync_workers_per_subscription: 2

Il convient à présent de déclarer les slots de réplication dans la configuration de Patroni, afin de les rendre permanents et qu’ils soient préservés lors d’une bascule.

La déclaration dans la configuration va créer les slots de réplication logique sur tous les nœuds secondaires, et Patroni se chargera d’avancer leur position via l’appel de la fonction pg_replication_slot_advance. Le paramètre hot_standby_feedback est activé aussi par Patroni sur les secondaires.

postgres@pgdeb01:~$ patronictl -c /etc/patroni/config.yml edit-config --- +++ @@ -8,6 +8,11 @@ recovery_conf: restore_command: pgbackrest --stanza=loxodemo archive-get %f %p use_pg_rewind: false - use_slots: false + use_slots: true retry_timeout: 10 ttl: 30 +slots: + logical_slot_emp: + database: employees + plugin: pgoutput + type: logical Apply these changes? [y/N]: y Configuration changed

Un exemple de configuration:

loop_wait: 10 maximum_lag_on_failover: 1048576 postgresql: parameters: archive_command: pgbackrest --stanza=loxodemo archive-push %p archive_mode: 'on' wal_level: logical recovery_conf: restore_command: pgbackrest --stanza=loxodemo archive-get %f %p use_pg_rewind: false use_slots: true retry_timeout: 10 slots: logical_slot_emp: database: employees plugin: pgoutput type: logical ttl: 30
  • use_slots permet d’activer les slots de réplication;
  • section slots permet de définir les slots de réplication permanents;
  • logical_slot_emp correspond au nom du slot de réplication;
  • database est le nom de la base de données depuis laquelle la publication est créée;
  • plugin est le plugin de décodage utilisé (le plugin pgoutput est le plugin natif de PostgreSQL);
  • type est le type de réplication, ici logical (sinon physical);

Il est aussi possible de créer le slot de réplication logique auparavant, et de spécifier le nom de ce slot dans la configuration de Patroni. Par contre, la suppression de la définition de ce slot dans la configuration supprimera également le slot.

Attention au nom du slot donné dans la configuration, qui ne doit pas rentrer en conflit avec les slots de réplication physique.

On peut vérifier l’existence des slots de réplications avec la vue pg_replication_slots, en s’intéressant à celui de type logical:

employees=# select * from pg_replication_slots; slot_name | plugin | slot_type | datoid | database | temporary | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn | wal_status | safe_wal_size | two_phase | conflicting ------------------+----------+-----------+--------+-----------+-----------+--------+------------+------+--------------+-------------+---------------------+------------+---------------+-----------+------------- logical_slot_emp | pgoutput | logical | 16389 | employees | f | f | | | 817 | 0/170001C0 | 0/170001F8 | reserved | | f | f
  • catalog_xmin correspondant à la transaction la plus ancienne affectant le catalogue système et requis par le slot;
  • restart_lsn la position du plus ancien WAL requis par la souscription;
  • confirmed_flush_lsn la dernière position reçue et rejouée côté souscription;

Supervision

L’essentiel à suite de la mise en place de cette configuration est de superviser la réplication logique et son état d’avancement.

Pour ce faire, il existe de nombreuses vues système pour la supervision.

Côté publication, nous pouvons utiliser les vues suviantes:

Et côté souscription:

Par exemple avec la vue pg_replication_slots et la requête suivante:

SELECT slot_name, active, confirmed_flush_lsn, pg_current_wal_lsn(), pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_walsize, pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), confirmed_flush_lsn)) AS subscriber_lag FROM pg_replication_slots; slot_name | active | confirmed_flush_lsn | pg_current_wal_lsn | retained_walsize | subscriber_lag -----------------------------------------+--------+---------------------+--------------------+------------------+---------------- logical_slot_emp | t | 0/72B96B50 | 0/72B96B50 | 385 kB | 0 bytes
  • active donnant le status du slot de réplication;
  • confirmed_flush_lsn la dernière position reçue et rejouée côté souscription;
  • retained_walsize la quantité de WAL (en octet) retenue par le slot côté publication
  • subscriber_lag le retard de réplication logique (en octet) entre la publication et la souscription.

Qu’attendre de la version 17 de PostgreSQL?

Comme nous l’avons vu, les versions actuelles ne prennent pas en charge les bascules des slots de réplication logique, ce qui dans un contexte de haute disponibilité de service assuré par Patroni, rend la mise en place de la réplication logique plus contraignante.

La version 17 de PostgreSQL va permettre de gérer nativement la bascule des slots de réplication et rendre plus aisée l’utilisation de la réplication logique.

Cependant, il reste encore des fonctionnalités attendues comme la réplication des séquences ou des schémas de bases de données, qui doivent se faire manuellement avant la mise en place d’une souscription.