rnsrRuleDetect - Attribution d’identifiant(s) RNSR à une adresse (Alignements)

Niveau d'utilisation :  Avancé
Niveau de validation :  Validé
Objectif

Le web service attribue, à l’aide de règles, un ou plusieurs identifiants RNSR à partir d’une adresse d’affiliation d’auteur et d’une année de publication.

Quand aucun code RNSR n’est trouvé, le service renvoie un tableau vide.

Méthode

Règles

Les règles certaines utilisées par affAlign, appliquées à l’adresse de l’affiliation à aligner sont les suivantes:

  • le code_postal ou la ville_postale de la structure doivent être présents,
  • et pour au moins une des tutelles (etabAssoc.*.etab, et etabAssoc.*.etab.natTutEtab vaut «TUTE») :
    • soit etabAssoc.*.etab.sigle ou le etabAssoc.*.etab.libelle sont présents,
    • soit etabAssoc.*.etab.libelle commence par «Université» et le etabAssoc.*.etab.libelle est présent (mais pas le etabAssoc.*.etab.sigle).
  • et on trouve la bonne structure :
    • soit etabAssoc.*.label et etabAssoc.*.numero sont présents proches et en séquence (ex: « GDR2945 », « GDR 2945 » ou « GDR mot 2945 »),
    • soit sigle est présent,
    • soit intitule est présent.
  • et la structure existait lors de la publication : la date de publication est entre annee_creation et l’éventuelle an_fermeture.

Sachant qu’on appauvrit (casse, accents, tiret, apostrophe) tous les champs.

Ressource

Le RNSR, Référentiel National des Structures de Recherche (français), référence les structures de recherche publiques et privées au niveau national. Il est administré par le ministère de l’enseignement supérieur de la recherche et de l’innovation (MESRI). Il attribue à chaque structure de recherche un identifiant (par exemple 199213009E), et recense différents éléments décrivant la structure comme la date de création, l’éventuelle date de fermeture, l’adresse, le sigle, l’intitulé etc.

Les données actuelles remontent à 2023.

Métriques

Précautions :

  • Quand l’année n’est pas précisée, plusieurs codes RNSR peuvent être associés à un même établissement. Il est donc préférable de renseigner l’année.
  • Comme il s’agit d’une recherche de chaîne de caractères, des termes fréquents (comme « DES », « CASE », « PASTEUR », « IMAGES », …) peuvent être repérés comme des sigles de laboratoires.
  • Les développés des sigles présentent une écriture complète contrairement à celle du WoS qui les abrège et les traduit (ex: « Institut de Physique » ==> « Inst. of Phys. »).
  • La ressource est en français ; les résultats seront meilleurs sur des adresses en français.
Variantes

Informations complémentaires

Une variante de ce service web renvoie aussi des informations associées au code RNSR, telles que l’intitulé, le sigle, les tutelles, des données géographiques, le code labo…

https://affiliations-tools.services.istex.fr/v1/rnsr/info

Données en CSV

Vous pouvez aussi utiliser la variante de ce service qui prend un CSV (séparateur: virgule), et qui en sortie renvoie un CSV (séparateur : point-virgule) qui reprend les données envoyées et leur ajoute une colonne RNSR.

https://affiliations-tools.services.istex.fr/v1/rnsr/csv

 

Traitement

Chaque entrée doit contenir l’adresse d’une affiliation (exemple : « University of Bordeaux, IMS, CNRS UMR5218, Talence, F-33405, France »), et éventuellement une année.

year: 2021
address: CNRS UMR AMAP MONTPELLIER FRA
==> 200317641S
year: 2021
address: IRD UMR AMAP MONTPELLIER FRA
==> 200317641S
year: 2021
address: CENBG CNRS/IN2P3 Chemin du Solarium B. P. 120 Gradignan F-33175 France
==>
year: 2021
address: Nulle part
==>
Pour aller plus loin

Mode d’enrichissement avancé

Si la plupart des web services sont simples d’utilisation dans LODEX, certains ont besoin de plus d’informations.

C’est le cas de rnsrRuleDetect qui, à partir d’une adresse de laboratoire, renvoie un ou plusieurs identifiants du Référentiel National des Structures de Recherche.
Les laboratoires évoluent au fil du temps : ils changent de nom, fusionnent, se séparent, naissent et meurent. Ainsi ce service demande également une année (typiquement une année de publication, quand on utilise des notices bibliographiques).

Au lieu d’une information unique, deux sont à envoyer : year et address.

Étape 1

La première étape est d’avoir une colonne comportant uniquement les affiliations sous la forme suivante de tableau d’éléments :

[“Denver Nephrology, Denver, Colorado”, “University of Rochester, Rochester, New York”, “Inserm, Université de Picardie, Amiens, France”]

 

