Metadades i mapes de metadades¶
Traducció assistida per IA - més informació i suggeriments
En qualsevol anàlisi científica, rarament treballem només amb els fitxers de dades en brut. Cada fitxer porta la seva pròpia informació addicional: què és, d'on prové i què el fa especial. Aquesta informació extra és el que anomenem metadades.
Les metadades són dades que descriuen altres dades. Les metadades fan un seguiment de detalls importants sobre els fitxers i les condicions experimentals, i ajuden a adaptar les anàlisis a les característiques úniques de cada conjunt de dades.
Penseu-hi com en un catàleg de biblioteca: mentre que els llibres contenen el contingut real (les dades en brut), les fitxes del catàleg proporcionen informació essencial sobre cada llibre—quan es va publicar, qui el va escriure, on trobar-lo (metadades). En els pipelines de Nextflow, les metadades es poden utilitzar per a:
- Fer un seguiment de la informació específica de cada fitxer al llarg del workflow
- Configurar processos en funció de les característiques dels fitxers
- Agrupar fitxers relacionats per a una anàlisi conjunta
Objectius d'aprenentatge¶
En aquesta missió secundària, explorarem com gestionar metadades en workflows. Partint d'un full de dades senzill (sovint anomenat samplesheet en bioinformàtica) que conté informació bàsica sobre els fitxers, aprendreu com:
- Llegir i analitzar metadades de fitxers CSV
- Entendre per què la interfície "meta map + fitxer de dades" és una convenció àmpliament utilitzada
- Afegir nous camps de metadades durant l'execució del workflow
- Utilitzar metadades per personalitzar el comportament dels processos i organitzar les sortides
Aquestes habilitats us ajudaran a construir pipelines més robustos i flexibles que puguin gestionar relacions complexes entre fitxers i requisits de processament.
Prerequisits¶
Abans d'emprendre aquesta missió secundària, hauríeu de:
- Haver completat el tutorial Hello Nextflow o un curs equivalent per a principiants.
- Estar còmodes amb els conceptes i mecanismes bàsics de Nextflow (processos, canals, operadors)
0. Primers passos¶
Obriu el codespace de formació¶
Si encara no ho heu fet, assegureu-vos d'obrir l'entorn de formació tal com es descriu a la Configuració de l'entorn.
Moveu-vos al directori del projecte¶
Anem al directori on es troben els fitxers d'aquest tutorial.
Podeu configurar VSCode perquè es centri en aquest directori:
L'editor s'obre amb el directori del projecte en focus.
Reviseu els materials¶
Trobareu un fitxer de workflow principal i un directori data que conté un full de dades i uns quants fitxers de dades.
Contingut del directori
El workflow del fitxer main.nf és un esquelet que anireu ampliant gradualment fins a convertir-lo en un workflow completament funcional.
El full de dades llista les rutes als fitxers de dades i algunes metadades associades, organitzades en 3 columnes:
id: autoexplicatiu, un identificador assignat al fitxercharacter: un nom de personatge, que utilitzarem més endavant per dibuixar diferents criaturesdata: rutes als fitxers.txtque contenen salutacions en diferents idiomes
id,character,recording
sampleA,squirrel,/workspaces/training/side-quests/metadata/data/bonjour.txt
sampleB,tux,/workspaces/training/side-quests/metadata/data/guten_tag.txt
sampleC,sheep,/workspaces/training/side-quests/metadata/data/hallo.txt
sampleD,turkey,/workspaces/training/side-quests/metadata/data/hello.txt
sampleE,stegosaurus,/workspaces/training/side-quests/metadata/data/hola.txt
sampleF,moose,/workspaces/training/side-quests/metadata/data/salut.txt
sampleG,turtle,/workspaces/training/side-quests/metadata/data/ciao.txt
Cada fitxer de dades conté text de salutació en un dels cinc idiomes (fr: francès, de: alemany, es: espanyol, it: italià, en: anglès).
Utilitzarem una eina anomenada COWPY per generar art ASCII de cada personatge dient la seva salutació gravada.
Què fa COWPY?
COWPY és una eina de línia de comandes que genera art ASCII per mostrar entrades de text arbitràries d'una manera divertida.
És una implementació en Python de l'eina clàssica cowsay de Tony Monroe.
______________________________________________________
< Hello Nextflow >
------------------------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Opcionalment, podeu seleccionar un personatge (o 'cowacter') per utilitzar en lloc de la vaca per defecte.
A més, utilitzarem una eina d'anàlisi de llenguatge anomenada langid per identificar en quin idioma parla cada personatge i organitzar les sortides del pipeline en conseqüència.
Reviseu l'assignació¶
El vostre repte és escriure un workflow de Nextflow que:
- Generi art ASCII de cada personatge
- Organitzi les sortides per família lingüística (llengües germàniques vs. romàniques)
Això representa un patró típic de workflow on les metadades específiques de cada fitxer guien les decisions de processament; exactament el tipus de problema que els mapes de metadades resolen de manera elegant.
Llista de comprovació de preparació¶
Creieu que esteu a punt per submergir-vos?
- Entenc l'objectiu d'aquest curs i els seus prerequisits
- El meu codespace està en funcionament
- He configurat el meu directori de treball adequadament
- Entenc l'assignació
Si podeu marcar totes les caselles, esteu a punt per començar.
1. Opcions bàsiques per carregar i utilitzar metadades¶
Obriu el fitxer de workflow main.nf per examinar l'esquelet del workflow que us donem com a punt de partida.
| main.nf | |
|---|---|
L'operador splitCsv llegeix cada fila del fitxer com un element del canal.
Aquest és el mateix enfocament que utilitzem per carregar dades CSV a Hello Nextflow, el nostre curs per a principiants.
Consulteu aquesta secció si necessiteu un recordatori de com funciona.
Amb header: true, la primera fila es tracta com a capçaleres de columna, de manera que cada element es converteix en un mapa de parells clau-valor indexats pel nom de columna.
Tingueu en compte que com que encara no estem executant cap procés sobre les dades, els blocs publish i output són simplement esquelets.
1.1. Executeu el workflow¶
Executeu el workflow per veure com s'estructura el contingut del canal un cop tot s'ha carregat:
Sortida de la comanda
N E X T F L O W ~ version 25.10.4
Launching `main.nf` [exotic_albattani] DSL2 - revision: c0d03cec83
[id:sampleA, character:squirrel, recording:/workspaces/training/side-quests/metadata/data/bonjour.txt]
[id:sampleB, character:tux, recording:/workspaces/training/side-quests/metadata/data/guten_tag.txt]
[id:sampleC, character:sheep, recording:/workspaces/training/side-quests/metadata/data/hallo.txt]
[id:sampleD, character:turkey, recording:/workspaces/training/side-quests/metadata/data/hello.txt]
[id:sampleE, character:stegosaurus, recording:/workspaces/training/side-quests/metadata/data/hola.txt]
[id:sampleF, character:moose, recording:/workspaces/training/side-quests/metadata/data/salut.txt]
[id:sampleG, character:turtle, recording:/workspaces/training/side-quests/metadata/data/ciao.txt]
Com podeu veure, l'operador ha construït un mapa de parells clau-valor per a cada fila del fitxer CSV, amb les capçaleres de columna com a claus per als valors corresponents.
Cada entrada del mapa correspon a una columna del nostre full de dades:
idcharacterrecording
Això facilita l'accés a camps específics de cada fila.
Per exemple, podríem accedir a l'identificador del fitxer amb id o a la ruta del fitxer txt amb recording.
(Opcional) Més informació sobre els mapes de Groovy
En Groovy, el llenguatge de programació sobre el qual es construeix Nextflow, un mapa és una estructura de dades de clau-valor similar als diccionaris en Python, els objectes en JavaScript o els hashes en Ruby.
Aquí teniu un script executable que mostra com podeu definir un mapa i accedir al seu contingut en la pràctica:
#!/usr/bin/env nextflow
// Crea un mapa senzill
def my_map = [id:'sampleA', character:'squirrel']
// Imprimeix el mapa sencer
println "map: ${my_map}"
// Accedeix als valors individuals amb notació de punt
println "id: ${my_map.id}"
println "character: ${my_map.character}"
Tot i que no té un bloc workflow pròpiament dit, Nextflow pot executar-lo com si fos un workflow:
I aquí teniu el que podeu esperar veure a la sortida:
1.2. Seleccionar un camp específic amb map¶
Utilitzarem l'operador map per iterar sobre cada element del canal i seleccionar només el camp character, al qual podem accedir pel nom utilitzant la notació de punt.
1.2.1. Afegiu l'operació map¶
Per accedir a la columna character, afegiu l'operació map abans de l'operació .view() de la manera següent:
Aquesta manera d'accedir a un camp específic s'explica amb més detall a aquesta secció de Hello Nextflow, si necessiteu un recordatori de com funciona.
1.2.2. Executeu el workflow¶
Executeu el workflow per verificar que podeu veure els noms dels personatges extrets.
Sortida de la comanda
Això mostra que podem accedir als valors de la columna character per a cada fila.
Ara fem alguna cosa amb aquestes dades: utilitzem els camps character i recording junts per generar art ASCII amb COWPY.
1.3. Emetre sub-canals amb multiMap¶
Us proporcionem un mòdul de procés preescrit per a COWPY, de manera que primer heu d'examinar els requisits d'entrada del procés.
Podeu obrir el fitxer per veure com és el procés:
| modules/cowpy.nf | |
|---|---|
Com podeu veure, el procés pren dues entrades separades: un fitxer de gravació i un nom de personatge. Importantment, tenim valors per a tots dos, però actualment estan agrupats dins de cada element del canal.
Una manera d'extreure múltiples camps en canals separats és l'operador multiMap, que divideix un canal en múltiples sub-canals amb nom en una sola operació.
1.3.1. Afegiu l'operació multiMap¶
Substituïu l'operació map per multiMap:
El bloc multiMap defineix dos sub-canals amb nom (file i character) a partir de cada fila, als quals podem accedir com a ch_datasheet.file i ch_datasheet.character.
1.3.2. Crideu COWPY sobre els sub-canals¶
Ara, incloeu el procés COWPY i passeu-li cada sub-canal com a argument separat:
| main.nf | |
|---|---|
Això ens permet passar els dos camps per separat tal com requereix COWPY.
1.3.3. Configureu la publicació de la sortida¶
Finalment, afegiu la sortida de COWPY al bloc publish::
Això ens permetrà veure fàcilment les sortides produïdes pel workflow.
1.3.4. Executeu el workflow¶
Executeu el workflow per comprovar que COWPY s'executa sobre les entrades que hem proporcionat:
Sortida de la comanda
Com podeu veure, COWPY s'ha executat sobre cada fitxer utilitzant el personatge correcte per a cadascun.
Contingut del directori de resultats
Contingut de results/cowpy-guten_tag.txt
Aquest enfocament funciona, però té una limitació: hem hagut de dividir el canal en dos sub-canals separats. Si volguéssim passar més camps al procés, hauríem de dividir-los en més sub-canals. Això podria resultar molest i desordenat.
Bona notícia: hi ha una manera més senzilla de fer-ho.
1.4. Agrupar-ho tot com una sola entrada al procés¶
En lloc de dividir els camps en canals separats, podem actualitzar el procés per rebre totes les entrades com una sola tupla, la qual cosa simplifica la crida al procés.
1.4.1. Actualitzeu el procés COWPY¶
Actualitzeu COWPY per acceptar una tupla corresponent als tres elements de cada fila:
| modules/cowpy.nf | |
|---|---|
| modules/cowpy.nf | |
|---|---|
Ara el procés pren una sola entrada que conté tot el que li volem passar.
1.4.2. Utilitzeu map() per crear la tupla d'entrada¶
Encara hem d'utilitzar una operació de mapeig per enumerar els elements que volem passar a la tupla del procés:
Potser us pregunteu per què no podem simplement passar el mapa de Groovy sencer que prové de splitCsv tal com és.
És perquè hem de dir-li a Nextflow explícitament que el fitxer de gravació s'ha de gestionar com a ruta (és a dir, s'ha de preparar correctament).
Això passa a nivell de la interfície d'entrada de COWPY, on l'element recording es designa explícitament com a path.
1.4.3. Actualitzeu la crida al procés¶
Finalment, substituïm les dues entrades separades de la crida al procés per la tupla única que acabem de crear:
Això simplifica una mica la crida al procés.
1.4.4. Executeu el workflow¶
Executeu el workflow per verificar que COWPY encara pot processar les dades correctament:
Sortida de la comanda
La sortida és els mateixos set fitxers cowpy-*.txt que abans, ara produïts amb una crida més senzilla a COWPY.
Contingut del directori de resultats
Contingut de results/cowpy-guten_tag.txt
Això és una lleugera millora respecte a l'enfocament amb multiMap.
Però encara hem hagut de desempaquetar el mapa de Groovy original per crear la tupla d'entrada, i hi ha un acoblament estret entre el procés i el full de dades: la definició d'entrada de COWPY ara fa referència directament als noms de columna id, character i recording.
Si un col·laborador utilitza un full de dades amb una estructura diferent —amb columnes addicionals, o columnes en un ordre diferent— aquest procés no funcionarà sense modificacions. Això fa que el procés sigui fràgil, perquè la seva estructura d'entrada està lligada a la composició exacta del full de dades.
Per resoldre-ho, necessitem una manera de passar totes les metadades com un paquet sense codificar la seva estructura exacta a la interfície del procés.
1.5. Utilitzar una interfície de meta map + fitxer¶
La solució és separar dues preocupacions diferents al canal: les metadades sobre una mostra i el fitxer de dades en si. Agrupant totes les metadades en un sol mapa —el "meta map"— obtenim una tupla consistent de dos elements independentment de quantes columnes de metadades contingui el full de dades:
Afegir o eliminar columnes del full de dades canvia el contingut de meta, però la forma de la tupla [meta, file] es manté constant.
Els processos que accepten aquesta estructura no necessiten saber ni preocupar-se de quants camps de metadades existeixen.
1.5.1. Reorganitzeu el contingut de la tupla en un meta map¶
Reestructurem l'operació map per produir una tupla [meta, file]:
| main.nf | |
|---|---|
Notareu que també hem afegit una instrucció view(), hem comentat la crida a COWPY i hem substituït COWPY.out per channel.empty() perquè la definició d'entrada del procés encara no coincideix amb la nova estructura.
1.5.2. Executeu el workflow per inspeccionar el contingut reorganitzat¶
Executeu el workflow per veure la nova forma del canal:
Sortida de la comanda
N E X T F L O W ~ version 25.10.4
Launching `main.nf` [lethal_booth] DSL2 - revision: 0d8f844c07
[[id:sampleA, character:squirrel], /workspaces/training/side-quests/metadata/data/bonjour.txt]
[[id:sampleB, character:tux], /workspaces/training/side-quests/metadata/data/guten_tag.txt]
[[id:sampleC, character:sheep], /workspaces/training/side-quests/metadata/data/hallo.txt]
[[id:sampleD, character:turkey], /workspaces/training/side-quests/metadata/data/hello.txt]
[[id:sampleE, character:stegosaurus], /workspaces/training/side-quests/metadata/data/hola.txt]
[[id:sampleF, character:moose], /workspaces/training/side-quests/metadata/data/salut.txt]
[[id:sampleG, character:turtle], /workspaces/training/side-quests/metadata/data/ciao.txt]
Ara, cada element del canal és una tupla de dos elements: primer el meta map i segon el fitxer.
[
[id:sampleA, character:squirrel],
/workspaces/training/side-quests/metadata/data/bonjour.txt
]
Si més endavant afegim una columna language al full de dades, estarà disponible com a meta.language sense necessitat de fer cap canvi a la definició d'entrada del procés.
1.5.3. Actualitzeu el procés COWPY per utilitzar el meta map¶
Actualitzeu COWPY per acceptar l'estructura de tupla [meta, file]:
| modules/cowpy.nf | |
|---|---|
| modules/cowpy.nf | |
|---|---|
Dins del bloc script, meta.character accedeix al camp character del meta map.
Qualsevol camp del meta map és accessible de la mateixa manera.
1.5.4. Actualitzeu la crida al procés¶
Restaureu la crida a COWPY i connecteu la seva sortida per a la publicació:
| main.nf | |
|---|---|
També hem restaurat la publicació de la sortida.
1.5.5. Executeu el workflow¶
Executeu el workflow per comprovar que tot funciona:
Sortida de la comanda
El directori de resultats ara conté els fitxers d'art ASCII.
Contingut del directori
Contingut de results/cowpy-guten_tag.txt
El procés ara rep totes les metadades com un paquet a través de meta, utilitza el que necessita (meta.character) i ignora la resta.
Aquesta és la interfície estàndard que utilitzen tots els mòduls de nf-core.
El patró tuple val(meta), path(file) apareix de manera consistent a tota la biblioteca de mòduls nf-core, per la qual cosa els workflows que adopten aquesta convenció poden incorporar mòduls nf-core amb una fricció mínima.
Conclusió¶
En aquesta secció, heu après:
- Com llegir fulls de dades: Utilitzant
splitCsvper analitzar fitxers CSV amb informació de capçalera - Per què existeix la convenció del meta map: Separar les metadades dels fitxers de dades en tuples
[meta, file]manté l'estructura del canal estable a mesura que el full de dades evoluciona - Com utilitzar els camps del meta map dins d'un procés: Qualsevol camp del meta map és accessible mitjançant la notació de punt al bloc script
2. Manipulacions addicionals de metadades¶
Ara que la interfície del meta map està en funcionament, podem enriquir-la a mesura que les dades flueixen pel pipeline.
Utilitzarem una eina anomenada langid per identificar l'idioma de cada fitxer de gravació.
Donat un fragment de text, produeix una predicció d'idioma i una puntuació de probabilitat a stdout.
2.1. Afegir un pas d'identificació de l'idioma¶
Us proporcionem un mòdul de procés preescrit anomenat IDENTIFY_LANGUAGE que encapsula l'eina langid.
Obriu el fitxer del mòdul per examinar el seu codi:
La definició d'entrada utilitza la mateixa estructura tuple val(meta), path(file) que acabem de construir a la secció 1, de manera que ch_datasheet pot alimentar directament aquest procés sense cap adaptació.
La sortida afegeix stdout com a tercer element: això captura la predicció d'idioma que langid imprimeix a la consola.
La comanda sed elimina la puntuació de probabilitat i el salt de línia final, deixant només el codi d'idioma de dues lletres.
2.1.1. Afegiu una crida a IDENTIFY_LANGUAGE¶
Incloeu el mòdul de procés IDENTIFY_LANGUAGE i crideu-lo sobre el canal del full de dades:
La sortida principal d'aquest procés és simplement una cadena de text, de manera que no hi ha fitxers de sortida per publicar.
En canvi, utilitzem IDENTIFY_LANGUAGE.out.view() per veure els resultats de l'operació.
2.1.2. Executeu el workflow¶
Executeu el workflow per produir la identificació de l'idioma, utilitzant -resume per evitar tornar a executar les tasques de COWPY:
Sortida de la comanda
N E X T F L O W ~ version 25.10.4
Launching `main.nf` [voluminous_mcnulty] DSL2 - revision: f9bcfebabb
executor > local (14)
[5d/dffd4e] COWPY (7) [100%] 7 of 7, cached: 7 ✔
[4e/f722fe] IDENTIFY_LANGUAGE (7) [100%] 7 of 7 ✔
[[id:sampleA, character:squirrel], /workspaces/training/side-quests/metadata/work/eb/f7148ebdd898fbe1136bec6a714acb/bonjour.txt, fr]
[[id:sampleB, character:tux], /workspaces/training/side-quests/metadata/work/16/71d72410952c22cd0086d9bca03680/guten_tag.txt, de]
[[id:sampleD, character:turkey], /workspaces/training/side-quests/metadata/work/c4/b7562adddc1cc0b7d414ec45d436eb/hello.txt, en]
[[id:sampleC, character:sheep], /workspaces/training/side-quests/metadata/work/ea/04f5d979429e4455e14b9242fb3b45/hallo.txt, de]
[[id:sampleF, character:moose], /workspaces/training/side-quests/metadata/work/5a/6c2b84bf8fadb98e28e216426be079/salut.txt, fr]
[[id:sampleE, character:stegosaurus], /workspaces/training/side-quests/metadata/work/af/ee7c69bcab891c40d0529305f6b9e7/hola.txt, es]
[[id:sampleG, character:turtle], /workspaces/training/side-quests/metadata/work/4e/f722fe47271ba7ebcd69afa42964ca/ciao.txt, it]
Ara tenim una predicció d'idioma per a cada fitxer del conjunt de dades.
Tingueu en compte que la tupla de sortida es compon de [meta, file, lang_id], la qual cosa significa que el meta map i el fitxer es mantenen associats amb el nou resultat.
Nota
Aquest patró de mantenir el meta map associat amb els resultats facilita l'associació de resultats entre canals més endavant. No podeu confiar en l'ordre dels elements dels canals per associar les dades correctament. En canvi, heu d'utilitzar claus. Els meta maps proporcionen una estructura ideal per a aquest propòsit.
Aquest cas d'ús s'explora en detall a la missió secundària Splitting & Grouping.
2.2. Augmentar les metadades amb les sortides del procés¶
La predicció d'idioma és en si mateixa una metadada sobre les dades del fitxer. En lloc de mantenir-la com un element separat, incorporem-la de nou al meta map.
2.2.1. Creeu un meta map nou i ampliat¶
Podem crear un nou meta map per substituir l'original utilitzant l'operador + de Groovy:
El nucli d'aquesta operació és meta + [lang: lang_id].
Aquest codi essencialment crea un mapa temporal amb un sol parell clau-valor que conté el codi d'idioma ([lang: lang_id]), i després utilitza l'operador + de Groovy per combinar-lo amb el mapa meta original que conté les metadades preexistents, produint un meta map nou i ampliat.
Per a una explicació més detallada, consulteu el quadre a continuació.
Creació del nou meta map utilitzant l'operador +
Primer, heu de saber que podem fusionar el contingut de dos mapes utilitzant l'operador Groovy +.
Suposem que tenim els mapes següents:
Podem fusionar-los així:
El contingut de new_map serà:
Molt bé!
Però, i si heu d'afegir un camp que encara no forma part d'un mapa?
Suposem que torneu a partir de map1, però la predicció d'idioma no és al seu propi mapa (no hi ha cap map2).
En canvi, es troba en una variable anomenada lang_id, i sabeu que voleu emmagatzemar el seu valor ('fr') amb la clau lang.
En realitat podeu fer el següent:
Aquí, [lang: lang_id] crea un nou mapa sense nom al vol, i map1 + fusiona map1 amb el nou mapa sense nom, produint el mateix contingut de new_map que abans.
Elegant, oi?
Ara transposem-ho al context d'una operació channel.map() de Nextflow.
El codi es converteix en:
Això fa el següent:
map1, lang_id ->pren els dos elements de la tuplamap1 + [lang: lang_id]crea el nou mapa tal com s'ha detallat anteriorment
La sortida és un únic mapa sense nom amb el mateix contingut que new_map en el nostre exemple anterior.
Per tant, hem transformat efectivament:
en:
Esperem que pugueu veure que si canviem map1 per meta, això és bàsicament tot el que necessitem per afegir la predicció d'idioma al nostre meta map en el nostre workflow.
Excepte per una cosa!
En el cas del nostre workflow, també hem de tenir en compte la presència de l'objecte file a la tupla, que es compon de meta, file, lang_id.
Per tant, el codi aquí es convertiria en:
Si us costa seguir per què el file sembla que es mou a l'operació map, imagineu que en lloc de [meta + [lang: lang_id], file], aquella línia llegís [new_map, file].
Això hauria de deixar més clar que simplement estem deixant el file al seu lloc original en la segona posició de la tupla. Simplement hem pres el valor new_info i l'hem incorporat al mapa que es troba en la primera posició.
I això ens porta de nou a l'estructura de canal tuple val(meta), path(file)!
2.2.2. Executeu el workflow¶
Un cop estigueu segurs que enteneu el que fa aquest codi, executeu el workflow per veure si ha funcionat:
Sortida de la comanda
N E X T F L O W ~ version 25.10.4
Launching `main.nf` [cheeky_fermat] DSL2 - revision: d096281ee4
[5d/dffd4e] COWPY (7) [100%] 7 of 7, cached: 7 ✔
[4e/f722fe] IDENTIFY_LANGUAGE (7) [100%] 7 of 7, cached: 7 ✔
[[id:sampleA, character:squirrel, lang:fr], /workspaces/training/side-quests/metadata/work/eb/f7148ebdd898fbe1136bec6a714acb/bonjour.txt]
[[id:sampleB, character:tux, lang:de], /workspaces/training/side-quests/metadata/work/16/71d72410952c22cd0086d9bca03680/guten_tag.txt]
[[id:sampleC, character:sheep, lang:de], /workspaces/training/side-quests/metadata/work/ea/04f5d979429e4455e14b9242fb3b45/hallo.txt]
[[id:sampleD, character:turkey, lang:en], /workspaces/training/side-quests/metadata/work/c4/b7562adddc1cc0b7d414ec45d436eb/hello.txt]
[[id:sampleF, character:moose, lang:fr], /workspaces/training/side-quests/metadata/work/5a/6c2b84bf8fadb98e28e216426be079/salut.txt]
[[id:sampleE, character:stegosaurus, lang:es], /workspaces/training/side-quests/metadata/work/af/ee7c69bcab891c40d0529305f6b9e7/hola.txt]
[[id:sampleG, character:turtle, lang:it], /workspaces/training/side-quests/metadata/work/4e/f722fe47271ba7ebcd69afa42964ca/ciao.txt]
Sí, això és correcte!
Hem reorganitzat ordenadament la sortida del procés de meta, file, lang_id de manera que lang_id és ara una de les claus del meta map, i les tuples del canal s'ajusten de nou al model meta, file.
Consell: Eliminar claus d'un meta map
Podeu eliminar una clau d'un meta map utilitzant el mètode subMap de Groovy, que retorna un nou mapa que conté només les claus que especifiqueu:
Això és útil quan un procés o mòdul posterior no necessita tots els camps que s'han acumulat al meta map.
2.3. Assignar un grup lingüístic mitjançant condicionals¶
Amb la predicció d'idioma al meta map, podem derivar-ne més metadades.
Els idiomes del nostre conjunt de dades es divideixen en dues famílies: germàniques (anglès, alemany) i romàniques (francès, espanyol, italià).
Afegir un camp lang_group farà que aquesta classificació estigui disponible més endavant al pipeline.
2.3.1. Afegiu una operació map amb la lògica condicional¶
Utilitzarem una segona operació map amb lògica condicional per assignar la família lingüística:
.map { meta, file ->
// la lògica condicional que defineix lang_group va aquí
[meta + [lang_group: lang_group], file]
}
Aquí teniu la lògica a aplicar:
- Comenceu amb
lang_group = 'unknown'com a valor per defecte. - Si
meta.langés'de'o'en', establiulang_groupa'germanic'. - En cas contrari, si
meta.langes troba a['fr', 'es', 'it'], establiulang_groupa'romance'.
Consell
Podeu accedir al valor de lang dins de l'operació map amb meta.lang.
Feu els canvis següents al workflow:
Punts clau:
def lang_group = "unknown"inicialitza la variable amb un valor per defecte segur.- L'estructura
if / else ifgestiona les dues famílies lingüístiques; qualsevol altra cosa es manté com a'unknown'. .set { ch_languages }dóna un nom al canal resultant per utilitzar-lo al pas següent.
2.3.2. Executeu el workflow:¶
Executeu el workflow per verificar que funciona:
Sortida de la comanda
N E X T F L O W ~ version 25.10.4
Launching `main.nf` [wise_almeida] DSL2 - revision: 46778c3cd0
[5d/dffd4e] COWPY (7) [100%] 7 of 7, cached: 7 ✔
[da/652cc6] IDENTIFY_LANGUAGE (7) [100%] 7 of 7, cached: 7 ✔
[[id:sampleA, character:squirrel, lang:fr, lang_group:romance], /workspaces/training/side-quests/metadata/data/bonjour.txt]
[[id:sampleB, character:tux, lang:de, lang_group:germanic], /workspaces/training/side-quests/metadata/data/guten_tag.txt]
[[id:sampleC, character:sheep, lang:de, lang_group:germanic], /workspaces/training/side-quests/metadata/data/hallo.txt]
[[id:sampleD, character:turkey, lang:en, lang_group:germanic], /workspaces/training/side-quests/metadata/data/hello.txt]
[[id:sampleE, character:stegosaurus, lang:es, lang_group:romance], /workspaces/training/side-quests/metadata/data/hola.txt]
[[id:sampleF, character:moose, lang:fr, lang_group:romance], /workspaces/training/side-quests/metadata/data/salut.txt]
[[id:sampleG, character:turtle, lang:it, lang_group:romance], /workspaces/training/side-quests/metadata/data/ciao.txt]
El meta map ara conté quatre camps: id, character, lang i lang_group.
L'estructura del canal continua sent [meta, file].
2.4. Utilitzar metadades per anomenar i organitzar les sortides¶
Amb lang i lang_group ara disponibles al meta map, podem utilitzar-los per afegir un codi d'idioma als noms dels fitxers de sortida i organitzar-los en subdirectoris per família lingüística.
Això requereix tres canvis: actualitzar el procés COWPY per canviar el nom de la seva sortida i incloure meta en el que emet, actualitzar la crida a COWPY per executar-se sobre ch_languages, i actualitzar el bloc de sortida per especificar la ruta del subdirectori.
2.4.1. Actualitzeu el procés COWPY¶
Canvieu el nom del fitxer de sortida utilitzant el codi d'idioma del meta map, i afegiu meta a la sortida perquè el bloc de sortida pugui accedir a lang_group per a l'enrutament al subdirectori:
Això mostra com podem aprofitar altres camps de metadades per personalitzar el comportament d'un procés, sense haver de modificar la definició d'entrada en absolut.
2.4.2. Actualitzeu la crida a COWPY per executar-se sobre ch_languages¶
Substituïu COWPY(ch_datasheet) per COWPY(ch_languages):
També eliminem la línia ch_languages.view() ja que no necessitem inspeccionar el contingut del canal.
2.4.3. Actualitzeu el bloc de sortida¶
Afegiu una closure path al bloc output {} per enrutar cada fitxer al subdirectori del seu grup lingüístic:
Això mostra com podem utilitzar metadades per organitzar les sortides amb gran flexibilitat.
2.4.4. Executeu el pipeline complet¶
Esborreu els resultats anteriors i executeu el pipeline complet:
Sortida de la comanda
El directori de resultats ara està organitzat per família lingüística, amb cada fitxer anomenat segons l'idioma detectat:
results/
├── germanic
│ ├── de-guten_tag.txt
│ ├── de-hallo.txt
│ └── en-hello.txt
└── romance
├── es-hola.txt
├── fr-bonjour.txt
├── fr-salut.txt
└── it-ciao.txt
La closure path al bloc output {} rep cada tupla [meta, file] i retorna meta.lang_group com a nom del subdirectori.
El nom del fitxer en si prové del que el procés produeix ("${meta.lang}-${input_file}").
Tots dos elements de metadades (codi d'idioma i grup lingüístic) provenen del meta map enriquit construït en aquesta secció.
Conclusió¶
En aquesta secció, heu après:
- Com augmentar el meta map amb les sortides del procés: Afegir noves claus amb
meta + [clau: valor]manté l'estructura del canal[meta, file]intacta mentre s'enriqueixen les metadades. - Com derivar metadades a partir de metadades: La lògica condicional dins d'una operació
mappot calcular nous camps a partir dels existents. - Com utilitzar metadades per organitzar les sortides: La closure
pathal blocoutput {}pot llegir del meta map per enrutar fitxers a subdirectoris.
3. Consideracions de robustesa¶
Quan els valors de les metadades guien el comportament del procés, les dades que falten o estan incompletes poden causar problemes difícils de diagnosticar. Aquí teniu el que cal esperar i com gestionar-ho.
3.1. Què passa quan falta un camp de metadades requerit¶
El valor character és necessari perquè el procés COWPY produeixi un resultat vàlid.
El mode de fallada depèn de si la columna existeix al full de dades però està buida, o si és absent del tot.
3.1.1. La columna existeix però un valor està buit¶
Suposem que una entrada del full de dades té el camp character en blanc:
| datasheet.csv | |
|---|---|
La clau character es crea per a totes les entrades quan s'analitza el full de dades, però meta.character per a sampleA serà una cadena buida.
Quan Nextflow substitueix ${meta.character} a la comanda, l'eina COWPY rep un argument buit per a -c i falla:
Sortida de la comanda
N E X T F L O W ~ version 25.10.4
Launching `main.nf` [marvelous_hirsch] DSL2 - revision: 0dfeee3cc1
executor > local (9)
[c1/c5dd4f] process > IDENTIFY_LANGUAGE (7) [ 85%] 6 of 7
[d3/b7c415] process > COWPY (2) [ 0%] 0 of 6
ERROR ~ Error executing process > 'COWPY (1)'
Caused by:
Process `COWPY (1)` terminated with an error exit status (2)
Command executed:
cat bonjour.txt | cowpy -c > fr-bonjour.txt
Command exit status:
2
Command output:
(empty)
Command error:
usage: cowpy [-h] [-l] [-L] [-t] [-u] [-e EYES] [-c COWACTER] [-E] [-r] [-x]
[-C]
[msg ...]
cowpy: error: argument -c/--cowacter: expected one argument
Work dir:
/workspaces/training/side-quests/metadata/work/ca/9d49796612a54dec5ed466063c809b
Container:
community.wave.seqera.io/library/cowpy:1.1.5--3db457ae1977a273
Tip: you can try to figure out what's wrong by changing to the process work dir and showing the script file named `.command.sh`
-- Check '.nextflow.log' file for details
El missatge d'error (expected one argument) apunta a l'indicador -c buit.
Comprovar el fitxer .command.sh al directori de treball confirma que la comanda s'ha executat amb un valor buit.
3.1.2. La columna no existeix al full de dades¶
Si la columna character és absent del tot:
| datasheet.csv | |
|---|---|
La clau character no es crea mai al meta map.
Quan el script del procés avalua ${meta.character}, la clau absent retorna null, i Nextflow literalment substitueix la cadena null a la comanda:
Sortida de la comanda
N E X T F L O W ~ version 25.10.4
Launching `main.nf` [jovial_bohr] DSL2 - revision: eaaf375827
executor > local (9)
[0d/ada9db] process > IDENTIFY_LANGUAGE (5) [ 85%] 6 of 7
[06/28065f] process > COWPY (2) [ 0%] 0 of 6
ERROR ~ Error executing process > 'COWPY (2)'
Caused by:
Process `COWPY (2)` terminated with an error exit status (1)
Command executed:
cat guten_tag.txt | cowpy -c null > de-guten_tag.txt
Command exit status:
1
Command output:
(empty)
Command error:
Traceback (most recent call last):
File "/opt/conda/bin/cowpy", line 10, in <module>
sys.exit(main())
~~~~^^
File "/opt/conda/lib/python3.13/site-packages/cowpy/cow.py", line 1215, in main
print(cow(eyes=args.eyes,
~~~^^^^^^^^^^^^^^^^
tongue=args.tongue,
^^^^^^^^^^^^^^^^^^^
thoughts=args.thoughts
^^^^^^^^^^^^^^^^^^^^^^
).milk(msg)
^
TypeError: 'str' object is not callable
Work dir:
/workspaces/training/side-quests/metadata/work/06/28065f7d9fd7d22bba084aa941b6d6
Container:
community.wave.seqera.io/library/cowpy:1.1.5--3db457ae1977a273
Tip: you can replicate the issue by changing to the process work dir and entering the command `bash .command.run`
-- Check '.nextflow.log' file for details
El cowpy -c null a la comanda executada és la pista de diagnòstic.
3.2. Estratègies per gestionar metadades que falten¶
Hi ha dos enfocaments complementaris per fer els workflows més robustos davant de metadades que falten.
1. Validació d'entrada
La solució més fiable és validar el full de dades abans que comenci qualsevol processament, de manera que els problemes es detectin aviat amb un missatge d'error clar en lloc de manifestar-se com una fallada críptica del procés a mig camí. La formació de Hello nf-core explica com afegir validació d'entrada utilitzant el connector nf-schema.
2. Entrades explícites del procés per als valors requerits
Si voleu que la interfície del procés comuniqui que un valor determinat és obligatori, considereu extreure'l del meta map com a entrada explícita:
Aquest enfocament fa que character sigui una part visible i requerida del contracte del procés.
Qualsevol persona que llegeixi el mòdul pot veure immediatament que s'ha de proporcionar un valor de personatge.
Si el camp és absent, el workflow falla clarament a nivell del canal abans que el procés s'executi.
Això posa de manifest un principi de disseny útil:
Utilitzeu el meta map per a informació opcional o descriptiva; extraieu els valors requerits com a entrades explícites.
El meta map manté les estructures del canal netes i estables, però per als valors que un procés realment necessita, exposar-los com a entrades amb nom millora la claredat i fa que el mòdul sigui més fàcil d'utilitzar correctament en altres contextos.
Conclusió¶
En aquesta secció, heu vist:
- Com es manifesten les metadades que falten: Un camp buit produeix un argument buit; un camp absent produeix
nullsubstituït literalment a la comanda. - Dues estratègies complementàries: Validació d'entrada per detectar problemes aviat, i entrades explícites del procés per comunicar els requisits clarament.
Resum¶
En aquesta missió secundària, heu explorat com treballar eficaçment amb metadades en workflows de Nextflow.
El patró de tupla "meta map + fitxer de dades" és una convenció fonamental en Nextflow, que ofereix diversos avantatges respecte a passar metadades com a valors individuals:
- L'estructura del canal es manté estable a mesura que el full de dades evoluciona
- El comportament del procés es pot personalitzar per mostra sense codificar noms de camps
- Les metadades estan disponibles al llarg del pipeline per a l'anomenament, l'agrupació i l'organització de les sortides
- Els mòduls escrits per a aquesta interfície són intercanviables, inclosos els mòduls nf-core
Patrons clau¶
-
Lectura i estructuració de metadades: Analitzar un full de dades CSV i crear un meta map.
-
Ampliació de metadades durant el workflow: Afegir noves claus a partir de les sortides del procés o de lògica derivada.
// A partir d'una sortida del procés .map { meta, file, lang -> [ meta + [lang: lang], file ] } // A partir de lògica condicional .map { meta, file -> def lang_group = "unknown" if (meta.lang in ["de", "en"]) { lang_group = "germanic" } else if (meta.lang in ["fr", "es", "it"]) { lang_group = "romance" } [ meta + [lang_group: lang_group], file ] } -
Ús de metadades dins d'un procés: Accediu a qualsevol camp mitjançant la notació de punt al bloc script.
-
Organització de les sortides per valor de metadades: Utilitzeu la closure
pathal blocoutput {}.
Recursos addicionals¶
Què segueix?¶
Torneu al menú de missions secundàries o feu clic al botó a la part inferior dreta de la pàgina per continuar amb el tema següent de la llista.