xmldataset

develop
gwen 3 years ago
parent bcf411a582
commit 567aeed0a1

@ -26,103 +26,6 @@ Ce type de référentiel de données a un schéma défini qui nécessite un *ali
c'est-à-dire qu'il faut faire correspondre les colonnes et les types de données
afin de mettre à jour les données existantes avec de nouvelles données.
Le trajet dans le pipeline de données
-----------------------------------------
Qu'entend-t-on par "data processing" ?
- La collecte ou lextraction densembles de données brutes.
- La gouvernance des données. Une fois les données collectées, il faut constituer
une discipline pour organiser les données.
Cette discipline sappelle la gouvernance des données.
On commence par relier les données brutes au contexte pour quelles aient un sens.
On contrôle ensuite la qualité des données et la sécurité des données,
avant de les organiser pleinement en vue de leur consommation.
Le pipeline ETL
----------------
.. glossary::
ETL
ETL signifie **E**\ xtract, **T**\ ransform, **L**\ oad.
C'est historiquement le premier data pipeline, (pipeline sur les données).
.. rubric:: Exemple de YAML descriptif d'un pipeline
.. code-block:: yaml
stage:
prepared:
- name: bourbon_clean_up
depends: bourbon_xml_catalog
outputs: bourbon_data
Qu'est-ce que intégrer des données ?
---------------------------------------
.. glossary::
intégration des données
L'intégration des données est le processus qui consiste à combiner des données
provenant de différentes sources dans une vue unifiée : de l'importation au nettoyage
en passant par le mapping et la transformation dans un gisement cible,
pour finalement rendre les données plus exploitables et plus utiles.
.. rubric:: exemple
Les métadatas contenues dans un fichier CSV et les datas contenues dans un fichier XML.
Quest-ce que l'étiquetage des données ?
-------------------------------------------------------
Dans le cas de processus tels que lintégration des données, la migration des données,
lautomatisation des entrepôts de données, la synchronisation des données,
lextraction automatique de données ou dautres projets de gestion des données,
la qualité de l'étiquetage conditionnera la qualité des données qui seront analysées
pour en tirer des informations exploitables.
.. glossary::
étiquetage des données
Un label est associé à une donnée pour savoir par exemple quelle est
sa provenance.
**E**\ xtraire les données
-----------------------------
- **Extraire les données** c'est, dans ce cas, charger depuis le système de fichiers en local,
les fichiers CSV et XML.
.. note:: Pas besoin de collecte et agrégation des données.
Les Sources de datas sont présentes en local dans l'application.
.. admonition:: TODO
Il faudra les enlever de l'arborescence flask pour les mettre dans
un :term:`référentiel de données`.
Datasource CSV::
./app/static/csv/corpus-agnes-bourgogne.csv
./app/static/csv/corpus-charles-i.csv
./app/static/csv/actors.csv
Datasource XML :
Dans `./app/static/xml/` :
.. image:: img/xml.png
Le référentiel de données
--------------------------------
@ -215,68 +118,16 @@ La **T**\ ransformation des données
La transformation des données consiste à convertir les données dun format source dans un format cible. Cela peut inclure un nettoyage des données par une modification des types de données, une suppression des données invalides ou des doublons, une agrégation des données, un enrichissement des données ou dautres transformations.
- La transformation des données
- normalisation
- dédoublonnage
- vérification
- classement
- partage des données
Autres types de transformation :
- Cleaning
- Filtering
- Joining
- Sorting
- Splitting
- Deduplication
- Summarization
"The data cleaning and organization stage is the transformation stage."
.. rubric:: Quel type de transformation des données et pourquoi ?
La visualisation des pipelines
----------------------------------
Il s'agit surtout de les structurer, ce que faisait, avant, le storage
dans une base de données relationnelle.
Utiliser l'outil fournit avec kedro, lancer la commande::
Aujourd'hui, l'organisation des datas ne relève plus de la responsabilité du storage
(`cohérence de type ACID <http://monge.univ-mlv.fr/~dr/XPOSE2011/BDD/acid.html>`_),
le storage n'ayant que la responsabilité de type `BASE <http://monge.univ-mlv.fr/~dr/XPOSE2011/BDD/acid.html>`_
kedro viz
On obtient une interface de ce type :
Que signifie le data reshaping ?
--------------------------------------
.. image:: img/kedro-viz.png
On parle de data shape shifting ou data reshaping.
- data shape shifting (changement de forme des datas)
- data reshaping avec pandas
- data reshaping avec les schémas, que ce soient les schémas d'une database
ou bien les librairies de schémas d'une structure de données.
Avant, on utilisait uniquement les databases pour faire du data reshaping.
La database etait vue comme cela :
- PostgreSQL as a data processing engine,
- sqlite as a data processing engine.
Aujourd'hui, on utilise plutôt des librairies de validation de schémas (pydantic, JSON schema,
XML schema...)
Le chargement des données (**L**\ oad)
----------------------------------------
- mettre ces données dans un storage (dans ce contexte, une database nosql
de type mongodb).
.. note:: concernant le storage, un serveur mongo n'est pas gourmand en ressources
et reste dans le cadre d'outil "low tech" à mon avis.
On peut aussi utiliser une base nosql qui ne soit pas un serveur
(comme pour sqlite dans le monde des databases relationnelles).
.. note:: Chacune de ces étapes fait aujourd'hui l'objet d'un pipeline
indépendant.
Par exemple, dans le "data understanding", la question de l'extraction
d'information représente de nombreux pipelines.

