Sup Numérique

L'objectif de cette partie est de montrer comment nous avons "sémantifié" la description des ressources pédagogiques référencées par le moteur de recherche numérique Sup Numérique

Les métadonnées proposées par Sup Numérique en Open Data

Comme nous l'avons rappelé dans la présentation du sujet, le ministère de l'Enseignement Supérieur de la Recherche et de l'Innovation a lancé fin 2015 le portail sup-numerique.gouv.fr. Ce portail propose entre autres un moteur de recherche de ressources pédagogiques. Les ressources pédagogiques indexées sont issues des entrepôts ORI-OAI de :

Des données mises à plat

Les métadonnées décrivant ces fiches sont disponibles en opendata aux formats Excel, CSV et JSON.

Le choix des formats Excel et CSV est étonnant, car ces formats de fichier sont tabulaires, c'est-à-dire qu'ils ne peuvent représenter que des données à deux entrées alors qu'initialement dans l'entrepôt ORI-OAI elles étaient représentées hiérarchiquement, à l'aide de la grammaire XSD, définie par le SupLOMFR. Nous avons donc exclu d'utiliser ces deux formats, car nous savions que de fait les données seraient déstructurées.

Nous avons donc étudié et utilisé les données au format JSON qui permet justement de représenter hiérarchiquement de l'information. Ainsi si une convention est établie et suivie, tout document XML peut être représenté à l'aide du format JSON. Bien que cette convention ne soit pas donnée par SupNumérique, nous pensions qu'en étudiant les fichiers JSON nous pourrions la redécouvrir pour interpréter fidèlement ces données et retrouver les données structurées initiales. Quelle ne fut pas notre surprise lorsque nous avons découvert que ces données au format JSON n'étaient pas hiérarchiques.

Afin d'être bien clair, prenons l'exemple de la description de ressources pédagogiques Situated interaction and co-adaptive systems: creating a partnership between people and intelligent systems décrit par UNIT. Voici un extrait de code XML de cette fiche :

	  
<?xml version="1.0" encoding="UTF-8"?><lom:lom xmlns:lom="http://ltsc.ieee.org/xsd/LOM" xmlns:lomfr="http://www.lom-fr.fr/xsd/LOMFR">
<lom:general>
  <lom:identifier>
    <lom:catalog>URI</lom:catalog>
    <lom:entry>http://ori.unit-c.fr/uid/unit-ori-wf-1-4279</lom:entry>
  </lom:identifier>
  <lom:title>
    <lom:string language="eng">Situated interaction and co-adaptive systems: creating a partnership between people and intelligent systems </lom:string>
  </lom:title>
  <lom:language>eng</lom:language>
  <lom:description>
    <lom:string language="eng">Computer Science developed as....</lom:string>
  </lom:description>
  <lom:keyword>
    <lom:string language="fre">Interaction homme-ordinateur</lom:string>
    <lom:string language="eng">Human-computer Interaction </lom:string>
  </lom:keyword>
  <lom:keyword>
    <lom:string language="fre">Systèmes intelligents</lom:string>
    <lom:string language="eng">Intelligent systems</lom:string>
  </lom:keyword>
...

Les balises XML permettent d'une part de catégoriser les données conformément à ce qui a été défini par le LOM et le SupLOMFR (par exemple la balise lom:general). Et d'autre part, elles permettent de regrouper des données qui forment un tout, c'est le cas de la balise lom:keyword qui permet de rassembler des traductions d'un même mot clé.

Voici maintenant un extrait du code JSON que propose SupNumérique  (il est à noter que nous avons réordonné, pour plus de lisibilité, les champs lom) :

