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ésdc.creator
,dc.contibutor
etdc.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.