Différences
Ci-dessous, les différences entre deux révisions de la page.
| Les deux révisions précédentes Révision précédente Prochaine révision | Révision précédente | ||
| procedures:recuperation_et_integration_de_donnees_depuis_le_gbif [2026/01/31 22:05] – dmaillard | procedures:recuperation_et_integration_de_donnees_depuis_le_gbif [2026/02/03 07:59] (Version actuelle) – dmaillard | ||
|---|---|---|---|
| Ligne 11: | Ligne 11: | ||
| ===== Scripts ===== | ===== Scripts ===== | ||
| - | ==== R : Préparer | + | ==== Configurer |
| - | La récupération d' | + | La récupération d' |
| - | Dans le fonctionnement du pôle invertébrés, | + | Dans le fonctionnement du pôle invertébrés, |
| - | * Les données | + | * disposant de coordonnées géographiques |
| - | * Les données | + | * sans problème géospatial (géométries invalides etc) |
| - | * Les données disponibles | + | * situées |
| - | * Les données | + | * d'un ou certains jeux de données ciblés à l' |
| - | * Les données de faune invertébrée | + | * des groupes |
| Pour connaitre les " | Pour connaitre les " | ||
| Ligne 33: | Ligne 33: | ||
| + | La configuration de l' | ||
| + | |||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | ], | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | }, | ||
| + | { | ||
| + | " | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | ] | ||
| + | } | ||
| + | } | ||
| + | |||
| + | Autres configurations : | ||
| + | * [[Configuration Musée des Confluences]] | ||
| + | * [[Configuration Observations.org]] | ||
| ==== Serveur : Récupérer, | ==== Serveur : Récupérer, | ||
| + | Une fois le fichier query.json configuré, la requête est transmise à l'API à l'aide de la commande suivante (installation du package jq pour une meilleure lisibilité des réponses) : | ||
| + | |||
| + | sudo apt install jq | ||
| + | curl —silent --user USER_GBIF: | ||
| + | | ||
| + | **Cette commande retournera la clé de l' | ||
| + | |||
| + | On peut ensuite suivre l' | ||
| + | |||
| + | curl -Ss https:// | ||
| + | |||
| + | Une fois le statut " | ||
| + | |||
| + | cd /tmp | ||
| + | curl --location --remote-name https:// | ||
| + | |||
| + | |||
| + | Une fois les données récupérées, | ||
| + | |||
| + | cut -f 1, | ||
| + | cut -f 1,4 / | ||
| + | | ||
| + | Enfin, deux tables de destination sont créées dans la base de données (au premier usage) : | ||
| + | |||
| + | CREATE SCHEMA pinv_gbif; | ||
| + | | ||
| + | CREATE TABLE pinv_gbif.tmp_gbif_data ( | ||
| + | gbif_id bigint primary key, | ||
| + | modified timestamp, | ||
| + | " | ||
| + | basis_of_record varchar(255), | ||
| + | occurence_id varchar(255), | ||
| + | recorded_by varchar(255), | ||
| + | individual_count varchar(255), | ||
| + | sex varchar(255), | ||
| + | life_stage varchar(255), | ||
| + | reproductive_condition varchar(255), | ||
| + | caste varchar(255), | ||
| + | behavior varchar(255), | ||
| + | vitality varchar(255), | ||
| + | occurrence_status varchar(255), | ||
| + | occurrence_remarks text, | ||
| + | event_date timestamp, | ||
| + | verbatim_locality varchar(255), | ||
| + | decimal_latitude numeric, | ||
| + | decimal_longitude numeric, | ||
| + | coordinate_uncertainty_meters varchar(255), | ||
| + | identified_by varchar(255), | ||
| + | scientific_name varchar(255), | ||
| + | dataset_key uuid, | ||
| + | issue text, | ||
| + | taxonKey int, | ||
| + | verbatim_scientific_name varchar(255) | ||
| + | ); | ||
| + | | ||
| + | CREATE TABLE pinv_gbif.cor_multimedia ( | ||
| + | gbif_id bigint, | ||
| + | media_url text | ||
| + | ); | ||
| + | | ||
| + | Puis alimentées par les données récupérées : | ||
| + | |||
| + | sudo su postgres | ||
| + | psql -d < | ||
| + | \copy pinv_gbif.tmp_gbif_data | ||
| + | FROM PROGRAM 'tail -n +2 / | ||
| + | WITH ( | ||
| + | FORMAT text, | ||
| + | DELIMITER E' | ||
| + | ); | ||
| + | | ||
| + | \copy pinv_gbif.cor_multimedia | ||
| + | FROM PROGRAM 'tail -n +2 / | ||
| + | WITH ( | ||
| + | FORMAT text, | ||
| + | DELIMITER E' | ||
| + | ); | ||
| + | |||
| + | ==== Étape intermédiaire iNaturalist ==== | ||
| + | iNaturalist génère des uuid pour ses observations, | ||
| + | |||
| + | Le choix du Pôle invertébrés est donc : | ||
| + | * de récupérer les occurrences de taxons depuis le GBIF pour partager les mêmes scripts avec d' | ||
| + | * de récupérer les identifiants de données iNaturalist | ||
| + | * de récupérer uniquement les uuid de ces données sur l'API v2 de iNaturalist (pas optimal, mais moindre mal), afin de ne pas générer de nouveaux uuid à ces données | ||
| + | |||
| + | Les identifiants des données iNaturalist récupérées auprès du GBIF sont isolés : | ||
| + | |||
| + | SELECT id_synthese, | ||
| + | JOIN taxonomie.taxref t ON t.cd_nom=s.cd_nom | ||
| + | WHERE id_dataset=3125; | ||
| + | |||
| + | Ces id_inaturalist sont ensuite utilisés dans R, avec le script suivant, pour récupérer les uuids des données dans iNaturalist, | ||
| + | |||
| + | fetch_inat_uuid <- function( | ||
| + | df, | ||
| + | id_col = " | ||
| + | uri_col = " | ||
| + | uuid_col = " | ||
| + | batch_size = 50, | ||
| + | sleep_sec = 1 | ||
| + | ) { | ||
| + | | ||
| + | library(httr) | ||
| + | library(jsonlite) | ||
| + | library(progress) | ||
| + | | ||
| + | # typer les id_inaturalist en integer | ||
| + | df[[id_col]] <- as.integer(trimws(df[[id_col]])) | ||
| + | | ||
| + | if (!uuid_col %in% names(df)) { | ||
| + | df[[uuid_col]] <- NA_character_ | ||
| + | } | ||
| + | | ||
| + | if (!uri_col %in% names(df)) { | ||
| + | df[[uri_col]] <- NA_character_ | ||
| + | } | ||
| + | | ||
| + | ids_to_fetch <- df[[id_col]][is.na(df[[uuid_col]])] | ||
| + | | ||
| + | batches <- split(ids_to_fetch, | ||
| + | | ||
| + | pb <- progress_bar$new( | ||
| + | format = " | ||
| + | total = length(batches), | ||
| + | clear = FALSE, | ||
| + | width = 60 | ||
| + | ) | ||
| + | | ||
| + | for (batch_ids in batches) { | ||
| + | | ||
| + | res <- try( | ||
| + | GET( | ||
| + | " | ||
| + | query = list( | ||
| + | id = paste(batch_ids, | ||
| + | fields=" | ||
| + | per_page = length(batch_ids) | ||
| + | ), | ||
| + | user_agent(" | ||
| + | ), | ||
| + | silent = TRUE | ||
| + | ) | ||
| + | | ||
| + | if (!inherits(res, | ||
| + | pb$tick() | ||
| + | Sys.sleep(sleep_sec * 2) | ||
| + | next | ||
| + | } | ||
| + | | ||
| + | json <- fromJSON( | ||
| + | content(res, | ||
| + | flatten = TRUE | ||
| + | ) | ||
| + | | ||
| + | if (length(json$results) > 0) { | ||
| + | uuids <- setNames( | ||
| + | json$results$uuid, | ||
| + | as.integer(json$results$id) | ||
| + | ) | ||
| + | | ||
| + | uris <- setNames( | ||
| + | json$results$uri, | ||
| + | as.integer(json$results$id) | ||
| + | ) | ||
| + | | ||
| + | idx <- match(as.integer(names(uuids)), | ||
| + | df[[uuid_col]][idx] <- uuids | ||
| + | | ||
| + | idx <- match(as.integer(names(uris)), | ||
| + | df[[uri_col]][idx] <- uris | ||
| + | } | ||
| + | | ||
| + | pb$tick() | ||
| + | Sys.sleep(sleep_sec) | ||
| + | } | ||
| + | | ||
| + | return(df) | ||
| + | } | ||
| + | |||
| + | |||
| + | |||
| + | inaturalist_uuids <- fetch_inat_uuid( | ||
| + | inaturalist_ids, | ||
| + | id_col | ||
| + | uuid_col = " | ||
| + | batch_size = 50, | ||
| + | sleep_sec = 1 | ||
| + | ) | ||
| + | | ||
| + | Ces résultats sont ensuite exportés de R, importés dans la base de données postgresql dans une table pinv_gbif.cor_uuid_inaturalist, | ||
| + | | ||
| ==== Postgresql : Insérer ou actualiser les données en synthèse ==== | ==== Postgresql : Insérer ou actualiser les données en synthèse ==== | ||
| + | |||
| + | À partir des données stockées dans les tables temporaires, | ||
| + | |||
| + | Il faut ensuite disposer d'une source " | ||
| + | |||
| + | INSERT INTO gn_synthese.t_sources() | ||
| + | VALUES (); | ||
| + | |||
| + | Pour permettre l' | ||
| + | |||
| + | ALTER TABLE gn_synthese.synthese ADD CONSTRAINT WHERE id_source=X; | ||
| + | |||
| + | Une fois le ou les jeux de données préparés et bien identifiés (uuid), créer la fonction suivante : | ||
| + | |||
| + | TODO | ||
| + | | ||
| + | Puis déclencher l' | ||
| + | |||
| + | SELECT pinv_gbif.upsert_gbif_data(); | ||