Étape 2

La deuxième étape est consacrée à l’adaptation du script en mode avancé pour obtenir le bon format des données à envoyer au web service.

Le script à modifier pour pouvoir envoyer les 2 informations est visible en sélectionnant l’url du service, en sélectionnant la colonne consacrée aux affiliations, en sauvegardant. puis en activant l’interrupteur Mode avancé :

Interrupteur du mode avancé

Il ressemble à ça :

# load some plugins to activate some statements (URL Connect, exploding, aggregate)
[use]
plugin = basics
plugin = analytics

# Toggle ezs traces (see server stderr log)
[debug]
ezs = false

# We sometime have a stringified value (like "{id:1, name: 'Bob'}"), and we want to parse it, if possible
# This assign command aim is to do that, it update the Affiliations to JSON.parse it if possible.
# Can be simplified with the following statement : value = get('value.Affiliations')
[assign]
path = value
value = update("value.Affiliations", (item) => { try { return JSON.parse(item)} catch {return item } }).get("value.Affiliations")

# Process multivalues of 2 documents
[expand]
path = value
size = 2

# Ensure to process an array
[expand/assign]
path = value
value = get('value',[]).concat(null).filter(Boolean)

# Split the array to process each item
[expand/exploding]

# Group items to build a request for the web service
[expand/expand]
path = value
size = 10

# Uncomment to see each data sent to the webservice
#[expand/expand/debug]
# Send the request to the webservice
[expand/expand/URLConnect]
url = https://affiliations-tools.services.istex.fr/v1/rnsr/json
timeout = 3600000
noerror = false
retries = 5

# rebuild the original array
[expand/aggregate]

Les lignes commençant par # sont des commentaires.

On constate que le champ Colonne de la source est utilisé au début du script, sous l’instruction [assign] (ici, il utilise la colonne nommée Affiliations), et que le champ URL du web service se retrouve à la fin du script, sous l’instruction[expand/expand/URLConnect].

Ce sont les deux lignes qui nous intéressent, car du premier [expand] au dernier [expand/aggregate] se trouve le mécanisme qui s’occupe de créer et d’envoyer les données par lot.

Ce qu’il faut comprendre de la première ligne, c’est que tout document LODEX se trouve dans un objet dont le champ value contient toutes les colonnes, et que c’est aussi ce champ value qui devra, à la fin du traitement, contenir les enrichissements.

Nous transformons alors les lignes du script par défaut :

[assign]
path = value
value = update("value.Affiliations", (item) => { try { return JSON.parse(item)} catch {return item } }).get("value.Affiliations")

en

[assign]
path = value.addresses
value = get("value.Affiliations").flatten()

La méthode flatten, chaînée à la méthode get, qui renvoie la valeur de la colonne Affiliations, permet d’aplatir le tableau si vous ne l’avez pas fait auparavant lors de la création de la colonne  Affiliations:

Un autre changement a été effectué (bravo si vous l’avez repéré) : sur la ligne path, nous avons remplacé value par value.addresses, ce qui ajoute une colonne addresses au document LODEX.

Nous ajoutons une autre instruction [assign], qui va remplacer tout le champ value (donc toute la notice) par la structure que nous devons envoyer au web service :

[assign]
path = value
value = get("value.addresses").map((address) => ({ year: self.value.publicationDate, address }))

Pour mieux comprendre la ligne value = qui détermine la valeur du champ value (parce qu’on dit de changer le champ value via le paramètre path = ), on peut essayer de l’indenter :

get("value.addresses")
    .map(
        (address) => ({
            year: self.value.publicationDate,
            address
        })
    )

La méthode map va appliquer à tous les éléments du tableau obtenu par get une fonction (anonyme) qui s’écrit :

(address) => ({
    year: self.value.publicationDate,
    address
})

Qui est une syntaxe abrégée pour :

function (address) {
    return {
        year: self.value.publicationDate,
        address: address
    }
}

C’est map qui fournit son paramètre à cette fonction : address est l’élément du tableau qu’on va remplacer.

Ainsi, le tableau d’adresses à un seul niveau que nous avons vu plus haut donnera ce tableau :

[
  {
    "year": "2015-07-16",
    "address": "Department of Neonatal Medicine, Rouen University Hospital and Région-INSERM (ERI 28), Normandy University, Rouen, France."
  },
  {
    "year": "2015-07-16",
    "address": "Department of Biostatistics and INSERM UMR 657, Normandy University, Rouen, France."
  }
]

et c’est exactement la structure dont a besoin le service que nous interrogeons.

L’interface de LODEX affiche le script et l’aperçu de ce qui va être envoyé au service (en passant la souris au dessus de l’aperçu, les données complètes sont affichées sous forme d’infobulle).