@ -4,7 +4,7 @@ from typing import Dict
from lxml import etree
from actesdataset import XMLDataSet
from actesdataset import EtreeXMLDataSet
logger = logging.getLogger(__name__)
@ -16,7 +16,7 @@ def transform(source_doc: etree._ElementTree, xlststylesheet: str) -> str:
return str(xslt_transformer(source_doc))
def parse_xml_collection(datasets: Dict[str, XMLDataSet], param: str) -> Dict[str, XMLDataSet]:
def parse_xml_collection(datasets: Dict[str, EtreeXMLDataSet], param: str) -> Dict[str, EtreeXMLDataSet]:
"node function entry point, performs batch processing"
output_datasets = dict()
for dataset_filenamestem, dataset in datasets.items():
@ -26,7 +26,7 @@ def parse_xml_collection(datasets: Dict[str, XMLDataSet], param: str) -> Dict[st
output_source_doc = transform(dataset.get_source_doc(), param)
# set dataset's output filepath
output_filepath = dataset.get_filepath().replace("01_raw", "02_intermediate")
output_xmldataset = XMLDataSet(output_filepath)
output_xmldataset = EtreeXMLDataSet(output_filepath)
output_xmldataset.set_source_doc(output_source_doc)
output_datasets[dataset_filenamestem] = output_xmldataset
# let's create subfolders now, if they don't exist

@ -4,14 +4,17 @@ from typing import Dict, Any
from pathlib import Path
from lxml import etree
from bs4 import BeautifulSoup
from kedro.io import AbstractDataSet, DataSetError
from kedro.framework.session import KedroSession
logger = logging.getLogger(__name__)
# FIXME hériter de abc (cf dans le code de kedro)
class XMLDataSet:
"lxml.etree._ElementTree loader"
"Abstract base class for an XML dataset loader"
def __init__(self, filepath: str) -> None:
self._filepath = filepath
@ -31,9 +34,18 @@ class XMLDataSet:
def set_source_doc(self, source_doc: str) -> None:
"XML source_doc (xml as a string) setter"
self.source_doc = source_doc
def _describe(self) -> Dict[str, Any]:
"kedro's API-like repr()"
return dict(filepath=self._filepath)
class EtreeXMLDataSet(XMLDataSet):
"XMLDataSet loader with lxml.etree (lxml.etree._ElementTree)"
def _transform_source_doc(self) -> etree._ElementTree:
"xml transformer (with element tree)"
self.source_doc = etree.parse(self._filepath)
# removing namespace
query = "descendant-or-self::*[namespace-uri()!='']"
for element in self.source_doc.xpath(query):
@ -44,20 +56,73 @@ class XMLDataSet:
def _load(self) -> etree._ElementTree:
"kedro's API-like loader"
self.source_doc = etree.parse(self._filepath)
self._transform_source_doc()
return self.source_doc
def _save(self, data:str) -> None:
"kedro's API-like saver"
with open(self._filepath, 'w') as fhandle:
fhandle.write(data)
def _describe(self) -> Dict[str, Any]:
"kedro's API-like repr()"
return dict(filepath=self._filepath)
class BsXMLDataSet(XMLDataSet):
"XMLDataSet loaded with BeautifulSoup"
def _load(self) -> etree._ElementTree:
"kedro's API-like loader"
self._transform_source_doc()
return self.source_doc
def _load_soup(self):
"""open a xml file and return a BeautifulSoup object"""
with open(self._filepath, 'r', encoding="utf-8") as opening:
xml = BeautifulSoup(opening, 'xml')
return xml
def _save(self, data:str) -> None:
"kedro's API-like saver"
raise NotImplementedError("This DataSet shall not be saved...")
def _extract_data(self):
# FIXME -> traitement à déplacer dans le nodes.py
# make_soup -> _load_soup -> soup est déjà chargé
#soup = make_soup(os.path.join(folder, acte))
# 1.1/ Get all data from XML (9). counter is the id (= numb_acte)
numb = soup.TEI["xml:id"] # /TEI[@xml:id] is always the acte's ID
date_time = soup.msItem.docDate["when"] # YYYY-MM-DD or YYYY-MM date
date = soup.msItem.docDate.text # verbose date
analyse = soup.abstract.p.text # acte's short analysis
ref = soup.msIdentifier.find_all("idno", {"n": "2"})
# //sourceDesc//msIdentifier/idno[@n='2'] is the doc id inside the
# archive box or the page number inside a manuscript (see _create_doc)
# warning: the analysis may not have been written yet,
# which would result in List Index Out of Range Error. Hence :
if len(ref) > 0: # there is an analysis
ref_acte = ref[0].text
else: # there is no analysis
ref_acte = "NS"
prod_place = soup.find_all("placeName", {"type": "production_place"})[0].text
# //sourceDesc//msIdentifier/idno[@n='1'] is always the
# archive box or manuscript collection id
doc = soup.msIdentifier.find_all("idno", {"n": "1"})[0]
type_diplo = soup.body.div["subtype"]
diplo_state = soup.body.div["type"]
# 2/ Make the data list
actes.append({
"num_acte": counter,
"filename": numb,
"date_time": date_time,
"date": date,
"prod_place_acte": place_query[0],
"analysis": analyse,
"doc_acte": doc_query[0],
"ref_acte": ref_acte,
"state_doc": state_query[0],
"diplo_type_acte": diplo_query[0]
})
class XMLDataSetCollection(AbstractDataSet):
"""Stores instances of ``XMLDataSet``
implementations to provide ``_load`` and ``_save`` capabilities.
@ -76,15 +141,15 @@ class XMLDataSetCollection(AbstractDataSet):
attr_error_msg = str(self._describe())
raise AttributeError(f"Object {attr_error_msg} has no attribute named : 'datasets'")
def _load(self) -> dict[str, XMLDataSet]:
def _load(self) -> dict[str, EtreeXMLDataSet]:
"kedro's API loader"
self.datasets = dict()
for filepath in sorted(self._folderpath.glob("*.xml")):
self.datasets[filepath.stem] = XMLDataSet(
self.datasets[filepath.stem] = EtreeXMLDataSet(
filepath=str(filepath))
return self.datasets
def _save(self, datasets: dict[str, XMLDataSet]) -> None:
def _save(self, datasets: dict[str, EtreeXMLDataSet]) -> None:
"kedro's API saver"
for stemfilename, dataset in datasets.items():
dataset._save(dataset.get_source_doc())

Loading…
Cancel
Save