Metadane i mapy meta¶
Tłumaczenie wspomagane przez AI - dowiedz się więcej i zasugeruj ulepszenia
W każdej analizie naukowej rzadko pracujemy jedynie z surowymi plikami danych. Każdy plik zawiera dodatkowe informacje: czym jest, skąd pochodzi i co go wyróżnia. Te dodatkowe informacje nazywamy metadanymi.
Metadane to dane opisujące inne dane. Metadane śledzą ważne szczegóły dotyczące plików i warunków eksperymentalnych oraz pomagają dostosować analizy do unikalnych cech każdego zestawu danych.
Pomyśl o tym jak o katalogu bibliotecznym: podczas gdy książki zawierają faktyczną treść (surowe dane), karty katalogowe dostarczają istotnych informacji o każdej książce — kiedy została opublikowana, kto ją napisał, gdzie ją znaleźć (metadane). W pipeline'ach Nextflow metadane mogą być wykorzystywane do:
- Śledzenia informacji specyficznych dla pliku w całym workflow
- Konfigurowania procesów na podstawie cech pliku
- Grupowania powiązanych plików do wspólnej analizy
Cele edukacyjne¶
W tym side queście zbadamy sposób obsługi metadanych w workflow. Zaczynając od prostej tabeli danych (często nazywanej samplesheet w bioinformatyce) zawierającej podstawowe informacje o plikach, nauczysz się jak:
- Odczytywać i analizować metadane plików z plików CSV
- Tworzyć i manipulować mapami metadanych
- Dodawać nowe pola metadanych podczas wykonywania workflow
- Wykorzystywać metadane do dostosowywania zachowania procesów
Te umiejętności pomogą Ci tworzyć bardziej solidne i elastyczne pipeline'y, które potrafią obsługiwać złożone relacje między plikami i wymagania przetwarzania.
Wymagania wstępne¶
Przed rozpoczęciem tego side questu powinieneś:
- Ukończyć kurs Hello Nextflow lub równoważny kurs dla początkujących.
- Swobodnie posługiwać się podstawowymi koncepcjami i mechanizmami Nextflow (procesy, kanały, operatory)
0. Rozpocznij pracę¶
Otwórz środowisko szkoleniowe codespace¶
Jeśli jeszcze tego nie zrobiłeś, upewnij się, że otworzysz środowisko szkoleniowe zgodnie z opisem w Konfiguracja środowiska.
Przejdź do katalogu projektu¶
Przejdźmy do katalogu, w którym znajdują się pliki do tego kursu.
Możesz ustawić VSCode, aby skupił się na tym katalogu:
Przejrzyj materiały¶
Znajdziesz główny plik workflow oraz katalog data zawierający tabelę danych i kilka plików danych.
Zawartość katalogu
Workflow w pliku main.nf to szablon, który stopniowo rozwiniesz w w pełni funkcjonujący workflow.
Tabela danych zawiera ścieżki do plików danych i powiązane metadane, zorganizowane w 3 kolumnach:
id: oczywiste, ID nadane plikowicharacter: nazwa postaci, której użyjemy później do rysowania różnych stworzeńdata: ścieżki do plików.txt, które zawierają pozdrowienia w różnych językach
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
Każdy plik danych zawiera tekst powitania w jednym z pięciu języków (fr: francuski, de: niemiecki, es: hiszpański, it: włoski, en: angielski).
Dostarczymy Ci również konteneryzowane narzędzie do analizy języka o nazwie langid.
Przejrzyj zadanie¶
Twoim wyzwaniem jest napisanie workflow Nextflow, który:
- Zidentyfikuje język w każdym pliku automatycznie
- Zgrupuje pliki według rodziny językowej (języki germańskie kontra języki romańskie)
- Dostosuje przetwarzanie dla każdego pliku na podstawie jego języka i metadanych
- Zorganizuje wyjścia według grupy językowej
To reprezentuje typowy wzorzec workflow, gdzie metadane specyficzne dla pliku sterują decyzjami dotyczącymi przetwarzania; dokładnie taki rodzaj problemu, który mapy metadanych rozwiązują elegancko.
Lista kontrolna gotowości¶
Myślisz, że jesteś gotowy, aby się zagłębić?
- Rozumiem cel tego kursu i jego wymagania wstępne
- Mój codespace jest uruchomiony
- Ustawiłem odpowiednio mój katalog roboczy
- Rozumiem zadanie
Jeśli możesz zaznaczyć wszystkie pola, możesz zaczynać.
1. Wczytaj metadane z tabeli danych¶
Otwórz plik workflow main.nf, aby przeanalizować szablon workflow, który dajemy Ci jako punkt wyjścia.
| main.nf | |
|---|---|
Możesz zobaczyć, że skonfigurowaliśmy podstawową fabrykę kanałów, aby wczytać przykładową tabelę danych jako plik, ale to jeszcze nie odczyta zawartości pliku. Zacznijmy od dodania tego.
1.1. Odczytaj zawartość za pomocą splitCsv¶
Musimy wybrać operator, który odpowiednio zanalizuje zawartość pliku przy minimalnym wysiłku z naszej strony.
Ponieważ nasza tabela danych jest w formacie CSV, jest to zadanie dla operatora splitCsv, który wczytuje każdy wiersz w pliku jako element w kanale.
Wprowadź następujące zmiany, aby dodać operację splitCsv() do kodu konstrukcji kanału, plus operację view(), aby sprawdzić, czy zawartość pliku jest poprawnie wczytywana do kanału.
Zauważ, że używamy opcji header: true, aby powiedzieć Nextflow, aby odczytał pierwszy wiersz pliku CSV jako wiersz nagłówka.
Zobaczmy, co z tego wychodzi, dobrze? Uruchom workflow:
Wyjście polecenia
N E X T F L O W ~ version 25.10.2
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]
Możemy zobaczyć, że operator skonstruował mapę par klucz-wartość dla każdego wiersza w pliku CSV, z nagłówkami kolumn jako kluczami dla odpowiadających wartości.
Każdy wpis mapy odpowiada kolumnie w naszej tabeli danych:
idcharacterrecording
To jest świetne! Ułatwia to dostęp do określonych pól z każdego pliku.
Na przykład moglibyśmy uzyskać dostęp do ID pliku za pomocą id lub ścieżki do pliku txt za pomocą recording.
(Opcjonalnie) Więcej o mapach
W Groovy, języku programowania, na którym zbudowany jest Nextflow, mapa to struktura danych klucz-wartość podobna do słowników w Python, obiektów w JavaScript lub haszy w Ruby.
Oto skrypt do uruchomienia, który pokazuje, jak można zdefiniować mapę i uzyskać dostęp do jej zawartości w praktyce:
#!/usr/bin/env nextflow
// Utwórz prostą mapę
def my_map = [id:'sampleA', character:'squirrel']
// Wypisz całą mapę
println "map: ${my_map}"
// Uzyskaj dostęp do pojedynczych wartości za pomocą notacji kropkowej
println "id: ${my_map.id}"
println "character: ${my_map.character}"
Mimo że nie ma odpowiedniego bloku workflow, Nextflow może to uruchomić tak, jakby to był workflow:
A oto, co możesz spodziewać się zobaczyć w wyjściu:
1.2. Wyodrębnij określone pola za pomocą map¶
Powiedzmy, że chcemy uzyskać dostęp do kolumny character z tabeli danych i ją wydrukować.
Możemy użyć operatora Nextflow map, aby iterować po każdym elemencie w naszym kanale i specyficznie wybrać wpis character z obiektu mapy.
Wprowadź następujące edycje do workflow:
Teraz uruchom workflow ponownie:
Wyjście polecenia
Sukces! Wykorzystaliśmy strukturę mapy pochodzącą z naszej tabeli danych, aby uzyskać dostęp do wartości z poszczególnych kolumn dla każdego wiersza.
Teraz, gdy pomyślnie odczytaliśmy tabelę danych i mamy dostęp do danych w każdym wierszu, możemy zacząć implementować logikę naszego pipeline.
1.3. Zorganizuj metadane w 'mapę meta'¶
W obecnym stanie workflow pliki wejściowe (pod kluczem recording) i powiązane metadane (id, character) są na tym samym poziomie, jak gdyby wszystkie były w jednej dużej torbie.
Praktyczną konsekwencją jest to, że każdy proces, który konsumuje ten kanał, musiałby być skonfigurowany z tą strukturą na myśli:
To jest w porządku, dopóki liczba kolumn w tabeli danych się nie zmienia. Jednakże, jeśli dodasz nawet tylko jedną kolumnę do tabeli danych, kształt kanału nie będzie już pasował do tego, czego oczekuje proces, a workflow będzie generował błędy. Utrudnia to również dzielenie się procesem z innymi, którzy mogą mieć nieco inne dane wejściowe, i możesz skończyć na hardcodowaniu zmiennych do procesu, które nie są potrzebne przez blok script.
Aby uniknąć tego problemu, musimy znaleźć sposób na utrzymanie struktury kanału spójnej niezależnie od tego, ile kolumn zawiera tabela danych.
Możemy to zrobić, zbierając wszystkie metadane w element w krotce, który nazwiemy mapą metadanych, lub prościej 'mapą meta'.
Wprowadź następujące edycje do operacji map:
Zrestrukturyzowaliśmy nasze elementy kanału w krotkę składającą się z dwóch elementów: mapy meta i odpowiadającego obiektu pliku.
Uruchommy workflow:
Wyjście polecenia
N E X T F L O W ~ version 25.10.2
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]
Teraz każdy element w kanale zawiera najpierw mapę metadanych, a na drugim miejscu odpowiadający obiekt pliku:
[
[id:sampleA, character:squirrel],
/workspaces/training/side-quests/metadata/data/bonjour.txt
]
W rezultacie dodanie większej liczby kolumn w tabeli danych udostępni więcej metadanych w mapie meta, ale nie zmieni kształtu kanału.
To umożliwia nam pisanie procesów, które konsumują kanał bez konieczności hardcodowania elementów metadanych w specyfikacji wejściowej:
Jest to powszechnie stosowana konwencja organizowania metadanych w workflow Nextflow.
Wnioski¶
W tej sekcji nauczyłeś się:
- Dlaczego metadane są ważne: Utrzymywanie metadanych wraz z danymi zachowuje ważne informacje o plikach w całym workflow.
- Jak odczytywać tabele danych: Używanie
splitCsvdo odczytu plików CSV z informacjami nagłówkowymi i przekształcania wierszy w ustrukturyzowane dane - Jak utworzyć mapę meta: Oddzielanie metadanych od danych pliku za pomocą struktury krotki
[ [id:value, ...], file ]
2. Manipulowanie metadanymi¶
Teraz, gdy mamy załadowane metadane, zróbmy z nimi coś!
Użyjemy narzędzia o nazwie langid do identyfikacji języka zawartego w pliku nagrania każdego stworzenia.
Narzędzie jest wstępnie wytrenowane na zestawie języków i, biorąc fragment tekstu, wyprowadzi przewidywanie języka i powiązany wynik prawdopodobieństwa, oba do stdout.
2.1. Zaimportuj proces i przeanalizuj kod¶
Dostarczamy Ci wstępnie napisany moduł procesu o nazwie IDENTIFY_LANGUAGE, który opakowuje narzędzie langid, więc musisz tylko dodać instrukcję include przed blokiem workflow.
Wprowadź następującą edycję do workflow:
Możesz otworzyć plik modułu, aby przeanalizować jego kod:
Jak widać, definicja wejściowa używa tej samej struktury tuple val(meta), path(file), którą właśnie zastosowaliśmy do naszego kanału wejściowego.
Definicja wyjściowa jest zbudowana jako krotka o podobnej strukturze do wejścia, z wyjątkiem tego, że zawiera również stdout jako trzeci element.
Ten wzorzec tuple val(meta), path(file), <output> utrzymuje metadane powiązane zarówno z danymi wejściowymi, jak i wyjściowymi w miarę przepływu przez pipeline.
Zauważ, że używamy tu kwalifikatora wyjściowego stdout Nextflow, ponieważ narzędzie drukuje Swoje wyjście bezpośrednio do konsoli zamiast zapisywać plik; i używamy sed w wierszu poleceń, aby usunąć wynik prawdopodobieństwa, oczyścić ciąg znaków poprzez usunięcie znaków nowej linii i zwrócić tylko przewidywanie języka.
2.2. Dodaj wywołanie IDENTIFY_LANGUAGE¶
Teraz, gdy proces jest dostępny dla workflow, możemy dodać wywołanie procesu IDENTIFY_LANGUAGE, aby uruchomić go na kanale danych.
Wprowadź następujące edycje do workflow:
| main.nf | |
|---|---|
Zauważ, że usunęliśmy oryginalną operację .view() w konstrukcji kanału.
Możemy teraz uruchomić workflow:
Wyjście polecenia
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [voluminous_mcnulty] DSL2 - revision: f9bcfebabb
executor > local (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]
Doskonale! Mamy teraz przewidywanie, w jakim języku mówi każda postać.
I jak wspomniano wcześniej, uwzględniliśmy również plik wejściowy i mapę meta w wyjściu, co oznacza, że oba pozostają powiązane z nowymi informacjami, które właśnie wygenerowaliśmy. To okaże się przydatne w następnym kroku.
Note
Bardziej ogólnie, ten wzorzec utrzymywania mapy meta powiązanej z wynikami ułatwia kojarzenie powiązanych wyników, które dzielą te same identyfikatory.
Jak już się dowiedziałeś, nie możesz polegać na kolejności elementów w kanałach, aby dopasować wyniki między nimi. Zamiast tego musisz używać kluczy do prawidłowego kojarzenia danych, a mapy meta zapewniają idealną strukturę do tego celu.
Badamy ten przypadek użycia szczegółowo w side queście Splitting & Grouping.
2.3. Rozszerz metadane o wyjścia procesu¶
Biorąc pod uwagę, że wyniki, które właśnie wygenerowaliśmy, same w sobie są formą metadanych o zawartości plików, przydatne byłoby dodanie ich do naszej mapy meta.
Jednakże nie chcemy modyfikować istniejącej mapy meta w miejscu. Z technicznego punktu widzenia możliwe jest to zrobienie, ale jest to niebezpieczne.
Zamiast tego stworzymy nową mapę meta zawierającą zawartość istniejącej mapy meta plus nową parę klucz-wartość lang: lang_id przechowującą nowe informacje, używając operatora + (funkcja Groovy).
I połączymy to z operacją map, aby zastąpić starą mapę nową.
Oto edycje, które musisz wprowadzić do workflow:
Jeśli nie jesteś jeszcze zaznajomiony z operatorem +, lub jeśli wydaje się to mylące, poświęć kilka minut na przejrzenie szczegółowego wyjaśnienia poniżej.
Tworzenie nowej mapy meta przy użyciu operatora +
Po pierwsze, musisz wiedzieć, że możemy scalić zawartość dwóch map używając operatora Groovy +.
Powiedzmy, że mamy następujące mapy:
Możemy je scalić w ten sposób:
Zawartość new_map będzie:
Świetnie!
Ale co jeśli musisz dodać pole, które nie jest jeszcze częścią mapy?
Powiedzmy, że zaczynasz ponownie od map1, ale przewidywanie języka nie jest w Swojej własnej mapie (nie ma map2).
Zamiast tego jest przechowywane w zmiennej o nazwie lang_id i wiesz, że chcesz przechować jej wartość ('fr') z kluczem lang.
Możesz faktycznie zrobić następująco:
Tutaj [lang: new_info] tworzy nową nienazwaną mapę w locie, a map1 + scala map1 z nową nienazwaną mapą, produkując tę samą zawartość new_map jak wcześniej.
Ładne, prawda?
Teraz przetransponujmy to w kontekst operacji Nextflow channel.map().
Kod staje się:
To robi następującą rzecz:
map1, lang_id ->przyjmuje dwa elementy w krotce[map1 + [lang: lang_id]]tworzy nową mapę jak szczegółowo opisano powyżej
Wyjściem jest jedna nienazwana mapa z tą samą zawartością co new_map w naszym przykładzie powyżej.
Więc skutecznie przekształciliśmy:
w:
Miejmy nadzieję, że możesz zobaczyć, że jeśli zmienimy map1 na meta, to w zasadzie wszystko, czego potrzebujemy, aby dodać przewidywanie języka do naszej mapy meta w naszym workflow.
Z wyjątkiem jednej rzeczy!
W przypadku naszego workflow musimy również uwzględnić obecność obiektu file w krotce, który składa się z meta, file, lang_id.
Więc kod tutaj stałby się:
Jeśli masz trudności ze zrozumieniem, dlaczego file wydaje się poruszać w operacji map, wyobraź sobie, że zamiast [meta + [lang: lang_id], file], ten wiersz brzmi [new_map, file].
To powinno wyjaśnić, że po prostu pozostawiamy file w jego pierwotnym miejscu na drugiej pozycji w krotce. Po prostu wzięliśmy wartość new_info i włożyliśmy ją do mapy, która jest na pierwszej pozycji.
I to prowadzi nas z powrotem do struktury kanału tuple val(meta), path(file)!
Gdy będziesz pewny, że rozumiesz, co robi ten kod, uruchom workflow, aby zobaczyć, czy zadziałało:
Wyjście polecenia
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [cheeky_fermat] DSL2 - revision: d096281ee4
[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]
Tak, to się zgadza!
Starannie zreorganizowaliśmy wyjście procesu z meta, file, lang_id tak, że lang_id jest teraz jednym z kluczy w mapie meta, a krotki kanału ponownie pasują do modelu meta, file.
2.4. Przypisz grupę językową używając instrukcji warunkowych¶
Teraz, gdy mamy nasze przewidywania języków, użyjmy tych informacji do przypisania nowych grup.
W naszych przykładowych danych języki używane przez nasze postacie można podzielić na języki germańskie (angielski, niemiecki) i języki romańskie (francuski, hiszpański, włoski). Przydatne może być posiadanie tej klasyfikacji łatwo dostępnej gdzieś później w pipeline, więc dodajmy te informacje do mapy meta.
I, dobra wiadomość, to kolejny przypadek, który idealnie nadaje się do użycia operatora map!
Konkretnie, zdefiniujemy zmienną o nazwie lang_group, użyjemy prostej logiki warunkowej do określenia, jaką wartość przypisać lang_group dla każdego elementu danych.
Ogólna składnia będzie wyglądać tak:
.map { meta, file ->
// logika warunkowa definiująca lang_group idzie tutaj
[meta + [lang_group: lang_group], file]
}
Możesz zobaczyć, że jest to bardzo podobne do operacji scalania map w locie, którą użyliśmy w poprzednim kroku. Musimy tylko napisać instrukcje warunkowe.
Oto logika warunkowa, którą chcemy zastosować:
- Zdefiniuj zmienną o nazwie
lang_groupz wartością domyślną'unknown'. - Jeśli
langto niemiecki ('de') lub angielski ('en'), zmieńlang_groupnagermanic. - W przeciwnym razie, jeśli
langjest zawarty w liście zawierającej francuski ('fr'), hiszpański ('es') i włoski ('it'), zmieńlang_groupnaromance.
Spróbuj napisać to sam, jeśli już wiesz, jak pisać instrukcje warunkowe w Nextflow.
Tip
Możesz uzyskać dostęp do wartości lang wewnątrz operacji map za pomocą meta.lang.
Powinieneś wprowadzić następujące zmiany do workflow:
Oto kluczowe punkty:
- Używamy
def lang_group = "unknown"do utworzenia zmiennejlang_groupz wartością domyślną ustawioną naunknown. - Używamy struktury
if {} else if {}dla logiki warunkowej, z alternatywnymi testami.equals()dla dwóch języków germańskich oraz testem istnienia w liście dla trzech języków romańskich. - Używamy operacji scalania
meta + [lang_group:lang_group]jak wcześniej do wygenerowania zaktualizowanej mapy meta.
Gdy to wszystko ma sens, uruchom workflow ponownie, aby zobaczyć wynik:
Wyjście polecenia
N E X T F L O W ~ version 25.10.2
Launching `main.nf` [wise_almeida] DSL2 - revision: 46778c3cd0
[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]
Jak widać, elementy kanału utrzymują Swoją strukturę [meta, file], ale mapa meta zawiera teraz tę nową klasyfikację.
Wnioski¶
W tej sekcji nauczyłeś się, jak:
- Stosować metadane wejściowe do kanałów wyjściowych: Kopiowanie metadanych w ten sposób pozwala nam później kojarzyć wyniki na podstawie zawartości metadanych.
- Tworzyć niestandardowe klucze: Utworzyłeś dwa nowe klucze w Swojej mapie meta, scalając je za pomocą
meta + [new_key:value]z istniejącą mapą meta. Jeden oparty na obliczonej wartości z procesu, a drugi oparty na warunku ustawionym w operatorzemap.
Pozwalają one kojarzyć nowe i istniejące metadane z plikami w miarę postępu w pipeline. Nawet jeśli nie używasz metadanych jako części procesu, utrzymywanie mapy meta powiązanej z danymi w ten sposób ułatwia utrzymanie wszystkich istotnych informacji razem.
3. Używanie informacji z mapy meta w procesie¶
Teraz, gdy wiesz, jak tworzyć i aktualizować mapę meta, możemy przejść do naprawdę zabawnej części: faktycznego używania metadanych w procesie.
Dokładniej, dodamy drugi krok do naszego workflow, aby narysować każde zwierzę jako sztukę ASCII i sprawić, że powie nagrany tekst w dymku.
Zrobimy to za pomocą narzędzia o nazwie cowpy.
Co robi cowpy?
cowpy to narzędzie wiersza poleceń, które generuje sztukę ASCII do wyświetlania dowolnych wejść tekstowych w zabawny sposób.
Jest to implementacja w pythonie klasycznego narzędzia cowsay Tony'ego Monroe.
______________________________________________________
< Hello Nextflow >
------------------------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
Opcjonalnie możesz wybrać postać (lub 'cowacter') do użycia zamiast domyślnej krowy.
Jeśli przeszedłeś kurs Hello Nextflow, już widziałeś to narzędzie w akcji. Jeśli nie, nie martw się; omówimy wszystko, co musisz wiedzieć w trakcie.
3.1. Zaimportuj proces i przeanalizuj kod¶
Dostarczamy Ci wstępnie napisany moduł procesu o nazwie COWPY, który opakowuje narzędzie cowpy, więc musisz tylko dodać instrukcję include przed blokiem workflow.
Wprowadź następującą edycję do workflow:
Możesz otworzyć plik modułu, aby przeanalizować jego kod:
Jak widać, ten proces jest obecnie zaprojektowany tak, aby przyjmować plik wejściowy (zawierający tekst do wyświetlenia) i wartość określającą postać, która powinna być narysowana w sztuce ASCII, zwykle dostarczaną na poziomie workflow przez parametr wiersza poleceń.
3.2. Przekaż pole mapy meta jako wejście¶
Kiedy używaliśmy narzędzia cowpy w kursie Hello Nextflow, użyliśmy parametru wiersza poleceń do określenia, jakiej postaci użyć do narysowania końcowego obrazu.
To miało sens, ponieważ generowaliśmy tylko jeden obraz na uruchomienie pipeline.
Jednakże w tym kursie chcemy wygenerować odpowiedni obraz dla każdego podmiotu, który przetwarzamy, więc użycie parametru wiersza poleceń byłoby zbyt ograniczające.
Dobra wiadomość: mamy kolumnę character w naszej tabeli danych i dlatego w naszej mapie meta.
Użyjmy tego do ustawienia postaci, której proces powinien użyć dla każdego wpisu.
W tym celu będziemy musieli zrobić trzy rzeczy:
- Nadać nazwę kanałowi wyjściowemu wychodzącemu z poprzedniego procesu, abyśmy mogli na nim wygodniej operować.
- Określić, jak uzyskać dostęp do interesujących nas informacji
- Dodać wywołanie drugiego procesu i odpowiednio wprowadzić informacje.
Zaczynajmy.
3.2.1. Nazwij poprzedni kanał wyjściowy¶
Zastosowaliśmy poprzednie manipulacje bezpośrednio na kanale wyjściowym pierwszego procesu, IDENTIFY_LANGUAGE.out.
Aby przekazać zawartość tego kanału do następnego procesu (i zrobić to w sposób jasny i łatwy do odczytania) chcemy nadać mu własną nazwę, ch_languages.
Możemy to zrobić za pomocą operatora set.
W głównym workflow zastąp operator .view() przez .set { ch_languages } i dodaj linię testującą, że możemy odwoływać się do kanału po nazwie.
Uruchommy to:
Wyjście polecenia
N E X T F L O W ~ version 25.10.2
Launching `./main.nf` [friendly_austin] DSL2 - revision: 3dbe460fd6
[36/cca6a7] IDENTIFY_LANGUAGE (7) | 7 of 7 ✔
[[id:sampleB, character:tux, lang:de, lang_group:germanic], /workspaces/training/side-quests/metadata/work/e2/6db2402d83cf72081bcd2d11784714/guten_tag.txt]
[[id:sampleA, character:squirrel, lang:fr, lang_group:romance], /workspaces/training/side-quests/metadata/work/6c/114c818317d169457d6e7336d5d55b/bonjour.txt]
[[id:sampleC, character:sheep, lang:de, lang_group:germanic], /workspaces/training/side-quests/metadata/work/55/68c69c5efb527f3604ddb3daab8057/hallo.txt]
[[id:sampleD, character:turkey, lang:en, lang_group:germanic], /workspaces/training/side-quests/metadata/work/2a/4752055ccb5d1370b0ef9da41d3993/hello.txt]
[[id:sampleE, character:stegosaurus, lang:es, lang_group:romance], /workspaces/training/side-quests/metadata/work/f4/fcd3186dc666d5d239ffa6c37d125d/hola.txt]
[[id:sampleF, character:moose, lang:fr, lang_group:romance], /workspaces/training/side-quests/metadata/work/c3/3b2627f733f278a7088332a5806108/salut.txt]
[[id:sampleG, character:turtle, lang:it, lang_group:romance], /workspaces/training/side-quests/metadata/work/36/cca6a7dbfa26ac24f9329787a32e9d/ciao.txt]
To potwierdza, że możemy teraz odwoływać się do kanału po nazwie.
3.2.2. Uzyskaj dostęp do pliku i metadanych postaci¶
Wiemy z przyjrzenia się kodowi modułu, że proces COWPY oczekuje, że zostanie mu podany plik tekstowy i wartość character.
Aby napisać wywołanie procesu COWPY, musimy tylko wiedzieć, jak wyodrębnić odpowiadający obiekt pliku i metadane z każdego elementu w kanale.
Jak to często bywa, najprostszym sposobem jest użycie operacji map.
Nasz kanał zawiera krotki zorganizowane jako [meta, file], więc możemy uzyskać dostęp do obiektu file bezpośrednio, a możemy uzyskać dostęp do wartości character przechowywanej wewnątrz mapy meta, odwołując się do niej jako meta.character.
W głównym workflow wprowadź następujące zmiany w kodzie:
Zauważ, że używamy domknięć (takich jak { file -> "File: " + file }), aby uczynić wyjście operacji .view bardziej czytelnym.
Uruchommy to:
Wyjście polecenia
N E X T F L O W ~ version 25.10.2
Launching `./main.nf` [cheesy_cantor] DSL2 - revision: 15af9c1ec7
[43/05df08] IDENTIFY_LANGUAGE (7) [100%] 7 of 7, cached: 7 ✔
Character: squirrel
File: /workspaces/training/side-quests/metadata/work/8d/4b9498bbccb7a74f04e41877cdc3e5/bonjour.txt
File: /workspaces/training/side-quests/metadata/work/d3/604274985406e40d79021dea658e60/guten_tag.txt
Character: tux
Character: turkey
File: /workspaces/training/side-quests/metadata/work/d4/fafcc9415b61d2b0fea872e6a05e8a/hello.txt
File: /workspaces/training/side-quests/metadata/work/02/468ac9efb27f636715e8144b37e9a7/hallo.txt
Character: sheep
Character: moose
Character: stegosaurus
File: /workspaces/training/side-quests/metadata/work/d4/61a7e1188b4f2742bc72004e226eca/salut.txt
File: /workspaces/training/side-quests/metadata/work/ae/68364be238c11149c588bf6fc858b1/hola.txt
File: /workspaces/training/side-quests/metadata/work/43/05df081af5d879ab52e5828fa0357e/ciao.txt
Character: turtle
Ścieżki plików i wartości postaci mogą pojawić się w innej kolejności w Twoim wyjściu.
To potwierdza, że jesteśmy w stanie uzyskać dostęp do pliku i postaci dla każdego elementu w kanale.
3.2.3. Wywołaj proces COWPY¶
Teraz połóżmy to wszystko razem i faktycznie wywołajmy proces COWPY na kanale ch_languages.
W głównym workflow wprowadź następujące zmiany w kodzie:
Widzisz, że po prostu kopiujemy dwie operacje map (minus instrukcje .view()) jako wejścia do wywołania procesu.
Tylko upewnij się, że nie zapomnisz przecinka między nimi!
To trochę niezgrabne, ale zobaczymy, jak to poprawić w następnej sekcji.
Uruchommy to:
Wyjście polecenia
Jeśli spojrzysz w katalog results, powinieneś zobaczyć poszczególne pliki zawierające sztukę ASCII każdego powitania wymówionego przez odpowiednią postać.
Katalog i przykładowa zawartość pliku
To pokazuje, że byliśmy w stanie użyć informacji w mapie meta do sparametryzowania polecenia w drugim kroku pipeline.
Jednakże, jak wspomniano powyżej, część kodu była trochę niezgrabna, ponieważ musieliśmy rozpakować metadane będąc jeszcze w kontekście ciała workflow. To podejście działa dobrze dla używania niewielkiej liczby pól z mapy meta, ale słabo by się skalowało, gdybyśmy chcieli użyć znacznie więcej.
Jest inny operator o nazwie multiMap(), który pozwala nam to nieco usprawnić, ale nawet wtedy nie jest to idealne.
(Opcjonalnie) Alternatywna wersja z multiMap()
W przypadku, gdy się zastanawiasz, nie mogliśmy po prostu napisać pojedynczej operacji map(), która wyprowadza zarówno file, jak i character, ponieważ to zwróciłoby je jako krotkę.
Musieliśmy napisać dwie oddzielne operacje map(), aby przekazać elementy file i character do procesu osobno.
Technicznie istnieje inny sposób, aby to zrobić przez pojedynczą operację mapowania, używając operatora multiMap(), który jest w stanie emitować wiele kanałów.
Na przykład możesz zastąpić wywołanie COWPY powyżej następującym kodem:
To produkuje dokładnie taki sam wynik.
W obu przypadkach jest niezręcznie, że musimy robić trochę rozpakowywania na poziomie workflow.
Byłoby lepiej, gdybyśmy mogli przekazać całą mapę meta do procesu i wybrać, czego potrzebujemy, gdy tam jesteśmy.