Le script dans son entier est celui-ci (il suffit de le copier-coller pour s’en servir ; évidemment il faut adapter les lignes 15 et 19 de la copie d’écran aux noms de colonnes dont vous disposez) :

# load some plugins to activate some statements (URL Connect, exploding, aggregate)
[use]
plugin = basics
plugin = analytics

# Toggle ezs traces (see server stderr log)
[debug]
ezs = false

# We sometime have a stringified value (like "{id:1, name: 'Bob'}"), and we want to parse it, if possible
# This assign command aim is to do that, it update the Affiliations to JSON.parse it if possible.
# Can be simplified with the following statement : value = get('value.Affiliations')
[assign]
path = value.addresses
value = get("value.Affiliations")

[assign]
path = value
value = get('value.addresses').map((address, i) => ({ year: self.value.ApilPublicationDate, address }))

# Process multivalues of 2 documents
[expand]
path = value
size = 2

# Ensure to process an array
[expand/assign]
path = value
value = get('value',[]).concat(null).filter(Boolean)

# Split the array to process each item
[expand/exploding]

# Group items to build a request for the web service
[expand/expand]
path = value
size = 10

# Uncomment to see each data sent to the webservice
#[expand/expand/debug]
# Send the request to the webservice
[expand/expand/URLConnect]
url = https://affiliations-tools.services.istex.fr/v1/rnsr/json
timeout = 3600000
noerror = false
retries = 5

# rebuild the original array
[expand/aggregate]

Finitions

On s’aperçoit quand même que la colonne produite est un tableau de tableaux, sans relation avec le tableau des tableaux d’adresses.

Résultat de l'enrichissement

On peut, pour aplanir tout cela, et supprimer les doublons au niveau de la notice, ajouter à la fin du script :

[assign]
path = value
value = get("value",[]).flatten().uniq()

qui va réaffecter la valeur de la colonne avec le tableau résultant, mais en le mettant sur un seul niveau (flatten), et en dédoublonnant ses valeurs (uniq).

La colonne enrichie, dédoublonnée

Pour aller encore plus loin

Pour les plus hardis, voici quelques points purement techniques que vous pouvez approfondir :

  • ajouter .uniq() derrière .flatten(), permet de dédoublonner les valeurs du tableau, ainsi les éléments du tableau ne seront jamais répétés.
  • ce qui est à droite de value = dans l’instruction [assign] est du javascript, et plus précisément un chaînage d’instructions lodash.
  • le javascript à droite de value = doit tenir sur une ligne.
  • dans le javascript à droite de value = , on peut faire appel à des fonctions lodash non chaînées, à condition d’ajouter _. devant le nom de la fonction, et d’ajouter en premier paramètre self, qui est le document courant.
    Ainsi, on aurait pu remplacer self.value.publicationDate par _.get(self, "value.publicationDate"), mais c’était plus long.
  • l’aperçu de la source n’est pas forcément ce qui est envoyé au service, car le script pouvant avoir n’importe quelle structure, il peut faire complètement autre chose que ce pour quoi il a été initialement prévu (prétraiter des colonnes existantes par exemple). La solution retenue, est de remplacer l’instruction URLConnect qui fait l’appel au web service par l’instruction transit qui ne fait rien (elle transmet les données à l’instruction suivante). Donc si une instruction qui modifie les données se trouve en-dessous de URLConnect, elle sera aussi interprétée pour afficher l’aperçu.
  • le script affiché au passage en mode avancé n’est pas forcément conforme à celui de l’article (en particulier la partie à partir de [expand]), c’est parce que LODEX déduit ce script de la structure du champ concerné (est-ce une chaîne de caractères, un tableau, …) mais seulement pour le premier document. Il suffit que ce document n’ait pas de valeur pour que LODEX utilise un script moins adapté.

Vous souhaitez connaître les entités de recherche à partir d’une adresse ou d’une affiliation ? Vous souhaitez les homogénéiser ? Vous souhaitez mettre en évidence les coopérations entre ces entités ?
En lançant rnsrRuleDetect sur vos données depuis Lodex, logiciel libre de visualisation, vous obtiendrez les codes RNSR et leur verbalisation ainsi que des représentations graphiques liées.

Graphes issus d’une étude réalisée pour la Direction des Données Ouvertes de la Recherche (DDOR) (Comptes rendus annuels d’activité des chercheurs CNRS 2020-2021).

En poursuivant votre navigation, sans modifier vos paramètres, vous acceptez l'utilisation et le dépôt de cookies destinés à mesurer la fréquentation du site grâce au logiciel Matomo.
OK
Modifier les paramètres