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 Dernière révision Les deux révisions suivantes | ||
besson_sylvain:etapes_fusion [2021/06/14 12:11] Sylvain Besson |
besson_sylvain:etapes_fusion [2021/07/22 19:03] Sylvain Besson [Importation des instances de BnF Data] |
||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
Allez vers la [[etapes|page précédente - étapes]] | Allez vers la [[etapes|page précédente - étapes]] | ||
- | ====== Fusionner les bases de données ====== | + | ====== Importer les données ====== |
- | Une fois que l'on a pris connaissance des données que l'on souhaite obtenir des différentes bases de données, il est possible de créer un serveur local afin de stocker les données. Cela permet aussi d'aligner les bases de données pour avoir un vocabulaire contrôlé. Pour cela, nous avons fait le choix d'utiliser **[[projets_individuels:documentation_sparql&#vocabulaire|GraphDB]]** pour sa facilité d'utilisation et ses fonctionnalités. L'importation des données se fait en deux étapes, d'abord nous importons les instances et ensuite leur(s) propriété(s). | + | Une fois que l'on a pris connaissance des données que l'on souhaite obtenir des différentes bases de données, il est possible de créer un serveur local afin de stocker les données. Cela permet aussi d'aligner les bases de données pour avoir un vocabulaire contrôlé. Pour cela, nous avons fait le choix d'utiliser **[[besson_sylvain:documentation_sparql#GraphDB|GraphDB]]** pour sa facilité d'utilisation et ses fonctionnalités. L'importation des données se fait en deux étapes, d'abord nous importons les instances et ensuite leur(s) propriété(s). |
====Importation des instances de Wikidata==== | ====Importation des instances de Wikidata==== | ||
Nous avons fait le choix d'importer en premier les données provenant de Wikidata car c'est le plus gros silos avec plus de 130 000 instances. Il est important d'importer à la fois les économistes et les juristes afin de ne pas avoir des doublons pour les personnes qui serait dans les deux populations. Ensuite, nous donnons à chaque instance un [[https://fr.wikipedia.org/wiki/Uniform_Resource_Name|URN]] unique afin que lorsque l'on ajoute d'autres bases de données, l'URN correspond à une personne réelle si elle est présente sur plusieurs bases de données. Pour cela il faut utiliser la clause [[https://www.w3.org/TR/sparql11-query/#func-uuid|UUID]] qui présente un URN sous la forme: "urn:uuid:b9302fb5-642e-4d3b-af19-29a8f6d894c9". | Nous avons fait le choix d'importer en premier les données provenant de Wikidata car c'est le plus gros silos avec plus de 130 000 instances. Il est important d'importer à la fois les économistes et les juristes afin de ne pas avoir des doublons pour les personnes qui serait dans les deux populations. Ensuite, nous donnons à chaque instance un [[https://fr.wikipedia.org/wiki/Uniform_Resource_Name|URN]] unique afin que lorsque l'on ajoute d'autres bases de données, l'URN correspond à une personne réelle si elle est présente sur plusieurs bases de données. Pour cela il faut utiliser la clause [[https://www.w3.org/TR/sparql11-query/#func-uuid|UUID]] qui présente un URN sous la forme: "urn:uuid:b9302fb5-642e-4d3b-af19-29a8f6d894c9". | ||
- | Préalablement, il est aussi possible dans Wikidata de fusionner des pages (et leur URI) qui correspondent à une même personne (la méthode est sur cette **[[projets_individuels:documentation_wikidata|page]]**). | + | Préalablement, il est aussi possible dans Wikidata de fusionner des pages (et leur URI) qui correspondent à une même personne (la méthode est sur cette **[[documentation_wikidata|page]]**). |
+ | |||
+ | La requête se présente de la façon suivante: | ||
- | La requête se présente de la façon suivante: | ||
<code sparql> | <code sparql> | ||
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> | PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> | ||
Ligne 50: | Ligne 51: | ||
{ ?person wdt:P106 wd:Q185351 ; # juriste ("jurist") | { ?person wdt:P106 wd:Q185351 ; # juriste ("jurist") | ||
wdt:P569 ?birthDate | wdt:P569 ?birthDate | ||
- | FILTER ( ?birthDate >= "1770-01-01"^^xsd:dateTime ) | ||
- | } | ||
- | UNION | ||
- | {?person wdt:P106 wd:Q40348; # avocat ("lawyer") | ||
- | wdt:P569 ?birthDate | ||
- | FILTER ( ?birthDate >= "1770-01-01"^^xsd:dateTime ) | ||
- | } | ||
- | UNION | ||
- | {?person wdt:P106 wd:Q16533; # juge ("judge") | ||
- | wdt:P569 ?birthDate | ||
- | FILTER ( ?birthDate >= "1770-01-01"^^xsd:dateTime ) | ||
- | } | ||
- | UNION | ||
- | {?person wdt:P106 wd:Q758225; # avocat ("attorney at law") | ||
- | wdt:P569 ?birthDate | ||
- | FILTER ( ?birthDate >= "1770-01-01"^^xsd:dateTime ) | ||
- | } | ||
- | UNION | ||
- | {?person wdt:P106 wd:Q380075; # avocat("advocate") | ||
- | wdt:P569 ?birthDate | ||
- | FILTER ( ?birthDate >= "1770-01-01"^^xsd:dateTime ) | ||
- | } | ||
- | UNION | ||
- | {?person wdt:P106 wd:Q16009129; # magistrat ("magistrate") | ||
- | wdt:P569 ?birthDate | ||
- | FILTER ( ?birthDate >= "1770-01-01"^^xsd:dateTime ) | ||
- | } | ||
- | UNION | ||
- | {?person wdt:P106 wd:Q791243; # avocat en France ("legal advocate in France") | ||
- | wdt:P569 ?birthDate | ||
FILTER ( ?birthDate >= "1770-01-01"^^xsd:dateTime ) | FILTER ( ?birthDate >= "1770-01-01"^^xsd:dateTime ) | ||
} | } | ||
Ligne 113: | Ligne 84: | ||
La méthode pour importer les propriétés est assez similaire à celle des instances. L'exemple suivant a pour but d'importer les lieux de naissance dans la base de données. La requête se construit de la façon suivante: | La méthode pour importer les propriétés est assez similaire à celle des instances. L'exemple suivant a pour but d'importer les lieux de naissance dans la base de données. La requête se construit de la façon suivante: | ||
+ | |||
<code sparql> | <code sparql> | ||
PREFIX owl: <http://www.w3.org/2002/07/owl#> | PREFIX owl: <http://www.w3.org/2002/07/owl#> | ||
Ligne 150: | Ligne 122: | ||
</code> | </code> | ||
- | Cette requête est utile mais elle permet seulement d'inserer dans la base de données, les URI de Wikidata des lieux de naissance. il est plus intéressant de pouvoir insérer aussi d'autres éléments comme l'étiquette du lieu ou bien ses coordinnées géographique. Une fois encore la requête est assez similaire, mais demande quelques rafinements supplémentaires: | + | Cette requête est utile, mais elle permet seulement d'insérer dans la base de données, les URI de Wikidata des lieux de naissance. Il est plus intéressant de pouvoir insérer aussi d'autres éléments comme l'étiquette du lieu ou bien ses coordonnées géographiques. Une fois encore la requête est assez similaire, mais demande quelques raffinements supplémentaires : |
- | <code squarl> | + | <code sparql> |
PREFIX bd: <http://www.bigdata.com/rdf#> | PREFIX bd: <http://www.bigdata.com/rdf#> | ||
PREFIX owl: <http://www.w3.org/2002/07/owl#> | PREFIX owl: <http://www.w3.org/2002/07/owl#> | ||
Ligne 168: | Ligne 140: | ||
GRAPH <http://economists_jurists.org/import_wikidata> { | GRAPH <http://economists_jurists.org/import_wikidata> { | ||
#CONSTRUCT { | #CONSTRUCT { | ||
- | ?uri wdt:P19 ?placeOfBirth . | + | ?uri wdt:P19 ?placeOfBirth . # à chaque instance tu ajoutes le lieu de naissance |
- | ?placeOfBirth rdfs:label ?labelOfPlaceOfBirth . | + | ?placeOfBirth rdfs:label ?labelOfPlaceOfBirth . # à ce lieu de naissance, tu lui ajoutes son étiquette |
- | ?placeOfBirth wikibase:geoLatitude ?lat . | + | ?placeOfBirth wikibase:geoLatitude ?lat . # À chaque lieu de naissance, tu lui ajoutes sa latitude |
- | ?placeOfBirth wikibase:geoLongitude ?long . | + | ?placeOfBirth wikibase:geoLongitude ?long . # À chaque lieu de naissance, tu lui ajoutes sa longitude |
} | } | ||
} | } | ||
Ligne 177: | Ligne 149: | ||
{ ?uri owl:sameAs ?person | { ?uri owl:sameAs ?person | ||
{ SERVICE <https://query.wikidata.org/sparql> | { SERVICE <https://query.wikidata.org/sparql> | ||
- | { SELECT ?person ?placeOfBirth ?placeOfBirthLabel ?labelOfPlaceOfBirth ?lat ?long ?GeoNames | + | { SELECT ?person ?placeOfBirth ?placeOfBirthLabel ?labelOfPlaceOfBirth ?lat ?long |
WHERE | WHERE | ||
- | { { SELECT DISTINCT ?person ?placeOfBirth ?placeOfBirthLabel ?latitude ?longitude ?oldURI | + | { { SELECT DISTINCT ?person ?placeOfBirth ?placeOfBirthLabel ?latitude ?longitude |
WHERE | WHERE | ||
{ ?person wdt:P19 ?placeOfBirth . | { ?person wdt:P19 ?placeOfBirth . | ||
Ligne 216: | Ligne 188: | ||
</code> | </code> | ||
+ | Comme on peut le voir, Wikidata intègre pas mal de préfixes qui permettent d'aller assez loin dans les données qui sont possibles d'étudier ou de récupérer. Ces services sont documentés avec de nombreux exemples qu'il est possible de tester comme c'est le cas sur cette [[https://www.wikidata.org/wiki/Wikidata:SPARQL_query_service/queries/examples#Wikibase_predicates|page]]. Pour ce qui est d'importer les coordonnées géographiques, cette [[https://en.wikibooks.org/wiki/SPARQL/WIKIDATA_Precision,_Units_and_Coordinates|ressource]] est très utile. | ||
+ | |||
+ | Dans ce type de requête, il est aussi très important de bien les structurer afin de limiter le nombre d'erreurs et des contre-sens dans les résultats obtenues. Un premier réflexe est de toujours réaliser un CONSTRUCT avant d'importer les données, puisque qu'il permet vraiment de comprendre comment les données se trouveront dans la base de données. | ||
+ | |||
+ | Il est aussi important dans ce type de requête avec beaucoup d'éléments de bien imbriquer les différentes parties de la requête. Il est nécessaire par exemple de réaliser une sous-requête avec les instances que l'on souhaite récupérer, puis une requête où l'on cherche à obtenir une propriété. Ensuite, il est aussi très important de structurer la requête en remettant un SELECT lorsque l'on cherche à obtenir autres choses pour bien faire comprendre à la machine les différentes étapes. Ici, par exemple, un premier SELECT cherche les données “brutes” et dans un second SELECT la clause BIND, qui permet d'enlever les formats, est utilisé. Cette façon de faire est d'autant plus nécessaire lorsque l'on souhaite insérer les données. | ||
==== Importation des instances de BnF Data ==== | ==== Importation des instances de BnF Data ==== | ||
+ | Nous importons ensuite les instances de BnF Data. La méthode est assez similaire à celle de Wikidata, mais elle demande quelques étapes préliminaires. Avant d'attribuer aux instances un URN, il faut d'abord aligner les instances de BnF Data avec celle de Wikidata. Pour cela, plusieurs méthodes sont disponibles. Tout d'abord, il est possible lier les instances de Wikidata qui renvoient vers une instance de BnF Data. Il faut commencer par importer la propriété BnF Data présente dans Wikidata. La requête peut être réalisée de la façon suivante : | ||
+ | |||
+ | <code sparql> | ||
+ | PREFIX owl: <http://www.w3.org/2002/07/owl#> | ||
+ | PREFIX wdt: <http://www.wikidata.org/prop/direct/> | ||
+ | PREFIX ome: <https://ontome.net/class/> | ||
+ | PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> | ||
+ | PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> | ||
+ | PREFIX wd: <http://www.wikidata.org/entity/> | ||
+ | |||
+ | INSERT { | ||
+ | GRAPH <http://economists_jurists.org/import_wikidata> { | ||
+ | # CONSTRUCT { | ||
+ | ?uri wdt:P268 ?uri_bnf . | ||
+ | } | ||
+ | } | ||
+ | WHERE | ||
+ | { ?uri owl:sameAs ?person | ||
+ | { SERVICE <https://query.wikidata.org/sparql> | ||
+ | { SELECT DISTINCT ?person ?uri_bnf | ||
+ | WHERE | ||
+ | { ?person wdt:P268 ?uri_bnf1 | ||
+ | { { ?person wdt:P106 wd:Q188094 ; # economist | ||
+ | wdt:P569 ?birthDate ; | ||
+ | wdt:P268 ?uri_bnf1 | ||
+ | FILTER ( ?birthDate >= "1770-01-01"^^xsd:dateTime ) | ||
+ | } | ||
+ | UNION | ||
+ | { ?person wdt:P106 wd:Q185351 ; # jurist | ||
+ | wdt:P569 ?birthDate ; | ||
+ | wdt:P268 ?uri_bnf1 | ||
+ | FILTER ( ?birthDate >= "1770-01-01"^^xsd:dateTime ) | ||
+ | } | ||
+ | } | ||
+ | BIND(uri(concat("https://data.bnf.fr/ark:/12148/cb", strafter(str(?uri_bnf1), ""))) AS ?uri_bnf2) | ||
+ | BIND(uri(concat(str(?uri_bnf2), "#about")) AS ?uri_bnf) # Les deux BIND sont essentiels car dans wikidata seul la partie de l'URI propre à chaque URI est indiqué donc il est necessaire d'ajouter les autres partie de l'URI pour pouvoir lier les instance de Wikidata à celles de BnF Data. | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | # LIMIT 10 | ||
+ | </code> | ||
- | Nous importons ensuite les instances de BnF Data. La méthode est assez similaire à celle de Wikidata, mais elle demande quelques étapes préliminaires. Avant d'attribuer aux instances un URN, il faut d'abord aligner les instances de BnF Data avec celle de Wikidata. Pour cela plusieurs méthodes sont disponibles. Tout d'abord, il est possible le lier les instances de Wikidata qui renvoient vers une instances de BnF Data. [mettre la méthode quand je l'aurais trouvé]. Ensuite, il est possible de lier ces instances avec un identifiant VIAF qu'elles ont en commun. Nous procédons de la façon suivante: | + | Ensuite, il est possible de lier ces instances avec un identifiant VIAF qu'elles ont en commun. Il faut bien sûr préablement importer la propriété VIAF présente dans Wikidata. Nous procédons de la façon suivante: |
<code sparql> | <code sparql> | ||
Ligne 244: | Ligne 263: | ||
{ # La sous-requête cherche les identifiants VIAF dans BnF Data | { # La sous-requête cherche les identifiants VIAF dans BnF Data | ||
{ ?person_bnf egr:biographicalInformation ?bio ; | { ?person_bnf egr:biographicalInformation ?bio ; | ||
- | egr:dateOfBirth ?bd ; | + | egr:dateOfBirth ?bd ; |
- | owl:sameAs ?uri_viaf | + | owl:sameAs ?uri_viaf |
FILTER regex(?uri_viaf, "viaf.org", "i") | FILTER regex(?uri_viaf, "viaf.org", "i") | ||
BIND(strbefore(strafter(str(?bd), "http://data.bnf.fr/date/"), "/") AS ?bd1) | BIND(strbefore(strafter(str(?bd), "http://data.bnf.fr/date/"), "/") AS ?bd1) | ||
Ligne 257: | Ligne 276: | ||
FILTER regex(?uri_viaf, "viaf.org", "i") | FILTER regex(?uri_viaf, "viaf.org", "i") | ||
BIND(strbefore(strafter(str(?bd), "http://data.bnf.fr/date/"), "/") AS ?bd1) | BIND(strbefore(strafter(str(?bd), "http://data.bnf.fr/date/"), "/") AS ?bd1) | ||
- | FILTER ( ( ( regex(?bio, "économiste") || regex(?bio, "Economiste") ) || regex(?bio, "professeur d'économie", "i") ) || regex(?bio, "docteur en économie", "i") ) | + | FILTER ( ( ( regex(?bio, "économiste", "i") || regex(?bio, "Economiste", "i") ) || regex(?bio, "professeur d'économie", "i") ) || regex(?bio, "docteur en économie", "i") ) |
FILTER ( ?bd1 > "1770" ) | FILTER ( ?bd1 > "1770" ) | ||
} | } | ||
Ligne 267: | Ligne 286: | ||
</code> | </code> | ||
- | Enfin la dernière méthode qui permet de connaître si des personnes sont dans plus bases de données, c'est le Recordlinkage. Nous la présentons en détail ci-dessous. | + | Enfin une fois que l'on a réalisé ces étapes préliminaires pour lier les personnes présentes dans les deux bases de données, il est possible d'importer les personnes qui ne sont pas présentes dans la base de données graphe. Il est nécessaire d'enlever avec la clause MINUS les personnes qui sont déjà présentes, car comme le but est de créer un URI unique, si l'on ne procède pas ainsi les données seront dupliqués comme l'URI locale sera différent. C'est donc une étape qu'il faut faire avec beaucoup de précautions. Il est préférable de faire un SELECT seul au préalable afin de déterminer si les personnes ne sont effectivement pas déjà dans la base de données locale. Si les résultats ne correspondent à aucun URI BnF, alors il est possible de faire l'insertion. Elle se réalise de la façon suivante (la même requête peut être réalisée pour le SELECT, il faudra enlever la partie INSERT) : |
+ | |||
+ | <code sparql> | ||
+ | PREFIX xsd: <http://www.w3.org/2001/XMLSchema#> | ||
+ | PREFIX egr: <http://rdvocab.info/ElementsGr2/> | ||
+ | PREFIX owl: <http://www.w3.org/2002/07/owl#> | ||
+ | PREFIX ome: <https://ontome.net/class/> | ||
+ | PREFIX wdt: <http://www.wikidata.org/prop/direct/> | ||
+ | |||
+ | INSERT { | ||
+ | GRAPH <http://economists_jurists.org/import_bnf_data> { | ||
+ | # CONSTRUCT{ | ||
+ | ?uri <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ome:21 . | ||
+ | ?uri owl:sameAs ?person_bnf . | ||
+ | } | ||
+ | } | ||
+ | WHERE | ||
+ | { { SELECT DISTINCT ?person_bnf | ||
+ | WHERE | ||
+ | { | ||
+ | { SERVICE <https://data.bnf.fr/sparql> | ||
+ | { | ||
+ | { ?person_bnf egr:biographicalInformation ?bio ; | ||
+ | egr:dateOfBirth ?bd | ||
+ | BIND(strbefore(strafter(str(?bd), "http://data.bnf.fr/date/"), "/") AS ?bd1) | ||
+ | FILTER ( ( ( ( ( regex(?bio, "juriste", "i") || regex(?bio, "droit", "i") ) || regex(?bio, "avocat", "i") ) || regex(?bio, "juge", "i") ) || regex(?bio, "magistrat", "i") ) ) | ||
+ | FILTER ( ?bd1 > "1770" ) | ||
+ | } | ||
+ | UNION | ||
+ | { ?person_bnf egr:biographicalInformation ?bio ; | ||
+ | egr:dateOfBirth ?bd | ||
+ | BIND(strbefore(strafter(str(?bd), "http://data.bnf.fr/date/"), "/") AS ?bd1) | ||
+ | FILTER ( ( ( regex(?bio, "économiste", "i") || regex(?bio, "economiste", "i") ) || regex(?bio, "professeur d'économie", "i") ) || regex(?bio, "docteur en économie", "i") ) | ||
+ | FILTER ( ?bd1 > "1770" ) | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | MINUS { | ||
+ | ?uri_wikidata owl:sameAs ?person_bnf | ||
+ | FILTER regex(str(?person_bnf), "bnf", "i") | ||
+ | } | ||
+ | } | ||
+ | ORDER BY ?person_bnf | ||
+ | } | ||
+ | BIND(uuid() AS ?uri) | ||
+ | } | ||
+ | #LIMIT 100 | ||
+ | </code> | ||
+ | |||
+ | Toute la méthode réalisée pour lier les instances BnF Data et Wikidata peut être réalisée pour DBpedia. | ||
+ | Nous l'allons donc pas la détailler ici. Mais vous pouvez retrouver l'ensemble des requêtes dans notre espace **[[https://github.com/Semantic-Data-for-Humanities/Economists_Jurists/blob/main/Notebooks/data/sparql_queries.db|Github]]** en téléchargeant la base de données et en l'ouvrant avec un logiciel de requêtage de base de données comme [[https://dbeaver.io/|DBeaver]] ([[https://dbeaver.io/download/|lien]] vers le téléchargement, Mac Os, Windows et Linux). | ||
+ | . | ||
+ | |||
+ | Enfin la dernière méthode qui permet de connaître si des personnes sont dans plusieurs bases de données, c'est le Recordlinkage. Nous la présentons en détail ci-dessous. | ||
==== Recordlinkage ==== | ==== Recordlinkage ==== | ||
Ligne 345: | Ligne 417: | ||
potential_matches | potential_matches | ||
</code> | </code> | ||
+ | |||
L'ensemble de la méthode est disponible sur un **[[https://github.com/Semantic-Data-for-Humanities/Economists_Jurists/blob/development/Notebooks/Merge/Merge_DBpedia_BnF_Data_Wikidata.ipynb|carnet]]** sur Github. Vous pouvez aussi directement accéder aux requêtes en téléchargeant la **[[https://github.com/Semantic-Data-for-Humanities/Economists_Jurists/tree/development/Notebooks/Merge/data/sparql_queries.db|base de données]]** et en l'ouvrant avec un logiciel de requêtage de base de données comme [[https://dbeaver.io/|DBeaver]] ([[https://dbeaver.io/download/|lien]] vers le téléchargement, Mac Os, Windows et Linux). | L'ensemble de la méthode est disponible sur un **[[https://github.com/Semantic-Data-for-Humanities/Economists_Jurists/blob/development/Notebooks/Merge/Merge_DBpedia_BnF_Data_Wikidata.ipynb|carnet]]** sur Github. Vous pouvez aussi directement accéder aux requêtes en téléchargeant la **[[https://github.com/Semantic-Data-for-Humanities/Economists_Jurists/tree/development/Notebooks/Merge/data/sparql_queries.db|base de données]]** et en l'ouvrant avec un logiciel de requêtage de base de données comme [[https://dbeaver.io/|DBeaver]] ([[https://dbeaver.io/download/|lien]] vers le téléchargement, Mac Os, Windows et Linux). | ||