[{"datasetid": "fr_esr_ressources-pedagogiques",
 "recordid": "41e6c47ee3a96def04ec6d9c9beb1717db6cf6b7",
"fields": {
"lom_metametadata_identifier_entry": "http://ori.unit-c.fr/uid/unit-ori-wf-1-4280",
"lom_general_identifier_catalog": "URI",
"lom_general_identifier_entry": "http://ori.unit-c.fr/uid/unit-ori-wf-1-4279",
"lom_general_title_language": "eng",
"lom_general_title_text": "Situated interaction and co-adaptive systems: creating a partnership between people and intelligent systems",
"lom_general_language": "eng",
"lom_general_keyword_language": "fre,eng,fre,eng,fre,eng,fre,eng,eng,fre,eng,eng,fre,fre,eng,fre,eng,fre",
"lom_general_keyword_text": "Interaction homme-ordinateur,Human-computer Interaction,Systèmes intelligents,Intelligent systems,Reconnaissance geste,Gesture recognition,interface interactive,interactive interface,Human in the loop,papier électronique,Interactive Paper,interactive systems,systèmes interactifs,interface tactile,touch interface,réalité virtuelle,virtual reality,fuscia",
...

On constate que les données sont stockées dans la valeur du champs fields et que ces données sont représentées par une succession de couples clé-valeur.

Premier constat, les clés représentent les balises XML et les valeurs des balises, et en aucun cas les balises internes. Ainsi, l'organisation hiérarchique des balises a disparu, seuls les noms des clés JSON peuvent nous permettre, par un traitement ad-hoc, de les retrouver (traitement assez simple car le séparateur utilisé, le tiret bas "_", n'est pas utilisé dans le nom des balises). Par exemple la clé JSON lom_general_language représente la langue du document, c'est-à-dire la métadonnée language de la catégorie general du LOM.

Deuxième constat, le plus gênant, concerne les métadonnées du LOM qui peuvent avoir plusieurs valeurs, comme c'est le cas par exemple pour les mots clés (keywords). On constate alors que ces valeurs ont été agrégées en une ou plusieurs valeurs JSON en séparant les valeurs initiales par des virgules. Ainsi la suite des mots clés (keywords) se retrouvent dans deux champs JSON, lom_general_keyword_language et lom_general_keyword_text, la langue d'une des parties de lom_general_keyword_text est caractérisée par la partie correspondante de lom_general_keyword_language. Par exemple la langue du mot clé "Human-computer Interaction" est l'anglais car à cette valeur est associée la valeur eng de lom_general_keyword_language, elles sont toutes les deux en deuxième position lorsque l'on prend la virgule comme séparateur.

Or ceci peut poser problème lorsque l'une des valeurs initiales contient aussi ce séparateur (la virgule). Dans ce cas le "nombre de valeurs" séparées par des virgules dans un champ JSON n'est plus égal au nombre de valeurs de l'autre champs JSON associé. C'est par exemple le cas pour représenter le titre de la ressource Conférence de Herta Müller, Prix Nobel de littérature 2009 - 1ère partie. Comme le titre de cette ressource n'est décrit qu'en français, il n'y a qu'une valeur pour le champ lom_general_title_language mais comme il y a une virgule dans le titre, tout logiciel qui essaye d'interpréter la donnée du champ lom_general_title_text en trouvera deux.

Le programme Java de génération de triplets RDF

Ce petit exemple de problème, plus d'autres que nous ne détaillerons pas ici, nous ont obligés à définir des stratégies de sémantification de ces données JSON qui ont été implantées dans un programme Java (cf. l'annexe). Ce programme est téléchargeable ici et s'utilise en ligne de commande :

java -jar Json2RDF-1.0.jar

Ce programme accepte des options qui permettent de spécifier (dans l'ordre) :

  • le nom du fichier JSON,
  • le nom du fichier où seront écrits les triplets RDF générés au format turtle (par défaut tripletsLofarV2.ttl),
  • le préfixe des URI qui seront générés (par défaut http://lofar2.insa-rouen.fr/enseignementsup-recherche/.

Ces informations sont données par l'aide en ligne :

$ java -jar Json2RDF-1.0.jar --help

SYNOPSIS
     java -jar Json2RDF-1.0.jar SOURCE [DESTINATION] [NAMESPACE-FOR-URIs] [2>ERROR_FILE]

DESCRIPTION
     - SOURCE, an "application/json" mime-type file.
     - DESTINATION, if file name is not provided, output file will be "./tripletsLofarV2.ttl"
     - NAMESPACE-FOR-URIs, if this third argument is not provided, default namespace for URIs will be "http://lofar2.insa-rouen.fr/enseignementsup-recherche/"

	(tip) use '2>'redirection command to redirect errors (i.e. stderr) to specified file instead of standard output.

Lors de l'exécution, ce programme affiche dans la sortie d'erreur standard des statistiques (nombre de champs JSON interprétés, nombre d'erreurs mineures qui suppriment quelques propriétés d'une ressource, nombre d'erreurs fatales qui suppriment une ressource, etc.). Lorsque le programme est exécuté sans paramètre, il récupère automatiquement depuis SupNumérique les métadonnées de 45 ressources de types pédagogiques "cours" et "scénario pédagogique", dont certaines posent des problèmes (une est exclue totalement et quinze n'ont pas pu être totalement interprétées) :

$ java -jar Json2RDF-1.0.jar 
Le fichier JSON attendu n'a pas été donné en argument : le traitement va être exécuté sur un exemple de jeu de données en ligne.
<https://data.enseignementsup-recherche.gouv.fr/explore/dataset/fr_esr_ressources-pedagogiques/download/?format=json&refine.lom_educational_learningresourcetype_value=sc%C3%A9nario%20p%C3%A9dagogique&refine.lom_educational_learningresourcetype_value=lecture&timezone=Europe/Berlin>

Wed May 31 15:27:35 CEST 2017
Début du traitement...

Parcours des données Json et génération du code RDF des objets SuplomFR

Minor:recordid:8e0251ed49466495bff1f4b2711d0f4139552b54 | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:2 Entities:3 Dates:2
Minor:recordid:f5ac63566bfb32d8333266028f5c38b640fb0caf | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:2 Entities:3 Dates:2
Minor:recordid:71d837fbdb1ebedf741610f3f1a93aff4b03e1fb | lom_general_title_language | DuplicateLangStringException | Duplicate language entry:langTag=fr, valeur=Virtual biodiversity garden
Minor:recordid:71d837fbdb1ebedf741610f3f1a93aff4b03e1fb | lom_relation_kind_value | UnbalancedFieldsException | nbRelations <> nbDescriptions.
Minor:recordid:71d837fbdb1ebedf741610f3f1a93aff4b03e1fb | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:6 Entities:0 Dates:6
Minor:recordid:9caf257b7c9f41a0abc325f274683dfaf0a8332b | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:19 Entities:0 Dates:19
Minor:recordid:53439009225d254121ca4803d4fd3bf5556a78d4 | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:17 Entities:18 Dates:17
Minor:recordid:86647e744942eb9c6fa68a58cb3b7030121b9213 | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:4 Entities:5 Dates:4
Minor:recordid:f4d3ba88609ecfd1b7606daeee4484ce96093012 | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:2 Entities:3 Dates:2
FATAL:recordid:4cf3a135791319cec3d2719ee05959b19a226ddf | lom_general_keyword_language | MajorToolboxException | createListLangStringFromMapField | lom_general_keyword | nbLocale < nbText or bad separator [Analyse financière,bilan fonctionnel,gestion,autofinancement,ratios,économie,droit du travail,gestion et administration des entreprises],[fre,fre,fre,fre]
No properties written ! recordid:4cf3a135791319cec3d2719ee05959b19a226ddf | MajorToolboxException | createListLangStringFromMapField | lom_general_keyword | nbLocale < nbText or bad separator [Analyse financière,bilan fonctionnel,gestion,autofinancement,ratios,économie,droit du travail,gestion et administration des entreprises],[fre,fre,fre,fre]
Minor:recordid:15bc2b667b1e2c9342fa57af7c55a926d520035c | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:2 Entities:0 Dates:2
Minor:recordid:e5e4de919ac1c0bdbe23b64635b52c2438c23ca3 | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:2 Entities:0 Dates:2
Minor:recordid:c03d62dae14aa91ec49163a7d4aeaeaafaf2265e | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:2 Entities:3 Dates:2
Minor:recordid:5282c9284cf73fcd79edca01c0ed7e57733eb288 | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:2 Entities:8 Dates:2
Minor:recordid:e50b61939634e06efcff4d89277edde8acdb86a4 | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:3 Entities:5 Dates:3
Minor:recordid:7bc639b812de34b0d786f5f6d9560b97b798de0e | lom_lifecycle_contribute_role_value | ToolboxException | Err cardinalité : lom_lifecycle_contribute | Roles:2 Entities:0 Dates:2
Wed May 31 15:27:35 CEST 2017

Étape SupLOMFR réalisée.

Wed May 31 15:27:35 CEST 2017
nbRead : 45 ;
nbErr fatal : 1 soit 2.22% d'erreur fatale ;
nbMinor:15
Erreur FATALE signifie que l'objet n'avait pas assez de cohérence pour pouvoir être retenu.
Erreur mineure signifie que le remplissage de l'objet a été prématurément interrompu suite à une erreur sur un champ non-vital.

...

Génération des triplets RDF du pool...

Wed May 31 15:27:35 CEST 2017
Traitement terminé.
Les triplets RDF ont été générés dans le fichier passé en deuxième argument de la commande, sinon par défaut dans le fichier ./tripletsLofarV2.ttl

811 ms d'exécution

Triplets RDF générés

Les triplets générés utilisent le schéma ontologique créé par UNIT (http://unit-1.crihan.fr/lro/schema#, le préfixe de cet URI est nommé lro). L'utilisation de ce schéma a mis en évidence quelques erreurs ou manques :

  • il n'y a pas de propriété pour désigner l'URL de la ressource ! Nous avons utilisé la propriété lro:location;
  • il y a une erreur dans le nom de la propriété lro:hasSubjectExpertMatter;
  • il manque les propriétés lro:hasCreator, lro:hasContributor, lro:hasPublisher (équivalentes aux propriétés dc.creator, dc.contibutor et dc.publisher du Dublin Core);
  • il n'y a pas de classe Relation (mais il y a la propriété lro:hasRelation).

620060 triplets RDF ont été générés à partir des données JSON récupérées début 2016.

L'entrée SPARQL et des exemples de requêtes

Nous avons inséré les triplets RDF générés par le programme précédent dans le système de gestion de base de données RDF Jena/Fuseki de l'INSA Rouen Normandie. L'entrée SPARQL est : http://linkeddata.insa-rouen.fr/dataset.html?tab=query&ds=/SupNumerique.

Il est à noter que cette entrée SPARQL est maintenant référencée officiellement par Sup Numérique : https://data.enseignementsup-recherche.gouv.fr/explore/dataset/fr_esr_ressources-pedagogiques/.

Voici quelques exemple de requêtes SPARQL qui utilisent tous les préfixes suivants :

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
prefix owl: <http://www.w3.org/2002/07/owl#>
prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>
prefix lro: <http://unit-1.crihan.fr/lro/schema#>

Nombre de ressources

On peut obtenir le nombre de ressources indexées en comptant le nombre d'instances (propriété rdf:type) de la classe lro:LroSuplomfr ou lro:Lro :
SELECT (count(distinct ?u) as ?count)
WHERE {
  VALUES (?classe) {(lro:LroSuplomfr) (lro:Lro)}
  ?u rdf:type ?classe
}

On obtient alors le résultat suivant : 37307

Les noms des 100 premières ressources proposées par un établissement

En supposant que les ressources d'un établissement sont hébergées par une machine de son nom de domaine, on peut sélectionner celles dont l'URL possède ce nom de domaine. Ainsi pour les ressources de l'INSA Rouen Normandie on a la requête :

SELECT ?titre
WHERE {
  ?u lro:location ?v.
  ?u lro:title ?titre
  FILTER contains(?v, "insa-rouen.fr/")
} LIMIT 100

On obtient alors le titre de 52 ressources.