Ajouter de la sémantique à un croissant
Un fichier RoboCroissant liste les fichiers d'une base de connaissances et les colonnes qu'ils contiennent. Cette compétence ajoute ce que les données signifient : quelles colonnes décrivent ensemble un gène ou une maladie, ce qu'affirme une ligne, quel préfixe d'identifiant les identifiants d'une colonne utilisent, ce que représentent les codes. Elle écrit cela dans un nouveau croissant en utilisant les constructions Croissant 1.1, et enregistre pourquoi chaque déclaration a été faite.
Vous produisez un plan (JSON, par disposition), les scripts l'appliquent et le vérifient. Vous ne modifiez pas le croissant à la main.
Entrées et sorties
- Entrée : un croissant (
croissant.jsonoucroissant.json.gz) et un répertoire de sortie, plus le fichiersemantics_answers.jsondes mainteneurs à côté du croissant, s'il existe. - Sortie, dans le répertoire de sortie :
semantics_plan.json— le plan (format :reference/plan-format.md)croissant.semantic.json(ou.json.gzsi l'entrée était compressée) — le résultatcheck_report.md— la sortie decheck.py(etcheck_report.load_errors.txt, erreurs mlcroissant complètes, lorsque le chargement des enregistrements a échoué)notes.md— décisions, dispositions omises et pourquoi, et questions pour les mainteneurs de la base de connaissances
Le croissant d'entrée n'est jamais modifié. Placez les téléchargements, scripts d'aide et autres travaux temporaires
dans OUT/work/, pas ailleurs.
Scripts
Tous dans scripts/, exécutés directement (ce sont des fichiers uv run --script qui installent leurs propres
dépendances). Utilisez --help sur n'importe lequel d'entre eux.
| Script | Utilisation |
|---|---|
inventory.py CROISSANT [--layout ID] [--json F] [--common-columns] | Lister les dispositions (ensembles de colonnes distincts), du plus grand au plus petit ; décrire les colonnes d'une disposition, les jeux d'enregistrements et les fichiers ; lister les colonnes que la plupart des jeux d'enregistrements partagent |
sample.py CROISSANT --layout ID | Lire des lignes réelles de trois fichiers de la disposition ; montrer les valeurs d'exemple de chaque colonne et leur forme (CURIE et leurs préfixes, identifiants nus, listes, codes) |
dialects.py list/show/detect/read | Formats de fichiers connus (VCF, GAF, MITAB, CTD, ...) sous forme de dialectes calculables ; lequel lit les fichiers d'une disposition ; lire les enregistrements en utilisant uniquement ce qu'un croissant dit du fichier |
vocab.py class/slot/search/associations/prefix/identify/term/ols/infores | Rechercher des classes et slots Biolink (avec suggestions de quasi-correspondance), classes d'association pour une paire sujet/objet, préfixes d'identifiants (Biolink + Bioregistry), quels préfixes correspondent à des identifiants nus, termes d'ontologie par identifiant ou texte, et identifiants infores pour les noms de sources |
apply_plan.py CROISSANT PLAN OUT | Écrire le plan dans un nouveau croissant |
check.py CROISSANT PLAN OUT --report R --load-records | --plan-only d'abord : termes, préfixes, dialectes et unités en secondes. Puis la vérification complète : vérifie les termes, préfixes, codes et dialectes par rapport à Biolink et aux données échantillonnées, exécute le validateur MLCommons, lit quelques enregistrements via mlcroissant (à partir des premières lignes de chaque fichier, pas des téléchargements complets), et rapporte la couverture |
Workflow
-
Enquête. S'il existe un fichier
semantics_answers.jsonà côté du croissant, lisez-le d'abord : il contient les réponses des mainteneurs de la base de connaissances aux questions précédentes (voir "Réponses des mainteneurs" ci-dessous). Ne reposez pas ces questions ;apply_plan.pyetcheck.pyappliquent les réponses à votre plan automatiquement. Ensuite, lancezinventory.py CROISSANT. Notez la base de connaissances (nom, description, URL dans le croissant) et comment les jeux d'enregistrements sont répartis entre les dispositions. Les grandes bases de connaissances ont des centaines de dispositions ; travaillez à partir du haut de la liste.Trouvez l'identifiant infores de la base de connaissances maintenant (
vocab.py infores NOM; essayez son nom complet, son acronyme et son URL) et définissez-le commeinforesdu plan. Il nomme la ressource dont ces fichiers sont issus, et les constructeurs de graphes la citent comme source de tout ce qui est lu à partir d'eux : sans elle, l'étape de transformation ne construira pas la base de connaissances du tout. Lorsque plusieurs entrées correspondent, choisissez celle pour la ressource qui publie ces fichiers, pas un service qui la rediffuse (infores:reactome, pasinfores:automat-reactome).check.pyla compare avec ce que le reste de votre plan dit : un agrégateur unique ou une constante provided_by nomme la base de connaissances aussi (les orthologues de HCOP sont agrégés parinfores:hgnc), et une discordance est un avertissement à résoudre.Lorsqu'aucune ne correspond, proposez-en une :
infores:et le nom court de la base de connaissances en minuscules mots séparés par des tirets (infores:bioplex,infores:expression-atlas), avec"infores_proposed": truedans le plan. Ensuite, écrivez son entrée de catalogue avecvocab.py infores-entry CROISSANT --id infores:NOM, en ajoutant--knowledge-levelet--agent-typelorsque la documentation les rend clairs, et placez-la dansnotes.mdsous un en-tête Identifiant infores à enregistrer, près du haut. Dites-y que l'utilisateur doit l'enregistrer avec une pull request vers le registre infores (la commande imprime où), et que l'identifiant peut changer lors de la relecture.check.pyconserve un avertissement sur un identifiant proposé jusqu'à ce qu'il soit enregistré ; ne l'expliquez pas. -
Choisissez les dispositions à traiter. Visez les dispositions qui couvrent le plus de jeux d'enregistrements et le contenu central (associations et les principales tables d'entités) — généralement les 5 à 15 premières, ou jusqu'à ce que les dispositions restantes soient mineures (fichiers de type readme, logs, comptages par version). S'il y a de nombreuses petites dispositions (
inventory.pyle dira), les jeux d'enregistrements partagent probablement des colonnes centrales : utilisezinventory.py --common-columnset planifiez ces colonnes une fois avecmatch.has_columns. Tout ce que vous omettez va dans la listeskippeddu plan avec une raison. Faire moins de dispositions bien est mieux que beaucoup mal. -
Pour chaque disposition, regardez les données avant de décider quoi que ce soit.
inventory.py CROISSANT --layout IDpour les colonnes, descriptions et noms de fichiers. Une colonne marquéeMIXEDa des types atomiques différents dans différents jeux d'enregistrements (le pipeline les infère par fichier) ; décidez de son type à partir des données et définissezatomic.- Pour les tables,
dialects.py detect CROISSANT --layout IDtrouve comment les fichiers sont écrits (lignes de commentaire, en-tête ou non, délimiteur) parmi les formats connus. Les formats bien connus (VCF, GAF, MITAB) ont des spécifications publiées ; appuyez-vous sur elles plutôt que de redécouvrir le format. Si rien ne correspond, décrivez le dialecte en ligne (reference/dialects.md). Ensuite, échantillonnez avec--dialect NOMafin que les lignes soient lues comme le format le dit, pas deviné. sample.py CROISSANT --layout IDpour les valeurs réelles. Il lit trois fichiers de la disposition (le plus récent par son nom, le plus grand, le plus petit), car un seul fichier — souvent un ancien instantané ou un sous-ensemble filtré — peut cacher des valeurs (placeholdersN/A, valeurs de code supplémentaires, autres types d'identifiants).--files Nen échantillonne davantage ;--record-set IDéchantillonne un fichier particulier. Si l'échantillonnage échoue (un fichier énorme, une archive, un ensemble de fichiers), dites-le dans labasisdu plan et réduisez la confiance.- Pour les colonnes de code (types, preuves, relations, sources), un échantillon manque les valeurs rares.
sample.py CROISSANT --record-set ID --profile COL1,COL2lit le fichier entier et compte chaque valeur distincte ; répétez--record-setpour additionner plusieurs fichiers. Mappez à partir du profil, pas de l'échantillon. - Soyez gentil avec les serveurs de la base de connaissances. Exécutez une commande d'échantillonnage ou de vérification à la fois
par base de connaissances, jamais plusieurs en parallèle : les hôtes bloquent les rafales avec un défi anti-bot, puis
chaque requête ultérieure échoue. Les scripts espacent leurs propres requêtes et mettent en cache les téléchargements (dans
~/.cache/croissant-semantics/downloads;--refreshtélécharge à nouveau), donc ré-exécuter est peu coûteux (une copie mise en cache sous un plus grand--max-mbsert un plus petit). Si un script signale un défi anti-bot ou une erreur HTTP 403, arrêtez d'échantillonner cet hôte, n'essayez pas de le contourner, et dites dansnotes.mdquelles vérifications n'ont pas pu être exécutées. Les scripts refusent alors cet hôte pendant une heure, entre les exécutions, et travaillent à partir des fichiers en cache. - Les feuilles de calcul (xlsx et legacy xls), les bases de données SQLite et les fichiers parquet sont également échantillonnés et profilés : la
feuille ou la table est celle dont le nom du jeu d'enregistrements se termine ("fichier.xlsx — Sheet1",
"fichier.xlsx : Sheet1"), et l'échantillonnage échoue plutôt que de deviner quand il ne peut pas dire. Ils sont lus
en entier, donc augmentez
--max-mbsi nécessaire (surcheck.pyégalement). mlcroissant ne peut pas lire les feuilles de calcul ou les bases de données, donc leurs enregistrements ne sont pas chargés. - XML, RDF (Turtle, RDF/XML, OWL), FASTA et autres fichiers qui ne sont pas des tables ne peuvent pas être échantillonnés :
les scripts le disent. Si une disposition est importante, vérifiez ses identifiants avec un petit script dans
OUT/work/(uv run --with rdflibpour RDF ; diffusez XML avecxml.etree.ElementTree.iterparse), et dites comment dansnotes.md. Leurs champs n'ont généralement pas d'extract, donc aucun outil ne peut les lire : un problème de générateur à signaler. --profileavec--layoutprofile--filesjeux d'enregistrements de la disposition (par défaut 3, ouall) au lieu de nommer chacun avec--record-set.--prefixescompte le préfixe ou la balise de chaque valeur, pour toutes les colonnes profilées ou seulement celles listées (--prefixes COL1,COL2) ;--by COLtabule croisé avec une autre colonne (quels types d'objets chaque code apparaît avec) ;--split SEPcompte les éléments des cellules de liste ;--per-fileprofile chaque jeu d'enregistrements séparément (pour vérifier que les identifiants sont uniques par fichier) ;--stop-mb Narrête chaque fichier après N Mo, pour des fichiers de plusieurs Go (les comptages ne couvrent alors que le début ; dans un fichier trié par espèce ou identifiant, cela peut être un seul groupe, donc dites-le).- Profilez les colonnes d'identifiants des dispositions principales (
--profile COL --shapes) avant de leur faire confiance : la vérification des données lit les premières lignes de quelques fichiers, donc une colonne dont les lignes ultérieures manquent d'identifiants, ou contiennent une autre famille d'identifiants, la passe. Plusieurs bases de connaissances avaient 20 à 30 % de lignes sans identifiant après des centaines de lignes qui en avaient toutes un. - Une entrée
match.has_columnsqui couvre de nombreuses dispositions est échantillonnée parcheck.pysur seulement quelques-uns de ses fichiers. Échantillonnez les dispositions qu'elle couvre qui diffèrent (--record-set-name,--files) avant de lui faire confiance. - Les scripts utilisent le magasin de certificats du système d'exploitation. Si les téléchargements échouent encore avec une erreur de certificat, signalez-la avec la sortie ; ne désactivez pas la vérification.
- Si la documentation est derrière une vérification anti-bot ("verify you are human", un défi Cloudflare ou
ALTCHA), n'essayez pas de la contourner ; planifiez à partir des données et des noms, et plafonnez la confiance à
mediumpour les significations que seule la documentation pourrait confirmer. La provenance du croissant peut citer des pages qui ont depuis été mises derrière une vérification : citez seulement ce que vous avez pu lire. - Dans un fichier volumineux, les premières lignes peuvent ne pas être représentatives (le fichier
genes_diseasesde 3 Go de CTD commence avec des milliers de lignes inférées). Profilez un fichier plus petit de la même disposition (le sous-ensemble curé) plutôt que de diffuser l'ensemble. - Pour sélectionner des jeux d'enregistrements par nom, utilisez
--record-set-name REGEX(au lieu de--layout) plutôt que de construire une liste d'arguments--record-setdans le shell (zsh ne divise pas les variables en mots).--per-filemontre chaque fichier échantillonné séparément, pour les dispositions dont les fichiers diffèrent (un type d'identifiant par fichier). - La vérification des données lit les premières lignes de quelques fichiers. Les lignes ultérieures d'une colonne peuvent différer (nœuds
blancs après 200 IRI, un code rare) : confirmez les formes d'identifiants et les codes avec
--profile, qui lit les fichiers entiers. inventory.pyliste les fichiers de documentation livrés avec les données (README.pdf dans un zip, un dictionnaire de données) après les dispositions. Lisez ceux qui sont pertinents :sample.py CROISSANT --dump FICHIERimprime un fichier sous forme de texte,--member NOMun membre d'une archive (un zip est lu en entier, donc augmentez--max-mbpour un gros) (il liste les membres d'un zip lorsque le nom est incorrect),--sheet NOMune feuille d'un tableur.sample.pysignale les colonnes dont le type déclaré ne correspond pas aux valeurs (une colonnesc:Integercontenant27152464|29518214) et les fichiers dont les lignes sont plus larges ou plus étroites que l'en-tête. Les deux sont généralement des problèmes de pipeline : corrigez les types avecatomic, et signalez-les.- Lorsque les scripts ne peuvent pas lire une source, récupérez les fichiers vous-même (un à la fois, dans
OUT/work/) et pointez les scripts vers eux avec--url-map OLD=file:///abs/path/afin que leurs vérifications puissent toujours s'exécuter, plutôt que d'écrire vos propres profileurs. Les téléchargements sont mis en cache, et~/.cache/croissant-semantics/downloads/index.tsvmappe chaque fichier en cache à son URL. - Si les "noms de colonnes" d'une disposition sont en réalité des données (pas de ligne d'en-tête, donc le pipeline a pris la
première ligne de données comme noms, et chaque fichier est devenu sa propre disposition), ignorez-la et signalez-la dans
notes.mdcomme un problème de pipeline. - Si les URL des données sont absentes (HTTP 404), la base de connaissances est probablement passée à une version plus récente.
Trouvez les URL actuelles depuis sa page de téléchargement et passez
--url-map OLD=NEWàsample.pyetcheck.py(par exemple--url-map 202607=202610). Lorsque plus que la version a changé (un autre chemin ou nom de fichier), mappez les URL entières, un--url-map OLD_URL=NEW_URLpar fichier. Lorsque les URL elles-mêmes contiennent=(chaînes de requête), écrivezOLD=>NEW. Dites-le dansnotes.md; c'est aussi un problème de pipeline. Une URL de point d'accès SPARQL qui renvoie du JSON alors que le croissant décrit une table nécessite généralement&format=csv(outext/csv) mappé. - Archives : les membres des archives zip et tar sont échantillonnés. Un zip est téléchargé en entier (jusqu'à
--max-mb) ; un tar est diffusé jusqu'à ce que le membre soit trouvé, donc un membre profondément dans un énorme tar peut dépasser--max-mb. Une archive qui échoue une fois n'est pas réessayée, et l'échantillonnage s'arrête après des échecs répétés. Si vous le devez, extrayez un membre dansOUT/work/vous-même, et enregistrez ce que vous avez vérifié et comment dansnotes.md. - Si les données nécessitent une connexion ou une clé API (HTTP 401/403, ou le
conditionsOfAccessdu croissant le dit), ne cherchez pas d'identifiants. Planifiez à partir de la documentation et des noms de colonnes uniquement :sourceestdocumentationouagent,confidenceau plusmedium, etnotes.mddit que rien n'a été vérifié par rapport aux données. - Cherchez un da
[Le contenu a été tronqué pour la traduction]