16-12-2021
Cosa ho fatto
- Novità relative a index_orcid_doi
- Miglioramenti legati all’efficienza.
La presenza del tag common:external-id è ora la prima condizione a essere controllata. In questo modo, se un file non contiene tale informazione viene immediatamente scartato. In precedenza, la prima informazione controllata era la presenza dei dettagli personali dell’autore, che invece ci sono sempre. Dato che molti file non contengono alcun DOI, questa modifica velocizza il processo.
Alla prima lettura di un CSV esistente, vengono estratti gli ORCID e i file corrispondenti vengono saltati. Tale meccanismo agisce come una cache automatica, senza la necessità di salvare un file in locale e di specificare ulteriori flag. In altre parole, l’output fa sia da output che da cache.
1
2# È velocissimo nonostante le chiavi siano milioni
self.cache = set(el.split(" [")[1][:-1] for _,v in self.csvstorage.data.items() for el in v)L’output ora contiene anche quegli ORCID privi di DOI associati. In questo caso, il campo ‘id’ è ‘None’ e il campo ‘value’ è l’ORCID. Tale informazione è fondamentale per il buon funzionamento della cache. In sua assenza, verrebbero riprocessati anche quei file che non contengono alcuna informazione utile e il cui ORCID sarebbe perciò assente nell’output.
L’output non viene più scritto riga per riga come in precedenza, ma in bulk dopo un threshold (10,000 file di default). Infatti, aprire, scrivere e chiudere l’output ogni 10,000 file è molto più rapido che aprirlo, scriverlo e chiuderlo a ogni riga. Tale threshold è personalizzabile tramite il nuovo flag opzionale -t o —threshold.
- Inoltre, dopo ogni threshold viene sempre generato un nuovo file, non sovrascritto il precedente. In questo modo si evita di avere un unico file di 2 GB complicato da leggere e verificare. I file hanno nome [start]-[end].csv. Ad esempio, se il threshold è 100, il primo file si chiama 1-100.csv, il secondo 101-200.csv e così via. La numerazione tiene conto anche della cache.
- Pertanto, il parametro -c non riceve più in input il nome del file di output, ma la directory che conterrà tutti i file di output. Questa modifica è coerente con tutti gli altri flag, i quali ricevono sempre una directory.
- Se si specifica il nuovo flag opzionale -v o —verbose viene mostrata una barra di caricamento, il tempo trascorso e il tempo stimato. Contare tutti i file per generare la barra richiede qualche minuto (9,747,030 file per il dump di ORCID del 2020), ma può valerne la pena per capire quanto manca.
- Ho aggiunto i test relativi a Index_orcid_doi.
- Miglioramenti legati all’efficienza.
- Novità relative a run_prepocess:
- Risolti vari mini-bug elencati in questo commit e due problemi di performance micidiali:
- L’indice DOI-ORCID e il CSV con i DOI di COCI venivano riletti per ogni file di Crossref.
- Ogni CSV in output conteneva tutto il contenuto del CSV precedente più quello nuovo. Quindi le dimensioni dei CSV aumentavano in maniera esponenziale.
- Ho unificato la gestione di autori ed editor in una nuova funzione get_agents_strings_list, che è stata testata. In questo modo, l’indice DOI-ORCID viene sfruttato per cercare sia l’id degli autori che degli editor (in precedenza solo degli autori).
- È ora possibile lanciare il processo direttamente sui file zippati (.json.gz), senza la necessità di estrarli preventivamente. In questo modo lo spazio necessario per ospitare il dump di Crossref passa da 564 GB a 99 GB. Inoltre, il tempo per processare i singoli file è pressoché invariato. Considerato che unzippare tutto il dump di Crossref richiede svariate ore, lavorare direttamente sugli zip comporta anche un notevole risparmio di tempo.
- Ho aggiunto nuovi test con dati reali.
- Risolti vari mini-bug elencati in questo commit e due problemi di performance micidiali:
- Ho parlato con Fabio, che mi ha molto aiutato a comprendere varie parti di curator.py. Dalla chiacchierata è anche emerso che l’albero decisionale presente nella tesi non mostra due casi implementati e va quindi aggiornato:
- Ci sono più entità associate allo stesso ID ma non c’è un MetaID.
- Due entità precedentemente scollegate sul ts diventano la stessa grazie alle informazioni presenti su un CSV di input.
Ho generato:
- L**‘indice DOI-ORCID** a partire dall’intero dump 2020 di ORCID.
- Pesa 1,81 GB.
- Generarlo ha richiesto circa 50 ore.
- Un CSV contenente tutti i DOI presenti su COCI, ovvero i campi “citing” e “cited” del dump in CSV. Tale CSV serve a filtrare Crossref in modo che OCMeta sia 1:1 rispetto a COCI.
- Numero di DOI su COCI: 69,897,399.
- Il file pesa 1,75 GB.
- I CSV di input per OCMeta derivanti dal dump di Crossref. Qualche osservazione:
- Generare i CSV di input ha richiesto esattamente 8 ore 44 minuti e 15 secondi.
- L’indice DOI-ORCID e il set di tutti i DOI di COCI occupano circa 16 GB sulla RAM. Ottimo direi.
- Il dump di Crossref decompresso pesa 564 GB, i CSV che ne derivano 21,2 GB. Era ovvio che pesassero di meno (meno caratteri, meno DOI, meno metadati), ma non pensavo così tanto!
Domande
Per la rubrica Stranger Things:
- Ho incontrato due tipologie di titoli rotti/strani sul dump di Crossref, scoperti grazie ai warning di Beautiful Soup:
- “title”: [“.”]
- Il titolo è un URL
- Esempio: “title”: [“http://www.hisf.no/njmt“] → https://api.crossref.org/works/10.1080/08098139909477948
Per ciascuna di queste due tipologie ci sono decine di esempi. Cosa ne pensi? Come li devo trattare?
- Esempio: “title”: [“http://www.hisf.no/njmt“] → https://api.crossref.org/works/10.1080/08098139909477948
- Ho incontrato due tipologie di titoli rotti/strani sul dump di Crossref, scoperti grazie ai warning di Beautiful Soup:
Qual è il modo più veloce di ottenere la lista di tutti i DOI presenti in COCI? Devo necessariamente utilizzare il dump come ho fatto? Dall’endpoint ricevo giustamente un errore di timeout.
Può essere utile aggiungere un flag o un nuovo script per generare il CSV contenente tutti i DOI di COCI a partire dal dump?
Ho provato a velocizzare crossrefProcessing utilizzando il multi-processing. Senza l’indice DOI-ORCID e i wanted DOIs da controllare c’è stato un +1200% di miglioramento prestazionale (da 1 it/s a 12 it/s). Aggiungendo l’indice e il set da controllare, invece, il processo principale è diventato lentissimo. Hai ipotesi sul perché?
Il dump di Crossref contiene tutto Crossref o c’è un dump a parte per i Crossref Metadata Plus members?
Ho notato che in vari punti di meta viene controllata la presenza di un item in un set/dizionario prima di aggiungerlo. Questa soluzione è stata adottata perché più efficiente? Secondo questo risposta lo è:
Should I check if an item is already in a set before adding it?
Ad esempio, ciò viene fatto da add_value in CSVManager.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15def add_value(self, id_string, value):
if id_string not in self.data:
self.data[id_string] = set()
if value not in self.data[id_string]:
self.data[id_string].add(value)
if self.csv_path is not None and self.store_new:
if not exists(self.csv_path):
with open(self.csv_path, "w", encoding='utf-8') as f:
f.write('"id","value"\n')
with open(self.csv_path, "a", encoding='utf-8') as f:
f.write('"%s","%s"\n' % (id_string.replace('"', '""'),
value.replace('"', '""')))