Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create mv taxref_tree #269

Closed
wants to merge 2 commits into from
Closed

create mv taxref_tree #269

wants to merge 2 commits into from

Conversation

jbdesbas
Copy link
Contributor

@jbdesbas jbdesbas commented Jun 21, 2021

Le ltree (inclue par défaut) ajoute le type de données ltree permettant de représenter des chemins dans un arbre taxonomique.

Un index GIST sur le type ltree est alors très efficace pour rechercher des taxons parents/enfants.

Vue matérialisée

taxonomie.taxref_tree

cd_nom path
189953 349525.187496.951105.187499.460634.437076.189953
191722 349525.187496.951105.187499.460638.437077.191722
197552 349525.187496.951105.187499.460638.437077.197552

Le VM est assez légère et rapide à générer (~140Mo, et 1 minute pour la construire, index compris, sur l'ensemble du taxref).
La colonne path (ltree) contient les cd_noms de l'ensemble des parents, jusqu'à la racine de l'arbre. Elle ne concerne que les taxons de référence (cd_nom = cd_ref). Elle pourrait être générée sur l'ensemble des synonymes, mais cela ferait du stockage inutile d'information dupliquée. Le cd_nom étant unique dans la VM, on est bien sur une cardinalité "1-0..1" avec la table taxonomie.taxref.

J'avais initialement exploré la piste d'une VM type "cd_nom int | cd_nom_parent int" , avec pour chaque cd_nom l'ensemble des ancêtres. Mais cette dernière solution était plus lourde, moins performante et moins intuitive.

Utilisation et exemples

L'opérateur @> permet de comparer deux path en utilisant l'index GIST. Il renvoi TRUE si le chemin à gauche est un ancêtre du chemin à droite.

-- Compter les données Odonates présentes dans la synthèse (approche avec JOIN)
SELECT
count(*)
FROM gn_synthese.synthese s
JOIN taxonomie.taxref t ON t.cd_nom = s.cd_nom
JOIN taxonomie.taxref_tree tree ON tree.cd_ref = t.cd_ref
JOIN taxonomie.taxref_tree tree_parent ON tree_parent.path @> tree.path
JOIN taxonomie.taxref tparent ON tparent.cd_nom = tree_parent.cd_ref
WHERE tparent.lb_nom = 'Odonata';
-- Lister les taxons enfants présents dans la synthèse (approche avec WHERE)
SELECT
    DISTINCT tref.lb_nom
FROM gn_synthese.synthese s
JOIN taxonomie.taxref t ON t.cd_nom = s.cd_nom
JOIN taxonomie.taxref tref ON tref.cd_nom = t.cd_ref
JOIN taxonomie.taxref_tree tt ON tt.cd_ref = tref.cd_nom
WHERE 
   (SELECT "path" FROM taxonomie.taxref_tree WHERE cd_ref = 186233  /*chiroptera */   ) @> tt."path"
-- Générer un jsonb avec les différents ancêtres
SELECT ancestors.lst_ancestors ->> 'CL'::text AS classe,
    ancestors.lst_ancestors ->> 'OR'::text AS ordre,
    ancestors.lst_ancestors ->> 'FM'::text AS famille,
    lb_nom,
    ancestors.lst_ancestors AS ancestors
  FROM taxonomie.taxref t
     JOIN taxonomie.taxref_tree tt ON tt.cd_ref = t.cd_ref
     JOIN LATERAL ( SELECT jsonb_object_agg(taxref.id_rang, taxref.lb_nom) AS lst_ancestors
           FROM taxonomie.taxref_tree
             JOIN taxonomie.taxref ON taxref.cd_nom = taxref_tree.cd_ref
          WHERE tt.path <@ taxref_tree.path) ancestors ON TRUE
      WHERE t.cd_nom = t.cd_ref AND id_rang ='ES';

ltree intègre aussi une fonction lca() permettant de trouver les ancêtres communs à une liste de path.

-- Trouver l’ancêtre commun (= portée taxonomique) d'un JDD
-- Attention, il est possible que le résultat remonte d'un niveau trop haut
-- (cf https://www.postgresql.org/message-id/CAKnjZ0KTVw63SM5wkWqAkNRv5%2B-GPXF8r60vtssvhOWJ3N5otA%40mail.gmail.com) --> fonction a redéfinir ?
SELECT
(SELECT lb_nom FROM taxonomie.taxref WHERE cd_nom =  subpath( lca( array_agg(tt."path") ) ,-1)::text::int ) AS a
FROM gn_synthese.synthese s 
JOIN taxonomie.taxref t USING (cd_nom)
JOIN taxonomie.taxref_tree tt ON tt.cd_ref = t.cd_ref 
WHERE id_dataset = 8

Discussion

Le module ltree intègre aussi un type lquery qui permet des recherches types regex dans les path (par exemple pour recherche un cd_nom au début, dans ou à la fin d'un path : '*.'||cd_nom||'.*' , mais l'usage est beaucoup plus lent que les opérateurs permettant de comparer deux path.

Il existe plusieurs approches possibles, plus ou moins verbeuses et/ou claires. Les différentes fonctions et opérateurs inclus avec ltree semble couvrir la plupart des usages possibles (subpath, index, nlevel, etc.).

A voir :
https://www.cybertec-postgresql.com/en/postgresql-speeding-up-recursive-queries-and-hierarchic-data/
http://patshaughnessy.net/2017/12/13/saving-a-tree-in-postgres-using-ltree
http://patshaughnessy.net/2017/12/15/looking-inside-postgres-at-a-gist-index
https://docs.postgresql.fr/12/ltree.html

VM permettant de naviguer dans l'arbre taxonomique
@TheoLechemia
Copy link
Member

TheoLechemia commented Jun 21, 2021

Interessant. Je ne connsaissais pas ce type de données. ça pourrait être bien utile sur Taxhub et l'atlas

Renommer la colonne cd_nom en cd_ref pour plus de clarté
@jbdesbas jbdesbas marked this pull request as ready for review October 1, 2021 13:30
@bouttier bouttier force-pushed the develop branch 2 times, most recently from c992f3a to 10e91b4 Compare August 4, 2022 10:06
@jbdesbas jbdesbas closed this by deleting the head repository Jan 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants