<?xml version="1.0" encoding="UTF-8"?>
<rss  xmlns:atom="http://www.w3.org/2005/Atom" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns:content="http://purl.org/rss/1.0/modules/content/" 
      xmlns:dc="http://purl.org/dc/elements/1.1/" 
      version="2.0">
<channel>
<title>aborruso&#39;s website</title>
<link>https://aborruso.github.io/blog.html</link>
<atom:link href="https://aborruso.github.io/blog.xml" rel="self" type="application/rss+xml"/>
<description></description>
<generator>quarto-1.5.56</generator>
<lastBuildDate>Wed, 05 Feb 2025 23:00:00 GMT</lastBuildDate>
<item>
  <title>Pubblicati i dati dell’Archivio Nazionale dei Numeri Civici e delle Strade Urbane</title>
  <dc:creator>Andrea Borruso</dc:creator>
  <link>https://aborruso.github.io/posts/accesso_archivio_nazionale_numeri_civici_e_strade_urbane/</link>
  <description><![CDATA[ 





<section id="introduzione" class="level2">
<h2 class="anchored" data-anchor-id="introduzione">Introduzione</h2>
<p>Il <a href="https://eur-lex.europa.eu/legal-content/IT/TXT/?uri=CELEX:32023R0138">Regolamento di esecuzione (UE) 2023/138 della Commissione del 21 dicembre 2022</a> prevede la pubblicazione di una serie di <strong>dati di alto valore</strong>.<br> Tra questi i dati che alimentano l’<a href="https://www.anncsu.gov.it/"><strong>Archivio Nazionale dei Numeri Civici e delle Strade Urbane</strong></a>.</p>
<p>Da oggi sono disponibili in formato aperto e leggibili tramite API, e se ne ha evidenza dal dataset disponibile sul <a href="https://geodati.gov.it/geoportale/visualizzazione-metadati/scheda-metadati/?uuid=age:consultazioneANNCSU">Repertorio nazionale dei dati territoriali</a> (RNDT).</p>
<p>Viva Lorenzo e Andrea</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Aggiornamento
</div>
</div>
<div class="callout-body-container callout-body">
<p>Questo dataset è stato pubblicato sul <a href="https://www.dati.gov.it/view-dataset/dataset?id=c71b8aca-da9f-486a-bd22-9b532accf7df"><strong>catalogo nazionale dei dati aperti</strong></a>, in cui sono presenti anche gli URL per <strong>scaricare in blocco</strong> i dati regionali e/o quelli nazionali.</p>
</div>
</div>
</section>
<section id="come-accedere" class="level2">
<h2 class="anchored" data-anchor-id="come-accedere">Come accedere</h2>
<p>Leggendo la documentazione ufficiale è possibile costruire alcuni esempi base.</p>
<p>Il primo tipo di <em>query</em> è per <strong>odonimi</strong> (l’odonimo è il nome di una strada) e si può fa a partire dal <a href="https://dait.interno.gov.it/territorio-e-autonomie-locali/sut/elenco_codici_comuni.php">codice Belfiore</a> del Comune di interesse (è un codice alfanumerico di 4 caratteri usato in Italia per identificare in modo univoco ogni comune). Quello di Palermo è ad esempio <code>G273</code>.</p>
<p>Se si vuole cercare l’elenco delle strade che contengono <code>ROMA</code> nel nome, si può fare una richiesta come questa:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">curl</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-X</span> GET <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://anncsu.open.agenziaentrate.gov.it/age-inspire/opendata/anncsu/querydata.php?resource=odonimi&amp;codicecomune=G273&amp;denominazione=ROMA"</span></span></code></pre></div>
<p>Si può <a href="https://anncsu.open.agenziaentrate.gov.it/age-inspire/opendata/anncsu/querydata.php?resource=odonimi&amp;codicecomune=G273&amp;denominazione=ROMA">aprire anche nel browser</a> ed è composta da:</p>
<ul>
<li><code>resource=odonimi</code></li>
<li><code>codicecomune=G273</code></li>
<li><code>denominazione=ROMA</code></li>
</ul>
<p>In output un <code>JSON</code>, che per ogni strada ha questo tipo di schema:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode json code-with-copy"><code class="sourceCode json"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-2">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Progressivo_nazionale"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"576388"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-3">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Codice_comunale"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-4">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"DUG"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"VIA"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-5">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"DUF"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"ROMA"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-6">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Denominazione_localita"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-7">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Denominazione_lingua1"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-8">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Denominazione_lingua2"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span></span>
<span id="cb2-9"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div>
<p>Se si vuole cercare l’elenco degli <strong>accessi</strong> (i numeri civici) di questa strada, si deve partire dal codice numerico della strada. La strada di sopra ha il codice <code>576388</code> e si può fare una richiesta come questa:</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">curl</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-X</span> GET <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://anncsu.open.agenziaentrate.gov.it/age-inspire/opendata/anncsu/querydata.php?resource=accessi&amp;progressivoodonimo=576388&amp;accesso=1"</span></span></code></pre></div>
<p>Anche questa si può <a href="https://anncsu.open.agenziaentrate.gov.it/age-inspire/opendata/anncsu/querydata.php?resource=accessi&amp;progressivoodonimo=576388&amp;accesso=1">consultare via browser</a> e dà in output un <code>JSON</code> con questo schema:</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode json code-with-copy"><code class="sourceCode json"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb4-2">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Progressivo_nazionale_accesso"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1885499"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-3">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Codice_comunale_accesso"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-4">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Civico"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"179"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-5">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Esponente"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-6">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Specificita"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-7">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Metrico"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-8">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"CoordX"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-9">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"CoordY"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-10">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Quota"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">""</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb4-11">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"Metodo"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"4"</span></span>
<span id="cb4-12"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div>
</section>
<section id="la-lista-delle-strade-di-una-città" class="level2">
<h2 class="anchored" data-anchor-id="la-lista-delle-strade-di-una-città">La lista delle strade di una città</h2>
<p>Guardando la documentazione non sembra possibile ottenerla. Però forse (da verificare) è possibile utilizzare questo <em>hack</em>: <code>denominazione=%20%20%20</code>.</p>
<p>Quindi per Palermo, la query potrebbe essere:</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">curl</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-X</span> GET <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://anncsu.open.agenziaentrate.gov.it/age-inspire/opendata/anncsu/querydata.php?resource=odonimi&amp;codicecomune=G273&amp;denominazione=%20%20%20"</span></span></code></pre></div>
</section>
<section id="non-ci-sono-le-coordinate-geografiche" class="level2">
<h2 class="anchored" data-anchor-id="non-ci-sono-le-coordinate-geografiche">Non ci sono le coordinate geografiche</h2>
<p>Al momento <strong>non sono leggibili le coordinate geografiche dei numeri civici</strong>. E siccome non è possibile e non è sensato pubblicare questi dati senza queste informazioni, è ipotizzabile e sperabile che sia un errore e che a breve saranno leggibili.</p>
<p>Del resto l’ANNCSU, deve ancora annunciare il rilascio del servizio.</p>
</section>
<section id="documentazione-ufficiale" class="level2">
<h2 class="anchored" data-anchor-id="documentazione-ufficiale">Documentazione ufficiale</h2>
<p>La documentazione ufficiale è leggibile in formato <code>JSON</code> in questa pagina:<br> <a href="https://anncsu.open.agenziaentrate.gov.it/age-inspire/opendata/anncsu/querydata.php?help_show" class="uri">https://anncsu.open.agenziaentrate.gov.it/age-inspire/opendata/anncsu/querydata.php?help_show</a></p>
<p>Si riporta a seguire tradotta in italiano (fatto con un LLM).</p>
<section id="descrizione" class="level3">
<h3 class="anchored" data-anchor-id="descrizione">Descrizione</h3>
<p>L’azione <code>querydata</code> consente di cercare dati relativi a <strong>odonimi</strong> e <strong>accessi</strong> nel database ANNCSU.</p>
<p>Le richieste possono essere effettuate tramite <strong>GET</strong> o <strong>POST</strong>, utilizzando gli stessi parametri descritti di seguito.</p>
</section>
<section id="parametri-di-richiesta" class="level3">
<h3 class="anchored" data-anchor-id="parametri-di-richiesta">Parametri di richiesta</h3>
<section id="richiesta-di-odonimi" class="level4">
<h4 class="anchored" data-anchor-id="richiesta-di-odonimi">Richiesta di <strong>ODONIMI</strong></h4>
<ul>
<li><code>resource</code>: valore fisso <code>'odonimi'</code></li>
<li><code>codicecomune</code>: codice univoco del comune (codice “Belfiore”, ad es. H501, F205, …)</li>
<li><code>denominazione</code>: nome dell’odonimo, anche parziale; se contiene più parole, è consigliato sostituire gli spazi con <code>%20</code> (URL encoding)</li>
</ul>
</section>
<section id="richiesta-di-accessi" class="level4">
<h4 class="anchored" data-anchor-id="richiesta-di-accessi">Richiesta di <strong>ACCESSI</strong></h4>
<ul>
<li><code>resource</code>: valore fisso <code>'accessi'</code></li>
<li><code>codicecomune</code>: codice univoco del comune (codice “Belfiore”, ad es. H501, F205, …)</li>
<li><code>denominazione</code>: nome dell’odonimo, anche parziale; se contiene più parole, è consigliato sostituire gli spazi con <code>%20</code> (URL encoding)</li>
</ul>
</section>
</section>
<section id="esempi-di-richieste" class="level3">
<h3 class="anchored" data-anchor-id="esempi-di-richieste">Esempi di richieste</h3>
<section id="esempi-con-get" class="level4">
<h4 class="anchored" data-anchor-id="esempi-con-get">Esempi con <strong>GET</strong></h4>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb6-1">.../querydata.php?resource=odonimi&amp;codicecomune=H501&amp;denominazione=VIA%20MILANO</span>
<span id="cb6-2">.../querydata.php?resource=accessi&amp;progressivoodonimo=2000083&amp;accesso=1</span></code></pre></div>
</section>
<section id="alternativa-con-get" class="level4">
<h4 class="anchored" data-anchor-id="alternativa-con-get">Alternativa con <strong>GET</strong></h4>
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb7-1">.../querydata.php/odonimi/H501/MILANO</span>
<span id="cb7-2">.../querydata.php/accessi/2000083/1</span></code></pre></div>
</section>
<section id="esempi-con-post-contenuto-nel-corpo-della-richiesta" class="level4">
<h4 class="anchored" data-anchor-id="esempi-con-post-contenuto-nel-corpo-della-richiesta">Esempi con <strong>POST</strong> (contenuto nel corpo della richiesta)</h4>
<div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode json code-with-copy"><code class="sourceCode json"><span id="cb8-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"resource"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"odonimi"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"codicecomune"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"H501"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"denominazione"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"VIA MILANO"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb8-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"resource"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"accessi"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"progressivoodonimo"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"2000083"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"accesso"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div>
</section>
</section>
<section id="struttura-della-risposta" class="level3">
<h3 class="anchored" data-anchor-id="struttura-della-risposta">Struttura della risposta</h3>
<section id="dati-relativi-agli-odonimi" class="level4">
<h4 class="anchored" data-anchor-id="dati-relativi-agli-odonimi">Dati relativi agli <strong>ODONIMI</strong></h4>
<ul>
<li><code>Progressivo_nazionale</code>: Progressivo nazionale dell’odonimo in ANNCSU</li>
<li><code>Codice_comunale</code>: Codice comunale dell’odonimo</li>
<li><code>DUG</code>: Denominazione Urbanistica Generica (es. “via”, “piazza”)</li>
<li><code>DUF</code>: Denominazione Urbanistica Ufficiale (es. “Dante Alighieri”, “Vittorio Emanuele Secondo”)</li>
<li><code>Denominazione_localita</code>: Nome della località</li>
<li><code>Denominazione_lingua1</code>: Prima denominazione in un’altra lingua</li>
<li><code>Denominazione_lingua2</code>: Seconda denominazione in un’altra lingua</li>
</ul>
</section>
<section id="dati-relativi-agli-accessi" class="level4">
<h4 class="anchored" data-anchor-id="dati-relativi-agli-accessi">Dati relativi agli <strong>ACCESSI</strong></h4>
<ul>
<li><code>Progressivo_nazionale_accesso</code>: Progressivo nazionale dell’accesso in ANNCSU</li>
<li><code>Codice_comunale_accesso</code>: Codice comunale dell’accesso</li>
<li><code>Civico</code>: Numero civico (esclusivo rispetto al metrico)</li>
<li><code>Esponente</code>: Esponente del civico</li>
<li><code>Specificita</code>: Specificità dell’accesso</li>
<li><code>Metrico</code>: Ubicazione metrica (esclusiva rispetto al civico)</li>
<li><code>CoordX</code>: Coordinata geografica X (Longitudine) del civico, determinata dal Comune, espressa in gradi decimali</li>
<li><code>CoordY</code>: Coordinata geografica Y (Latitudine) del civico, determinata dal Comune, espressa in gradi decimali</li>
<li><code>Quota</code>: Coordinata geografica Z (Altitudine) del civico, determinata dal Comune, espressa in metri</li>
<li><code>Metodo</code>: Metodo di rilevazione delle coordinate del civico usato dal Comune, con la seguente codifica:
<ul>
<li><strong>1</strong> = Rilevazione strumentale sul campo, accuratezza &lt; 5 m</li>
<li><strong>2</strong> = Rilevazione strumentale sul campo, accuratezza ≥ 5 m</li>
<li><strong>3</strong> = Derivazione indiretta da base dati territoriale, accuratezza stimabile &lt; 5 m</li>
<li><strong>4</strong> = Derivazione indiretta da base dati territoriale, accuratezza stimabile ≥ 5 m</li>
<li><strong>5</strong> = Derivazione indiretta tramite Portale per i Comuni, accuratezza stimabile ≥ 2 m</li>
</ul></li>
</ul>


</section>
</section>
</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Torna in cima</a> ]]></description>
  <category>opendata</category>
  <category>hvd</category>
  <category>europa</category>
  <guid>https://aborruso.github.io/posts/accesso_archivio_nazionale_numeri_civici_e_strade_urbane/</guid>
  <pubDate>Wed, 05 Feb 2025 23:00:00 GMT</pubDate>
  <media:content url="https://aborruso.github.io/posts/accesso_archivio_nazionale_numeri_civici_e_strade_urbane/images/anncsu.png" medium="image" type="image/png" height="93" width="144"/>
</item>
<item>
  <title>Tutti i dati aperti del PNRR in 500 kB</title>
  <dc:creator>Andrea Borruso</dc:creator>
  <link>https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/</link>
  <description><![CDATA[ 





<section id="introduzione" class="level2">
<h2 class="anchored" data-anchor-id="introduzione">Introduzione</h2>
<p><strong>Strumenti</strong> e <strong>dati</strong> “<strong>giusti</strong>” consentono di ottenere risultati sorprendenti, e soprattutto <strong>allargano</strong> la <strong>platea</strong> di chi può fare <strong>analisi</strong> e <strong>ricerca</strong> su certe informazioni.</p>
<p>In questo post sarà illustrato come un piccolo <strong>file</strong> di <strong>500 kB</strong>, possa essere il punto di ingresso sui dati aperti del <strong>Piano Nazionale di Ripresa e Resilienza</strong> (<strong>PNRR</strong>).<br> Si tratta di un file, di un database <a href="https://duckdb.org/"><strong>DuckDB</strong></a>, che “contiene” l’elenco delle principali tabelle del <a href="https://www.italiadomani.gov.it/content/sogei-ng/it/it/catalogo-open-data.html">Catalogo Open Data</a> di Italiadomani, il portale del Governo che ospita i dati del PNRR.</p>
<p>La parola “contiene” è tra virgolette perché il file non contiene realmente i dati, ma semplicemente delle viste, dei puntatori ai dati veri e propri. Ma per le modalità in cui è stato costruito, è possibile fare <em>query</em> e analisi senza quasi accorgersi di questo.</p>
<p>In questo modo è possibile allargare il numero di persone che possono elaborare questi dati, ma c’è un <strong>prerequisito</strong>: <strong>conoscere</strong> il linguaggio <strong><code>SQL</code></strong>.<br>Il <code>SQL</code> è un linguaggio di programmazione che consente di interrogare le tabelle di un database.</p>
</section>
<section id="come-interrogare-il-database" class="level2">
<h2 class="anchored" data-anchor-id="come-interrogare-il-database">Come interrogare il database</h2>
<p>Il <strong>file</strong> in formato DuckDB si può <strong>scaricare</strong> da <a href="https://raw.githubusercontent.com/ondata/italian-public-sector-pnrr-data-guide/refs/heads/main/data/italia-domani/parquet/pnrr.db">qui</a>. È leggibile con decine di <em>software</em>, per tutti i sistemi operativi.</p>
<p>Uno degli strumenti che si possono utilizzare è <a href="https://dbeaver.io/">DBeaver</a>, un client <code>SQL</code> <em>open source</em> per tutte le principali piattaforme, che consente di interrogare database di diversi tipi, tra cui DuckDB.</p>
<p>Una volta installato e lanciato, si potrà scegliere a che tipo di database connettersi: in questo caso DuckDB (vedi Figura&nbsp;1).</p>
<div id="fig-dbeaver_select" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dbeaver_select-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/images/dbeaver_select.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dbeaver_select-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;1: Scegliere il database a cui connettersi
</figcaption>
</figure>
</div>
<p>Nei passaggi successivi della configurazione si dovrà indicare a quale file <code>DuckDB</code> connettersi. Qui sarà il file <a href="https://raw.githubusercontent.com/ondata/italian-public-sector-pnrr-data-guide/refs/heads/main/data/italia-domani/parquet/pnrr.db"><code>pnrr.db</code></a> scaricato in precedenza.<br> Una volta connessi, il database sarà visibile sulla sinistra, nel navigatore dei database. E facendo clic sui vari segni <code>&gt;</code>, sarà possibile vedere le 1️⃣ tabelle e le 2️⃣ viste, ecc. in cui è strutturato (vedi Figura&nbsp;2).</p>
<div id="fig-dbeaver_tree" class="lightbox quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dbeaver_tree-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="images/dbeaver_tree.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1" title="Figura&nbsp;2: Database DuckDB in DBeaver"><img src="https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/images/dbeaver_tree.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dbeaver_tree-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;2: Database DuckDB in DBeaver
</figcaption>
</figure>
</div>
<p>La tabella è soltanto una, si chiama <code>info_viste</code> e contiene l’elenco di tutte le viste presenti nel database. In questa tabella, per ogni vista:</p>
<ul>
<li>il nome della vista;</li>
<li>il titolo del dataset;</li>
<li>l’URL della pagina del dataset;</li>
<li>il file che ha fatto da sorgente;</li>
<li>la descrizione del dataset;</li>
<li>la data di osservazione dei dati che hanno fatto da sorgente.</li>
</ul>
<p>Questa tabella è quindi una <strong>tabella di metadati</strong>. Mentre per <strong>accedere</strong> ai <strong>dati</strong> bisogna utilizzare una o più delle <strong>viste</strong> presenti.</p>
<p>E una prima <em>query</em> potrebbe essere quella per conteggiare il <strong>numero di progetti del PNRR</strong>:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb1-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">COUNT</span>() conteggio <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">from</span> pnrr.main.PNRR_Progetti;</span></code></pre></div>
<p>Sono, al momento, <strong>269.300 progetti</strong>. La cosa interessante è che il risultato è molto rapido, nonostante il db non contenga i dati, ma solo dei puntatori.</p>
<p>Ed è molto comodo, che strumenti come DBeaver abbiano l’auto-completamento delle <em>query</em>, come è possibile vedere in Figura&nbsp;3.</p>
<div id="fig-dbeaver_autocomplete" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dbeaver_autocomplete-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/images/select_autocomplete.gif" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dbeaver_autocomplete-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;3: Esempio di query con autocompletamento in DBeaver
</figcaption>
</figure>
</div>
<p>Il PNRR è suddiviso in Missioni e la <em>query</em> per conteggiare il numero di progetti per Missione - che viene eseguita in <strong>0.5 secondi</strong>, è:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb2-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span></span>
<span id="cb2-2">  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"Descrizione Missione"</span>,</span>
<span id="cb2-3">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">COUNT</span>() conteggio</span>
<span id="cb2-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span></span>
<span id="cb2-5">  pnrr.main.PNRR_Progetti</span>
<span id="cb2-6"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">GROUP</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">BY</span></span>
<span id="cb2-7">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">ALL</span></span>
<span id="cb2-8"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">ORDER</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">BY</span></span>
<span id="cb2-9">  conteggio <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">DESC</span>;</span></code></pre></div>
<table class="caption-top table">
<thead>
<tr class="header">
<th>Descrizione Missione</th>
<th style="text-align: right;">conteggio</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Digitalizzazione, innovazione, competitività e cultura</td>
<td style="text-align: right;">83661</td>
</tr>
<tr class="even">
<td>Rivoluzione verde e transizione ecologica</td>
<td style="text-align: right;">81486</td>
</tr>
<tr class="odd">
<td>Istruzione e ricerca</td>
<td style="text-align: right;">75677</td>
</tr>
<tr class="even">
<td>Inclusione e coesione</td>
<td style="text-align: right;">18088</td>
</tr>
<tr class="odd">
<td>Salute</td>
<td style="text-align: right;">10084</td>
</tr>
<tr class="even">
<td>Infrastrutture per una mobilità sostenibile</td>
<td style="text-align: right;">285</td>
</tr>
<tr class="odd">
<td>REPowerEU</td>
<td style="text-align: right;">19</td>
</tr>
</tbody>
</table>
<p>Ma per dare un’idea più efficace della comodità, di poter utilizzare un piccolo file da 500 kB, si può costruire una query più complessa che mette in relazione <strong>due viste</strong>, ovvero <strong>due dataset</strong>: quello dei <strong>Progetti</strong> e quello delle <strong>Localizzazioni</strong>.<br> L’obiettivo è quello di creare una tabella di sintesi, una tabella <em>pivot</em>, per restituisca il numero di progetti per Missione per ogni Regione.</p>
<p>La query è</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb3-1">PIVOT (</span>
<span id="cb3-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span></span>
<span id="cb3-3">    loc.<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"Descrizione Regione"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">AS</span> Regione,</span>
<span id="cb3-4">    p.Missione</span>
<span id="cb3-5">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span></span>
<span id="cb3-6">    <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"pnrr"</span>.<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"PNRR_Progetti"</span> p</span>
<span id="cb3-7">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">LEFT</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">JOIN</span> (</span>
<span id="cb3-8">      <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span></span>
<span id="cb3-9">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">DISTINCT</span> CUP,</span>
<span id="cb3-10">        <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"CODICE Locale Progetto"</span>,</span>
<span id="cb3-11">        <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"Descrizione Regione"</span></span>
<span id="cb3-12">      <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span></span>
<span id="cb3-13">        <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"pnrr"</span>.<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"PNRR_Localizzazione"</span></span>
<span id="cb3-14">    ) loc <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">ON</span> p.CUP <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> loc.CUP</span>
<span id="cb3-15">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">AND</span> p.<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"Codice Locale Progetto"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> loc.<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"CODICE Locale Progetto"</span></span>
<span id="cb3-16">) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">ON</span> Missione</span></code></pre></div>
<p>E in pochi secondi viene restituito il risultato (vedi Figura&nbsp;4).</p>
<div id="fig-pivot" class="lightbox quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-pivot-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="images/pivot.png" class="lightbox" data-gallery="quarto-lightbox-gallery-2" title="Figura&nbsp;4: Tabella pivot con numero di progetti per Missione per Regione"><img src="https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/images/pivot.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-pivot-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;4: Tabella pivot con numero di progetti per Missione per Regione
</figcaption>
</figure>
</div>
</section>
<section id="come-è-stato-creato-il-database" class="level2">
<h2 class="anchored" data-anchor-id="come-è-stato-creato-il-database">Come è stato creato il database</h2>
<p>L’ispirazione per la creazione di questa modalità di accesso ai dati del PNRR, viene dalla lettura di <a href="https://motherduck.com/blog/from-data-lake-to-lakehouse-duckdb-portable-catalog/">questo ottimo articolo</a>, in cui si spiega come DuckDB possa diventare un <strong>catalogo portatile</strong> per la <strong>gestione</strong> dei <strong>dati</strong>, da fonti diverse (file <code>parquet</code> da fonti Amazon S3, database PostgreSQL, tabelle su Google Cloud, ecc.).</p>
<p>Per questo file è stata replicata la logica descritta nell’articolo, ma sono state <strong>necessarie</strong> delle <strong>pre-lavorazioni</strong> dei dati.</p>
<p>Sul sito Italiadomani i file sono disponibili in formato <code>CSV</code> (<code>JSON</code> e <code>XLSX</code>) e una query <code>SQL</code> tramite DuckDB si può fare puntando direttamente all’URL del file. Per sapere ad esempio quanti sono i progetti del PNRR la <code>query</code> sarebbe:</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb4-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">COUNT</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> read_csv_auto(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://www.italiadomani.gov.it/content/dam/sogei-ng/opendata/PNRR_Progetti.csv'</span>)</span></code></pre></div>
<p>Questo è possibile grazie all’<a href="https://duckdb.org/docs/extensions/httpfs/overview.html">estensione <code>httpfs</code></a> di DuckDB, che consente di leggere file da URL HTTP o da Amazon S3. Ci sono però dei problemi:</p>
<ul>
<li>a volte il <strong>server</strong> di <strong>Italiadomani non risponde in modo adeguato</strong>, e la <em>query</em> fallisce;</li>
<li>il formato <strong><code>CSV</code></strong> <strong>non</strong> è <strong>ottimizzato</strong> per <strong><em>query</em> su file “grandi”</strong>, che <strong>non</strong> risiedano sul <strong>proprio</strong> <strong>PC</strong>, perché è necessario scaricare tutto il file per fare la <em>query</em>.</li>
</ul>
<p>Entrambi i <strong>punti</strong> sono abbastanza <strong>bloccanti</strong> e, per superarli, sono state fatte due cose:</p>
<ol type="1">
<li>pubblicare i file con i dati in uno spazio web che rispondesse meglio alle chiamate <code>HTTP</code>;</li>
<li>convertire i file <code>CSV</code> in un formato più adatto per fare <em>query</em> su file “grandi” remoti, come il formato <code>parquet</code>.</li>
</ol>
<p>Lo spazio web creato, che ospita i file è GitHub, e la cartella è questa:<br> <a href="https://github.com/ondata/italian-public-sector-pnrr-data-guide/tree/main/data/italia-domani/parquet" class="uri">https://github.com/ondata/italian-public-sector-pnrr-data-guide/tree/main/data/italia-domani/parquet</a></p>
<p>L’URL di accesso diretto ai file ha questa struttura:<br> <code>https://raw.githubusercontent.com/ondata/italian-public-sector-pnrr-data-guide/refs/heads/main/data/italia-domani/parquet/Nome_File.parquet</code></p>
<p>Quindi ad esempio l’URL del dataset dei progetti è:<br> <a href="https://raw.githubusercontent.com/ondata/italian-public-sector-pnrr-data-guide/refs/heads/main/data/italia-domani/parquet/PNRR_Progetti.parquet" class="uri">https://raw.githubusercontent.com/ondata/italian-public-sector-pnrr-data-guide/refs/heads/main/data/italia-domani/parquet/PNRR_Progetti.parquet</a></p>
<p>E la query per conteggiare i progetti è quindi:</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb5-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">COUNT</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">AS</span> numero_progetti</span>
<span id="cb5-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span></span>
<span id="cb5-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://raw.githubusercontent.com/ondata/italian-public-sector-pnrr-data-guide/refs/heads/main/data/italia-domani/parquet/PNRR_Progetti.parquet'</span>;</span></code></pre></div>
<p>Il database DuckDB è stato implementato creando una vista per ogni file <code>parquet</code> presente nella suddetta cartella:</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb6-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">CREATE</span></span>
<span id="cb6-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">OR</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">replace</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">view</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"PNRR_Progetti"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">AS</span></span>
<span id="cb6-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span></span>
<span id="cb6-4">  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span></span>
<span id="cb6-5"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span></span>
<span id="cb6-6">  read_parquet(</span>
<span id="cb6-7">    <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://raw.githubusercontent.com/ondata/italian-public-sector-pnrr-data-guide/refs/heads/main/data/italia-domani/parquet/PNRR_Progetti.parquet'</span></span>
<span id="cb6-8">  );</span></code></pre></div>
</section>
<section id="due-esempi-di-accesso-live" class="level2">
<h2 class="anchored" data-anchor-id="due-esempi-di-accesso-live">Due esempi di accesso “live”</h2>
<p>Un database così strutturato, dà la possibilità di abilitare l’accesso ai dati in modo “live”, ovvero senza dover scaricare il file e interrogarlo in locale.</p>
<p>Due applicazioni web, che consentono di accedere a risorse remote e interrogarle, lanciando una versione di DuckDB nel browser, senza dovere installare nulla sono queste due:</p>
<ul>
<li>la <a href="https://shell.duckdb.org/">DuckDB Shell</a>;</li>
<li>il <a href="https://sql-workbench.com/">SQL Workbench</a>.</li>
</ul>
<p>In entrambi i casi basta prima dare il comando di <code>ATTACH</code> per collegare il database DuckDB remoto, e poi fare tutte le <em>query</em> che si vogliono.</p>
<p>Ad esempio, per la tabella pivot vista sopra, basterà per entrambi i casi:</p>
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb7-1">ATTACH <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://raw.githubusercontent.com/ondata/italian-public-sector-pnrr-data-guide/refs/heads/main/data/italia-domani/parquet/pnrr.db'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">as</span> pnrr (READ_ONLY);</span>
<span id="cb7-2"></span>
<span id="cb7-3">PIVOT (</span>
<span id="cb7-4">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span></span>
<span id="cb7-5">    loc.<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"Descrizione Regione"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">AS</span> Regione,</span>
<span id="cb7-6">    p.Missione</span>
<span id="cb7-7">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span></span>
<span id="cb7-8">    <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"pnrr"</span>.<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"PNRR_Progetti"</span> p</span>
<span id="cb7-9">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">LEFT</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">JOIN</span> (</span>
<span id="cb7-10">      <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span></span>
<span id="cb7-11">        <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">DISTINCT</span> CUP,</span>
<span id="cb7-12">        <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"CODICE Locale Progetto"</span>,</span>
<span id="cb7-13">        <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"Descrizione Regione"</span></span>
<span id="cb7-14">      <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span></span>
<span id="cb7-15">        <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"pnrr"</span>.<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"PNRR_Localizzazione"</span></span>
<span id="cb7-16">    ) loc <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">ON</span> p.CUP <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> loc.CUP</span>
<span id="cb7-17">    <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">AND</span> p.<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"Codice Locale Progetto"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> loc.<span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"CODICE Locale Progetto"</span></span>
<span id="cb7-18">) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">ON</span> Missione <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">ORDER</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">BY</span> REGIONE;</span></code></pre></div>
<p>Ed è interessante il fatto che le <strong><em>query</em></strong> costruite in questo modo, possano essere <strong>condivise</strong> con altre persone con un <em>link</em>, come questi due (sotto le immagini con l’anteprima dei risultati):</p>
<ul>
<li><a href="https://shell.duckdb.org/#queries=v0,ATTACH-'https%3A%2F%2Fraw.githubusercontent.com%2Fondata%2Fitalian%20public%20sector%20pnrr%20data%20guide%2Frefs%2Fheads%2Fmain%2Fdata%2Fitalia%20domani%2Fparquet%2Fpnrr.db'-as-pnrr-(READ_ONLY)~%0D%0A%0D%0APIVOT-(%0D%0A--SELECT%0D%0A----loc.%22Descrizione-Regione%22-AS-Regione%2C%0D%0A----p.Missione%0D%0A--FROM%0D%0A----%22pnrr%22.%22PNRR_Progetti%22-p%0D%0A----LEFT-JOIN-(%0D%0A------SELECT%0D%0A--------DISTINCT-CUP%2C%0D%0A--------%22CODICE-Locale-Progetto%22%2C%0D%0A--------%22Descrizione-Regione%22%0D%0A------FROM%0D%0A--------%22pnrr%22.%22PNRR_Localizzazione%22%0D%0A----)-loc-ON-p.CUP-%3D-loc.CUP%0D%0A----AND-p.%22Codice-Locale-Progetto%22-%3D-loc.%22CODICE-Locale-Progetto%22%0D%0A)-ON-Missione-ORDER-BY-REGIONE~">DuckDB shell</a>;</li>
<li><a href="https://sql-workbench.com/#queries=v0,ATTACH-'https%3A%2F%2Fraw.githubusercontent.com%2Fondata%2Fitalian%20public%20sector%20pnrr%20data%20guide%2Frefs%2Fheads%2Fmain%2Fdata%2Fitalia%20domani%2Fparquet%2Fpnrr.db'-as-pnrr-(READ_ONLY)~,PIVOT-(--SELECT--loc.%22Descrizione-Regione%22-AS-Regione%2C--p.Missione--FROM--%22pnrr%22.%22PNRR_Progetti%22-p--LEFT-JOIN-(--SELECT--DISTINCT-CUP%2C--%22CODICE-Locale-Progetto%22%2C--%22Descrizione-Regione%22--FROM--%22pnrr%22.%22PNRR_Localizzazione%22--)-loc-ON-p.CUP-%3D-loc.CUP--AND-p.%22Codice-Locale-Progetto%22-%3D-loc.%22CODICE-Locale-Progetto%22-)-ON-Missione-ORDER-BY-REGIONE~">SQL Workbench</a>.</li>
</ul>
<div>

</div>
<div class="quarto-layout-panel" data-layout-ncol="2">
<div class="quarto-layout-row">
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div id="fig-query_live_1" class="lightbox quarto-float quarto-figure quarto-figure-center anchored" data-group="query_live">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-query_live_1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="images/query_live_01.png" class="lightbox" data-gallery="query_live" title="Figura&nbsp;5: DuckDB Shell"><img src="https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/images/query_live_01.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-query_live_1-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;5: DuckDB Shell
</figcaption>
</figure>
</div>
</div>
<div class="quarto-layout-cell" style="flex-basis: 50.0%;justify-content: flex-start;">
<div id="fig-query_live_2" class="lightbox quarto-float quarto-figure quarto-figure-center anchored" data-group="query_live">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-query_live_2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="images/query_live_02.png" class="lightbox" data-gallery="query_live" title="Figura&nbsp;6: SQL Workbench"><img src="https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/images/query_live_02.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-query_live_2-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;6: SQL Workbench
</figcaption>
</figure>
</div>
</div>
</div>
</div>
</section>
<section id="lo-strumento-consigliato" class="level2">
<h2 class="anchored" data-anchor-id="lo-strumento-consigliato">Lo strumento consigliato</h2>
<p>Una cosa comodissima di questa modalità di accesso ai dati PNRR, è che è possibile leggerli nel modo preferito: con un <em>client</em> <code>SQL</code> come DBeaver da installare sulla propria macchina, con un <em>client web</em> come DuckDB Shell o SQL Workbench, con un linguaggio di programmazione come Python o R, ecc. e anche da <strong>riga di comando</strong>.</p>
<p>Per chi è abituato a lavorare da riga di comando, un ottimo strumento è il sorprendente e comodissimo <a href="https://harlequin.sh/"><strong>Harlequin</strong></a>, gratuito e <em>open source</em>, installabile su qualsiasi sistema operativo, e in grado di accedere a decine di database, tra cui DuckDB.</p>
<div id="fig-harlequin" class="lightbox quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-harlequin-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="images/harlequin.png" class="lightbox" data-gallery="quarto-lightbox-gallery-5" title="Figura&nbsp;7: Esempio d’uso di Harlequin"><img src="https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/images/harlequin.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-harlequin-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;7: Esempio d’uso di Harlequin
</figcaption>
</figure>
</div>
</section>
<section id="note-conclusive" class="level2">
<h2 class="anchored" data-anchor-id="note-conclusive">Note conclusive</h2>
<p>In questo post si vuole sottolineare la <strong>comodità</strong> di <strong>accedere</strong> a una <strong>banca dati</strong>, a partire da un file piccolo e senza rinunciare alla possibilità di costruire analisi complesse e ricche.<br> Non è la modalità facile e unica con cui capire tutto sui numeri del PNRR, ma si ha la possibilità di fare un primo passo, e di farlo in modo molto più semplice di quanto si possa pensare.</p>
<p>Ci sono alcuni <strong>requisiti propedeutici</strong>: <strong>approfondire</strong> come è strutturato il <strong>PNRR</strong>, <strong>leggere</strong> i <strong>metadati</strong> delle tabelle (in ogni pagina dei dati, c’è un link ai metadati, vedi Figura&nbsp;8), e <strong>conoscere</strong> il <strong>linguaggio <code>SQL</code></strong>.</p>
<div id="fig-metadati" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-metadati-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="https://www.italiadomani.gov.it/content/sogei-ng/it/it/catalogo-open-data/Progetti_del_PNRR.html"><img src="https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/images/metadati.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-metadati-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;8: Metadati di una tabella
</figcaption>
</figure>
</div>
<p>Questo è un primo rilascio del database, per mostrare un caso d’uso “tecnico”. Al momento non è una risorsa su cui è pianificato un aggiornamento automatico e non è stato fatto alcun controllo di qualità.<br> In prospettiva è probabile che verrà creata una procedura automatica per aggiornare il database, e verrà migliorata la qualità dei dati con verifiche sulla coerenza dello schema dati.</p>
<p>I file sorgente, pubblicati su Italiadomani hanno alcuni problemi, di facile risoluzione, a da conoscere:</p>
<ul>
<li>l’<strong>encoding</strong> dei file <code>CSV</code>. È nella gran parte dei casi <strong><code>UTF-8</code></strong>, ma in alcuni casi non è così e bisogna fare attenzione per l’accesso e l’eventuale conversione;</li>
<li>l’importante file <code>CSV</code> sui “<a href="https://www.italiadomani.gov.it/content/sogei-ng/it/it/catalogo-open-data/soggetti-dei-progetti-del-pnrr.html">Soggetti dei progetti del PNRR</a>” - che fra l’altro è uno di quelli di dimensioni maggiori - contiene <strong>diverse righe</strong> non corrette, con un <strong>numero</strong> di <strong>colonne</strong> <strong>non compatibile con lo schema</strong>.</li>
</ul>
<p>Riprendo infine una <strong>riflessione</strong> già fatta nell’apprezzato post “<a href="http://localhost:6074/posts/duckdb-intro-csv/"><strong>Gestire file CSV grandi, brutti e cattivi</strong></a>”: con uno sforzo piccolo e un po’ di cura, è possibile <strong>pubblicare</strong> dati in <strong>modalità</strong> che <strong>ampliano</strong> di molto il <strong>numero</strong> di <strong>persone</strong> che possono <strong>accedervi</strong> e <strong>utilizzarli</strong> in <strong>modo efficace</strong>.<br> Ad esempio:</p>
<ul>
<li>questi <em>file</em> potrebbero pure essere <strong>pubblicati</strong> su un <em>bucket</em> di Amazon S3 (o altre modalità simili), e DuckDB (o altri <em>client</em>) potrebbe leggerli da lì, con grande rapidità;</li>
<li>si potrebbero pubblicare anche in <strong>formato compresso</strong>, ad esempio in <code>csv.gz</code>, o ancora meglio in <strong>formati</strong> efficienti e <strong>specializzati per l’analisi</strong>, come il <strong><code>parquet</code></strong>;</li>
<li>si potrebbe pubblicare anche <strong>un unico file in formato DuckDB</strong>, con tutte le tabelle del PNRR, con la corretta <strong>definizione</strong> dei <strong>tipi di campo</strong>, con <strong>definite</strong> le <strong>chiavi</strong> primarie, le chiavi esterne, ecc..</li>
</ul>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Torna in cima</a> ]]></description>
  <category>duckdb</category>
  <category>open-data</category>
  <category>cli</category>
  <category>parquet</category>
  <category>pnrr</category>
  <guid>https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/</guid>
  <pubDate>Wed, 01 Jan 2025 23:00:00 GMT</pubDate>
  <media:content url="https://aborruso.github.io/posts/tutto-il-pnrr-in-500k/images/harlequin.png" medium="image" type="image/png" height="104" width="144"/>
</item>
<item>
  <title>I (quasi) tre milioni di beni immobili della Pubblica Amministrazione</title>
  <dc:creator>Andrea Borruso</dc:creator>
  <dc:creator>Matteo Fortini</dc:creator>
  <link>https://aborruso.github.io/posts/beni_immobili_pubblica_amministrazione/</link>
  <description><![CDATA[ 





<section id="introduzione" class="level2">
<h2 class="anchored" data-anchor-id="introduzione">Introduzione</h2>
<p>L’<strong>ENEA</strong> - Agenzia nazionale per le nuove tecnologie, l’energia e lo sviluppo economico sostenibile - ha <a href="https://www.pubblicazioni.enea.it/le-pubblicazioni-enea/edizioni-enea/anno-2024/la-consistenza-del-parco-immobiliare-nazionale.html">pubblicato</a> a fine luglio del 2024 il rapporto “<strong><a href="https://www.pubblicazioni.enea.it/download.html?task=download.send&amp;id=698:la-consistenza-del-parco-immobiliare-nazionale&amp;catid=3">La consistenza del parco immobiliare nazionale</a></strong>”.<br> Per la parte relativa ai <strong>fabbricati di proprietà pubblica</strong> è stato realizzato con il contributo dei dati forniti dal Dipartimento dell’Economia (DE) – Direzione III Valorizzazione del patrimonio pubblico.</p>
<p>Questo dipartimento infatti gestisce la <strong>banca dati degli immobili pubblici</strong>, alla quale è associata la pubblicazione dei dati aperti in formato <strong><code>CSV</code></strong>, con licenza <a href="https://creativecommons.org/licenses/by/4.0/deed.it">CC-BY 4.0</a>: <br><a href="https://www.de.mef.gov.it/it/attivita_istituzionali/patrimonio_pubblico/censimento_immobili_pubblici/open_data_immobili/dati_immobili_2019.html"><strong>Elenco dei beni immobili dichiarati dalle Amministrazioni Pubbliche</strong> per l’anno 2019, ai sensi dell’art. 2, comma 222, legge 23 dicembre 2009, n.&nbsp;191</a></p>
<blockquote class="blockquote">
<p>Per ciascuna Amministrazione sono riportate le seguenti informazioni sui beni immobili dichiarati: identificativo univoco del bene (unità immobiliare, u.i.), identificativi catastali (o codice bene nel caso di immobili non accatastati), titolo e quota di proprietà, localizzazione, tipologia immobiliare, dimensione (superficie/cubatura), epoca di costruzione, natura giuridica, vincolo culturale paesaggistico, appartenenza a un compendio, tipo di utilizzo e finalità, indicazione se l’unità immobiliare è data in uso a terzi, totalmente o in parte. Per beni non di proprietà, sono riportati: titolo di detenzione, superficie detenuta (se non si detiene l’intera u.i.), Amministrazione da cui si è ricevuto il bene (Amministrazione cedente). Le informazioni sulle detenzioni a favore di terzi, relative all’intera u.i. o ad una parte, sono contenute nel corrispondente file .csv Detenzioni a favore di terzi.</p>
</blockquote>
<p>“In considerazione dell’elevato numero di record” - circa <strong>2,8 milioni</strong> - il Dipartimento ha suddiviso la pubblicazione di questi dati in circa <strong>30 file <code>CSV</code> compressi</strong> (<code>zip</code>). Per fortuna tutti con <strong>un solo schema</strong>.</p>
<p>In questo articolo voglio mostrare come <strong>metterli di nuovo insieme</strong>, in modo da poter <strong>fare</strong> <strong>elaborazioni</strong> e <strong>sintesi</strong> come quelle dell’ENEA. Tenuti compressi, separati e in questo formato, infatti, non sono molto comodi da gestire.<br> <strong>DuckDB</strong> si rivela nuovamente uno strumento prezioso per questo compito (vedi l’articolo “<a href="../../posts/duckdb-intro-csv/index.html">Gestire file CSV grandi, brutti e cattivi</a>”).</p>
<p>Ancora una volta sarà l’occasione - lo farò in rappresentanza dell’associazione onData - di <strong>proporre</strong> al Dipartimento di <strong>pubblicare</strong> i <strong>dati</strong> anche in <strong>altre modalità</strong>. E magari andrà bene, così come è avvenuto con <a href="https://opencoesione.gov.it/it/news/opendata-rilasciati-dataset-formato-parquet/">OpenCoesione</a>.</p>
<p>Prima di passare all’“azione”, una nota sulla sottostante Figura&nbsp;1. Si tratta di una mappa che rappresenta la densità degli immobili pubblici in Italia, una cosiddetta <em>heatmap</em>: le aree più scure indicano una maggiore densità di immobili.<br> Nella <strong><a href="https://xkcd.com/1138/">brillante vignetta di xkcd</a></strong>, viene mostrato come le heatmap siano spesso inutili perché, in sostanza, riflettono la distribuzione della popolazione: le “cose” si trovano dove ci sono le persone.<br> Anche in questo caso è così, ma si notano colori insolitamente tenui anche in alcune aree densamente popolate del Sud Italia. Tuttavia, questa è un’analisi che spetterà a qualche altra persona.</p>
<div id="fig-heatmap" class="quarto-float quarto-figure quarto-figure-center anchored" alt="Heatmap della posizione degli immobili">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-heatmap-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/beni_immobili_pubblica_amministrazione/heat_map.png" class="img-fluid figure-img" alt="Heatmap della posizione degli immobili">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-heatmap-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;1: heatmap della posizione degli immobili
</figcaption>
</figure>
</div>
</section>
<section id="scaricare-i-file" class="level2">
<h2 class="anchored" data-anchor-id="scaricare-i-file">Scaricare i file</h2>
<p>L’ho fatto in blocco. Ho prima esplorato un po’ <a href="https://www.de.mef.gov.it/it/attivita_istituzionali/patrimonio_pubblico/censimento_immobili_pubblici/open_data_immobili/dati_immobili_2019.html">la pagina</a> e ho notato che tutti i file hanno un <code>URL</code> che inizia con la stringa <code>/modules</code> e termina per <code>.zip</code>. Allora ho iniziato dall’estrarre la lista di questi file, usando l’espressione regolare <code>/modules.+.zip</code>:</p>
<p>Supponiamo di lavorare in una cartella immobili_pubblici:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb1-1"></span>
<span id="cb1-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mkdir</span> immobili_pubblici</span>
<span id="cb1-3"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">cd</span> immobili_pubblici</span>
<span id="cb1-4"></span>
<span id="cb1-5"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># usiamo la variabile $folder per tener traccia della cartella di lavoro</span></span>
<span id="cb1-6"></span>
<span id="cb1-7"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">folder</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$(</span><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">pwd</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">)</span></span></code></pre></div>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb2-1"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">URL</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://www.de.mef.gov.it/it/attivita_istituzionali/patrimonio_pubblico/censimento_immobili_pubblici/open_data_immobili/dati_immobili_2019.html"</span></span>
<span id="cb2-2"></span>
<span id="cb2-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Otteniamo il file con i cookies del sito per poter accedere successivamente</span></span>
<span id="cb2-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mkdir</span> tmp</span>
<span id="cb2-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">curl</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/tmp/cookies.txt"</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$URL</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb2-6"></span>
<span id="cb2-7"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">curl</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-s</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-b</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/tmp/cookies.txt"</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-H</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36'</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$URL</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-P</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-o</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'/modules.+.zip'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">tee</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/tmp/filelist.txt"</span></span></code></pre></div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Nota
</div>
</div>
<div class="callout-body-container callout-body">
<ul>
<li>è necessario generare prima il file <code>cookies.txt</code> con il comando <code>curl -c "$folder"/tmp/cookies.txt "$URL"</code> e poi leggerlo;</li>
<li><code>grep -P -o</code> è per usare le espressioni regolari Perl ed estrarre solo la parte che interessa;</li>
<li><code>$folder</code> è la mia cartella di lavoro dello script;</li>
</ul>
</div>
</div>
<p>In output si ottiene (ne metto soltanto una piccola parte):</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb3-1">/modules/documenti_it/attivo_patrimonio/2019/open_data_imm/Imm_Camere_di_commercio_ed_Unioni_di_Camere_di_Commercio_2019.zip</span>
<span id="cb3-2">/modules/documenti_it/attivo_patrimonio/2019/open_data_imm/Imm_Province_e_Citta_Metropolitane_2019.zip</span>
<span id="cb3-3">/modules/documenti_it/attivo_patrimonio/2019/open_data_imm/Imm_Enti_Locali_del_Servizio_Sanitario_Nazionale_2019.zip</span>
<span id="cb3-4">/modules/documenti_it/attivo_patrimonio/2019/open_data_imm/Imm_Amministrazioni_Regionali_2019.zip</span>
<span id="cb3-5">/modules/documenti_it/attivo_patrimonio/2019/open_data_imm/Imm_Universita_2019.zip</span>
<span id="cb3-6">/modules/documenti_it/attivo_patrimonio/2019/open_data_imm/Imm_Amministrazioni_Comunali_ABRUZZO_2019.zip</span>
<span id="cb3-7">/modules/documenti_it/attivo_patrimonio/2019/open_data_imm/Imm_Amministrazioni_Comunali_BASILICATA_2019.zip</span></code></pre></div>
<p>Con la lista degli URL dei file disponibile, basta generare un <code>while loop</code> per scaricarli tutti (sempre con <code>curl</code> o <code>wget</code>).</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mkdir</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">&amp;&amp;</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">cd</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw/"</span></span>
<span id="cb4-2"></span>
<span id="cb4-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Scarico tutti i file in filelist.txt</span></span>
<span id="cb4-4"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">xargs</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-I</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'{}'</span>  wget <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'https://www.de.mef.gov.it{}'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/tmp/filelist.txt"</span></span>
<span id="cb4-5"></span>
<span id="cb4-6"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">cd</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span></code></pre></div>
</section>
<section id="elaborazione-dei-file-scaricati" class="level2">
<h2 class="anchored" data-anchor-id="elaborazione-dei-file-scaricati">Elaborazione dei file scaricati</h2>
<p>A partire dalla lista dei file <code>zip</code> scaricati, ancora una volta si può generare un <code>while loop</code> per estrarli tutti in una cartella temporanea.</p>
<div class="callout callout-style-default callout-warning callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Avviso
</div>
</div>
<div class="callout-body-container callout-body">
<p>Facendolo è emerso un primo piccolo problema: uno dei file <code>zip</code> ha una struttura diversa: contiene il <code>CSV</code> in una sotto cartella. Quindi era necessario creare un processo di <em>unzip</em> automatico che non tenesse conto della eventuale struttura a cartelle presente.</p>
</div>
</div>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw"</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-type</span> f <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-name</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"*.zip"</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-exec</span> unzip <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-j</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'{}'</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-d</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw"</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\;</span></span></code></pre></div>
<p>Una volta estratti tutti i file e in presenza di uno schema dati comune, è molto semplice creare un unico file di output, usando <code>duckdb</code>.<br> Il comando di base è:</p>
<div id="lst-duckdb-merge" class="listing quarto-float quarto-figure quarto-figure-left anchored">
<figure class="quarto-float quarto-float-lst figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-lst" id="lst-duckdb-merge-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Lista&nbsp;1: esempio di unione di più file <code>CSV</code> a partire da una cartella che li contiene.
</figcaption>
<div aria-describedby="lst-duckdb-merge-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="sourceCode" id="lst-duckdb-merge" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="lst-duckdb-merge-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SELECT * FROM read_csv_auto('</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw/*.csv')"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span>output.csv</span></code></pre></div>
</div>
</figure>
</div>
<p>Al primo tentativo però <code>duckdb</code> è andato in errore, per ragioni legate all’<em>encoding</em> dei caratteri dei file <code>CSV</code>, perché DuckDB <a href="https://duckdb.org/docs/data/csv/overview#limitations">supporta solo file <code>CSV</code> con <em>encoding</em> <code>UTF-8</code></a>.</p>
<p>Ma <strong>qual</strong> è l’<strong><em>encoding</em></strong> dei file <code>CSV</code> dell’Elenco dei beni immobili dichiarati dalle Amministrazioni Pubbliche? Purtroppo sul sito del Dipartimento <strong>non c’è traccia di questa informazione</strong>.<br> Nelle <strong>linee guida open data</strong> dell’Agenzia per l’Italia Digitale (AgID) è <a href="https://ondata.github.io/linee-guida-opendata/allegato-B.html#formati-aperti">riportato</a>:</p>
<blockquote class="blockquote">
<p>è sempre necessario utilizzare una codifica standardizzata dei caratteri. In genere, UTF-8 è la codifica utilizzata nel web. È <strong>utile</strong>, in ogni caso, <strong>indicare</strong> qual è la <strong>codifica</strong> dei caratteri <strong>utilizzata</strong>.</p>
</blockquote>
<p>In assenza dell’informazione si può provare a estrarre l’<em>encoding</em> facendo inferenza dai dati. Io in questi casi uso l’ottimo <a href="https://github.com/chardet/chardet"><code>chardet</code></a>, che per questi file ha dato come risultato la codifica <a href="https://www.wikiwand.com/it/articles/Windows-1252"><code>Windows-1252</code></a>.</p>
<p>Mappata la codifica di input li ho convertiti in <code>UTF-8</code> con <code>iconv</code>:</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">mkdir</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw/utf8"</span></span>
<span id="cb6-2"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">cd</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw"</span></span>
<span id="cb6-3"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">find</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-type</span> f <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-name</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"*.csv"</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-exec</span> iconv <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-f</span> Windows-1252 <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-t</span> UTF-8 <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'{}'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'utf8/{}'</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\;</span></span></code></pre></div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb7" data-startfrom="160" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 159;"><span id="cb7-160">r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">2830855</span></span>
<span id="cb7-161">r_ita<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toLocaleString</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'it-IT'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-162">c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">51</span></span>
<span id="cb7-163">c_ita<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>c<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toLocaleString</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'it-IT'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb7-164">celle<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>(r<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>c)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">toLocaleString</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'it-IT'</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-1-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-1-2" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-1-3" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-1-4" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-1-5" data-nodetype="declaration">

</div>
</div>
</div>
</div>
<p>Con la conversione di <em>encoding</em> fatta, si può lanciare il comando visibile in Lista&nbsp;1 e ottenere il file <code>output.csv</code> con tutti i dati “uniti”.<br> Ma sono <span><span id="ojs-element-id-1"></span></span> righe per <span><span id="ojs-element-id-2"></span></span> colonne, ovvero <span><span id="ojs-element-id-3"></span></span> di celle ed è meglio <strong>comprimere</strong> l’<em>output</em>, così come <a href="../../posts/duckdb-intro-csv/index.html#compressione-dei-file-csv">consigliato qui</a>.</p>
<p>Si può modificare il comando di Lista&nbsp;1 in questo modo:</p>
<div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb8-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COPY (SELECT * FROM read_csv_auto('</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw/utf8/*.csv'))</span></span>
<span id="cb8-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">TO 'beni_immobili_pubblici.csv.gz'"</span></span></code></pre></div>
<p>In 20 secondi si ottiene un file <code>CSV</code> compresso di circa <strong>68</strong> MB. Non è un formato comodo per rapide elaborazioni, ma con gli strumenti giusti può sempre sorprendere.<br> Il <a href="https://duckdb.org/docs/guides/meta/summarize"><code>summarize</code></a> di duckdb viene eseguito ad esempio in <strong>2 secondi</strong>, con una comodissima sintesi su <strong><span><span id="ojs-element-id-4"></span></span></strong> di <strong>celle</strong>. Il file <code>csv.gz</code> di <em>output</em> è <a href="https://github.com/aborruso/beni_immobili_pubblica_amministrazione/raw/main/data/beni_immobili_pubblici.csv.gz?download=">disponibile qui</a>.</p>
<div id="fig-summarize" class="lightbox quarto-float quarto-figure quarto-figure-center anchored" alt="Esempio di output del comando summarize di duckdb">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-summarize-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="summarize.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1" title="Figura&nbsp;2: esempio di output del comando summarize duckdb"><img src="https://aborruso.github.io/posts/beni_immobili_pubblica_amministrazione/summarize.png" class="img-fluid figure-img" alt="Esempio di output del comando summarize di duckdb"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-summarize-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;2: esempio di <em>output</em> del comando <code>summarize</code> duckdb
</figcaption>
</figure>
</div>
<p>Per altri tipi di <em>query</em>, i tempi sarebbero molto più lunghi.</p>
<p>Se si vuole conciliare un’<strong>ottima compressione</strong>, con una <strong>grande</strong> <strong>velocità</strong> di interrogazione e <strong>analisi</strong> dei dati, si può scegliere come formato di output il <strong><a href="../../posts/duckdb-intro-csv/index.html#parquet"><code>Parquet</code></a></strong>.</p>
<p>Il comando per creare un file in questo formato è molto simile a quello per il <code>CSV</code>:</p>
<div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb9-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COPY (</span></span>
<span id="cb9-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  SELECT</span></span>
<span id="cb9-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    *</span></span>
<span id="cb9-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FROM</span></span>
<span id="cb9-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    read_csv_auto('</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw/utf8/*.csv')</span></span>
<span id="cb9-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">) TO 'beni_immobili_pubblici.parquet'</span></span>
<span id="cb9-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">(</span></span>
<span id="cb9-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FORMAT PARQUET,</span></span>
<span id="cb9-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  COMPRESSION 'zstd',</span></span>
<span id="cb9-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  ROW_GROUP_SIZE 100_000</span></span>
<span id="cb9-11"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)"</span></span></code></pre></div>
<p>In circa 25 secondi si ha in output un file <code>Parquet</code> di circa <strong>55</strong> MB, che si può interrogare molto rapidamente con tanti strumenti ed essenzialmente da tutti i linguaggi di programmazione; su questo Davide Taibi e io abbiamo scritto <a href="../../posts/leggere-interrogare-file-parquet/index.html">un articolo di approfondimento</a>.</p>
<p>Creato il file <code>Parquet</code>, ho iniziato a fare le prime <em>query</em> e subito mi hanno dato fastidio tre cose:</p>
<ol type="1">
<li>i <strong>nomi</strong> delle <strong>colonne</strong> sono troppo <strong><em>human readable</em></strong>, con spazi, caratteri speciali e mescola di maiuscole e minuscole (<code>Sup. aree pertinenziali (mq)</code>, <code>Vinc. culturale/paesaggistico</code>, <code>Immobile Geo-Ref.</code>, ecc.);</li>
<li>alcuni <strong>campi numerici</strong>, come <code>superficie</code> e <code>cubatura</code> dei beni, risultano in <em>output</em> come <strong>stringhe</strong>;</li>
<li>si <strong>perde</strong> la <strong>traccia</strong> dei <strong>file di origine</strong> (il record xxx, da che file CSV di <em>input</em> ha origine?).</li>
</ol>
<p>Per il punto <strong><code>1</code></strong>, c’è l’eccezionale <a href="https://duckdb.org/docs/data/csv/overview#parameters">parametro</a> <code>normalize_names</code>, che se impostato a <code>TRUE</code> converte i nome delle colonne in <code>snake_case</code>, con tutte le lettere minuscole, gli spazi sostituiti da <code>_</code> e con rimossi i caratteri speciali.</p>
<p>Per il punto <strong><code>2</code></strong>, si possono forzare i tipi di campo (parametro <code>types</code>) e il separatore dei decimali (parametro <code>decimal_separator</code> che per questi <em>file</em> di <em>input</em> è la <code>,</code>).</p>
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Nota bene
</div>
</div>
<div class="callout-body-container callout-body">
<p>Nella <a href="https://github.com/duckdb/duckdb/discussions/13295#discussioncomment-10251603">prossima versione</a> di duckdb, basterà dichiarare che il separatore decimale sia la virgola e <code>duckdb</code> sarà in grado di inferire correttamente i tipi campo <code>FLOAT</code>; non sarà più necessario dichiararlo esplicitamente per ognuno (vedi paragrafo in fondo).</p>
</div>
</div>
<p>Per il punto <strong><code>3</code></strong> si può usare il parametro <code>filename</code>, che se impostato a <code>TRUE</code> aggiunge una colonna con il nome del file di origine.</p>
<p>Mettendo tutto insieme, il comando per creare un file <code>Parquet</code> diventa:</p>
<div id="lst-duckdb-parquet" class="listing quarto-float quarto-figure quarto-figure-left anchored">
<figure class="quarto-float quarto-float-lst figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-lst" id="lst-duckdb-parquet-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Lista&nbsp;2: comando finale per creare al meglio il file <code>Parquet</code>.
</figcaption>
<div aria-describedby="lst-duckdb-parquet-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="sourceCode" id="lst-duckdb-parquet" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="lst-duckdb-parquet-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COPY (</span></span>
<span id="lst-duckdb-parquet-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  SELECT</span></span>
<span id="lst-duckdb-parquet-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    * REPLACE (regexp_replace(filename, '^.+/', '') AS filename)</span></span>
<span id="lst-duckdb-parquet-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FROM</span></span>
<span id="lst-duckdb-parquet-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    read_csv_auto(</span></span>
<span id="lst-duckdb-parquet-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      '</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw/utf8/*.csv',</span></span>
<span id="lst-duckdb-parquet-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      filename = TRUE,</span></span>
<span id="lst-duckdb-parquet-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      types = { 'id_bene': 'VARCHAR',</span></span>
<span id="lst-duckdb-parquet-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'id_compendio': 'VARCHAR',</span></span>
<span id="lst-duckdb-parquet-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'latitudine': 'FLOAT',</span></span>
<span id="lst-duckdb-parquet-11"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'longitudine': 'FLOAT',</span></span>
<span id="lst-duckdb-parquet-12"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'superficie_mq': 'FLOAT',</span></span>
<span id="lst-duckdb-parquet-13"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'cubatura_mc': 'FLOAT',</span></span>
<span id="lst-duckdb-parquet-14"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'sup_aree_pertinenziali_mq': 'FLOAT',</span></span>
<span id="lst-duckdb-parquet-15"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'superficie_di_riferimento_mq': 'FLOAT' },</span></span>
<span id="lst-duckdb-parquet-16"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      normalize_names = TRUE,</span></span>
<span id="lst-duckdb-parquet-17"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      decimal_separator = ','</span></span>
<span id="lst-duckdb-parquet-18"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    )</span></span>
<span id="lst-duckdb-parquet-19"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">) TO 'beni_immobili_pubblici.parquet' (</span></span>
<span id="lst-duckdb-parquet-20"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FORMAT PARQUET,</span></span>
<span id="lst-duckdb-parquet-21"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  COMPRESSION 'zstd',</span></span>
<span id="lst-duckdb-parquet-22"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  ROW_GROUP_SIZE 100_000</span></span>
<span id="lst-duckdb-parquet-23"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)"</span></span></code></pre></div>
</div>
</figure>
</div>
<p>Nella Lista&nbsp;2 è stato aggiunto il comando <code>REPLACE (regexp_replace(filename, '^.+/', '') AS filename)</code>. Questo comando rimuove il percorso del file e lascia solo il suo nome.</p>
<p>Il file <code>parquet</code> di <em>output</em> è <a href="https://github.com/aborruso/beni_immobili_pubblica_amministrazione/raw/main/data/beni_immobili_pubblici.parquet?download=">disponibile qui</a>.</p>
</section>
<section id="analisi-geografica-dei-dati" class="level2">
<h2 class="anchored" data-anchor-id="analisi-geografica-dei-dati">Analisi geografica dei dati</h2>
<p>Il 99% dei dati è associato a una coppia di coordinate geografiche, con le colonne <code>latitudine</code> e <code>longitudine</code>. Non entro qui nel merito sulla qualità (tutta da verificare) di questi dati, ma voglio mostrare come può esser comodo anche in questo caso <strong>duckdb</strong>.<br> Questa applicazione ha infatti anche l’<a href="https://duckdb.org/docs/extensions/spatial.html">estensione spaziale</a> ed è quindi possibile fare delle interrogazioni geografiche.</p>
<p><strong>Quanti</strong> sono ad esempio i <strong>beni</strong> immobili che ricadono in <strong>provincia</strong> di <strong>Bergamo</strong>?</p>
<p>Con questa banca dati c’è un modo “tradizionale” per farlo, perché è presente la colonna <code>provincia_del_bene</code> e basta fare una <em>query</em> come quella di sotto, per sapere in 0,1 secondi che sono 39.154:</p>
<div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb10-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SELECT count(*) conteggio</span></span>
<span id="cb10-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">FROM read_parquet('beni_immobili_pubblici.parquet')</span></span>
<span id="cb10-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">WHERE provincia_del_bene = 'BERGAMO'"</span></span></code></pre></div>
<p>Ma immaginiamo di non avere la colonna <code>provincia_del_bene</code> e avere soltanto le coordinate dei beni e il poligono che rappresenta la provincia di Bergamo.<br> Questo poligono si può ottenere in formato <code>geojson</code> dal comodo <a href="https://confini-amministrativi.it/"><strong>confini-amministrativi.it</strong></a> e ha questo URL:<br> <a href="https://confini-amministrativi.it/api/v2/it/20240101/unita-territoriali-sovracomunali/16.geo.json" class="uri">https://confini-amministrativi.it/api/v2/it/20240101/unita-territoriali-sovracomunali/16.geo.json</a></p>
<p>Voglio arricchire il risultato e <strong>conteggiare</strong> i <strong>beni</strong> <strong>per</strong> <strong>epoca</strong> di <strong>costruzione</strong> e <strong>suddividerli</strong> per <strong>utilizzo</strong> del bene. La <em>query</em> spaziale che in pochi secondi restituisce il risultato è la seguente:</p>
<div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb11-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PIVOT (</span></span>
<span id="cb11-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  SELECT</span></span>
<span id="cb11-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    id_bene,</span></span>
<span id="cb11-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    epoca_costruzione,</span></span>
<span id="cb11-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    utilizzo_del_bene</span></span>
<span id="cb11-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FROM</span></span>
<span id="cb11-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    'beni_immobili_pubblici.parquet' AS immobili</span></span>
<span id="cb11-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    JOIN ST_READ(</span></span>
<span id="cb11-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'https://confini-amministrativi.it/api/v2/it/20240101/unita-territoriali-sovracomunali/16.geo.json'</span></span>
<span id="cb11-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    ) AS bergamo ON ST_Within(ST_POINT(longitudine, latitudine), bergamo.geom)</span></span>
<span id="cb11-11"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">) ON utilizzo_del_bene USING COUNT(id_bene)</span></span>
<span id="cb11-12"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">GROUP BY epoca_costruzione</span></span>
<span id="cb11-13"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">ORDER BY epoca_costruzione"</span></span></code></pre></div>
<p>A partire da un sottoinsieme di colonne - <code>id_bene</code>, <code>epoca_costruzione</code> e <code>utilizzo_del_bene</code> - viene creata una <a href="https://duckdb.org/docs/sql/statements/pivot.html">tabella pivot</a> (vedi Tabella&nbsp;1). Questa organizza i dati in modo che ogni tipologia di utilizzo dei beni (<code>utilizzo_del_bene</code>) diventi una colonna separata. Le celle della tabella mostrano il numero di beni per ciascuna combinazione di epoca di costruzione (<code>epoca_costruzione</code>) e utilizzo, utilizzando la funzione di aggregazione <code>COUNT(id_bene)</code>. Infine, i risultati vengono raggruppati per epoca di costruzione e ordinati in base a questa colonna.</p>
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
La ricerca stavolta è geografica
</div>
</div>
<div class="callout-body-container callout-body">
<p>Nella <em>query</em> precedente si filtravano le righe per ricerca testuale, ovvero <code>provincia_del_bene = 'BERGAMO'</code>. In questa invece si filtrano le righe in base alla posizione geografica, ovvero <code>ST_Within(ST_POINT(longitudine, latitudine), bergamo.geom)</code>:</p>
<ul>
<li>prima si trasformano le colonne <code>longitudine</code> e <code>latitudine</code> in punti con <code>ST_POINT(longitudine, latitudine)</code>;</li>
<li>poi si verifica quali sono i punti che ricadono dentro il poligono della provincia di Bergamo con la funzione <code>ST_Within()</code>.</li>
</ul>
</div>
</div>
<div id="tbl-bergamo" class="striped table table-responsive table-sm table-bordered quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-bergamo-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Tabella&nbsp;1: numero di beni immobili pubblici per epoca di costruzione e utilizzo, all’interno della provincia di Bergamo
</figcaption>
<div aria-describedby="tbl-bergamo-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="table-responsive">
<table class="table-striped table table-sm table-bordered small caption-top">
<colgroup>
<col style="width: 18%">
<col style="width: 30%">
<col style="width: 14%">
<col style="width: 14%">
<col style="width: 22%">
</colgroup>
<thead>
<tr class="header">
<th style="text-align: left;">epoca_costruzione</th>
<th style="text-align: right;">In ristrutturazione/manutenzione</th>
<th style="text-align: right;">Inutilizzabile</th>
<th style="text-align: right;">Non utilizzato</th>
<th style="text-align: right;">Utilizzato direttamente</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td style="text-align: left;">Dal 1919 al 1945</td>
<td style="text-align: right;">20</td>
<td style="text-align: right;">100</td>
<td style="text-align: right;">145</td>
<td style="text-align: right;">637</td>
</tr>
<tr class="even">
<td style="text-align: left;">Dal 1946 al 1960</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">53</td>
<td style="text-align: right;">83</td>
<td style="text-align: right;">441</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Dal 1961 al 1970</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">26</td>
<td style="text-align: right;">214</td>
<td style="text-align: right;">650</td>
</tr>
<tr class="even">
<td style="text-align: left;">Dal 1971 al 1980</td>
<td style="text-align: right;">8</td>
<td style="text-align: right;">17</td>
<td style="text-align: right;">392</td>
<td style="text-align: right;">685</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Dal 1981 al 1990</td>
<td style="text-align: right;">9</td>
<td style="text-align: right;">12</td>
<td style="text-align: right;">190</td>
<td style="text-align: right;">1585</td>
</tr>
<tr class="even">
<td style="text-align: left;">Dal 1991 al 2000</td>
<td style="text-align: right;">4</td>
<td style="text-align: right;">5</td>
<td style="text-align: right;">176</td>
<td style="text-align: right;">1018</td>
</tr>
<tr class="odd">
<td style="text-align: left;">Dal 2001 al 2010</td>
<td style="text-align: right;">2</td>
<td style="text-align: right;">7</td>
<td style="text-align: right;">104</td>
<td style="text-align: right;">868</td>
</tr>
<tr class="even">
<td style="text-align: left;">Dopo il 2010</td>
<td style="text-align: right;">1</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">43</td>
<td style="text-align: right;">195</td>
</tr>
<tr class="odd">
<td style="text-align: left;">ND</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">6</td>
<td style="text-align: right;">62</td>
<td style="text-align: right;">469</td>
</tr>
<tr class="even">
<td style="text-align: left;">Prima del 1919</td>
<td style="text-align: right;">20</td>
<td style="text-align: right;">78</td>
<td style="text-align: right;">226</td>
<td style="text-align: right;">993</td>
</tr>
<tr class="odd">
<td style="text-align: left;"></td>
<td style="text-align: right;">15</td>
<td style="text-align: right;">256</td>
<td style="text-align: right;">9294</td>
<td style="text-align: right;">11510</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
<p>È un esempio di base, in cui è evidente come è possibile <strong>combinare</strong> <strong>dati</strong> <strong>geografici</strong> e <strong>non</strong>, in modo molto semplice e veloce, anche da <strong>fonti</strong> <strong>remote</strong> da raggiungere in <code>HTTP</code>.</p>
<p>Nel contesto “spaziale” può essere utile creare un file in formato geografico, da usare su un sistema GIS.<br> Ad esempio per creare un file in <a href="https://github.com/flatgeobuf/flatgeobuf">formato <code>FlatGeobuf</code></a>, progettato per memorizzare dati geografici in modo efficiente e compatto, si può usare una sintassi simile a quella vista sopra:</p>
<div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb12-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COPY (</span></span>
<span id="cb12-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  SELECT</span></span>
<span id="cb12-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    *,</span></span>
<span id="cb12-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    ST_POINT(longitudine, latitudine) geom</span></span>
<span id="cb12-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FROM</span></span>
<span id="cb12-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    'beni_immobili_pubblici.parquet'</span></span>
<span id="cb12-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  WHERE</span></span>
<span id="cb12-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    longitudine IS NOT NULL</span></span>
<span id="cb12-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    OR latitudine IS NOT NULL</span></span>
<span id="cb12-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">) TO 'output.fgb' WITH (FORMAT GDAL, DRIVER 'FlatGeobuf', SRS 'EPSG:4326')"</span></span></code></pre></div>
<p>Il formato <code>parquet</code> ha anche la sua versione geografica, il <a href="https://geoparquet.org/"><code>GeoParquet</code></a>, molto compresso e molto veloce da interrogare. Per crearlo non si può ancora usare <code>duckdb</code>, ma si può usare il comando <a href="https://gdal.org/en/latest/programs/ogr2ogr.html"><code>ogr2ogr</code></a> di <code>GDAL</code>:</p>
<div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb13-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">ogr2ogr</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-f</span> parquet <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-lco</span> COMPRESSION=ZSTD beni_immobili_pubblici_geo.parquet output.fgb</span></code></pre></div>
<p>Il file GeoParquet è <a href="https://github.com/aborruso/beni_immobili_pubblica_amministrazione/raw/main/data/beni_immobili_pubblici_geo.parquet?download=">disponibile qui</a>, pesa soltanto 80 MB, ed è visualizzabile con <a href="https://www.qgis.org/"><code>QGIS</code></a> e altre applicazioni GIS.</p>
<div id="fig-qgis" class="lightbox quarto-float quarto-figure quarto-figure-center anchored" alt="File GeoParquet visualizzato in QGIS">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-qgis-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="qgis.png" class="lightbox" data-gallery="quarto-lightbox-gallery-2" title="Figura&nbsp;3: file GeoParquet visualizzato in QGIS"><img src="https://aborruso.github.io/posts/beni_immobili_pubblica_amministrazione/qgis.png" class="img-fluid figure-img" alt="File GeoParquet visualizzato in QGIS"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-qgis-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;3: file <code>GeoParquet</code> visualizzato in QGIS
</figcaption>
</figure>
</div>
</section>
<section id="alcune-considerazioni-sui-dati" class="level2">
<h2 class="anchored" data-anchor-id="alcune-considerazioni-sui-dati">Alcune considerazioni sui dati</h2>
<p>È possibile <strong>combinare</strong> <strong>rapidamente</strong> e <strong>facilmente</strong> <strong>questi file</strong> per <strong>creare</strong> una <strong>base di dati efficiente</strong> e pronta per l’<strong>analisi</strong> e le <strong>interrogazioni</strong>. Questo avviene non solo grazie a strumenti come DuckDB, ma anche perché i file di <em>input</em> condividono uno schema unico, che permette di unire i file <code>CSV</code> senza difficoltà.</p>
<p>E come scritto nelle conclusioni di un <a href="../../posts/duckdb-intro-csv/index.html#in-conclusione">“famoso” articolo</a>:</p>
<blockquote class="blockquote">
<p>Con le dovute precauzioni, con gli <strong>strumenti giusti</strong>, con un corredo informativo adeguato e per dimensioni non eccessive, (il CSV) può essere un formato comodo e pratico. <a href="https://aborruso.github.io/posts/duckdb-intro-csv/#descrivere-i-csv"><strong>Descrivendolo</strong></a>, <a href="https://aborruso.github.io/posts/duckdb-intro-csv/#csv-standard">“<strong>standardizzandolo</strong>”</a> e <a href="https://aborruso.github.io/posts/duckdb-intro-csv/#compressione-dei-file-csv"><strong>comprimendolo</strong></a>, diventa molto più usabile.</p>
</blockquote>
<p>A proposito di “descrizione”, il Dipartimento dell’Economia pubblica un file <a href="https://www.de.mef.gov.it/export/sites/sitodt/modules/documenti_it/attivo_patrimonio/2019/Dizionario_Immobili_2019.pdf" title="PDF, 200 Kb">dizionario</a>, uno schema, ma soltanto in formato <code>PDF</code>. Quindi non è possibile creare una procedura automatica di importazione dei dati, in cui sono ad esempio impostati correttamente i tipi di campo (testuali, numerici, ecc.).</p>
<div class="callout callout-style-default callout-important callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
📌 Importante
</div>
</div>
<div class="callout-body-container callout-body">
<p>La <strong>pubblicazione</strong> non si dovrebbe limitare a rendere disponibile dei file, ma essere <strong>accompagnata da una descrizione del file stesso</strong>, leggibile dalle persone e <strong>dalle applicazioni</strong>.</p>
</div>
</div>
<p>Sui CSV sarebbe ideale:</p>
<ul>
<li><strong>documentare</strong> qual è l’<strong><em>encoding</em></strong> dei caratteri;</li>
<li>avere come <em>encoding</em> l’<code>UTF-8</code>;</li>
<li>evitare l’utilizzo di spazi, virgolette o altri caratteri speciali nei <strong>nomi dei campi</strong>;</li>
<li><strong>dichiarare</strong> quali sono i <strong>separatori</strong> di <strong>campo</strong> e dei <strong>decimali</strong>;</li>
<li><strong>pubblicarli</strong> anche <strong>non separati</strong> in 30 file, ma in unico file compresso <code>gzip</code>.</li>
</ul>
<p>Questi preziosi dati inoltre <strong>non</strong> sono ancora <strong>disponibili</strong> anche nel <a href="https://www.dati.gov.it/"><strong>portale</strong> <strong>nazionale</strong> dei <strong>dati</strong> aperti</a>. Ed è un peccato in termini di valorizzazione e diffusione degli stessi. Questo è anche un <a href="https://ondata.github.io/linee-guida-opendata/capitolo-7.html#req-29"><strong>requisito</strong></a> previsto dalle linee guida nazionali sui dati aperti.</p>
<p>Interrogando la banca dati si ha evidenza di alcuni beni con <strong>coordinate geografiche</strong> <strong>incoerenti</strong> con gli <strong>attributi territoriali</strong> dichiarati in altri campi. Ad esempio il bene con <code>id_bene=2442321</code>, ha coordinate YX <code>37.926914</code> e <code>15.28337</code>, ovvero in provincia di Messina; ma nel campo <code>comune_del_bene</code> il valore è “Frascati”.</p>
<p>Aggiungo anche una nota sull’opportunità di un <strong>formato</strong> <strong>aggiuntivo</strong> di <strong>pubblicazione</strong>: il tante volte citato <strong><code>Parquet</code></strong>.<br> È diventato uno dei formati standard per consentire a chiunque di fare <strong>analisi</strong> <strong>rapide</strong> ed <strong>efficienti</strong>, anche su <strong>grandi</strong> <strong>quantità</strong> di <strong>dati</strong>, quasi su <strong>qualsiasi</strong> <strong>PC</strong>. E sarebbe ideale <strong>pubblicare la banca dati degli immobili pubblici anche in formato <code>Parquet</code></strong>.<br> Un buon esempio da emulare è quello di <strong>OpenCoesione</strong> - uno dei portali di dati aperti più importanti in Italia - che da febbraio 2024 pubblica anche in <a href="https://opencoesione.gov.it/it/news/opendata-rilasciati-dataset-formato-parquet/">questo formato</a>.</p>
<p>Sono <strong>dati</strong> al <strong>2019</strong>. Sarebbe interessante che fossero aggiornati con una <strong>frequenza</strong> <strong>maggiore</strong>, magari <strong>annuale</strong>.<br> Sul portale del Tesoro <a href="https://portaletesoro.mef.gov.it/it/singlenewspublic.wp?contentId=NWS245">si legge</a> “<em>Fissata al 27 settembre 2024 la chiusura della rilevazione dei dati dei beni immobili pubblici riferiti al 31/12/2023</em>” e quindi c’è da aspettarsi un prossimo aggiornamento.</p>
<hr>
</section>
<section id="cosa-cambia-con-duckdb-v1.1.0." class="level2">
<h2 class="anchored" data-anchor-id="cosa-cambia-con-duckdb-v1.1.0.">Cosa cambia con DuckDB v1.1.0.</h2>
<p>Oggi, 9 settembre 2024, a una settimana dalla pubblicazione di questo articolo, è stata rilasciata la <a href="https://duckdb.org/2024/09/09/announcing-duckdb-110.html">versione 1.1.0 di DuckDB</a>.</p>
<p>Risolve un <a href="https://github.com/duckdb/duckdb/discussions/13295#discussioncomment-10251603"><em>bug</em></a> che non consentiva di utilizzare pienamente il comodissimo parametro <code>decimal_separator</code>: si era costretti comunque a dichiarare esplicitamente il tipo di campo <code>FLOAT</code> come in Lista&nbsp;2. Se si impostava <code>decimal_separator = ','</code>, DuckDB non era in grado di inferire correttamente i tipi campo <code>FLOAT</code> e li considerava sempre delle stringhe.<br> Ora, con la versione 1.1.0, basta dichiarare il separatore decimale e DuckDB sarà in grado di inferire correttamente i tipi campo <code>FLOAT</code>.</p>
<p>Sotto le due versioni del comando per creare il file <code>Parquet</code>:</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true">Versione 1.1.0</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false">Versione 1.0.0</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb14-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COPY (</span></span>
<span id="cb14-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  SELECT</span></span>
<span id="cb14-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    * REPLACE (regexp_replace(filename, '^.+/', '') AS filename)</span></span>
<span id="cb14-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FROM</span></span>
<span id="cb14-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    read_csv_auto(</span></span>
<span id="cb14-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      '</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw/utf8/*.csv',</span></span>
<span id="cb14-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      filename = TRUE,</span></span>
<span id="cb14-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      normalize_names = TRUE,</span></span>
<span id="cb14-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      decimal_separator = ','</span></span>
<span id="cb14-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    )</span></span>
<span id="cb14-11"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">) TO 'beni_immobili_pubblici.parquet' (</span></span>
<span id="cb14-12"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FORMAT PARQUET,</span></span>
<span id="cb14-13"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  COMPRESSION 'zstd',</span></span>
<span id="cb14-14"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  ROW_GROUP_SIZE 100_000</span></span>
<span id="cb14-15"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)"</span></span></code></pre></div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb15-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COPY (</span></span>
<span id="cb15-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  SELECT</span></span>
<span id="cb15-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    * REPLACE (regexp_replace(filename, '^.+/', '') AS filename)</span></span>
<span id="cb15-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FROM</span></span>
<span id="cb15-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    read_csv_auto(</span></span>
<span id="cb15-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      '</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">${folder}</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">/data/raw/utf8/*.csv',</span></span>
<span id="cb15-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      filename = TRUE,</span></span>
<span id="cb15-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      types = { 'id_bene': 'VARCHAR',</span></span>
<span id="cb15-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'id_compendio': 'VARCHAR',</span></span>
<span id="cb15-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'latitudine': 'FLOAT',</span></span>
<span id="cb15-11"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'longitudine': 'FLOAT',</span></span>
<span id="cb15-12"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'superficie_mq': 'FLOAT',</span></span>
<span id="cb15-13"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'cubatura_mc': 'FLOAT',</span></span>
<span id="cb15-14"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'sup_aree_pertinenziali_mq': 'FLOAT',</span></span>
<span id="cb15-15"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      'superficie_di_riferimento_mq': 'FLOAT' },</span></span>
<span id="cb15-16"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      normalize_names = TRUE,</span></span>
<span id="cb15-17"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      decimal_separator = ','</span></span>
<span id="cb15-18"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    )</span></span>
<span id="cb15-19"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">) TO 'beni_immobili_pubblici.parquet' (</span></span>
<span id="cb15-20"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FORMAT PARQUET,</span></span>
<span id="cb15-21"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  COMPRESSION 'zstd',</span></span>
<span id="cb15-22"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  ROW_GROUP_SIZE 100_000</span></span>
<span id="cb15-23"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)"</span></span></code></pre></div>
</div>
</div>
</div>


<div class="ojs-auto-generated hidden">
<script type="ojs-module-contents">
eyJjb250ZW50cyI6WyAgeyJtZXRob2ROYW1lIjoiaW50ZXJwcmV0IiwiaW5saW5lIjoidHJ1ZSIsInNvdXJjZSI6Imh0bC5odG1sYDxzcGFuPiR7cl9pdGF9PC9zcGFuPmAiLCAiY2VsbE5hbWUiOiJvanMtZWxlbWVudC1pZC0xIn0sICB7Im1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJpbmxpbmUiOiJ0cnVlIiwic291cmNlIjoiaHRsLmh0bWxgPHNwYW4+JHtjfTwvc3Bhbj5gIiwgImNlbGxOYW1lIjoib2pzLWVsZW1lbnQtaWQtMiJ9LCAgeyJtZXRob2ROYW1lIjoiaW50ZXJwcmV0IiwiaW5saW5lIjoidHJ1ZSIsInNvdXJjZSI6Imh0bC5odG1sYDxzcGFuPiR7Y2VsbGV9PC9zcGFuPmAiLCAiY2VsbE5hbWUiOiJvanMtZWxlbWVudC1pZC0zIn0sICB7Im1ldGhvZE5hbWUiOiJpbnRlcnByZXQiLCJpbmxpbmUiOiJ0cnVlIiwic291cmNlIjoiaHRsLmh0bWxgPHNwYW4+JHtjZWxsZX08L3NwYW4+YCIsICJjZWxsTmFtZSI6Im9qcy1lbGVtZW50LWlkLTQifV19
</script>
</div>
</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Torna in cima</a> ]]></description>
  <category>duckdb</category>
  <category>open-data</category>
  <category>cli</category>
  <category>parquet</category>
  <guid>https://aborruso.github.io/posts/beni_immobili_pubblica_amministrazione/</guid>
  <pubDate>Sun, 01 Sep 2024 22:00:00 GMT</pubDate>
  <media:content url="https://aborruso.github.io/posts/beni_immobili_pubblica_amministrazione/heat_map.png" medium="image" type="image/png" height="85" width="144"/>
</item>
<item>
  <title>I suggerimenti dell’intelligenza artificiale per la riga di comando</title>
  <dc:creator>Andrea Borruso</dc:creator>
  <link>https://aborruso.github.io/posts/llm-cmd-suggerimenti-ai-a-riga-di-comando/</link>
  <description><![CDATA[ 





<p>Una delle vignette più famose e (da me) amate di <strong>xkcd</strong> è quella che mostra una persona che deve disattivare una bomba, ma per farlo deve ricordarsi la sintassi di <code>tar</code>.<br> Ma l’impresa è ardua, perché è uno di quei comandi della <code>cli</code>, di cui spesso <strong>non ricordiamo la sintassi</strong>.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><a href="https://xkcd.com/1168/"><img src="https://aborruso.github.io/posts/llm-cmd-suggerimenti-ai-a-riga-di-comando/tar.png" class="img-fluid figure-img" alt="A drawing of an elephant."></a></p>
<figcaption>“<strong>tar</strong>”, una meravigliosa vignetta di xkcd</figcaption>
</figure>
</div>
<p>Con l’“uscita” quotidiana di “cose” legate all’intelligenza artificiale, stanno arrivando soluzioni anche per questo problema: una ce la dà il bellissimo progetto di quel genio di <strong>Simon Willison</strong>, che ha creato il <a href="https://github.com/simonw/llm-cmd"><strong><em>plugin</em> <em>llm-cmd</em></strong></a> per la sua <a href="https://llm.datasette.io/en/stable/">straordinaria applicazione <strong>LLM</strong></a>.</p>
<p>Una volta installato, si apre la <code>shell</code> e si digita il comando <code>llm cmd</code> seguito da una richiesta, da un <em>prompt</em>, su ciò che si vuole fare.</p>
<p>Sotto ad esempio chiedo <code>come decomprimo il file data.tar.gz dalla cartella corrente alla cartella /home/tmp?</code>.</p>
<p>E in risposta ho <code>tar -xzvf data.tar.gz -C /home/tmp</code>. E se lo valuto corretto, posso premere <kbd>INVIO</kbd> e il comando verrà eseguito.</p>
<p>👏 A Simon!!</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://aborruso.github.io/posts/llm-cmd-suggerimenti-ai-a-riga-di-comando/llm-cmd.gif" class="img-fluid figure-img"></p>
<figcaption>Esempio di utilizzo di <code>llm-cmd</code></figcaption>
</figure>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Nota
</div>
</div>
<div class="callout-body-container callout-body">
<p><code>LLM</code> di default utilizza il modello <code>gpt-3.5-turbo</code> di OpenAI, ma è possibile configurare il proprio modello.</p>
</div>
</div>



<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Torna in cima</a> ]]></description>
  <category>cmd</category>
  <category>ai</category>
  <guid>https://aborruso.github.io/posts/llm-cmd-suggerimenti-ai-a-riga-di-comando/</guid>
  <pubDate>Tue, 26 Mar 2024 23:00:00 GMT</pubDate>
  <media:content url="https://aborruso.github.io/posts/llm-cmd-suggerimenti-ai-a-riga-di-comando/tar.png" medium="image" type="image/png" height="188" width="144"/>
</item>
<item>
  <title>Come leggere un file Parquet</title>
  <dc:creator>Andrea Borruso</dc:creator>
  <dc:creator>Davide Taibi</dc:creator>
  <link>https://aborruso.github.io/posts/leggere-interrogare-file-parquet/</link>
  <description><![CDATA[ 





<section id="introduzione" class="level2">
<h2 class="anchored" data-anchor-id="introduzione">Introduzione</h2>
<p>In questa piccola guida, ti porteremo per mano alla scoperta del <strong>formato Parquet</strong> e ti spiegheremo cos’è. Potresti preferirlo al buon vecchio formato <code>CSV</code>, visto che può rendere la tua vita con i dati un po’ <strong>più facile</strong> e molto <strong>più veloce</strong>.<br></p>
<p>È un formato di archiviazione ottimizzato per lavorare con <strong>dati complessi</strong> e <strong>voluminosi</strong>. A differenza del CSV - che <strong>memorizza</strong> i dati <strong>per riga</strong> - <strong>Parquet organizza i dati per colonne</strong>.</p>
<p>Immagina di avere una tabella con le 4 colonne <code>ID</code>, <code>Nome</code>, <code>Età</code>, <code>E-mail</code>. Come differisce l’<strong>accesso</strong> ai <strong>dati</strong> tra un file CSV e un file Parquet?</p>
<p>In un file <code>CSV</code>, se vuoi accedere soltanto alla colonna <code>Età</code> per tutte le righe, <strong>il sistema deve leggere l’intero file</strong>, riga per riga, per estrarre l’informazione relativa.<br> Questo processo può essere piuttosto inefficiente, soprattutto con grandi volumi di dati, perché comporta la lettura di molti dati inutili (quelli delle colonne <code>ID</code>, <code>Nome</code> e <code>E-mail</code>).</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>tabella.csv</strong></pre>
</div>
<div class="sourceCode" id="cb1" data-filename="tabella.csv" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb1-1">ID,Nome,Età,E-mail</span>
<span id="cb1-2">1,Mario Rossi,30,mario.rossi@email.com</span>
<span id="cb1-3">2,Laura Bianchi,25,laura.bianchi@email.com</span>
<span id="cb1-4">...</span></code></pre></div>
</div>
<p>Viceversa ad un file <code>Parquet</code>, essendo organizzato <strong>per colonne</strong>, si può accedere direttamente, e anche esclusivamente, alla colonna <code>Età</code>, <strong>senza dover leggere anche le altre colonne</strong>.<br> Qui sotto un esempio, in si vede per accedere alla colonna <code>Età</code>, si possono saltare tutte le altre e leggere soltanto quella.</p>
<div class="code-with-filename">
<div class="code-with-filename-file">
<pre><strong>tabella.parquet</strong></pre>
</div>
<div class="sourceCode" id="cb2" data-filename="tabella.parquet" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb2-1"><span class="an" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">ID:</span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"> 1,2,...</span></span>
<span id="cb2-2"><span class="an" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">Nome:</span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"> Mario Rossi,Laura Bianchi,...</span></span>
<span id="cb2-3"><span class="an" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">Età:</span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"> 30,25,...</span></span>
<span id="cb2-4"><span class="an" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">E-mail:</span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"> mario.rossi@email.com,laura.bianchi@email.com,...</span></span></code></pre></div>
</div>
<p>Questo rende l’accesso ai dati molto più veloce ed efficiente.</p>
</section>
<section id="lesempio-di-opencoesione" class="level2">
<h2 class="anchored" data-anchor-id="lesempio-di-opencoesione">L’esempio di OpenCoesione</h2>
<p><a href="https://opencoesione.gov.it/"><strong>OpenCoesione</strong></a> è un progetto nazionale il cui obiettivo è <strong>promuovere</strong> <strong>trasparenza</strong>, <strong>collaborazione</strong> e <strong>partecipazione</strong> riguardo alle <strong>politiche</strong> di <strong>coesione</strong> nel paese.</p>
<p>È da sempre uno dei progetti di riferimento per l’<strong>apertura dei dati</strong> in Italia, che <strong>ha fatto sempre scuola</strong>.<br> E lo ha fatto ancora una volta: dal <a href="https://opencoesione.gov.it/it/news/opendata-rilasciati-dataset-formato-parquet/">21 febbraio 2024 ha iniziato a <strong>pubblicare</strong></a> la <strong>propria banca dati</strong> anche in <strong>formato</strong> <strong>Parquet</strong>.</p>
<p>Ed è probabilmente il <strong>primo progetto italiano di una Pubblica Amministrazione a farlo</strong>, e sicuramente il primo con una banca dati di questa ricchezza e dimensione.</p>
<p>➡️ Stiamo parlando del catalogo dei <strong>Progetti con tracciato esteso</strong>, disponibile qui, anche in formato Parquet: <a href="https://opencoesione.gov.it/it/opendata/#!progetti_section" class="uri">https://opencoesione.gov.it/it/opendata/#!progetti_section</a></p>
<p>Abbiamo sottolineato come il <strong>formato <code>Parquet</code></strong> sia molto <strong>più efficiente</strong> per l’accesso e l’analisi dei dati, rispetto al <strong><code>CSV</code></strong>.<br> Questa caratteristica è molto evidente, soprattutto per tabelle molto grandi, come questa dei <strong>progetti</strong> di <a href="https://opencoesione.gov.it/it/opendata/#!progetti_section"><strong>OpenCoesione</strong></a>, composta da circa <code>2.000.000 di righe x 200 colonne</code>.</p>
<p>È possibile ad esempio interrogarla, per avere restituito il <strong>totale di finanziamento pubblico</strong> per ogni <strong>ciclo di finanziamento</strong> (vedi Tabella&nbsp;1), e avere la risposta <strong>in 0,07 secondi</strong>.</p>
<div class="cell" data-execution_count="2">
<div id="tbl-cicli" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="2">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-cicli-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Tabella&nbsp;1: totale di finanziamento pubblico per ciclo di finanziamento
</figcaption>
<div aria-describedby="tbl-cicli-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display" data-execution_count="2">
<style type="text/css">
#T_07539 th.col1 {
  text-align: right;
}
#T_07539_row0_col1, #T_07539_row1_col1, #T_07539_row2_col1, #T_07539_row3_col1 {
  text-align: right;
}
</style>

<table id="T_07539" class="do-not-create-environment cell caption-top table table-sm table-striped small" data-quarto-postprocess="true">
<thead>
<tr class="header">
<th id="T_07539_level0_col0" class="col_heading level0 col0" data-quarto-table-cell-role="th">Ciclo</th>
<th id="T_07539_level0_col1" class="col_heading level0 col1" data-quarto-table-cell-role="th">Totale finanziamento pubblico (€)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td id="T_07539_row0_col0" class="data row0 col0">Ciclo di programmazione 2000-2006</td>
<td id="T_07539_row0_col1" class="data row0 col1">17.667.666.307,18</td>
</tr>
<tr class="even">
<td id="T_07539_row1_col0" class="data row1 col0">Ciclo di programmazione 2007-2013</td>
<td id="T_07539_row1_col1" class="data row1 col1">101.629.942.347,96</td>
</tr>
<tr class="odd">
<td id="T_07539_row2_col0" class="data row2 col0">Ciclo di programmazione 2014-2020</td>
<td id="T_07539_row2_col1" class="data row2 col1">154.061.098.680,89</td>
</tr>
<tr class="even">
<td id="T_07539_row3_col0" class="data row3 col0">Ciclo di programmazione 2021-2027</td>
<td id="T_07539_row3_col1" class="data row3 col1">7.465.189.173,71</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
</div>
<p>E questa rapidità si ottiene sul proprio computer di lavoro, <strong>senza</strong> che sia necessario mettere in campo <strong>risorse</strong> di <strong>calcolo</strong> particolarmente potenti e dispendiose sul <strong><em>cloud</em></strong>.<br> O <strong>senza</strong> che sia necessario <strong>importare</strong> il <strong>file</strong> in un <strong>database</strong> <strong>relazionale</strong>, con tutte le operazioni di trasformazione e pulizia dei dati che questo comporta evitando anche l’installazione e la configurazione di un db relazionale.</p>
</section>
<section id="come-leggere-un-file-parquet" class="level2">
<h2 class="anchored" data-anchor-id="come-leggere-un-file-parquet">Come leggere un file Parquet</h2>
<p>Se non hai mai sentito parlare di questo formato, probabilmente penserai che per te sia impossibile usarlo per leggere, filtrare, analizzare, ecc. i dati di OpenCoesione. Penserai che è un formato solo per “tecnici”.<br> Niente di più sbagliato! Leggere un file Parquet è <strong>facile</strong> e <strong>veloce</strong>, e paradossalmente è più <strong>necessario</strong> l’<strong>aiuto</strong> di un <strong>tecnico</strong> per leggere <strong>un file <code>CSV</code> di 4,5 Gigabyte</strong> (come quello dei progetti di OpenCoesione). Per la gran parte degli utenti è infatti impossibile leggere un file di queste dimensioni, anche con un buon Personal Computer.<br> E non pensare di utilizzare programmi come <strong>Excel</strong>, hanno un <strong>limite</strong> di circa <strong>1.000.000 di righe</strong> per foglio di lavoro (tante ma non sufficienti nel nostro caso in cui ne abbiamo circa 2.000.000).</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Nota bene
</div>
</div>
<div class="callout-body-container callout-body">
<p>Un file di queste dimensioni, aldilà del formato, deve essere gestito con attenzione e con un minimo di competenza.</p>
</div>
</div>
<section id="al-doppio-click" class="level3">
<h3 class="anchored" data-anchor-id="al-doppio-click">Al doppio click</h3>
<p>Per visualizzare un file Parquet con un semplice doppio click, puoi usare <a href="https://www.tadviewer.com/"><strong>Tad</strong></a>, un visualizzatore di file Parquet (e anche <code>CSV</code>, <a href="https://www.sqlite.org"><code>SQLite</code></a> e <a href="http://duckdb.org/"><code>DuckDB</code></a>) <em>open source</em>, gratuito e disponibile per Windows, Mac e Linux.</p>
<p>Una volta installato, basterà fare doppio click sul file per aprirlo e visualizzarne il contenuto (vedi Figura&nbsp;1). Questo di OpenCoesione è un file grande e sarà necessario qualche secondo.</p>
<div id="fig-tad" class="lightbox quarto-float quarto-figure quarto-figure-center anchored" alt="esempio di visualizzazione e filtro dati con Tad">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-tad-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="images/tad_02.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1" title="Figura&nbsp;1: esempio di visualizzazione e filtro dati con TAD"><img src="https://aborruso.github.io/posts/leggere-interrogare-file-parquet/images/tad_02.png" class="img-fluid figure-img" alt="esempio di visualizzazione e filtro dati con Tad"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-tad-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;1: esempio di visualizzazione e filtro dati con <a href="https://www.tadviewer.com/">TAD</a>
</figcaption>
</figure>
</div>
<p>Tra le funzionalità di Tad c’è anche la possibilità di <strong>filtrare</strong> i dati. Nell’immagine di sopra:</p>
<ol type="1">
<li>il filtro applicato;</li>
<li>il modulo per costruire il filtro;</li>
<li>il mini report sul numero di righe filtrate.</li>
</ol>
</section>
<section id="con-un-client-visuale-sql" class="level3">
<h3 class="anchored" data-anchor-id="con-un-client-visuale-sql">Con un client visuale SQL</h3>
<p><strong><code>SQL</code></strong> è uno dei linguaggi più diffusi e standard per l’interrogazione e la manipolazione dei dati. È <strong>nato 50 anni fa</strong>, quindi c’è un gran numero di libri, <em>tutorial</em>, corsi, forum, <em>cheatsheet</em>, ecc. per imparare a usarlo, e ci sono centinaia di applicazioni, librerie, <em>framework</em>, dedicati.</p>
<p><strong>Un file <code>Parquet</code> è interrogabile con <code>SQL</code></strong>, quindi tutti possono usarlo per interrogare e analizzare i dati in questo formato.</p>
<p>Un’<strong>applicazione SQL “visuale”</strong>, <em>open source</em> e multi-piattaforma, che puoi usare per interrogare un file Parquet è <a href="https://dbeaver.io/"><strong>DBeaver</strong></a>. Questi i passi che dovrai seguire per interrogare un file Parquet con DBeaver:</p>
<ul>
<li>scaricarla e installarla (<a href="https://dbeaver.io/download/" class="uri">https://dbeaver.io/download/</a>);</li>
<li>lanciarla, aprire il menu <code>Database</code> e selezionare <code>New Database Connection</code>;</li>
<li>cercare <code>DuckDB</code>, selezionarlo e fare click su <code>Next</code>;</li>
</ul>
<div id="fig-dbeaver" class="quarto-float quarto-figure quarto-figure-center anchored" alt="DBeaver - selezionare DuckDB come database">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dbeaver-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/leggere-interrogare-file-parquet/images/dbeaver_01.png" class="img-fluid figure-img" alt="DBeaver - selezionare DuckDB come database">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dbeaver-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;2: DBeaver - selezionare DuckDB come database
</figcaption>
</figure>
</div>
<ul>
<li>impostare <code>:memory:</code> come <code>Path</code>;</li>
</ul>
<div id="fig-dbeaver" class="quarto-float quarto-figure quarto-figure-center anchored" alt="DBeaver - impostazione path DuckDB">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dbeaver-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/leggere-interrogare-file-parquet/images/dbeaver_02.png" class="img-fluid figure-img" alt="DBeaver - impostazione path DuckDB">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dbeaver-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;3: DBeaver - impostazione path DuckDB
</figcaption>
</figure>
</div>
<ul>
<li>fare click su <code>Test Connection</code>, che verificherà la necessità di installare eventuali componenti mancanti. Se manca qualcosa, installarla facendo click su <code>Download</code>.</li>
</ul>
<p>A questo punto, nel riquadro di sinistra “<em>Database Navigator</em>” dovrebbe apparire una connessione al database DuckDB <code>memory</code>.</p>
<div id="fig-dbeaver" class="lightbox quarto-float quarto-figure quarto-figure-center anchored" alt="DBeaver - riquadro Database">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dbeaver-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="images/dbeaver_04.png" class="lightbox" data-gallery="quarto-lightbox-gallery-2" title="Figura&nbsp;4: DBeaver - riquadro Database"><img src="https://aborruso.github.io/posts/leggere-interrogare-file-parquet/images/dbeaver_04.png" class="img-fluid figure-img" alt="DBeaver - riquadro Database"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dbeaver-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;4: DBeaver - riquadro Database
</figcaption>
</figure>
</div>
<p>Per lanciare una <em>query</em> non ti resta che fare <em>click</em> con il pulsante destro del <em>mouse</em> su <code>memory</code>, selezionare <code>SQL Editor</code>, poi <code>New SQL script</code> e scrivere la tua prima <em>query</em>, per leggere ad esempio le prime 5 righe del file <code>Parquet</code>:</p>
<div class="sourceCode" id="annotated-cell-3" style="background: #f1f3f5;"><pre class="sourceCode sql code-annotation-code code-with-copy code-annotated"><code class="sourceCode sql"><span id="annotated-cell-3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span>  <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span></span>
<a class="code-annotation-anchor" data-target-cell="annotated-cell-3" data-target-annotation="1" onclick="event.preventDefault();">1</a><span id="annotated-cell-3-2" class="code-annotation-target"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"c:\tmp\progetti_esteso_20230831.parquet"</span></span>
<span id="annotated-cell-3-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">LIMIT</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">5</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div>
<dl class="code-annotation-container-grid">
<dt data-target-cell="annotated-cell-3" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-3" data-code-lines="2" data-code-annotation="1">Per puntare al file, è stato inserito il percorso del file Parquet.</span>
</dd>
</dl>
<div id="fig-dbeaver" class="lightbox quarto-float quarto-figure quarto-figure-center anchored" alt="DBeaver - la prima query">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-dbeaver-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="images/dbeaver_05.png" class="lightbox" data-gallery="quarto-lightbox-gallery-3" title="Figura&nbsp;5: DBeaver - la prima query"><img src="https://aborruso.github.io/posts/leggere-interrogare-file-parquet/images/dbeaver_05.png" class="img-fluid figure-img" alt="DBeaver - la prima query"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-dbeaver-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;5: DBeaver - la prima query
</figcaption>
</figure>
</div>
<p>La <em>query</em> di esempio di sopra, con i dati per ciclo di finanziamento di Tabella&nbsp;1, è invece il risultato di questa <em>query</em>, che puoi provare a lanciare in DBeaver:</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb3-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> oc_descr_ciclo Ciclo, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">SUM</span>(finanz_totale_pubblico) <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"Totale finanziamento pubblico (€)"</span></span>
<span id="cb3-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">"C\tmp\progetti_esteso_20230831.parquet"</span></span>
<span id="cb3-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">GROUP</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">BY</span> oc_descr_ciclo</span>
<span id="cb3-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">ORDER</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">BY</span> ciclo;</span></code></pre></div>
</section>
<section id="a-riga-di-comando-con-duckdb" class="level3">
<h3 class="anchored" data-anchor-id="a-riga-di-comando-con-duckdb">A riga di comando con DuckDB</h3>
<p>Se preferisci lavorare da riga di comando, puoi usare lo straordinario <a href="https://duckdb.org/"><strong>DuckDB</strong></a>, un sistema di gestione di database relazionali (RDBMS), che supporta il formato Parquet.</p>
<p>Per installarlo, puoi seguire le istruzioni disponibili qui: <a href="https://duckdb.org/docs/installation" class="uri">https://duckdb.org/docs/installation</a>.</p>
<p>Per usarlo non ti resta che lanciare il comando <code>duckdb</code> e scrivere la tua prima <em>query</em>.</p>
<p>Potrebbe essere diversa dalle precedenti, come quella <strong>comodissima</strong> per avere un <strong>riepilogo rapido</strong> dei <strong>dati</strong>, basata sul comando <a href="https://duckdb.org/docs/guides/meta/summarize.html"><code>SUMMARIZE</code></a> di DuckDB: restituisce per ogni campo, il tipo di campo e una ricca serie di calcoli, il numero di valori distinti, la percentuali di valori nulli, il minimo, il massimo, la media, ecc..<br> Qui sotto la sintassi della <em>query</em> e un esempio di <em>output</em> in Figura&nbsp;6.</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb4-1">SUMMARIZE <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">select</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">from</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'progetti_esteso_20231231.parquet'</span>;</span></code></pre></div>
<div id="fig-duckdb" class="lightbox quarto-float quarto-figure quarto-figure-center anchored" alt="Esempio di output del comando SUMMARIZE">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-duckdb-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="images/duckdb-summarize.png" class="lightbox" data-gallery="quarto-lightbox-gallery-4" title="Figura&nbsp;6: Esempio di output del comando SUMMARIZE"><img src="https://aborruso.github.io/posts/leggere-interrogare-file-parquet/images/duckdb-summarize.png" class="img-fluid figure-img" alt="Esempio di output del comando SUMMARIZE"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-duckdb-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;6: Esempio di <em>output</em> del comando <code>SUMMARIZE</code>
</figcaption>
</figure>
</div>
<p>È un comando di grande comodità, che si può usare ad esempio per sapere <strong>quali</strong> sono le <strong>colonne</strong> che hanno <strong>meno del 10% di valori nulli</strong>:</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb5-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> (summarize <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">select</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">from</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'progetti_esteso_20231231.parquet'</span>)</span>
<span id="cb5-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">WHERE</span></span>
<span id="cb5-3">null_percentage <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">10</span>;</span></code></pre></div>
<p>Sono <strong>86 colonne su circa 200</strong> e si potrebbe scegliere di concentrarsi su questo campione più ristretto e velocizzare ulteriormente le operazioni.</p>
<p>E sempre da <code>SUMMARIZE</code> ci si può fare un’idea delle colonne più “datose”, ovvero quelle con <strong>meno valori distinti</strong>, che sono spesso quelle più interessanti per fare analisi e visualizzazioni, perché consentono di definire categorie (le regioni, il settore, la natura, ecc.).</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="cb6-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> (summarize <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">select</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">from</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'progetti_esteso_20231231.parquet'</span>)</span>
<span id="cb6-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">WHERE</span></span>
<span id="cb6-3">approx_unique <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">30</span>;</span></code></pre></div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Nota
</div>
</div>
<div class="callout-body-container callout-body">
<p><code>SUMMARIZE</code> restituisce in realtà un <strong>valore approssimativo</strong>, ma molto vicino al reale, dei valori distinti. Questo per ottimizzare i tempi di esecuzione.</p>
</div>
</div>
</section>
<section id="a-riga-di-comando-con-visidata" class="level3">
<h3 class="anchored" data-anchor-id="a-riga-di-comando-con-visidata">A riga di comando con VisiData</h3>
<p><a href="https://ondata.github.io/guidaVisiData/"><strong>VisiData</strong></a> è “il coltellino svizzero per i dati, che probabilmente non conosci”. E proprio con il formato Parquet se ne ha un’idea.</p>
<p>Basta scrivere <code>vd nome_file.parquet</code> e premere <kbd>INVIO</kbd>, per aprire il file e iniziare a esplorarlo, filtrarlo, analizzarlo, ecc..<br> Con il file di OpenCoesione ci mette qualche secondo, perché è un file grande, ma poi si può iniziare a esplorarlo e ad esempio avere restituito il totale di finanziamento pubblico per regione.</p>
<div id="fig-visidata" class="quarto-float quarto-figure quarto-figure-center anchored" alt="VisiData - esplorare un file Parquet">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-visidata-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/leggere-interrogare-file-parquet/images/visidata.png" class="img-fluid figure-img" alt="VisiData - esplorare un file Parquet">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-visidata-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;7: VisiData - esplorare un file Parquet
</figcaption>
</figure>
</div>
</section>
<section id="accesso-tramite-python" class="level3">
<h3 class="anchored" data-anchor-id="accesso-tramite-python">Accesso tramite Python</h3>
<p>La Tabella&nbsp;1 è generata proprio a partire da codice <strong>Python</strong>, che legge il file Parquet dei progetti di OpenCoesione e ne estrae una sintesi.<br> Un modo comodissimo per farlo è usare la libreria <code>duckdb</code> e il suo metodo <code>query</code>, che permette di eseguire una <em>query</em> <code>SQL</code> e trasformare il risultato in un <code>DataFrame</code> di <code>pandas</code>.</p>
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># importa modulo duckdb</span></span>
<span id="cb7-2"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> duckdb</span>
<span id="cb7-3"></span>
<span id="cb7-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># definisci la query</span></span>
<span id="cb7-5">query<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"""</span></span>
<span id="cb7-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  SELECT oc_descr_ciclo Ciclo, SUM(finanz_totale_pubblico) "Totale finanziamento pubblico (€)"</span></span>
<span id="cb7-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FROM 'progetti_esteso_20231231.parquet'</span></span>
<span id="cb7-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  GROUP BY oc_descr_ciclo</span></span>
<span id="cb7-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  ORDER BY ciclo;</span></span>
<span id="cb7-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  """</span></span>
<span id="cb7-11"></span>
<span id="cb7-12"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># esegui la query e trasforma il risultato in un DataFrame</span></span>
<span id="cb7-13">riepilogo_finanziamento<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span>duckdb.query(query).df()</span></code></pre></div>
<p>Ti consigliamo di approfondire nella <a href="https://duckdb.org/docs/api/python/overview.html">documentazione ufficiale dedicata</a>.</p>
</section>
<section id="accesso-observable" class="level3">
<h3 class="anchored" data-anchor-id="accesso-observable">Accesso Observable</h3>
<p>L’ultima modalità di accesso che ti proponiamo è tramite <a href="https://observablehq.com/"><strong>Observable</strong></a>, una delle più importanti e belle piattaforme/<em>framework</em> per la visualizzazione e l’analisi dei dati.</p>
<p>È un esempio a nostro avviso significativo, perché mostra come il Parquet sia un formato pronto all’uso per una grandissima varietà di ambienti, linguaggi e strumenti.</p>
<p>Il linguaggio di programmazione di Observable è <strong>JavaScript</strong>. La prima cosa da fare è caricare il file Parquet, che può essere fatto con la libreria <code>duckdb</code>.</p>
<div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb8-1">db <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DuckDBClient<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">of</span>({</span>
<span id="cb8-2">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">progetti</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">FileAttachment</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"progetti_esteso_20231231.parquet"</span>)</span>
<span id="cb8-3">})</span></code></pre></div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Nota
</div>
</div>
<div class="callout-body-container callout-body">
<p>Nella versione di Observable gratuita e <em>online</em>, il limite delle dimensioni di un file è di 50 MB. Ma utilizzando <a href="https://observablehq.com/framework/">Observable Framework</a> o con <a href="https://quarto.org/docs/computations/ojs.html">Quarto</a>, le dimensioni dei file non sono un problema.<br> In ogni caso, è bene evitare di fare caricare nel <code>DOM</code> della pagina web <em>array</em> di dati molto grandi.</p>
</div>
</div>
<p>Poi ad esempio si può interrogare il file, ancora una volta con una <em>query</em> <code>SQL</code>, per avere ad esempio il conteggio dei progetti, per stato del progetto:</p>
<div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb9-1">viewof tbl_stato_proggetti <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb9-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> db<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">query</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`SELECT</span></span>
<span id="cb9-3"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  OC_STATO_PROGETTO AS "Stato Progetto", count(*) Conteggio FROM progetti</span></span>
<span id="cb9-4"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  GROUP BY OC_STATO_PROGETTO</span></span>
<span id="cb9-5"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  ORDER BY Conteggio DESC`</span>)</span>
<span id="cb9-6">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Inputs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table</span>(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">height</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">200</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">layout</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"auto"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span><span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">locale</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"it-IT"</span>})</span>
<span id="cb9-7">}</span></code></pre></div>
<p>In output:</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb10" data-startfrom="282" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 281;"><span id="cb10-282">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">FileAttachment</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"observable.csv"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">csv</span>({ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">typed</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span> })</span>
<span id="cb10-283">Inputs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table</span>(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span>{<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">locale</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"it-IT"</span>})</span></code></pre></div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-1-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display">
<div>
<div id="ojs-cell-1-2" data-nodetype="expression">

</div>
</div>
</div>
</div>
<p>E visto che siamo in un ambiente specializzato per la visualizzazione e l’analisi dei dati, si può anche visualizzare il risultato con un <strong>grafico a barre</strong>.</p>
<div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="cb11-1">viewof graficoStatoProgetti <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb11-2">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">await</span> db<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">query</span>(<span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`SELECT</span></span>
<span id="cb11-3"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  OC_STATO_PROGETTO AS "Stato Progetto", count(*) AS Conteggio FROM progetti</span></span>
<span id="cb11-4"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  GROUP BY OC_STATO_PROGETTO</span></span>
<span id="cb11-5"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  ORDER BY Conteggio DESC`</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-6"></span>
<span id="cb11-7">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Definisci una funzione di formattazione per il locale "it-IT"</span></span>
<span id="cb11-8">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> formatter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Intl</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">NumberFormat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"it-IT"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">format</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-9"></span>
<span id="cb11-10">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Crea il grafico a barre utilizzando Plot con formattazione personalizzata</span></span>
<span id="cb11-11">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>({</span>
<span id="cb11-12">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">marks</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [</span>
<span id="cb11-13">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">barY</span>(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Stato Progetto"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conteggio"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">fill</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Stato Progetto"</span>})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-14">    ]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-15">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">width</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">600</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-16">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">height</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-17">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">marginLeft</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-18">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">color</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {</span>
<span id="cb11-19">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">legend</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span></span>
<span id="cb11-20">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-21">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {</span>
<span id="cb11-22">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Stato Progetto"</span></span>
<span id="cb11-23">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-24">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {</span>
<span id="cb11-25">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conteggio"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-26">      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usa la funzione di formattazione per le etichette dell'asse Y</span></span>
<span id="cb11-27">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">tickFormat</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> formatter</span>
<span id="cb11-28">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb11-29">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">style</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {</span>
<span id="cb11-30">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">overflow</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"visible"</span></span>
<span id="cb11-31">    }</span>
<span id="cb11-32">  })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb11-33">}</span></code></pre></div>
<p>In output:</p>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb12" data-startfrom="327" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 326;"><span id="cb12-327">viewof graficoStatoProgetti <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> {</span>
<span id="cb12-328"></span>
<span id="cb12-329">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Definisci una funzione di formattazione per il locale "it-IT"</span></span>
<span id="cb12-330">  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">const</span> formatter <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">new</span> <span class="bu" style="color: null;
background-color: null;
font-style: inherit;">Intl</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">NumberFormat</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"it-IT"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">format</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb12-331"></span>
<span id="cb12-332">  <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Crea il grafico a barre utilizzando Plot con formattazione personalizzata</span></span>
<span id="cb12-333">  <span class="cf" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">return</span> Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">plot</span>({</span>
<span id="cb12-334">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">marks</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> [</span>
<span id="cb12-335">      Plot<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">barY</span>(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Stato Progetto"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conteggio"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">fill</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Stato Progetto"</span>})<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-336">    ]<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-337">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">width</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">600</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-338">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">height</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">400</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-339">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">marginLeft</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">50</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-340">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">color</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {</span>
<span id="cb12-341">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">legend</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span></span>
<span id="cb12-342">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-343">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">x</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {</span>
<span id="cb12-344">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Stato Progetto"</span></span>
<span id="cb12-345">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-346">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">y</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {</span>
<span id="cb12-347">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">label</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Conteggio"</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-348">      <span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">// Usa la funzione di formattazione per le etichette dell'asse Y</span></span>
<span id="cb12-349">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">tickFormat</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> formatter</span>
<span id="cb12-350">    }<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb12-351">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">style</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> {</span>
<span id="cb12-352">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">overflow</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"visible"</span></span>
<span id="cb12-353">    }</span>
<span id="cb12-354">  })<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">;</span></span>
<span id="cb12-355">}</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-2" data-nodetype="declaration">

</div>
</div>
</div>
</section>
</section>
<section id="note-finali" class="level2">
<h2 class="anchored" data-anchor-id="note-finali">Note finali</h2>
<p>Abbiamo scritto questo post, perché crediamo che il formato Parquet sia un’opportunità per <strong>molte persone</strong> di <strong>migliorare</strong> la <strong>propria esperienza</strong> con i <strong>dati</strong>. E non solo per chi è “esperto”, ma anche per chi ha delle competenze di base con <code>SQL</code>. Perché come è evidente le modalità di accesso sono molteplici e adatte a diversi livelli di competenza.</p>
<p>Il fatto che <strong>OpenCoesione</strong> sia stato <strong>il primo progetto</strong> a scegliere di pubblicare i propri dati in formato Parquet è un <strong>segnale</strong> molto <strong>importante</strong>: siamo confidenti che possa essere seguito presto da altre amministrazioni e organizzazioni.</p>
<p>Non avremmo mai immaginato che la <a href="../../posts/duckdb-intro-csv/index.html"><strong>scrittura di questo altro post</strong></a> avrebbe contribuito a generare questa bella conseguenza. E per questo gli autori del post e tutta l’<strong>associazione onData</strong> ringraziano OpenCoesione e il suo <em>staff</em> per essere stati prima in ascolto e poi protagonisti di questa scelta.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Torna in cima</a> ]]></description>
  <category>duckdb</category>
  <category>parquet</category>
  <category>sql</category>
  <guid>https://aborruso.github.io/posts/leggere-interrogare-file-parquet/</guid>
  <pubDate>Wed, 21 Feb 2024 23:00:00 GMT</pubDate>
  <media:content url="https://aborruso.github.io/posts/leggere-interrogare-file-parquet/images/dbeaver_05.png" medium="image" type="image/png" height="89" width="144"/>
</item>
<item>
  <title>Lavorare con grandi file CSV compressi</title>
  <dc:creator>Andrea Borruso</dc:creator>
  <dc:creator>Matteo Fortini</dc:creator>
  <link>https://aborruso.github.io/posts/csv-ventitre-gigabyte-senza-affanno/</link>
  <description><![CDATA[ 





<div class="callout callout-style-default callout-warning callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Nota successiva alla pubblicazione
</div>
</div>
<div class="callout-body-container callout-body">
<p>Questo post ci ha consentito di fare una prima lettura di questa importante banca dati e sono <strong>emerse</strong> alcune <strong>criticità</strong>. Una è quelle citata nel post, sulle righe con numero di colonne errato.<br> Quella che ci sembra più importante è relativa alla <strong>natura dei progetti</strong>, che era la novità più importante: sul <code>CSV</code> <strong>ci sono soltanto 3 tipologie</strong>, quindi nulla è cambiato. Le altre tipologie al momento sono visibili soltanto sul <em>front-end</em> del sito.<br> È stato annunciato, anche dopo una nostra segnalazione, che i dati saranno aggiornati in tal senso entro la fine di febbraio 2024.</p>
</div>
</div>
<p>Da pochissimo, dal 14 febbraio 2024, è andato online il <a href="https://www.opencup.gov.it/"><strong>nuovo portale OpenCUP</strong></a>.</p>
<p>OpenCUP mette a disposizione di tutti - cittadini, istituzioni ed altri enti - i dati, in formato aperto, sulle <strong>decisioni di investimento pubblico</strong> finanziate con fondi pubblici nazionali, comunitarie o regionali o con risorse private registrate con il Codice Unico di Progetto.</p>
<div id="fig-opencup" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-opencup-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="https://www.opencup.gov.it/"><img src="https://aborruso.github.io/posts/csv-ventitre-gigabyte-senza-affanno/opencup.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-opencup-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;1: La home di OpenCUP
</figcaption>
</figure>
</div>
<p>La <strong>novità più importante</strong> di questo aggiornamento, è legata alla <strong>natura degli interventi in elenco</strong>: a “Lavori Pubblici” e “Incentivi alle imprese e Contributi per calamità naturali”, si aggiungono “acquisti di beni, servizi, corsi di formazione, strumenti finanziari, progetti di ricerca e contributi a entità diverse dalle unità produttive per una Pubblica Amministrazione più trasparente e vicina al cittadino” (qui la <a href="https://www.opencup.gov.it/portale/web/opencup/home/-/asset_publisher/zIMyNGpUy0tF/content/14-febbraio-2024-il-nuovo-portale-opencup">notizia</a> di lancio).<br></p>
<p>In numeri si passa <strong>da circa 6,5 a 9,5 milioni di progetti</strong>.</p>
<section id="gli-open-data-di-opencup" class="level2">
<h2 class="anchored" data-anchor-id="gli-open-data-di-opencup">Gli Open Data di OpenCUP</h2>
<p>Sul sito di OpenCUP, è disponibile da tempo la <a href="https://www.opencup.gov.it/portale/web/opencup/accesso-agli-open-data"><strong>sezione OpenData</strong></a>. Con questo aggiornamento, sono stati pubblicati i nuovi dati, in formato <code>CSV</code> e <code>XML</code>.<br> Bisogna scorrere la pagina e guardare la sezione “<strong>Progetti OpenData</strong>”.</p>
<p>In questo post, mostreremo rapidamente come esplorare il <a href="https://www.opencup.gov.it/portale/web/opencup/dettaglio-opendata-complessivo">file “Complessivo”</a> di tutti i progetti.</p>
<p>È un <strong>file “grande”</strong>. Quello in formato <code>CSV</code> è compresso come zip: pesa circa <strong>2.9 GB</strong>, e <strong>decompresso 23 GB</strong>. È probabilmente <strong>il file CSV più grande</strong> (o uno dei più grandi), pubblicato in una sezione open data di un sito di una <strong>Pubblica Amministrazione italiana</strong>.</p>
<p>Non è gestibile con un comune foglio di calcolo, né con tanti altri strumenti.<br> A riga di comando invece si può osservare, filtrare, e analizzare, con grande leggerezza e rapidità.</p>
<div class="callout callout-style-default callout-warning callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Avviso
</div>
</div>
<div class="callout-body-container callout-body">
<p>Ci sono alcune righe con un <strong>numero di separatori di campo errato</strong>: devono essere 90. Per estrarre soltanto quelle con 90 separatori si può usare <code>awk</code>:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unzip</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OpenData Complessivo.zip"</span>  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">awk</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'{if(gsub(/\|/,"&amp;") == 90) print}'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span>open_cup_corrette.csv</span></code></pre></div>
<p>Vedi anche la sezione Importazione dell’intero file.</p>
</div>
</div>
</section>
<section id="la-prima-lettura" class="level2">
<h2 class="anchored" data-anchor-id="la-prima-lettura">La prima lettura</h2>
<p>Un file così grande richiede un po’ di tempo per il download e poi per la decompressione.<br> Per fortuna però è possibile fare <strong>una prima lettura</strong> immediata, dopo il download, <strong>senza decomprimere per intero il file</strong>.</p>
<p>Si può usare l’<em>utilty</em> <code>unzip</code> e lanciare il comando <code>unzip -p nomefile.zip</code>. Ma per una prima esplorazione, l’ideale è leggere soltanto le prime righe. E per fortuna esiste il comando <code>head</code>, che fa proprio questo e di default legge le prime 10 righe.:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unzip</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OpenData Complessivo.zip"</span>  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span></span></code></pre></div>
<p>E subito si vedrà qualcosa come in Figura&nbsp;2, che ci restituisce già elementi interessanti:</p>
<ul>
<li>i nomi dei campi;</li>
<li>il separatore è il <code>|</code></li>
</ul>
<div id="fig-head" class="lightbox quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-head-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="immagini/head.png" class="lightbox" data-gallery="quarto-lightbox-gallery-1" title="Figura&nbsp;2: Le prime righe del file con i progetti"><img src="https://aborruso.github.io/posts/csv-ventitre-gigabyte-senza-affanno/immagini/head.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-head-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;2: Le prime righe del file con i progetti
</figcaption>
</figure>
</div>
</section>
<section id="estrazione-di-un-campione" class="level2">
<h2 class="anchored" data-anchor-id="estrazione-di-un-campione">Estrazione di un campione</h2>
<p>Viste le prime 10 righe e mappate le caratteristiche del CSV, il passo consigliato successivo è quello dell’estrazione di un campione di righe più ampio, per fare un’analisi più approfondita.<br> Con una piccola modifica al comando soprastante, si possono ad esempio estrarre le prime 10.000 righe e salvarle in un nuovo file <code>CSV</code> (in <code>0.055</code> secondi):</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unzip</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OpenData Complessivo.zip"</span>  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-n</span> 10000 <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> campione.csv</span></code></pre></div>
<p>E questo nuovo file sarà esplorabile con <strong>foglio elettronico</strong> o con altri strumenti. A me ad esempio piace usare <a href="https://ondata.github.io/guidaVisiData/"><strong>VisiData</strong></a> per queste cose, con cui di solito subito osservo un po’ di dati sui campi (i valori nulli, i valori distinti, ecc.).</p>
<div id="fig-vd" class="lightbox quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-vd-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="immagini/vd.png" class="lightbox" data-gallery="quarto-lightbox-gallery-2" title="Figura&nbsp;3: Esplorazione dei dati campione con VisiData"><img src="https://aborruso.github.io/posts/csv-ventitre-gigabyte-senza-affanno/immagini/vd.png" class="img-fluid figure-img"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-vd-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;3: Esplorazione dei dati campione con VisiData
</figcaption>
</figure>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Nota
</div>
</div>
<div class="callout-body-container callout-body">
<p>Il <a href="https://www.linkedin.com/in/davide-taibi-b6825113/">professore Taibi</a> ci ha fatto notare che <strong>questo non è un vero campione</strong>, ma soltanto le prime <code>n</code> righe del file. Un vero campione dovrebbe essere estratto in modo casuale, ma sarebbe necessario decomprimere tutto il file per farlo. E quindi qui, per un’esplorazione rapida, ci accontentiamo di questo.</p>
</div>
</div>
</section>
<section id="filtrare-lintero-file" class="level2">
<h2 class="anchored" data-anchor-id="filtrare-lintero-file">Filtrare l’intero file</h2>
<p>L’esplorazione del campione consente di farsi un’idea di quali sono quei campi/colonne che fanno un po’ da elementi “categorici”, da usare come filtro per estrarre solo le righe che ci interessano.<br> Tra questi ad esempio il campo <code>SOGGETTO_TITOLARE</code>, con il nome della Pubblica Amministrazione, titolare del progetto, che posso usare per estrarre ad esempio tutti i progetti in cui la PA titolare è “<code>REGIONE AUTONOMA DELLA SICILIA</code>”.</p>
<p>L’<em>utility</em> <strong><code>grep</code></strong> - una delle più importanti di tutti i tempi - è perfetta per questo scopo.</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unzip</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OpenData Complessivo.zip"</span>  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-P</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'\|REGIONE AUTONOMA DELLA SICILIA\|'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span>regione_siciliana.csv</span></code></pre></div>
<p>Si applica un filtro al file <code>CSV</code> zippato di input, e per ogni riga in cui è presente la stringa <code>REGIONE AUTONOMA DELLA SICILIA</code> tra due caratteri <code>|</code>, viene salvata nel file <code>regione_siciliana.csv</code>. Nel filtro è stato inserito il carattere <code>\</code> prima del <code>|</code>, perché <code>|</code> è un carattere speciale.<br> E in un minuto e mezzo circa, sul mio buon (ma normale) PC ottengo <code>392.395</code> progetti associati alla Regione Siciliana, dopo aver letto <code>9,5</code> milioni di righe.</p>
<p>Ma così c’è un <strong>problema</strong>: si perde l’intestazione del file, <strong>si perdono i nomi delle colonne</strong>. C’è allora da modificare il filtro ed estrarre anche la prima riga. E tutto questo è facile, grazie all’esplorazione fatta, in cui ho visto che la prima riga contiene ad esempio la stringa “<code>ANNO_DECISIONE</code>”.<br> Il nuovo comando sarà:</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unzip</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OpenData Complessivo.zip"</span>  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb5-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-P</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'(ANNO_DECISIONE|\|REGIONE AUTONOMA DELLA SICILIA\|)'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span>regione_siciliana.csv</span></code></pre></div>
<p>Così vengono cercate tutte le righe che contengono o <code>ANNO_DECISIONE</code> o <code>|REGIONE AUTONOMA DELLA SICILIA|</code> e quindi viene restituito un <code>CSV</code> con i nomi delle colonne e le righe filtrate.</p>
</section>
<section id="un-file-parquet-a-partire-dai-dati-filtrati" class="level2">
<h2 class="anchored" data-anchor-id="un-file-parquet-a-partire-dai-dati-filtrati">Un file parquet a partire dai dati filtrati</h2>
<p>Questo ultimo passo, perché è utile avere a disposizione questi dati anche in un formato più efficiente, come il <code>parquet</code>, che è un formato di file binario, compresso e colonnare, che permette di ridurre notevolmente lo spazio occupato e di velocizzare le operazioni di lettura e analisi.<br> Per chi non ne ha mai sentito parlare, <strong><a href="../../posts/duckdb-intro-csv/index.html">ne ho scritto lungamente qui</a></strong>.</p>
<p>L’<em>utility</em> stavolta è <a href="https://duckdb.org/"><strong>DuckDB</strong></a>. E il comando è:</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb6-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unzip</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OpenData Complessivo.zip"</span>  <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb6-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">grep</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-P</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'(ANNO_DECISIONE|\|REGIONE AUTONOMA DELLA SICILIA\|)'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb6-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COPY(</span></span>
<span id="cb6-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  SELECT * FROM read_csv_auto('/dev/stdin', delim = '|')</span></span>
<span id="cb6-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">) TO 'regione_siciliana.parquet' (</span></span>
<span id="cb6-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  FORMAT 'parquet',</span></span>
<span id="cb6-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  COMPRESSION 'ZSTD',</span></span>
<span id="cb6-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  ROW_GROUP_SIZE 100000</span></span>
<span id="cb6-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)"</span></span></code></pre></div>
<p>Alcune note su questo comando (messo su più righe, per migliorare la leggibilità):</p>
<ul>
<li>si parte dal comando precedente, con il filtro per estrarre il campione;</li>
<li>si passa l’<em>output</em> a <code>duckdb</code>, che legge il <code>CSV</code> da <code>stdin</code> e nel <code>SELECT</code> al posto del nome del file è necessario inserire <code>'/dev/stdin'</code>, che è il file virtuale che rappresenta lo <em>standard input</em>;</li>
<li>si usa il comando <code>COPY</code> per copiare questa selezione in un file <code>parquet</code> chiamato <code>regione_siciliana.parquet</code>, con compressione <code>ZSTD</code> e con un <code>ROW_GROUP_SIZE</code> di <code>100000</code>.</li>
</ul>
<p>Tutto circa sempre in un minuto e mezzo, con un file di <em>output</em> che pesa circa 33 MB, contro i 530 MB del file <code>CSV</code>.</p>
</section>
<section id="importazione-dellintero-file" class="level2">
<h2 class="anchored" data-anchor-id="importazione-dellintero-file">Importazione dell’intero file</h2>
<p>Il file CSV completo ha, alla data di oggi (15 Febbraio 2024) un problema a 2 righe (su 17.065.848), che hanno un numero errato di colonne (91 anziché 90). Per poterlo importare occorre filtrare solo le linee che hanno un numero di colonne corretto.</p>
<p>È possibile importare il file in un DB in formato DuckDB con i seguenti comandi (occorre avere il file CSV su disco per limitare l’occupazione di RAM):</p>
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb7-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unzip</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"OpenData Complessivo.zip"</span></span>
<span id="cb7-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">awk</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-F\|</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'{if (NF-1 == 90) { print } }'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&lt;</span> TOTALE.csv <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> TOTALEfix.csv</span>
<span id="cb7-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> OpenCUP.db <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CREATE TABLE OpenCUP AS SELECT * FROM read_csv_auto('TOTALEfix.csv',delim='|',header = true,dateformat='%d-%b-%y',parallel=FALSE,types={'DATA_ULTIMA_MODIFICA_SSC':'DATE','DATA_ULTIMA_MODIFICA_UTENTE':'DATE','DATA_CHIUSURA_REVOCA':'DATE','DATA_GENERAZIONE_CUP':'DATE'});"</span></span></code></pre></div>
<p>Notare che è stato esplicitato il formato delle date, e quali sono i campi di tipo <code>DATE</code>, in modo che DuckDB converta correttamente i campi relativi, che sono del tipo <code>01-JAN-15</code>. Questo permette sia una migliore gestione dei dati, che una rappresentazione più efficiente in termini di spazio su disco.</p>
<p>Il file DuckDB risultante, a fronte di un CSV di <code>23.946.237.777 byte</code>, è <code>4.431.294.464 byte</code>, con una riduzione a circa 1/6, merito del formato binario contro quello ASCII.</p>
<section id="prestazioni-del-formato-duckdb" class="level3">
<h3 class="anchored" data-anchor-id="prestazioni-del-formato-duckdb">Prestazioni del formato DuckDB</h3>
<p>Una query di esempio</p>
<div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb8-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">time</span> duckdb OpenCUP.db <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SELECT ANNO_DECISIONE, COUNT(*) FROM OpenCUP GROUP BY ANNO_DECISIONE"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> /dev/null</span>
<span id="cb8-2"></span>
<span id="cb8-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">real</span>    0m0,039s</span>
<span id="cb8-4"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">user</span>    0m0,156s</span>
<span id="cb8-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">sys</span> 0m0,063s</span></code></pre></div>
</section>
<section id="conversione-nel-formato-parquet" class="level3">
<h3 class="anchored" data-anchor-id="conversione-nel-formato-parquet">Conversione nel formato Parquet</h3>
<p>Con il comando</p>
<div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb9-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> OpenCUP.db  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COPY (SELECT * FROM OpenCUP) TO 'OpenCUP.parquet' (FORMAT 'PARQUET', CODEC 'ZSTD');</span></span></code></pre></div>
<p>si ottiene un file Parquet di 2.296.193.848 byte, con una riduzione di circa 1/2 rispetto al formato nativo DuckDB.</p>
<p>Se con questo comando si hanno problemi di memoria si può provare a impostare <code>SET preserve_insertion_order=false</code>:</p>
<div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb10-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> OpenCUP.db  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SET preserve_insertion_order=false;COPY (SELECT * FROM OpenCUP) TO 'OpenCUP.parquet' (FORMAT 'PARQUET', CODEC 'ZSTD');"</span></span></code></pre></div>
<p>Le prestazioni del formato Parquet sono notevoli</p>
<div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb11-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">time</span> duckdb <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-s</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SELECT ANNO_DECISIONE, COUNT (*) FROM read_parquet("OpenCUP.parquet") GROUP BY ANNO_DECISIONE;'</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span> /dev/null</span>
<span id="cb11-2"></span>
<span id="cb11-3"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">real</span>    0m0,074s</span>
<span id="cb11-4"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">user</span>    0m0,372s</span>
<span id="cb11-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">sys</span> 0m0,043s</span></code></pre></div>
</section>
<section id="note-sui-tempi-di-esecuzione" class="level3">
<h3 class="anchored" data-anchor-id="note-sui-tempi-di-esecuzione">Note sui tempi di esecuzione</h3>
<p>I tempi di esecuzione sono stati misurati su un computer abbastanza “normale”, con 16 GB di RAM e questo processore:</p>
<pre><code>Vendor ID:               GenuineIntel
  Model name:            12th Gen Intel(R) Core(TM) i7-1280P
    CPU family:          6
    Model:               154
    Thread(s) per core:  2
    Core(s) per socket:  10</code></pre>
<p>Questa la tabella riassuntiva dei tempi di esecuzione:</p>
<table class="caption-top table">
<colgroup>
<col style="width: 63%">
<col style="width: 36%">
</colgroup>
<thead>
<tr class="header">
<th>Operazione</th>
<th>Tempo (minuti:secondi)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Download (con <code>wget</code>)</td>
<td><code>12:13.81</code></td>
</tr>
<tr class="even">
<td>Decompressione (con <code>unzip</code>)</td>
<td><code>1:33.05</code></td>
</tr>
<tr class="odd">
<td>Estrazione delle sole righe corrette (con <code>ugrep</code>)<sup>1</sup></td>
<td><code>2:25.63</code></td>
</tr>
<tr class="even">
<td>Importazione in DuckDB</td>
<td><code>4:15.97</code></td>
</tr>
<tr class="odd">
<td>Conversione in Parquet</td>
<td><code>0:28.811</code></td>
</tr>
</tbody>
</table>
</section>
<section id="versione-più-sintetica-e-rapida" class="level3">
<h3 class="anchored" data-anchor-id="versione-più-sintetica-e-rapida">Versione più sintetica e rapida</h3>
<p>In DuckDB, nell’import dei file <code>CSV</code>, c’è l’opzione <code>ignore_errors=true</code>, che permette di ignorare le righe che contengono errori (come quelle con un numero di colonne errato). E quindi si può saltare la creazione di un secondo grande <code>CSV</code> per applicare il filtro.</p>
<p>Inoltre, se non abbiamo bisogno del database DuckDB, possiamo convertire direttamente il file <code>CSV</code> in <code>parquet</code> e saltare quindi un altro passaggio.</p>
<p>Il comando sintetico è:</p>
<div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb13-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"SET preserve_insertion_order=false;COPY(SELECT * FROM read_csv_auto('TOTALE.csv',delim='|',header = true,ignore_errors=true,dateformat='%d-%b-%y',parallel=FALSE,types={'DATA_ULTIMA_MODIFICA_SSC':'DATE','DATA_ULTIMA_MODIFICA_UTENTE':'DATE','DATA_CHIUSURA_REVOCA':'DATE','DATA_GENERAZIONE_CUP':'DATE'})) TO 'opencup.parquet' WITH (FORMAT PARQUET, COMPRESSION ZSTD,ROW_GROUP_SIZE 100000)"</span></span></code></pre></div>
<p>Così facendo, c’è un risparmio di tempo di circa il 30%.</p>
</section>
</section>
<section id="note-finali" class="level2">
<h2 class="anchored" data-anchor-id="note-finali">Note finali</h2>
<p>Questa descritta è <strong>soltanto</strong> una modalità per fare soprattutto una <strong>prima</strong> <strong>esplorazione</strong> e <strong>analisi</strong> di questo nuovo e importante aggiornamento dei dati di OpenCUP.<br> È utilissima per capire per cosa è possibile usare questi dati, quali sono le informazioni che ci interessano di più, che storia poter raccontare, che mappa creare, che <em>dashboard</em> realizzare, come usare l’intelligenza artificiale per arricchirli, come metterli in relazione con altri dati, ecc..</p>
<p>Ma sono dati grandi, e in produzione bisognerà andare un po’ oltre l’utilizzo delle eccezionali <em>utility</em> a riga di comando. In ogni caso <strong>DuckDB</strong>, se <strong>usato bene</strong>, fa già tanta tanta roba (partizionando il dataset originario in più file <code>parquet</code>, si ha disposizione tutto il dataset con una grandissima facilità di accesso e lettura).</p>


</section>


<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Torna in cima</a><div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Note</h2>

<ol>
<li id="fn1"><p><code>ugrep '^(?:[^|]*\|){90}[^|]*$' TOTALE.csv &gt;TOTALEfix.csv</code>↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>duckdb</category>
  <category>csv</category>
  <category>cli</category>
  <guid>https://aborruso.github.io/posts/csv-ventitre-gigabyte-senza-affanno/</guid>
  <pubDate>Wed, 14 Feb 2024 23:00:00 GMT</pubDate>
  <media:content url="https://aborruso.github.io/posts/csv-ventitre-gigabyte-senza-affanno/opencup.png" medium="image" type="image/png" height="106" width="144"/>
</item>
<item>
  <title>Usare la nuova intelligenza artificiale di Google</title>
  <dc:creator>Andrea Borruso</dc:creator>
  <link>https://aborruso.github.io/posts/accedere-google-ai-riga-di-comando/</link>
  <description><![CDATA[ 





<p>😉 Questo post è per <a href="https://twitter.com/CesareGerbino/status/1735723196270199040">Cesare Gerbino</a>.</p>
<section id="introduzione" class="level2">
<h2 class="anchored" data-anchor-id="introduzione">Introduzione</h2>
<p>Google <a href="https://blog.google/technology/ai/google-gemini-ai/">ha lanciato</a> a inizio dicembre del 2023 <strong>Gemini</strong>, il suo modello di intelligenza artificiale migliore. Può comprendere e combinare diversi tipi di informazioni, come testo, codice, audio, immagini e video.</p>
<p>Da poco sono disponibili le <a href="https://makersuite.google.com/app/apikey"><strong>API</strong></a> e ho voluto fare qualche test di base, usando la riga di comando.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Nota
</div>
</div>
<div class="callout-body-container callout-body">
<p>Al momento le API sono <strong>accessibili soltanto dagli Stati Uniti</strong>, quindi bisogna usare un VPN. Io ho usato quella gratuita di <a href="https://protonvpn.com/">Proton VPN</a> (grazie a Francesco Passantino per il suggerimento di anni fa).</p>
</div>
</div>
<p>A seguire una mini guida per testarle</p>
</section>
<section id="connessione-alla-vpn" class="level2">
<h2 class="anchored" data-anchor-id="connessione-alla-vpn">Connessione alla VPN</h2>
<p>Per prima cosa bisogna connettersi alla VPN e scegliere come paese di <strong>connessione</strong> gli <strong>Stati Uniti</strong>.</p>
<div class="quarto-figure quarto-figure-center">
<figure class="figure">
<p><img src="https://aborruso.github.io/posts/accedere-google-ai-riga-di-comando/images/Proton_VPN_USA.png" class="img-fluid figure-img"></p>
<figcaption>Esempio connessione usando Proton VPN</figcaption>
</figure>
</div>
</section>
<section id="generare-una-chiave-api" class="level2">
<h2 class="anchored" data-anchor-id="generare-una-chiave-api">Generare una chiave API</h2>
<p>Una volta connessi dagli Stati Uniti è necessario <strong>generare</strong> una <strong>chiave API</strong>, per autenticarsi. Si può fare da questa pagina: <a href="https://makersuite.google.com/app/apikey" class="uri">https://makersuite.google.com/app/apikey</a>.</p>
<p>Una volta generata - è una lunga stringa - è da archiviare da qualche parte.</p>
</section>
<section id="accesso-alle-api-in-rest-via-curl" class="level2">
<h2 class="anchored" data-anchor-id="accesso-alle-api-in-rest-via-curl">Accesso alle API in REST, via cURL</h2>
<p>È il modo più immediato e diretto. Si apre la <code>shell</code> e si manda una richiesta come questa, in cui si definisce prima una variabile con la chiave API e poi si lancia la chiamata.</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Una variabile dove inserire la chiave API</span></span>
<span id="cb1-2"><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">API_KEY</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"AIxxSyCnBOUyPuDLtjWY11HOwxxxxxxx"</span></span>
<span id="cb1-3"></span>
<span id="cb1-4"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># Lanciare la chiamata</span></span>
<span id="cb1-5"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">curl</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-s</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$API_KEY</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb1-6">-H <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Content-Type: application/json'</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb1-7">-X POST <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-d</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'{"contents": [{"parts":[{"text": "Creami tre nomi buffi per un gatto siamese con le orecchie molto grandi"}]}]}'</span></span></code></pre></div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-2-contents" aria-controls="callout-2" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Qui un esempio di output JSON
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-2" class="callout-2-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode json code-overflow-wrap code-with-copy"><code class="sourceCode json"><span id="cb2-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-2">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"candidates"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">[</span></span>
<span id="cb2-3">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-4">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"content"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-5">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"parts"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">[</span></span>
<span id="cb2-6">          <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-7">            <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"text"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"1. Dumbo</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">2. Flitzer</span><span class="ch" style="color: #20794D;
background-color: null;
font-style: inherit;">\n</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">3. Elicottero"</span></span>
<span id="cb2-8">          <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-9">        <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">]</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-10">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"role"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"model"</span></span>
<span id="cb2-11">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">},</span></span>
<span id="cb2-12">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"finishReason"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"STOP"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-13">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"index"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">0</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-14">      <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"safetyRatings"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">[</span></span>
<span id="cb2-15">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-16">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"category"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HARM_CATEGORY_SEXUALLY_EXPLICIT"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-17">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"probability"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NEGLIGIBLE"</span></span>
<span id="cb2-18">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-19">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-20">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"category"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HARM_CATEGORY_HATE_SPEECH"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-21">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"probability"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NEGLIGIBLE"</span></span>
<span id="cb2-22">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-23">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-24">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"category"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HARM_CATEGORY_HARASSMENT"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-25">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"probability"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NEGLIGIBLE"</span></span>
<span id="cb2-26">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-27">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-28">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"category"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HARM_CATEGORY_DANGEROUS_CONTENT"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-29">          <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"probability"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NEGLIGIBLE"</span></span>
<span id="cb2-30">        <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-31">      <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb2-32">    <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-33">  <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">]</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-34">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"promptFeedback"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-35">    <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"safetyRatings"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">[</span></span>
<span id="cb2-36">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-37">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"category"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HARM_CATEGORY_SEXUALLY_EXPLICIT"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-38">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"probability"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NEGLIGIBLE"</span></span>
<span id="cb2-39">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-40">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-41">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"category"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HARM_CATEGORY_HATE_SPEECH"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-42">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"probability"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NEGLIGIBLE"</span></span>
<span id="cb2-43">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-44">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-45">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"category"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HARM_CATEGORY_HARASSMENT"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-46">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"probability"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NEGLIGIBLE"</span></span>
<span id="cb2-47">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span><span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-48">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">{</span></span>
<span id="cb2-49">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"category"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"HARM_CATEGORY_DANGEROUS_CONTENT"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">,</span></span>
<span id="cb2-50">        <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">"probability"</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"NEGLIGIBLE"</span></span>
<span id="cb2-51">      <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-52">    <span class="ot" style="color: #003B4F;
background-color: null;
font-style: inherit;">]</span></span>
<span id="cb2-53">  <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span>
<span id="cb2-54"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">}</span></span></code></pre></div>
</div>
</div>
</div>
<p>Se si espande l’esempio di JSON qui sopra, la parte con la risposta alla chiamata è quella contenuta in <code>.candidates[0].content.parts[0].text</code>.<br> Si può modifcare il comando di sopra e usare <a href="https://jqlang.github.io/jq/"><code>jq</code></a> per estrarla:</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">curl</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-s</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$API_KEY</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb3-2">-H <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Content-Type: application/json'</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb3-3">-X POST <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-d</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'{"contents": [{"parts":[{"text": "Creami tre nomi buffi per un gatto siamese con le orecchie molto grandi"}]}]}'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb3-4"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">jq</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'.candidates[0].content.parts[0].text'</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-r</span></span></code></pre></div>
<p>In output si avrà qualcosa come:</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb4-1"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">1. </span>Dumbo</span>
<span id="cb4-2"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">2. </span>Flitzer</span>
<span id="cb4-3"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3. </span>Elicottero</span></code></pre></div>
<p>Non vi resta che testare e divertirvi, con esempi migliori del mio. La cosa interessante è che è un’<code>API REST</code>, quindi si può usare da qualsiasi linguaggio di programmazione.</p>
<p><img src="https://aborruso.github.io/posts/accedere-google-ai-riga-di-comando/gemini_via_cli.png" class="img-fluid"></p>
</section>
<section id="utilizzare-leccezionale-llm-via-cli" class="level2">
<h2 class="anchored" data-anchor-id="utilizzare-leccezionale-llm-via-cli">Utilizzare l’eccezionale <code>LLM</code> via cli</h2>
<p><a href="https://llm.datasette.io/en/stable/index.html#"><strong><code>LLM</code></strong></a> è un’<em>utility</em> a riga di comando e una libreria Python per interagire con <em>Large Language Models</em> (LLM), ovvero modelli di linguaggio avanzati.<br> Permette di utilizzare sia API remote per accedere a modelli ospitati su server esterni, sia modelli installati e eseguiti localmente sul proprio <em>computer</em>.</p>
<p>Ed è possibile quindi usarlo per connettersi con il <em>Large Language Models</em> di Google Gemini.</p>
<p>🙏 L’autore della cli <code>LLM</code> è quel genio di <a href="https://simonwillison.net/"><strong>Simon Willison</strong></a>.</p>
<section id="installazione" class="level3">
<h3 class="anchored" data-anchor-id="installazione">Installazione</h3>
<p>Per installarlo è sufficiente usare <code>pip</code>:</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip3</span> install llm</span></code></pre></div>
<p>Per usare Gemini, è necessario instalare il plug-in dedicato, <a href="https://github.com/simonw/llm-gemini"><code>llm-gemini</code></a>:</p>
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb6-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">llm</span> install llm-gemini</span></code></pre></div>
<p>O anche</p>
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb7-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">pip3</span> install llm-gemini</span></code></pre></div>
</section>
<section id="utilizzo" class="level3">
<h3 class="anchored" data-anchor-id="utilizzo">Utilizzo</h3>
<p>La prima cosa da fare è impostare la propria chiave API (quella richiesta sopra). Si apre la shell:</p>
<div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb8-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">llm</span> keys set gemini</span></code></pre></div>
<p>Si incolla la chiave API e si preme <code>Invio</code>.</p>
<p>Una volta fatto, si può testare il funzionamento con un esempio:</p>
<div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb9-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">llm</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-m</span> gemini-pro <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Creami tre nomi buffi per un gatto siamese con le orecchie molto grandi"</span></span></code></pre></div>
<p>In output si avrà qualcosa come:</p>
<div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb10-1"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">- </span>Dumbo</span>
<span id="cb10-2"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">- </span>Elio</span>
<span id="cb10-3"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">- </span>Pipistrello</span></code></pre></div>
<p>La cosa bella è che <code>llm</code>, come tutte le buone <code>cli</code>, può ricevere input dallo <code>stdin</code> e quindi può utilizzare l’output di altri comandi.</p>
<p>Ad esempio l’output di <code>echo</code>:</p>
<div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb11-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">echo</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Dieci nomi per un blog che parla della riga di comando'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">llm</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-m</span> gemini-pro</span></code></pre></div>
<p>E avrò in output qualcosa come:</p>
<div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb12-1"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">1. </span>Il Comando Centrale</span>
<span id="cb12-2"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">2. </span>Padronanza del Terminale</span>
<span id="cb12-3"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">3. </span>Il Mago della Riga di Comando</span>
<span id="cb12-4"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">4. </span>Il Domatore di Terminale</span>
<span id="cb12-5"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">5. </span>Il Maestro del Prompt</span>
<span id="cb12-6"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">6. </span>La Guida alla Riga di Comando</span>
<span id="cb12-7"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">7. </span>Il Tutorial del Terminale</span>
<span id="cb12-8"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">8. </span>Il Manuale del Terminale</span>
<span id="cb12-9"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">9. </span>Le Avventure di un SysAdmin</span>
<span id="cb12-10"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">10. </span>La Linea di Comando per Tutti</span></code></pre></div>
<p>Un esempio più carino, che mostra le info sul sistema operativo che sto usando adesso per testare Gemini. Il comando da cui parto è <code>uname -a</code>, che mi restituisce:</p>
<div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode markdown code-overflow-wrap code-with-copy"><code class="sourceCode markdown"><span id="cb13-1">Linux MSI 5.15.133.1-microsoft-standard-WSL2 #1 SMP Thu Oct 5 21:02:42 UTC 2023 x86_64 GNU/Linux</span></code></pre></div>
<p>Voglio creare un’informazione più leggile, e la voglio in formato <code>markdown</code>, per scriverla qui (il markdown è il formato in cui è scritto questo sito), e lo chiedo a Gemini, via <code>llm</code>:</p>
<div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb14-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">llm</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-m</span> gemini-pro <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Questo è il mio sistema operativo: </span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">$(</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">uname</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-a</span><span class="va" style="color: #111111;
background-color: null;
font-style: inherit;">)</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">. Dimmi qualcosa di più, e dimmelo in markdown."</span></span></code></pre></div>
<p>In output avrò qualcosa come:</p>
<div class="tabset-margin-container"></div><div class="panel-tabset">
<ul class="nav nav-tabs"><li class="nav-item"><a class="nav-link active" id="tabset-1-1-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-1" aria-controls="tabset-1-1" aria-selected="true">Output del comando</a></li><li class="nav-item"><a class="nav-link" id="tabset-1-2-tab" data-bs-toggle="tab" data-bs-target="#tabset-1-2" aria-controls="tabset-1-2" aria-selected="false">Output in HTML</a></li></ul>
<div class="tab-content">
<div id="tabset-1-1" class="tab-pane active" aria-labelledby="tabset-1-1-tab">
<div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb15-1"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">* </span>**Kernel**: Linux 5.15.133.1-microsoft-standard-WSL2</span>
<span id="cb15-2"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">    * </span>Questo è il kernel Linux utilizzato per eseguire WSL2. È una versione modificata del kernel Linux 5.15 che è stato ottimizzato per l'esecuzione in un ambiente Windows.</span>
<span id="cb15-3"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">* </span>**Nome Host**: MSI</span>
<span id="cb15-4"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">    * </span>Questo è il nome del computer WSL2.</span>
<span id="cb15-5"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">* </span>**Versione**: #1 SMP Thu Oct 5 21:02:42 UTC 2023</span>
<span id="cb15-6"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">    * </span>Questa è la versione della build del kernel Linux utilizzata per eseguire WSL2.</span>
<span id="cb15-7"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">* </span>**Architettura**: x86_64</span>
<span id="cb15-8"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">    * </span>Questa è l'architettura del processore del computer WSL2.</span>
<span id="cb15-9"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">* </span>**Sistema Operativo**: GNU/Linux</span>
<span id="cb15-10"><span class="ss" style="color: #20794D;
background-color: null;
font-style: inherit;">    * </span>Questo è il sistema operativo utilizzato per eseguire WSL2. GNU/Linux è una distribuzione Linux basata sul kernel Linux.</span></code></pre></div>
</div>
<div id="tabset-1-2" class="tab-pane" aria-labelledby="tabset-1-2-tab">
<ul>
<li><strong>Kernel</strong>: Linux 5.15.133.1-microsoft-standard-WSL2
<ul>
<li>Questo è il kernel Linux utilizzato per eseguire WSL2. È una versione modificata del kernel Linux 5.15 che è stato ottimizzato per l’esecuzione in un ambiente Windows.</li>
</ul></li>
<li><strong>Nome Host</strong>: MSI
<ul>
<li>Questo è il nome del computer WSL2.</li>
</ul></li>
<li><strong>Versione</strong>: #1 SMP Thu Oct 5 21:02:42 UTC 2023
<ul>
<li>Questa è la versione della build del kernel Linux utilizzata per eseguire WSL2.</li>
</ul></li>
<li><strong>Architettura</strong>: x86_64
<ul>
<li>Questa è l’architettura del processore del computer WSL2.</li>
</ul></li>
<li><strong>Sistema Operativo</strong>: GNU/Linux
<ul>
<li>Questo è il sistema operativo utilizzato per eseguire WSL2. GNU/Linux è una distribuzione Linux basata sul kernel Linux.</li>
</ul></li>
</ul>
</div>
</div>
</div>
</section>
<section id="chattare-in-modo-interattivo" class="level3">
<h3 class="anchored" data-anchor-id="chattare-in-modo-interattivo">Chattare in modo interattivo</h3>
<p>Per attivare una modalità interattiva, domande e risposte, come una chat, il comando è:</p>
<div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb16-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">llm</span> chat <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-m</span> gemini-pro</span></code></pre></div>
<p>Una volta attivato, si potrà attivare il dialogo in modalità <em>chat</em> (vedi Figura&nbsp;1).</p>
<div id="fig-llm-chat" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-llm-chat-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/accedere-google-ai-riga-di-comando/images/linux_date.gif" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-llm-chat-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;1: <code>llm</code> in modalità <em>chat</em>
</figcaption>
</figure>
</div>
</section>
</section>
<section id="il-costo-di-gemini-pro" class="level2">
<h2 class="anchored" data-anchor-id="il-costo-di-gemini-pro">Il costo di Gemini Pro</h2>
<blockquote class="blockquote">
<p>Right now, developers have free access to Gemini Pro and Gemini Pro Vision through Google AI Studio, with up to 60 requests per minute, making it suitable for most app development needs. Vertex AI developers can try the same models, with the same rate limits, at no cost until <a href="https://support.google.com/a/answer/11202276?hl=en#:~:text=General%20Availability%20(GA)&amp;text=Google%20typically%20supports%20General%20Availability,the%20particular%20product%20or%20feature.">general availability</a> early next year, after which there will be a charge per 1,000 characters or per image across <a href="https://ai.google.dev/pricing">Google AI Studio</a> and <a href="https://cloud.google.com/vertex-ai/docs/generative-ai/pricing">Vertex AI</a>.</p>
</blockquote>
<p>Fonte: <a href="https://blog.google/technology/ai/gemini-api-developers-cloud" class="uri">https://blog.google/technology/ai/gemini-api-developers-cloud</a></p>
</section>
<section id="conclusioni" class="level2">
<h2 class="anchored" data-anchor-id="conclusioni">Conclusioni</h2>
<p>Il bello di questo tipo di accesso, è quello di poter creare in modo diretto e semplici, un utilizzo programmatico di questi strumenti. E la cosa è applicabile alla gran parte dei “Large Language Model” (LLM), ovvero questi tipi di AI che si concentrano sulla comprensione e generazione del linguaggio naturale umano.</p>
<p>Questo <em>post</em> ha lo scopo soltanto di farvi <strong>due passi</strong> - non di più - nel nuovo motore di AI di Google, Gemini.<br> L’<em>utility</em> <strong><code>llm</code></strong> è un gioiellino e consente di <strong>fare</strong> molto, ma molto <strong>di più</strong>.</p>
<p>😉 Su entrambi lascio a chi legge tutti i necessari e divertenti approfondimenti del caso.</p>


</section>

<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Torna in cima</a> ]]></description>
  <category>ai</category>
  <category>google</category>
  <category>cli</category>
  <guid>https://aborruso.github.io/posts/accedere-google-ai-riga-di-comando/</guid>
  <pubDate>Sat, 16 Dec 2023 23:00:00 GMT</pubDate>
  <media:content url="https://aborruso.github.io/posts/accedere-google-ai-riga-di-comando/gemini_via_cli.png" medium="image" type="image/png" height="97" width="144"/>
</item>
<item>
  <title>Gestire file CSV grandi, brutti e cattivi</title>
  <dc:creator>Andrea Borruso</dc:creator>
  <link>https://aborruso.github.io/posts/duckdb-intro-csv/</link>
  <description><![CDATA[ 





<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Prima di continuare a leggere
</div>
</div>
<div class="callout-body-container callout-body">
<p>In questo post si parla dei dati in formato CSV di <strong>OpenCoesione</strong>. Ha suscitato il loro interesse e ci siamo confrontati sull’opportunità di pubblicare i loro dati anche in 21 febbraio 2024.<br> 🏅 Ebbene, dal 22 febbraio 2024 <strong>hanno pubblicato i loro dati in questo formato</strong>. I dettagli e un lungo tutorial in <a href="../../posts/leggere-interrogare-file-parquet/index.html">questo post</a>.</p>
</div>
</div>
<section id="tldr-una-breve-introduzione" class="level2">
<h2 class="anchored" data-anchor-id="tldr-una-breve-introduzione">TL;DR (una breve introduzione)</h2>
<p>Il formato <strong>CSV</strong>, con tutti i suoi <strong>difetti</strong>, è ancora <strong>uno dei formati più diffusi per lo scambio di dati</strong>. Ci sono <strong>modalità</strong> di gestire questi file ed eccezionali <strong>strumenti</strong>, che possono rendere molto semplice, efficace e rapido il loro utilizzo. Anche quando sono di <strong>grandi dimensioni</strong>.<br> E per fortuna ci sono banche dati “grosse” e importanti come <a href="https://opencoesione.gov.it"><strong>OpenCoesione</strong></a> che danno l’opportunità di fare pratica con questi strumenti.</p>
<p>In questo lungo post farò una carrellata della <strong>compressione</strong> dei file <strong><code>CSV</code></strong>, dell’importanza di <strong>descriverli</strong>, dell’utilizzo di <strong>DuckDB</strong> per analizzarli e del <strong>formato Parquet</strong> come alternativa al CSV.</p>
<p>⚠️ <strong>QUESTO POST NON È UN TUTORIAL</strong> (ma <em>doping</em> omeopatico per i tuoi criceti e per chi pubblica dati).</p>
<p><img src="https://aborruso.github.io/posts/duckdb-intro-csv/images/atutorial.png" class="img-fluid"></p>
<hr>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Prima di continuare a leggere
</div>
</div>
<div class="callout-body-container callout-body">
<p>In questo post faccio riferimento a diversi strumenti, tra cui <a href="https://duckdb.org/docs/archive/0.8.1/installation/"><strong>DuckDB</strong></a>, <a href="https://miller.readthedocs.io/en/latest/installing-miller/"><strong>Miller</strong></a> e <a href="https://www.visidata.org/install/"><strong>VisiData</strong></a>.<br> Se vuoi replicare alcune delle procedere descritte, è necessario installarli.<br> Soprattutto <strong>DuckDB</strong>.</p>
</div>
</div>
</section>
<section id="i-csv-sono-brutti-e-cattivi" class="level2">
<h2 class="anchored" data-anchor-id="i-csv-sono-brutti-e-cattivi">I CSV sono brutti e cattivi</h2>
<p>Il formato <strong>CSV</strong> è uno dei formati più diffusi per lo <strong>scambio di dati</strong>. È un formato <strong>testuale</strong>, che può essere letto e scritto da quasi tutti i linguaggi di programmazione e da quasi tutti gli strumenti di analisi dati (i “quasi” si potrebbero levare).<br> Non è consigliabile utilizzarlo come formato di lavoro, perché le operazioni di <strong>lettura</strong> e <strong>scrittura</strong> sono <strong>lente</strong> e <strong>costose</strong> in termini di risorse (tempo e memoria) e perché è in generale un formato “povero”.</p>
<p>Un file CSV è “brutto e cattivo” ad esempio per queste ragioni:</p>
<ul>
<li>non consente di definire il <strong>tipo di campo</strong> (stringa, numero, data, ecc.). Tipicamente si è costretti a fare l’<strong>inferenza</strong>, che può essere <strong>errata</strong>;</li>
<li>non consente di definire il <strong>separatore di campo</strong> (virgola, punto e virgola, tabulazione, ecc.). Si può fare l’inferenza e/o si può leggere (e si possono fare errori);</li>
<li>non consente di definire il <strong>separatore dei decimali</strong> (virgola, punto, ecc.). Si può fare l’inferenza e/o si può leggere (e si possono fare errori);</li>
<li>non consente di definire l’<strong><em>encoding</em></strong> (UTF-8, ISO-8859-1, ecc.). Tipicamente si è costretti a fare l’<strong>inferenza</strong>, che può essere <strong>errata</strong>.</li>
</ul>
<p>E per questo chi pubblica dati in questo formato, <strong>dovrebbe</strong> a maggior forza <strong>descriverli</strong> con dei <strong>metadati</strong>. Ma purtroppo nella gran parte dei casi, non ci resta che “morire di inferenza”.<br></p>
<p>E si potrebbero aggiungere altre brutture sul formato e di come spesso viene reso disponibile. Ma non è il tema del post.</p>
</section>
<section id="compressione-dei-file-csv" class="level2 page-columns page-full">
<h2 class="anchored" data-anchor-id="compressione-dei-file-csv">Compressione dei file CSV</h2>
<p>Molti siti che pubblicano file CSV - specie quando sono “grandi” - li pubblicano in formato compresso.<br> Questo - come nel caso del file dei progetti di OpenCoesione - è un ottimo modo per ridurre il tempo di <em>download</em>: il <a href="https://opencoesione.gov.it/it/opendata/progetti_esteso.zip">file</a> reso disponibile in formato compresso <code>ZIP</code> pesa circa (nella versione di aprile 2023) 240 MB, mentre il file CSV contenuto al suo interno pesa circa 4,4 GB.</p>
<p>Scegliendo un altro formato di compressione, diverso dallo <code>ZIP</code>, si possono dare <strong>ulteriori vantaggi</strong> a chi utilizzerà il file.</p>
<p>Uno è quello di <strong>renderlo subito pronto all’uso</strong>, come se fosse già decompresso. Che è una cosa molto comoda specie nelle prime <strong>fasi</strong> di lavoro “<strong>esplorative</strong>”, in cui si fanno un po’ di “ispezioni”, le prime prove di analisi, di verifica qualità, di adeguatezza dei dati, ecc..</p>
<section id="formato-gzip" class="level3 page-columns page-full">
<h3 class="anchored" data-anchor-id="formato-gzip">Formato GZIP</h3>
<p>È un formato introdotto nel 1992, che ha una <strong>buona compressione</strong> e che è <strong>veloce</strong> da decomprimere. È un formato <strong><em>lossless</em></strong>, non perde informazioni, e <strong><em>streaming</em></strong>, può essere decompresso man mano che i dati sono letti, senza dover attendere il completamento dell’estrazione dell’intero archivio.<br> La gran parte delle applicazioni e linguaggi di <em>scripting</em> sono in grado di accedere nativamente a un file <code>gz</code>; un po’ meno con il formato <code>zip</code>. Ed è compatibile con tutti i sistemi operativi e tutte le <em>utility</em> di compressione e decompressione.</p>
<p>A seguire alcuni esempi di quanto è pronto all’uso, basati sul <a href="https://www.italiadomani.gov.it/content/sogei-ng/it/it/catalogo-open-data/Universo_ReGiS_Progetti.html">CSV dei Progetti del PNRR</a>, compresso da me in <a href="file/PNRR_Progetti-Universo_REGIS_v2.1.csv.gz">formato <code>gz</code></a>.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-3-contents" aria-controls="callout-3" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Ambiente di lavoro utilizzato
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-3" class="callout-3-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>La gran parte degli esempi di comandi e di codice inseriti in questo articolo, sono pensati per essere eseguiti in <strong>ambiente Linux</strong>. Sono replicabili quindi in quasi tutti i sistemi operativi - compresi Mac e Windows - perché Linux o è disponibile “nativamente”, o lo è installando applicativi (su Windows ad esempio Windows Subsystem for Linux, WSL).</p>
</div>
</div>
</div>
<p>Lo posso esplorare con l’utility <a href="https://linux.die.net/man/1/zcat"><code>zcat</code></a>, che “stampa” sulla shell il contenuto del file <code>gz</code>:</p>
<div class="sourceCode" id="cb1" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb1-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">zcat</span> PNRR_Progetti-Universo_REGIS_v2.1.csv.gz <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-n</span> 5</span></code></pre></div>

<div class="no-row-height column-margin column-container"><div class="">
<p><code>head</code> estrae le prime 5 righe.</p>
</div></div><p>Mi verrà restituito l’<em>output</em> di Lista&nbsp;1, e potrò constatare che c’è una <strong>riga di intestazione</strong> (non è obbligatoria nei <code>CSV</code>), che il <strong>separatore di campo</strong> è il <code>;</code>, che il <strong>separatore dei decimali</strong> è la <code>,</code> e soprattutto farmi un’idea dei contenuti.</p>
<div id="lst-zcat-head" class="markdown listing quarto-float quarto-figure quarto-figure-left anchored">
<figure class="quarto-float quarto-float-lst figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-lst" id="lst-zcat-head-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Lista&nbsp;1: Prime righe del file
</figcaption>
<div aria-describedby="lst-zcat-head-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="sourceCode" id="lst-zcat-head" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="lst-zcat-head-1">Programma;Missione;Descrizione Missione;Componente;Descrizione Componente;ID Misura;Codice Univoco Misura;Descrizione Misura;ID Submisura;Codice CID;Codice Univoco Submisura;Descrizione Submisura;Amministrazione Titolare;Codice Identificativo Procedura di Attivazione;Titolo Procedura;Tipologia Procedura di Attivazione;CUP;Codice Locale Progetto;Stato CUP;CUP Codice Natura;CUP Descrizione Natura;CUP Codice Tipologia;CUP Descrizione Tipologia;CUP Codice Settore;CUP Descrizione Settore;CUP Codice Sottosettore;CUP Descrizione Sottosettore;CUP Codice Categoria;CUP Descrizione Categoria;Titolo Progetto;Sintesi Progetto;Descrizione Tipo Aiuto;Finanziamento - Stato;Finanziamento Stato - FOI;Finanziamento UE (Diverso da PNRR);Finanziamento Regione;Finanziamento Provincia;Finanziamento Comune;Finanziamento Altro Pubblico;Finanziamento Privato;Finanziamento Da Reperire;Finanziamento PNRR;Finanziamento PNC;Altri Fondi;Finanziamento Totale;Finanziamento Totale Pubblico;Finanziamento Totale Pubblico Netto;Soggetto Attuatore;Codice Fiscale Soggetto Attuatore;Flag Progetti in Essere;Data di Estrazione</span>
<span id="lst-zcat-head-2">PNRR;M1;Digitalizzazione, innovazione, competitività e cultura;M1C1;Digitalizzazione, innovazione e sicurezza nella PA;M1C1I1.2;M1C1I1.02;Abilitazione al cloud per le PA locali;M1C1I1.2;M1C1I1.2;M1C1I1.02.00;Abilitazione al cloud per le PA locali;PCM - DIPARTIM. TRASFORMAZIONE DIGITALE;1000000237;AVVISO AB. CLOUD COMUNI DEL 15/04/22;Bando;G61C22000240006;G61C22000240006;Attivo;02;ACQUISTO O REALIZZAZIONE DI SERVIZI;19;APPLICATIVI E PIATTAFORME WEB;10;SERVIZI PER LA P.A. E PER LA COLLETTIVITA';01;SERVIZI E TECNOLOGIE PER L'INFORMAZIONE E LE COMUNICAZIONI;007;SISTEMI INFORMATIVI PER LA P.A.;1.2. Ab.Cloud Com Cosoleto;MIGRAZIONE AL CLOUD DEI SERVIZI DIGITALI DELL'AMMINISTRAZIONE*TERRITORIO COMUNALE*N. 9 SERVIZI;INTERVENTO CHE NON COSTITUISCE AIUTO DI STATO;0,00;0,00;0,00;0,00;0,00;0,00;0,00;0,00;0,00;47427,00;0,00;0,00;47427,00;47427,00;47427,00;COMUNE DI COSOLETO;01234470803;No;13/06/2023</span>
<span id="lst-zcat-head-3">PNRR;M1;Digitalizzazione, innovazione, competitività e cultura;M1C1;Digitalizzazione, innovazione e sicurezza nella PA;M1C1I1.2;M1C1I1.02;Abilitazione al cloud per le PA locali;M1C1I1.2;M1C1I1.2;M1C1I1.02.00;Abilitazione al cloud per le PA locali;PCM - DIPARTIM. TRASFORMAZIONE DIGITALE;1000000237;AVVISO AB. CLOUD COMUNI DEL 15/04/22;Bando;F71C22000160006;F71C22000160006;Attivo;02;ACQUISTO O REALIZZAZIONE DI SERVIZI;19;APPLICATIVI E PIATTAFORME WEB;10;SERVIZI PER LA P.A. E PER LA COLLETTIVITA';01;SERVIZI E TECNOLOGIE PER L'INFORMAZIONE E LE COMUNICAZIONI;007;SISTEMI INFORMATIVI PER LA P.A.;1.2. Ab.Cloud Com Bompensiere;MIGRAZIONE AL CLOUD DEI SERVIZI DIGITALI DELL'AMMINISTRAZIONE*TERRITORIO COMUNALE*N. 9 SERVIZI DA MIGRARE;INTERVENTO CHE NON COSTITUISCE AIUTO DI STATO;0,00;0,00;0,00;0,00;0,00;0,00;0,00;0,00;0,00;47427,00;0,00;0,00;47427,00;47427,00;47427,00;COMUNE DI BOMPENSIERE;80005060852;No;13/06/2023</span>
<span id="lst-zcat-head-4">PNRR;M1;Digitalizzazione, innovazione, competitività e cultura;M1C1;Digitalizzazione, innovazione e sicurezza nella PA;M1C1I1.2;M1C1I1.02;Abilitazione al cloud per le PA locali;M1C1I1.2;M1C1I1.2;M1C1I1.02.00;Abilitazione al cloud per le PA locali;PCM - DIPARTIM. TRASFORMAZIONE DIGITALE;1000000237;AVVISO AB. CLOUD COMUNI DEL 15/04/22;Bando;B61C22000190006;B61C22000190006;Attivo;02;ACQUISTO O REALIZZAZIONE DI SERVIZI;19;APPLICATIVI E PIATTAFORME WEB;10;SERVIZI PER LA P.A. E PER LA COLLETTIVITA';01;SERVIZI E TECNOLOGIE PER L'INFORMAZIONE E LE COMUNICAZIONI;007;SISTEMI INFORMATIVI PER LA P.A.;1.2. Ab.Cloud Com Castelgrande;MIGRAZIONE AL CLOUD DEI SERVIZI DIGITALI DELL'AMMINISTRAZIONE*TERRITORIO COMUNALE*9 SERVIZI DA MIGRARE;INTERVENTO CHE NON COSTITUISCE AIUTO DI STATO;0,00;0,00;0,00;0,00;0,00;0,00;0,00;0,00;0,00;47427,00;0,00;0,00;47427,00;47427,00;47427,00;COMUNE DI CASTELGRANDE;80004060762;No;13/06/2023</span>
<span id="lst-zcat-head-5">PNRR;M1;Digitalizzazione, innovazione, competitività e cultura;M1C1;Digitalizzazione, innovazione e sicurezza nella PA;M1C1I1.2;M1C1I1.02;Abilitazione al cloud per le PA locali;M1C1I1.2;M1C1I1.2;M1C1I1.02.00;Abilitazione al cloud per le PA locali;PCM - DIPARTIM. TRASFORMAZIONE DIGITALE;1000000237;AVVISO AB. CLOUD COMUNI DEL 15/04/22;Bando;F31C22000020006;F31C22000020006;Attivo;02;ACQUISTO O REALIZZAZIONE DI SERVIZI;19;APPLICATIVI E PIATTAFORME WEB;10;SERVIZI PER LA P.A. E PER LA COLLETTIVITA';01;SERVIZI E TECNOLOGIE PER L'INFORMAZIONE E LE COMUNICAZIONI;007;SISTEMI INFORMATIVI PER LA P.A.;1.2. Ab.Cloud Com Ittireddu;MIGRAZIONE AL CLOUD DEI SERVIZI DIGITALI DELL'AMMINISTRAZIONE*TERRITORIO COMUNALE*N. 9 SERVIZI DA MIGRARE;INTERVENTO CHE NON COSTITUISCE AIUTO DI STATO;0,00;0,00;0,00;0,00;0,00;0,00;0,00;0,00;0,00;47427,00;0,00;0,00;47427,00;47427,00;47427,00;COMUNE DI ITTIREDDU;00283910909;No;13/06/2023</span></code></pre></div>
</div>
</figure>
</div>
<p>E posso usare in modo diretto strumenti di analisi, trasformazione e filtro di file CSV come lo <a href="https://miller.readthedocs.io/">straordinario <strong>Miller</strong></a>.<br> Ad esempio avere restituito il <strong>conteggio</strong> dei <em>record</em>, i <strong>valori nulli</strong> di ogni campo e anche i valori <strong>distinti</strong>.<br> Se voglio farlo soltanto per i campi <code>Missione</code>, <code>Codice Univoco Misura</code> e <code>CUP Codice Natura</code>, utilizzerò il verbo <a href="https://miller.readthedocs.io/en/6.8.0/reference-verbs/index.html#cut"><code>cut</code></a> e <a href="https://miller.readthedocs.io/en/6.8.0/reference-verbs/index.html#summary"><code>summary</code></a>, direttamente sul file compresso:</p>
<div class="sourceCode" id="cb2" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb2-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">mlr</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--ifs</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">";"</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb2-2">cut <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-f</span> Missione,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Codice Univoco Misura"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CUP Codice Natura"</span> then <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb2-3">summary <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-a</span> count,null_count,distinct_count PNRR_Progetti-Universo_REGIS_v2.1.csv.gz</span></code></pre></div>
<p>In output avrò:</p>
<div id="tbl-mlr-output" class="striped responsive small quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-mlr-output-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Tabella&nbsp;1: <em>Output</em> di <code>summary</code> di Miller
</figcaption>
<div aria-describedby="tbl-mlr-output-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="table-responsive">
<table class="table-striped small table-sm caption-top table">
<thead>
<tr class="header">
<th>field_name</th>
<th style="text-align: right;">count</th>
<th style="text-align: right;">null_count</th>
<th style="text-align: right;">distinct_count</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Missione</td>
<td style="text-align: right;">197546</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">6</td>
</tr>
<tr class="even">
<td>Codice Univoco Misura</td>
<td style="text-align: right;">197546</td>
<td style="text-align: right;">0</td>
<td style="text-align: right;">109</td>
</tr>
<tr class="odd">
<td>CUP Codice Natura</td>
<td style="text-align: right;">197546</td>
<td style="text-align: right;">17683</td>
<td style="text-align: right;">7</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
<p>E con questo file compresso potrò usare anche strumenti di analisi e trasformazione che mi consentono di eseguire una più “<em>standard</em>” <strong><em>query</em> SQL</strong>, come <strong>DuckDB</strong>.<br> Per avere il totale del finanziamento PNRR per ogni missione, posso usare questo comando:</p>
<div class="sourceCode" id="cb3" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<span id="cb3-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SELECT Missione, SUM("Finanziamento PNRR") AS total_PNRR</span></span>
<span id="cb3-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">FROM  read_csv_auto("PNRR_Progetti-Universo_REGIS_v2.1.csv.gz")</span></span>
<span id="cb3-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">GROUP BY Missione</span></span>
<span id="cb3-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span></code></pre></div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Informazioni utili
</div>
</div>
<div class="callout-body-container callout-body">
<p>Il parametro <code>-csv</code> è per avere l’output del comando in formato <code>CSV</code>, mentre <code>-c</code> per definire la <em>query</em> <code>SQL</code>.<br> Il <code>FROM</code> ha come input direttamente il file <code>CSV</code> compresso, letto tramite la funzione <a href="https://duckdb.org/docs/data/csv/auto_detection"><code>read_csv_auto</code></a> di DuckDB.</p>
</div>
</div>
<p><strong>Nota bene</strong>: la <em>query</em> di sopra non ti funzionerà.</p>
<p>Perché purtroppo “i CSV sono brutti e cattivi” e senza conoscere il <strong>separatore dei campi</strong>, il <strong>separatore dei decimali</strong>, i <strong>tipi di campo</strong>, sapere se c’è o no la <strong>riga di intestazione</strong>, ecc., è difficile riuscire a interrogare un CSV, anche con DuckDB.<br> Per questo motivo <strong>è molto raccomandato</strong> a chi rende disponibili file <code>CSV</code>:</p>
<ul>
<li>pubblicare <strong>CSV standard</strong>;</li>
<li><strong>descriverli</strong>.</li>
</ul>

<div class="no-row-height column-margin column-container"><div class="">
<p>Sono essenziali allo scopo, le operazioni di esplorazione descritte sopra.</p>
</div></div><p>E allora è meglio (a volte necessario) aggiungere un po’ di parametri al comando precedente (vedi Lista&nbsp;2): per fare in modo che le colonne possano essere correttamente distinte (fissando con il parametro <code>delim</code> il separatore dei campi), che siano mappati i nomi dei campi (fissando il parametro <code>header</code>), che i numeri decimali siano elaborabili come tali (fissando il parametro <code>decimal_separator</code> e specificando il tipo <code>FLOAT</code> per il campo <code>Finanziamento PNRR</code>).</p>

<div class="no-row-height column-margin column-container"><div class="">
<p><code>delim</code> e <code>header</code> sono riconosciuti automaticamente da DuckDB. Sono inseriti a scopo didattico.</p>
</div></div><div id="lst-query-duckdb" class="bash listing quarto-float quarto-figure quarto-figure-left anchored">
<figure class="quarto-float quarto-float-lst figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-lst" id="lst-query-duckdb-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Lista&nbsp;2: Query SQL tramite DuckDB su un CSV compresso
</figcaption>
<div aria-describedby="lst-query-duckdb-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="sourceCode" id="lst-query-duckdb" style="background: #f1f3f5;"><pre class="sourceCode code-annotation-code bash code-with-copy"><code class="sourceCode bash"><span id="lst-query-duckdb-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<span id="lst-query-duckdb-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SELECT Missione, SUM("Finanziamento PNRR") AS total_PNRR</span></span>
<span id="lst-query-duckdb-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">FROM  read_csv_auto(</span></span>
<span id="lst-query-duckdb-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    "PNRR_Progetti-Universo_REGIS_v2.1.csv.gz",</span></span>
<span id="lst-query-duckdb-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    delim=";",</span></span>
<span id="lst-query-duckdb-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    decimal_separator=",",</span></span>
<span id="lst-query-duckdb-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    header=True,</span></span>
<span id="lst-query-duckdb-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    types={"Finanziamento PNRR":"FLOAT"}</span></span>
<span id="lst-query-duckdb-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)</span></span>
<span id="lst-query-duckdb-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">GROUP BY Missione</span></span>
<span id="lst-query-duckdb-11"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span></code></pre></div>
</div>
</figure>
</div>
<ol type="1">
<li>imposta il separatore di campi a <code>;</code></li>
<li>imposta il separatore di decimali a <code>,</code></li>
<li>la prima riga è la riga di intestazione</li>
<li>il campo <code>Finanziamento PNRR</code> è di tipo <code>FLOAT</code></li>
</ol>
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Il vantaggio di un CSV standard
</div>
</div>
<div class="callout-body-container callout-body">
<p>Con un <strong>CSV standard</strong>, questi parametri aggiuntivi non sarebbero necessari e si potrebbe usare la prima versione della <em>query</em> SQL.</p>
</div>
</div>
<p>In output, in mezzo secondo (di fatto, non per dire “in breve tempo”), queste righe di output (per un CSV di circa 200.000 righe per 50 colonne, che è pure compresso):</p>
<div class="table-responsive">
<table class="table-striped small table-sm caption-top table">
<caption><em>Output</em> della <em>query</em> SQL</caption>
<thead>
<tr class="header">
<th>Missione</th>
<th style="text-align: right;">total_PNRR</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>M1</td>
<td style="text-align: right;">19245334466.82313</td>
</tr>
<tr class="even">
<td>M2</td>
<td style="text-align: right;">22688516407.240803</td>
</tr>
<tr class="odd">
<td>M3</td>
<td style="text-align: right;">22563735313.390625</td>
</tr>
<tr class="even">
<td>M4</td>
<td style="text-align: right;">20129269029.00844</td>
</tr>
<tr class="odd">
<td>M5</td>
<td style="text-align: right;">12998257338.579052</td>
</tr>
<tr class="even">
<td>M6</td>
<td style="text-align: right;">8059988416.008047</td>
</tr>
</tbody>
</table>
</div>
</section>
<section id="formato-zstd" class="level3">
<h3 class="anchored" data-anchor-id="formato-zstd">Formato ZSTD</h3>
<p>Si può scegliere un algoritmo di compressione alternativo allo <code>ZIP</code>, anche per ragioni di <strong>velocità</strong> di <strong>decompressione</strong> e <strong>compressione</strong> e per la <strong>percentuale</strong> di <strong>compressione</strong>.<br></p>
<p>Per questa accoppiata di caratteristiche il formato <a href="https://facebook.github.io/zstd/"><strong><code>ZSTD</code></strong></a> è sempre più diffuso tra le applicazioni e le librerie <em>software</em> di accesso ai dati.</p>
<p>Per dare qualche numero di confronto, basato sul file CSV da 4 GB di OpenCoesione e sul mio <em>notebook</em> con Pentium i7 di 12esima generazione con 16 GB di RAM:</p>
<ul>
<li>la compressione (standard) con <code>gzip</code> richiede 47 secondi, e il file compresso di <em>output</em> pesa 253 MB;</li>
<li>la compressione (standard) con <code>zstd</code> richiede 13 secondi, e il file compresso di <em>output</em> pesa 186 MB;</li>
<li>la decompressione del file <code>gzip</code> richiede 19 secondi;</li>
<li>la decompressione del file <code>zstd</code> richiede 5 secondi.</li>
</ul>
<p>L’<em>utility</em> a riga di comando per gestire i file <code>ZSTD</code> si chiama <code>zstd</code> e si può installare in (quasi) tutti i sistemi operativi. Un’applicazione <em>open source</em>, multipiattaforma, con interfaccia grafica, che supporta questa compressione è <a href="https://peazip.github.io/index.html">PeaZip</a>.<br> Molte applicazioni e librerie <em>software</em> di accesso ai dati, come DuckDB, <a href="https://arrow.apache.org/">Apache Arrow</a> e <a href="https://spark.apache.org/">Apache Spark</a>, lo supportano nativamente.</p>
<p>In DuckDB, si può leggere un file <code>CSV</code> compresso in formato <code>ZSTD</code>, semplicemente puntando ad esso (l’estensione <code>.zst</code> fa in modo che venga interpretato come file compresso in formato <code>ZSTD</code>):</p>
<div id="lst-select-count" class="bash listing quarto-float quarto-figure quarto-figure-left anchored">
<figure class="quarto-float quarto-float-lst figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-lst" id="lst-select-count-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Lista&nbsp;3: Esempio di conteggio delle righe
</figcaption>
<div aria-describedby="lst-select-count-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="sourceCode" id="lst-select-count" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="lst-select-count-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<span id="lst-select-count-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SELECT count(*) numero_righe</span></span>
<span id="lst-select-count-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">FROM  read_csv_auto(</span></span>
<span id="lst-select-count-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">        "PNRR_Progetti-Universo_REGIS_v2.1.csv.zst",</span></span>
<span id="lst-select-count-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">        delim=";",</span></span>
<span id="lst-select-count-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">        decimal_separator=",",</span></span>
<span id="lst-select-count-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">        header=True,</span></span>
<span id="lst-select-count-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">        types={"Finanziamento PNRR":"FLOAT"}</span></span>
<span id="lst-select-count-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)</span></span>
<span id="lst-select-count-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span></code></pre></div>
</div>
</figure>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
File di esempio
</div>
</div>
<div class="callout-body-container callout-body">
<p><a href="file/PNRR_Progetti-Universo_REGIS_v2.1.csv.zst">Qui</a> un file compresso <code>ZSTD</code> da usare come esempio.</p>
</div>
</div>
<p>Restituisce il numero di righe in circa 0,4 secondi per il <code>CSV</code> (compresso <code>ZSTD</code>) di circa 200.000 righe per 50 colonne, usato nell’esempio di sopra. E in 5 secondi per il <code>CSV</code> (compresso <code>ZSTD</code>) di circa 2.000.000 di righe per 200 colonne di OpenCoesione.</p>
<p>Si può esplorare analogamente un file <code>CSV</code> compresso <code>ZSTD</code>, “stampandolo” a schermo, con l’utility <code>zstdcat</code>. Per leggere le prime 5 righe del file:</p>
<div class="sourceCode" id="cb4" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">zstdcat</span> PNRR_Progetti-Universo_REGIS_v2.1.csv.zst <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-n</span> 5</span></code></pre></div>
<p>O sempre in accoppiata con Miller, per avere dei dati di sintesi (in 0.6 secondi) come quelli di Tabella&nbsp;1:</p>
<div class="sourceCode" id="cb5" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">zstdcat</span> PNRR_Progetti-Universo_REGIS_v2.1.csv.zst <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb5-2"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">mlr</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--ifs</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">";"</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb5-3">cut <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-f</span> Missione,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"Codice Univoco Misura"</span>,<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"CUP Codice Natura"</span> then <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<span id="cb5-4">summary <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-a</span> count,null_count,distinct_count</span></code></pre></div>
</section>
</section>
<section id="csv-standard" class="level2">
<h2 class="anchored" data-anchor-id="csv-standard">CSV “standard”</h2>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-7-contents" aria-controls="callout-7" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
A proposito di “standard”
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-7" class="callout-7-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<p>Il formato CSV <strong>non è uno standard</strong>, ma una convenzione non ufficiale che è stata ampiamente adotatta. È descritta nella <a href="https://tools.ietf.org/html/rfc4180">RFC 4180</a>.</p>
</div>
</div>
</div>
<p>Qui utilizzo l’aggettivo “<strong>standard</strong>” per alcune caratteristiche che rendono (nella gran parte dei casi) un CSV “<strong>subito pronto</strong>”, per essere letto da applicazioni e linguaggi di scripting per l’analisi dei dati.<br> Queste sono quelle consigliate e più tipiche:</p>
<ul>
<li><strong><code>UTF-8</code></strong> come <strong>codifica</strong> dei <strong>caratteri</strong>;</li>
<li><strong><code>,</code></strong> come separatore di campi;</li>
<li><strong><code>.</code></strong> come separatore dei decimali. In Italia il separatore è la <code>,</code>, e ci può stare usarla, ma usando il <code>.</code> e documentandolo, si mette a disposizione un file che sarà più <strong>pronto</strong> per una <strong>lettura automatica</strong>;</li>
<li>presenza della <strong>riga di intestazione</strong> (una sola);</li>
<li><strong>date</strong> nello standard <a href="https://www.wikiwand.com/it/ISO_8601"><strong><code>ISO 8601</code></strong></a> (ad esempio la data “8 marzo 2023” rappresentata come “2023-03-08”);</li>
<li>ogni colonna <strong>un solo tipo di campo</strong> (es. solo numeri, solo testo, solo date, ecc.). Questo sembra inutile evidenziarlo, ma capita spesso di trovare colonne che contengono valori di tipo diverso (es. numeri e testo) nella stessa colonna;</li>
<li>evitare l’utilizzo di spazi, virgolette o altri caratteri speciali nei <strong>nomi dei campi</strong>;</li>
<li><strong>non inserire</strong> il <strong>separatore</strong> delle <strong>migliaia</strong> nei valori delle celle dei campi numerici.</li>
</ul>
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Linee Guida open data
</div>
</div>
<div class="callout-body-container callout-body">
<p>Diversi di questi punti sono raccomandati anche nelle “<a href="https://www.agid.gov.it/sites/default/files/repository_files/lg-open-data_v.1.0_1.pdf">Linee Guida recanti regole tecniche per l’apertura dei dati e il riutilizzo dell’informazione del settore pubblico</a>”, purtroppo al momento leggibili soltanto in PDF.</p>
</div>
</div>
<section id="standardizzare-il-csv-di-opencoesione" class="level3">
<h3 class="anchored" data-anchor-id="standardizzare-il-csv-di-opencoesione">Standardizzare il CSV di OpenCoesione</h3>
<p>Nella sezione sui dati di OpenCoesione (leggila prima di proseguire) è riportato come sia <strong>necessario</strong> <strong>descrivere</strong> il file <strong><code>CSV</code></strong> descritto (quello dei progetti), per poterlo leggere al meglio con qualsiasi applicazione.<br> È necessario farlo, perché ha alcune problematiche e perché non è appunto “standard”.</p>
<p>Fatto lo sforzo di descriverlo, è possibile usare <strong>DuckDB</strong> per <strong>convertire</strong> un <strong><code>CSV</code></strong> “<strong>brutto, sporco e cattivo</strong>”, in un <strong><code>CSV</code></strong> molto più <strong>pronto all’uso</strong>.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Nota bene
</div>
</div>
<div class="callout-body-container callout-body">
<p>Anche un CSV creato come descritto a seguire potrebbe dare qualche problema, perché i programmi di analisi - con un file <code>CSV</code> - sono costretti a fare l’inferenza dei contenuti. E l’inferenza può essere errata.<br> Qui inoltre siamo di fronte a un file particolarmente “ricco” e “variegato”.</p>
</div>
</div>
<p>Il comando DuckDB da usare è in modo schematico <code>COPY INPUT TO OUTPUT</code> (documentazione <a href="https://duckdb.org/docs/archive/0.8.1/sql/statements/copy"><code>COPY</code></a>):</p>
<ul>
<li>l’<code>INPUT</code> è il “SELEZIONA TUTTO” del file <code>CSV</code> compresso originario, applicando le dovute operazioni di <em>casting</em> dei tipi di campo;</li>
<li>poi è necessario descrivere il <code>CSV</code> di <em>input</em> (i separatori, il formato dei campi con date, l’intestazione, i tipi di campo, ecc.);</li>
<li>infine, si definisce il <code>TO</code> scegliendo un nome per il file di <em>output</em> e alcune <a href="https://duckdb.org/docs/archive/0.8.1/sql/statements/copy#csv-options">opzioni di formato</a>.</li>
</ul>
<p>Dando al file di <em>output</em> l’estensione <code>.csv.gz</code> il formato sarà appunto un <code>CSV</code> e sarà compresso con algoritmo <code>GZIP</code>.<br> Con <code>(HEADER, timestampformat '%Y-%m-%d')</code> si fa in modo che l’output contenga la riga di intestazione e che le date siano rappresentate nel formato <code>ISO 8601</code> (<code>YYYY-MM-DD</code>).</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-10-contents" aria-controls="callout-10" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Comando da usare per la conversione
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-10" class="callout-10-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<div class="sourceCode" id="cb6" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb6-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">echo</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COPY (SELECT *</span></span>
<span id="cb6-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">REPLACE(</span></span>
<span id="cb6-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_1 AS FLOAT) AS PROGRAMMATO_INDICATORE_1,</span></span>
<span id="cb6-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_2 AS FLOAT) AS PROGRAMMATO_INDICATORE_2,</span></span>
<span id="cb6-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_3 AS FLOAT) AS PROGRAMMATO_INDICATORE_3,</span></span>
<span id="cb6-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_4 AS FLOAT) AS PROGRAMMATO_INDICATORE_4,</span></span>
<span id="cb6-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_1 AS FLOAT) AS REALIZZATO_INDICATORE_1,</span></span>
<span id="cb6-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_2 AS FLOAT) AS REALIZZATO_INDICATORE_2,</span></span>
<span id="cb6-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_3 AS FLOAT) AS REALIZZATO_INDICATORE_3,</span></span>
<span id="cb6-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_4 AS FLOAT) AS REALIZZATO_INDICATORE_4,</span></span>
<span id="cb6-11"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb6-12"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">from read_csv_auto(</span></span>
<span id="cb6-13"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'progetti_esteso_20230430.csv.gz',SEP=';',dateformat='%Y%m%d',decimal_separator=',',sample_size=100000,</span></span>
<span id="cb6-14"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">types={'OC_COD_ARTICOLAZ_PROGRAMMA':'VARCHAR','FINANZ_UE':'FLOAT','FINANZ_UE_FESR':'FLOAT','FINANZ_UE_FSE':'FLOAT','FINANZ_UE_FEASR':'FLOAT','FINANZ_UE_FEAMP':'FLOAT','FINANZ_UE_IOG':'FLOAT','FINANZ_STATO_FONDO_DI_ROTAZIONE':'FLOAT','FINANZ_STATO_FSC':'FLOAT','FINANZ_STATO_PAC':'FLOAT','FINANZ_STATO_COMPLETAMENTI':'FLOAT','FINANZ_STATO_ALTRI_PROVVEDIMENTI':'FLOAT','FINANZ_REGIONE':'FLOAT','FINANZ_PROVINCIA':'FLOAT','FINANZ_COMUNE':'FLOAT','FINANZ_RISORSE_LIBERATE':'FLOAT','FINANZ_ALTRO_PUBBLICO':'FLOAT','FINANZ_STATO_ESTERO':'FLOAT','FINANZ_PRIVATO':'FLOAT','FINANZ_DA_REPERIRE':'FLOAT','FINANZ_TOTALE_PUBBLICO':'FLOAT','ECONOMIE_TOTALI':'FLOAT','ECONOMIE_TOTALI_PUBBLICHE':'FLOAT','OC_FINANZ_UE_NETTO':'FLOAT','OC_FINANZ_UE_FESR_NETTO':'FLOAT','OC_FINANZ_UE_FSE_NETTO':'FLOAT','OC_FINANZ_UE_FEASR_NETTO':'FLOAT','OC_FINANZ_UE_FEAMP_NETTO':'FLOAT','OC_FINANZ_UE_IOG_NETTO':'FLOAT','OC_FINANZ_STATO_FONDO_ROT_NETTO':'FLOAT','OC_FINANZ_STATO_FSC_NETTO':'FLOAT','OC_FINANZ_STATO_PAC_NETTO':'FLOAT','OC_FINANZ_STATO_COMPL_NETTO':'FLOAT','OC_FINANZ_STATO_ALTRI_PROV_NETTO':'FLOAT','OC_FINANZ_REGIONE_NETTO':'FLOAT','OC_FINANZ_PROVINCIA_NETTO':'FLOAT','OC_FINANZ_COMUNE_NETTO':'FLOAT','OC_FINANZ_RISORSE_LIBERATE_NETTO':'FLOAT','OC_FINANZ_ALTRO_PUBBLICO_NETTO':'FLOAT','OC_FINANZ_STATO_ESTERO_NETTO':'FLOAT','OC_FINANZ_PRIVATO_NETTO':'FLOAT','OC_FINANZ_TOT_PUB_NETTO':'FLOAT','OC_COSTO_COESIONE':'FLOAT','IMPEGNI':'FLOAT','OC_IMPEGNI_GIURID_VINCOLANTI':'FLOAT','OC_IMPEGNI_TRASFERIMENTI':'FLOAT','OC_IMPEGNI_COESIONE':'FLOAT','TOT_PAGAMENTI':'FLOAT','OC_TOT_PAGAMENTI_BENEFICIARI':'FLOAT','OC_TOT_PAGAMENTI_TRASFERIMENTI':'FLOAT','COSTO_REALIZZATO':'FLOAT','COSTO_RENDICONTABILE_UE':'FLOAT','OC_TOT_PAGAMENTI_RENDICONTAB_UE':'FLOAT','OC_TOT_PAGAMENTI_FSC':'FLOAT','OC_TOT_PAGAMENTI_PAC':'FLOAT','OC_PAGAMENTI_COESIONE':'FLOAT','OC_DATA_INIZIO_PROGETTO':'DATE','OC_DATA_FINE_PROGETTO_PREVISTA':'DATE','OC_DATA_FINE_PROGETTO_EFFETTIVA':'DATE','DATA_INIZIO_PREV_STUDIO_FATT':'DATE','DATA_INIZIO_EFF_STUDIO_FATT':'DATE','DATA_FINE_PREV_STUDIO_FATT':'DATE','DATA_FINE_EFF_STUDIO_FATT':'DATE','DATA_INIZIO_PREV_PROG_PREL':'DATE','DATA_INIZIO_EFF_PROG_PREL':'DATE','DATA_FINE_PREV_PROG_PREL':'DATE','DATA_FINE_EFF_PROG_PREL':'DATE','DATA_INIZIO_PREV_PROG_DEF':'DATE','DATA_INIZIO_EFF_PROG_DEF':'DATE','DATA_FINE_PREV_PROG_DEF':'DATE','DATA_FINE_EFF_PROG_DEF':'DATE','DATA_INIZIO_PREV_PROG_ESEC':'DATE','DATA_INIZIO_EFF_PROG_ESEC':'DATE','DATA_FINE_PREV_PROG_ESEC':'DATE','DATA_FINE_EFF_PROG_ESEC':'DATE','DATA_INIZIO_PREV_AGG_BANDO':'DATE','DATA_INIZIO_EFF_AGG_BANDO':'DATE','DATA_FINE_PREV_AGG_BANDO':'DATE','DATA_FINE_EFF_AGG_BANDO':'DATE','DATA_INIZIO_PREV_STIP_ATTRIB':'DATE','DATA_INIZIO_EFF_STIP_ATTRIB':'DATE','DATA_FINE_PREV_STIP_ATTRIB':'DATE','DATA_FINE_EFF_STIP_ATTRIB':'DATE','DATA_INIZIO_PREV_ESECUZIONE':'DATE','DATA_INIZIO_EFF_ESECUZIONE':'DATE','DATA_FINE_PREV_ESECUZIONE':'DATE','DATA_FINE_EFF_ESECUZIONE':'DATE','DATA_INIZIO_PREV_COLLAUDO':'DATE','DATA_INIZIO_EFF_COLLAUDO':'DATE','DATA_FINE_PREV_COLLAUDO':'DATE','DATA_FINE_EFF_COLLAUDO':'DATE','COD_TIPO_PROCED_ATTIVAZIONE':'VARCHAR','OC_FLAG_REGIONE_UNICA':'INT','DATA_AGGIORNAMENTO':'DATE','OC_FLAG_CUP':'INT','PROGRAMMATO_INDICATORE_1':'VARCHAR','REALIZZATO_INDICATORE_1':'VARCHAR','PROGRAMMATO_INDICATORE_2':'VARCHAR','REALIZZATO_INDICATORE_2':'VARCHAR','PROGRAMMATO_INDICATORE_3':'VARCHAR','REALIZZATO_INDICATORE_3':'VARCHAR','PROGRAMMATO_INDICATORE_4':'VARCHAR','REALIZZATO_INDICATORE_4':'VARCHAR'}</span></span>
<span id="cb6-15"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)) TO 'progetti_esteso_20230430_standard.csv.gz' (HEADER, timestampformat '%Y-%m-%d');"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span>  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span></span></code></pre></div>
</div>
</div>
</div>
<p>Così facendo, il <code>CSV</code> di output avrà queste caratteristiche:</p>
<ul>
<li>nei campi con le date, ci saranno delle stringhe nel formato <code>ISO 8601</code> (<code>YYYY-MM-DD</code>) e non numeri interi;</li>
<li>i campi numerici avranno il <code>.</code> come separatore dei decimali e non ci sarà difformità nel modo di rappresentarlo;</li>
<li>il separatore di campo sarà la <code>,</code>.</li>
</ul>
</section>
</section>
<section id="descrivere-i-csv" class="level2">
<h2 class="anchored" data-anchor-id="descrivere-i-csv">Descrivere i CSV</h2>
<blockquote class="blockquote">
<p><em>CSV is one of the most popular formats for publishing data on the web. It is concise, easy to understand by both humans and computers, and aligns nicely to the tabular nature of most data.</em></p>
<p><em>But <strong>CSV</strong> is also a <strong>poor format for data</strong>. There is <strong>no mechanism</strong> within CSV to indicate the <strong>type of data</strong> in a particular <strong>column</strong>, or whether values in a particular column must be unique. It is therefore <strong>hard</strong> to <strong>validate</strong> and <strong>prone</strong> to <strong>errors</strong> such as missing values or differing data types within a column.</em></p>
</blockquote>
<p>Queste frasi sono presenti all’inizio di un lavoro di riferimento, per comprendere come si potrebbe descrivere un file in questo formato, in modo che sia utile, efficace e leggibile da umani, <em>personal computer</em> e applicazioni: <a href="https://www.w3.org/TR/tabular-data-primer/"><strong>CSV on the Web: A Primer</strong></a>.<br> Se non lo conosci, <strong>leggilo</strong>. Io qui non entrerò nei dettagli, perché non vale la pena ripetere quello che è già stato scritto molto bene.</p>
<p>Un altro progetto di riferimento per la descrizione di un file <code>CSV</code> è <strong>Frictionless Data</strong> e le sue <strong>specifiche</strong> per i <a href="https://specs.frictionlessdata.io/table-schema/#language"><strong>dati tabellari</strong></a>. E ancora una volta, per le stesse ragioni non entrerò nei dettagli.</p>
<p>Molti dei dati pubblicati nei <strong>portali Open Data italiani</strong> in questo formato, sono accompagnati <strong>soltanto</strong> da un <strong>titolo</strong> e una <strong>descrizione</strong>. È un <strong>vuoto informativo</strong> e molto spesso una <strong>barriera</strong> a un pieno uso dei dati.<br> Alle volte, come nel caso di OpenCoesione, è presente un file con i nomi dei campi, la loro tipologia e altre note. Nella gran parte dei casi sono però file descrittivi leggibili soltanto a schermo da chi dovrà analizzare i file. Non sono leggibili da un <em>personal computer</em> o da un’applicazione, <strong>non sono <em>machine readable</em></strong>.<br></p>
<p>E quando si hanno dati ricchi e complessi, questa diventa un’<strong>ulteriore barriera</strong> all’<strong>uso dei dati</strong>.</p>
<div class="callout callout-style-default callout-important callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
📌 Importante
</div>
</div>
<div class="callout-body-container callout-body">
<p>La <strong>pubblicazione</strong> non si dovrebbe limitare a rendere disponibile dei file, ma essere <strong>accompagnata da una descrizione del file stesso</strong>, leggibile dalle persone e dalle applicazioni.</p>
</div>
</div>
<p>Farlo in una delle due modalità descritte sopra sarebbe perfetto. Non è a costo zero, ma se è uno dei processi (“automatici”) di un progetto di pubblicazione, è un costo che si può sostenere, che si ripaga in termini di <strong>usabilità</strong> e <strong>riusabilità</strong> dei dati.</p>
<section id="associare-schema-sql" class="level3">
<h3 class="anchored" data-anchor-id="associare-schema-sql">Associare schema SQL</h3>
<p>Una “<strong>buona pratica</strong>” da suggerire a chi pubblica dati, basata su uno <strong>standard</strong> che è sia <strong>formale</strong> che <strong><em>de facto</em></strong>, è quella di <strong>accompagnare</strong> al file <code>CSV</code> anche la <strong><em>query</em> <code>SQL</code></strong> per la <strong>creazione</strong> della <strong>tabella</strong>.<br> Sotto l’esempio per la creazione della tabella dei progetti di OpenCoesione descritta qui (qui il <a href="risorse/progetti.sql">file <code>SQL</code></a> da prendere soltanto come spunto).</p>
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-12-contents" aria-controls="callout-12" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Schema <code>SQL</code> tabella progetti di OpenCoesione
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-12" class="callout-12-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<div class="sourceCode" id="cb7" style="background: #f1f3f5;"><pre class="sourceCode sql code-overflow-wrap code-with-copy"><code class="sourceCode sql"><span id="cb7-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">CREATE</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">TABLE</span> progetti(COD_LOCALE_PROGETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_TITOLO_PROGETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_SINTESI_PROGETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_LINK <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_CICLO BIGINT, OC_DESCR_CICLO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_TEMA_SINTETICO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_TEMA_SINTETICO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, COD_GRANDE_PROGETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCRIZIONE_GRANDE_PROGETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_FONTE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCR_FONTE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, FONDO_COMUNITARIO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_CODICE_PROGRAMMA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCRIZIONE_PROGRAMMA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, COD_OB_TEMATICO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCR_OB_TEMATICO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, COD_PRIORITA_INVEST <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCR_PRIORITA_INVEST <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_CATEGORIA_SPESA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCR_CATEGORIA_SPESA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_ARTICOLAZIONE_PROGRAMMA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_SUBARTICOLAZIONE_PROGRAMMA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_ARTICOLAZ_PROGRAMMA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCR_ARTICOLAZ_PROGRAMMA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_SUBARTICOLAZ_PROGRAMMA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCR_SUBARTICOLAZ_PROGRAMMA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, COD_STRUMENTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCR_STRUMENTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCR_TIPO_STRUMENTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP_COD_NATURA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP_DESCR_NATURA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP_COD_TIPOLOGIA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP_DESCR_TIPOLOGIA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP_COD_SETTORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP_DESCR_SETTORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP_COD_SOTTOSETTORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP_DESCR_SOTTOSETTORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP_COD_CATEGORIA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, CUP_DESCR_CATEGORIA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, COD_ATECO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCRIZIONE_ATECO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_TIPO_AIUTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCR_TIPO_AIUTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, COD_REGIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DEN_REGIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, COD_PROVINCIA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DEN_PROVINCIA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, COD_COMUNE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DEN_COMUNE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_MACROAREA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_SLL BIGINT, OC_DENOMINAZIONE_SLL <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, FINANZ_UE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_UE_FESR <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_UE_FSE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_UE_FEASR <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_UE_FEAMP <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_UE_IOG <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_STATO_FONDO_DI_ROTAZIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_STATO_FSC <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_STATO_PAC <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_STATO_COMPLETAMENTI <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_STATO_ALTRI_PROVVEDIMENTI <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_REGIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_PROVINCIA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_COMUNE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_RISORSE_LIBERATE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_ALTRO_PUBBLICO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_STATO_ESTERO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_PRIVATO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_DA_REPERIRE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, FINANZ_TOTALE_PUBBLICO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, ECONOMIE_TOTALI <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, ECONOMIE_TOTALI_PUBBLICHE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_UE_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_UE_FESR_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_UE_FSE_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_UE_FEASR_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_UE_FEAMP_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_UE_IOG_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_STATO_FONDO_ROT_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_STATO_FSC_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_STATO_PAC_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_STATO_COMPL_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_STATO_ALTRI_PROV_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_REGIONE_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_PROVINCIA_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_COMUNE_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_RISORSE_LIBERATE_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_ALTRO_PUBBLICO_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_STATO_ESTERO_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_PRIVATO_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FINANZ_TOT_PUB_NETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_COSTO_COESIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, IMPEGNI <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_IMPEGNI_GIURID_VINCOLANTI <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_IMPEGNI_TRASFERIMENTI <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_IMPEGNI_COESIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, TOT_PAGAMENTI <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_TOT_PAGAMENTI_BENEFICIARI <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_TOT_PAGAMENTI_TRASFERIMENTI <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, COSTO_REALIZZATO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, COSTO_RENDICONTABILE_UE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_TOT_PAGAMENTI_RENDICONTAB_UE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_TOT_PAGAMENTI_FSC <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_TOT_PAGAMENTI_PAC <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_PAGAMENTI_COESIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_DATA_INIZIO_PROGETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, OC_DATA_FINE_PROGETTO_PREVISTA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, OC_DATA_FINE_PROGETTO_EFFETTIVA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_PREV_STUDIO_FATT <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_EFF_STUDIO_FATT <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_PREV_STUDIO_FATT <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_EFF_STUDIO_FATT <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_PREV_PROG_PREL <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_EFF_PROG_PREL <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_PREV_PROG_PREL <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_EFF_PROG_PREL <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_PREV_PROG_DEF <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_EFF_PROG_DEF <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_PREV_PROG_DEF <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_EFF_PROG_DEF <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_PREV_PROG_ESEC <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_EFF_PROG_ESEC <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_PREV_PROG_ESEC <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_EFF_PROG_ESEC <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_PREV_AGG_BANDO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_EFF_AGG_BANDO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_PREV_AGG_BANDO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_EFF_AGG_BANDO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_PREV_STIP_ATTRIB <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_EFF_STIP_ATTRIB <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_PREV_STIP_ATTRIB <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_EFF_STIP_ATTRIB <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_PREV_ESECUZIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_EFF_ESECUZIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_PREV_ESECUZIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_EFF_ESECUZIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_PREV_COLLAUDO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_INIZIO_EFF_COLLAUDO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_PREV_COLLAUDO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, DATA_FINE_EFF_COLLAUDO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, OC_STATO_FINANZIARIO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_STATO_PROGETTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_STATO_PROCEDURALE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_FASE_CORRENTE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCR_FASE_CORRENTE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, COD_PROCED_ATTIVAZIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCR_PROCED_ATTIVAZIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, COD_TIPO_PROCED_ATTIVAZIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCR_TIPO_PROCED_ATTIVAZIONE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_CODFISC_PROGRAMMATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DENOM_PROGRAMMATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_FORMA_GIU_PROGRAMMATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCR_FORMA_GIU_PROGRAMMATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_TOTALE_PROGRAMMATORI BIGINT, OC_CODFISC_ATTUATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DENOM_ATTUATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_FORMA_GIU_ATTUATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCR_FORMA_GIU_ATTUATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_TOTALE_ATTUATORI BIGINT, OC_CODFISC_BENEFICIARIO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DENOM_BENEFICIARIO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_FORMA_GIU_BENEFICIARIO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCR_FORMA_GIU_BENEFICIARIO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_TOTALE_BENEFICIARI BIGINT, OC_CODFISC_REALIZZATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DENOM_REALIZZATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_COD_FORMA_GIU_REALIZZATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_DESCR_FORMA_GIU_REALIZZATORE <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, OC_TOTALE_REALIZZATORI BIGINT, OC_TOTALE_INDICATORI BIGINT, COD_INDICATORE_1 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCR_INDICATORE_1 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, UNITA_MISURA_INDICATORE_1 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, PROGRAMMATO_INDICATORE_1 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, REALIZZATO_INDICATORE_1 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, COD_INDICATORE_2 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCR_INDICATORE_2 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, UNITA_MISURA_INDICATORE_2 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, PROGRAMMATO_INDICATORE_2 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, REALIZZATO_INDICATORE_2 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, COD_INDICATORE_3 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCR_INDICATORE_3 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, UNITA_MISURA_INDICATORE_3 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, PROGRAMMATO_INDICATORE_3 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, REALIZZATO_INDICATORE_3 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, COD_INDICATORE_4 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, DESCR_INDICATORE_4 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, UNITA_MISURA_INDICATORE_4 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">VARCHAR</span>, PROGRAMMATO_INDICATORE_4 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, REALIZZATO_INDICATORE_4 <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">FLOAT</span>, OC_FLAG_REGIONE_UNICA <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">INTEGER</span>, OC_FLAG_VISUALIZZAZIONE BIGINT, OC_FLAG_PAC BIGINT, DATA_AGGIORNAMENTO <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">DATE</span>, OC_FLAG_CUP <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">INTEGER</span>);</span></code></pre></div>
</div>
</div>
</div>
<p>Con una tabella così ricca, di queste dimensioni e pubblicata in questo formato, avere lo schema <code>SQL</code> di creazione renderebbe l’uso dei dati da subito molto più efficace.<br> Perché il <strong><code>CSV</code></strong> è principalmente un <strong>formato di scambio</strong>, e <strong>poterlo</strong> <strong>importare</strong> subito in un <strong><em>database</em></strong> dà una marcia in più.</p>
</section>
</section>
<section id="parquet" class="level2">
<h2 class="anchored" data-anchor-id="parquet">Parquet</h2>
<p>Il formato <code>CSV</code> - con i suoi pregi e difetti - è molto diffuso. Un <strong>formato tabellare</strong> degno di nota che <strong>sta emergendo</strong>, è il <a href="https://parquet.apache.org/"><strong>Parquet</strong></a>.</p>
<p>È un <strong>formato</strong> <strong><em>open source</em></strong> progettato per l’<strong>archiviazione</strong> e l’<strong>analisi</strong> di <strong>grandi dataset</strong>.<br> Le principali caratteristiche sono:</p>
<ul>
<li><strong>Struttura a colonne</strong>: i dati sono memorizzati per colonna e non per riga, per una migliore compressione;</li>
<li><strong>Compressione efficace</strong>: supporta compressione <code>gzip</code>, <code>snappy</code> e <code>zstd</code>;</li>
<li><strong>Prestazioni elevate</strong>: consente analisi molto veloci grazie alla struttura a colonne;</li>
<li><strong>Formato descritto</strong>: contiene metadati sullo schema;</li>
<li><strong>Partizionabile</strong>: un unico dataset di dimensioni molto molto grandi, può essere suddiviso in più file e cartelle, partizionate (ad esempio per anno, per regione, per provincia, ecc.);</li>
<li><strong>Accessibile in <em>stream</em></strong>: invece di leggere o scrivere l’intero file in una volta sola, consente di lavorare con il file suddividendo i dati in pacchetti più piccoli;</li>
<li><strong>Supportato</strong> da molti <strong><em>data engine</em></strong> e da tutti i principali linguaggi di programmazione e librerie di elaborazione dati.</li>
</ul>
<p>Tra le più interessanti, specie per chi è nuovo al concetto e al formato, è la struttura di archiviazione a colonne.</p>
<section id="formato-colonnare" class="level3">
<h3 class="anchored" data-anchor-id="formato-colonnare">Formato colonnare</h3>
<p>In molti dei formati tabellari più noti e comuni, i dati sono archiviati come sequenze di righe. Avviene per i <code>CSV</code>, ma anche per importanti database relazionali come <code>PostgreSQL</code> e <code>MySQL</code>.</p>
<div id="tbl-parquet_colonne_start" class="striped responsive small quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-parquet_colonne_start-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Tabella&nbsp;2: Tabella dati di esempio
</figcaption>
<div aria-describedby="tbl-parquet_colonne_start-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="table-responsive">
<table class="table-striped small table-sm caption-top table">
<thead>
<tr class="header">
<th>Pizza</th>
<th>Cliente</th>
<th>Regione</th>
<th>Data</th>
<th>Costo</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Margherita</td>
<td>Marco Stretto</td>
<td>Sicilia</td>
<td>2023-01-01</td>
<td>5</td>
</tr>
<tr class="even">
<td>Parmigiana</td>
<td>Marco Stretto</td>
<td>Sicilia</td>
<td>2023-01-02</td>
<td>9</td>
</tr>
<tr class="odd">
<td>Romana</td>
<td>Guido La Vespa</td>
<td>Calabria</td>
<td>2023-01-01</td>
<td>7</td>
</tr>
<tr class="even">
<td>Romana</td>
<td>Chiara Mente</td>
<td>Sicilia</td>
<td>2023-01-03</td>
<td>7</td>
</tr>
<tr class="odd">
<td>Parmigiana</td>
<td>Guido La Vespa</td>
<td>Calabria</td>
<td>2023-01-02</td>
<td>9</td>
</tr>
<tr class="even">
<td>Romana</td>
<td>Marco Stretto</td>
<td>Sicilia</td>
<td>2023-01-05</td>
<td>7</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
<p>A partire da una tabella con dei dati sulle vendite di una pizzeria, come Tabella&nbsp;2, le domande che si potrebbero fare sono:</p>
<ul>
<li>quante pizze Margherita sono state vendute?</li>
<li>quanti utenti che vengono dalla Sicilia hanno ordinato una pizza Parmigiana?</li>
<li>quanto ha speso in totale Guido La Vespa?</li>
<li>quante vendite sono state fatte il 2 gennaio 2023?</li>
</ul>
<p>Per rispondere a queste domande, un motore di “tabelle” basato su righe, dovrà leggere tutte le righe della tabella, dall’inizio alla fine. Per sapere quanti utenti che vengono dalla Sicilia hanno ordinato una pizza Parmigiana, si dovrà scorrere la tabella come in Figura&nbsp;1.</p>
<div id="fig-row-based" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-row-based-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/duckdb-intro-csv/images/row-based.png" class="img-fluid figure-img" style="width:100.0%">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-row-based-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;1: Flusso lettura dati, in archivi basati su righe
</figcaption>
</figure>
</div>
<p>Basterebbe leggere soltanto i valori delle colonne <code>Pizza</code> e <code>Regione</code>, ma in uno schema di archiviazione basato su righe vengono lette anche le altre colonne.</p>
<p>Per rispondere a questa <em>query</em> è molto più efficiente un’<strong>archiviazione a colonne</strong>.<br> In questo caso, ogni colonna è un’entità, il che significa che ogni colonna è fisicamente separata dalle altre. <br> Tornando alla nostra precedente domanda: in uno schema a colonne il motore di analisi può leggere soltanto le colonne necessarie per la <em>query</em> (<code>Pizza</code> e <code>Regione</code>). E, nella maggior parte dei casi, questo migliorerà le prestazioni delle <em>query</em> analitiche.</p>
<table class="striped-table small table-sm caption-top table">
<thead>
<tr class="header">
<th>Pizza</th>
<th>Cliente</th>
<th>Regione</th>
<th>Data</th>
<th>Costo</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Margherita</td>
<td>Marco Stretto</td>
<td>Sicilia</td>
<td>2023-01-01</td>
<td>5</td>
</tr>
<tr class="even">
<td>Parmigiana</td>
<td>Marco Stretto</td>
<td>Sicilia</td>
<td>2023-01-02</td>
<td>9</td>
</tr>
<tr class="odd">
<td>Romana</td>
<td>Guido La Vespa</td>
<td>Calabria</td>
<td>2023-01-01</td>
<td>7</td>
</tr>
<tr class="even">
<td>Romana</td>
<td>Chiara Mente</td>
<td>Sicilia</td>
<td>2023-01-03</td>
<td>7</td>
</tr>
<tr class="odd">
<td>Parmigiana</td>
<td>Guido La Vespa</td>
<td>Calabria</td>
<td>2023-01-02</td>
<td>9</td>
</tr>
<tr class="even">
<td>Romana</td>
<td>Marco Stretto</td>
<td>Sicilia</td>
<td>2023-01-05</td>
<td>7</td>
</tr>
</tbody>
</table>
<p>Il formato <code>Parquet</code> è proprio un <strong>formato</strong> di <strong>archiviazione</strong> a <strong>colonne</strong>, anzi è più correttamente un formato di archiviazione <strong>a colonne</strong>, <strong>per gruppi di righe</strong>.<br></p>
<div id="fig-row-groups" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-row-groups-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/duckdb-intro-csv/images/row-groups.png" class="img-fluid figure-img" style="width:100.0%">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-row-groups-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;2: Struttura a colonne per gruppi di righe
</figcaption>
</figure>
</div>
<p>Le colonne sono memorizzate sempre come unità separate, ma Parquet introduce delle strutture aggiuntive chiamate “<strong><em>Row group</em></strong>” (vedi Figura&nbsp;2).</p>
<p>Perché sono un vantaggio? Nella <em>query</em> di esempio di sopra, non solo bastano due colonne, ma il <code>Gruppo 2</code> di righe è inutile (non c’è la “Parmigiana”).<br> Con questa struttura a gruppi di righe (qui semplificata per fini didattici) sarà possibile non tenere conto del “Gruppo 2” e la <em>query</em> sarà più rapida.</p>
<div id="fig-row-groups-skip" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-row-groups-skip-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/duckdb-intro-csv/images/row-groups-skip.png" class="img-fluid figure-img" style="width:100.0%">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-row-groups-skip-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;3: Per la <em>query</em> di esempio, il “Gruppo 2” è inutile
</figcaption>
</figure>
</div>
</section>
<section id="convertire-il-file-di-opencoesione-in-parquet" class="level3">
<h3 class="anchored" data-anchor-id="convertire-il-file-di-opencoesione-in-parquet">Convertire il file di OpenCoesione in Parquet</h3>
<p>Per convertire il file di OpenCoesione in formato <code>Parquet</code> si può usare ancora una volta un comando <strong>DuckDB</strong>.<br> Richiederà una ricca descrizione del file di <em>input</em>, e di base sarà <code>COPY INPUT TO OUTPUT</code> (documentazione <a href="https://duckdb.org/docs/archive/0.8.1/sql/statements/copy"><code>COPY</code></a>):</p>
<ul>
<li>l’<code>INPUT</code> è il “SELEZIONA TUTTO” del file <code>CSV</code> compresso originario, applicando le dovute operazioni di <em>casting</em> dei tipi di campo;</li>
<li>poi è necessario descrivere il <code>CSV</code> di <em>input</em> (i separatori, il formato dei campi con date, l’intestazione, i tipi di campo, ecc.);</li>
<li>infine, si definisce il <code>TO</code> scegliendo un nome per il file di <em>output</em> e alcune <a href="https://duckdb.org/docs/archive/0.8.1/sql/statements/copy#parquet-options">opzioni di formato</a>.</li>
</ul>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-13-contents" aria-controls="callout-13" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Comando da usare per la conversione da CSV a Parquet
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-13" class="callout-13-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<div class="sourceCode" id="cb8" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb8-1"><span class="bu" style="color: null;
background-color: null;
font-style: inherit;">echo</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"COPY (SELECT *</span></span>
<span id="cb8-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">REPLACE(</span></span>
<span id="cb8-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_1 AS FLOAT) AS PROGRAMMATO_INDICATORE_1,</span></span>
<span id="cb8-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_2 AS FLOAT) AS PROGRAMMATO_INDICATORE_2,</span></span>
<span id="cb8-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_3 AS FLOAT) AS PROGRAMMATO_INDICATORE_3,</span></span>
<span id="cb8-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_4 AS FLOAT) AS PROGRAMMATO_INDICATORE_4,</span></span>
<span id="cb8-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_1 AS FLOAT) AS REALIZZATO_INDICATORE_1,</span></span>
<span id="cb8-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_2 AS FLOAT) AS REALIZZATO_INDICATORE_2,</span></span>
<span id="cb8-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_3 AS FLOAT) AS REALIZZATO_INDICATORE_3,</span></span>
<span id="cb8-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_4 AS FLOAT) AS REALIZZATO_INDICATORE_4,</span></span>
<span id="cb8-11"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb8-12"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">from read_csv_auto(</span></span>
<span id="cb8-13"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'progetti_esteso_20230430.csv.gz',SEP=';',dateformat='%Y%m%d',decimal_separator=',',sample_size=100000,</span></span>
<span id="cb8-14"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">types={'OC_COD_ARTICOLAZ_PROGRAMMA':'VARCHAR','FINANZ_UE':'FLOAT','FINANZ_UE_FESR':'FLOAT','FINANZ_UE_FSE':'FLOAT','FINANZ_UE_FEASR':'FLOAT','FINANZ_UE_FEAMP':'FLOAT','FINANZ_UE_IOG':'FLOAT','FINANZ_STATO_FONDO_DI_ROTAZIONE':'FLOAT','FINANZ_STATO_FSC':'FLOAT','FINANZ_STATO_PAC':'FLOAT','FINANZ_STATO_COMPLETAMENTI':'FLOAT','FINANZ_STATO_ALTRI_PROVVEDIMENTI':'FLOAT','FINANZ_REGIONE':'FLOAT','FINANZ_PROVINCIA':'FLOAT','FINANZ_COMUNE':'FLOAT','FINANZ_RISORSE_LIBERATE':'FLOAT','FINANZ_ALTRO_PUBBLICO':'FLOAT','FINANZ_STATO_ESTERO':'FLOAT','FINANZ_PRIVATO':'FLOAT','FINANZ_DA_REPERIRE':'FLOAT','FINANZ_TOTALE_PUBBLICO':'FLOAT','ECONOMIE_TOTALI':'FLOAT','ECONOMIE_TOTALI_PUBBLICHE':'FLOAT','OC_FINANZ_UE_NETTO':'FLOAT','OC_FINANZ_UE_FESR_NETTO':'FLOAT','OC_FINANZ_UE_FSE_NETTO':'FLOAT','OC_FINANZ_UE_FEASR_NETTO':'FLOAT','OC_FINANZ_UE_FEAMP_NETTO':'FLOAT','OC_FINANZ_UE_IOG_NETTO':'FLOAT','OC_FINANZ_STATO_FONDO_ROT_NETTO':'FLOAT','OC_FINANZ_STATO_FSC_NETTO':'FLOAT','OC_FINANZ_STATO_PAC_NETTO':'FLOAT','OC_FINANZ_STATO_COMPL_NETTO':'FLOAT','OC_FINANZ_STATO_ALTRI_PROV_NETTO':'FLOAT','OC_FINANZ_REGIONE_NETTO':'FLOAT','OC_FINANZ_PROVINCIA_NETTO':'FLOAT','OC_FINANZ_COMUNE_NETTO':'FLOAT','OC_FINANZ_RISORSE_LIBERATE_NETTO':'FLOAT','OC_FINANZ_ALTRO_PUBBLICO_NETTO':'FLOAT','OC_FINANZ_STATO_ESTERO_NETTO':'FLOAT','OC_FINANZ_PRIVATO_NETTO':'FLOAT','OC_FINANZ_TOT_PUB_NETTO':'FLOAT','OC_COSTO_COESIONE':'FLOAT','IMPEGNI':'FLOAT','OC_IMPEGNI_GIURID_VINCOLANTI':'FLOAT','OC_IMPEGNI_TRASFERIMENTI':'FLOAT','OC_IMPEGNI_COESIONE':'FLOAT','TOT_PAGAMENTI':'FLOAT','OC_TOT_PAGAMENTI_BENEFICIARI':'FLOAT','OC_TOT_PAGAMENTI_TRASFERIMENTI':'FLOAT','COSTO_REALIZZATO':'FLOAT','COSTO_RENDICONTABILE_UE':'FLOAT','OC_TOT_PAGAMENTI_RENDICONTAB_UE':'FLOAT','OC_TOT_PAGAMENTI_FSC':'FLOAT','OC_TOT_PAGAMENTI_PAC':'FLOAT','OC_PAGAMENTI_COESIONE':'FLOAT','OC_DATA_INIZIO_PROGETTO':'DATE','OC_DATA_FINE_PROGETTO_PREVISTA':'DATE','OC_DATA_FINE_PROGETTO_EFFETTIVA':'DATE','DATA_INIZIO_PREV_STUDIO_FATT':'DATE','DATA_INIZIO_EFF_STUDIO_FATT':'DATE','DATA_FINE_PREV_STUDIO_FATT':'DATE','DATA_FINE_EFF_STUDIO_FATT':'DATE','DATA_INIZIO_PREV_PROG_PREL':'DATE','DATA_INIZIO_EFF_PROG_PREL':'DATE','DATA_FINE_PREV_PROG_PREL':'DATE','DATA_FINE_EFF_PROG_PREL':'DATE','DATA_INIZIO_PREV_PROG_DEF':'DATE','DATA_INIZIO_EFF_PROG_DEF':'DATE','DATA_FINE_PREV_PROG_DEF':'DATE','DATA_FINE_EFF_PROG_DEF':'DATE','DATA_INIZIO_PREV_PROG_ESEC':'DATE','DATA_INIZIO_EFF_PROG_ESEC':'DATE','DATA_FINE_PREV_PROG_ESEC':'DATE','DATA_FINE_EFF_PROG_ESEC':'DATE','DATA_INIZIO_PREV_AGG_BANDO':'DATE','DATA_INIZIO_EFF_AGG_BANDO':'DATE','DATA_FINE_PREV_AGG_BANDO':'DATE','DATA_FINE_EFF_AGG_BANDO':'DATE','DATA_INIZIO_PREV_STIP_ATTRIB':'DATE','DATA_INIZIO_EFF_STIP_ATTRIB':'DATE','DATA_FINE_PREV_STIP_ATTRIB':'DATE','DATA_FINE_EFF_STIP_ATTRIB':'DATE','DATA_INIZIO_PREV_ESECUZIONE':'DATE','DATA_INIZIO_EFF_ESECUZIONE':'DATE','DATA_FINE_PREV_ESECUZIONE':'DATE','DATA_FINE_EFF_ESECUZIONE':'DATE','DATA_INIZIO_PREV_COLLAUDO':'DATE','DATA_INIZIO_EFF_COLLAUDO':'DATE','DATA_FINE_PREV_COLLAUDO':'DATE','DATA_FINE_EFF_COLLAUDO':'DATE','COD_TIPO_PROCED_ATTIVAZIONE':'VARCHAR','OC_FLAG_REGIONE_UNICA':'INT','DATA_AGGIORNAMENTO':'DATE','OC_FLAG_CUP':'INT','PROGRAMMATO_INDICATORE_1':'VARCHAR','REALIZZATO_INDICATORE_1':'VARCHAR','PROGRAMMATO_INDICATORE_2':'VARCHAR','REALIZZATO_INDICATORE_2':'VARCHAR','PROGRAMMATO_INDICATORE_3':'VARCHAR','REALIZZATO_INDICATORE_3':'VARCHAR','PROGRAMMATO_INDICATORE_4':'VARCHAR','REALIZZATO_INDICATORE_4':'VARCHAR'}</span></span>
<span id="cb8-15"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)) TO 'progetti_esteso_20230430.parquet' (FORMAT 'PARQUET', CODEC 'ZSTD');"</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span>  <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span></span></code></pre></div>
</div>
</div>
</div>
<p>Con <code>(FORMAT 'PARQUET', CODEC 'ZSTD')</code> si imposta il <code>PARQUET</code> come formato di output e <code>ZSTD</code> come algoritmo di compressione.</p>
</section>
<section id="è-come-avere-delle-api" class="level3">
<h3 class="anchored" data-anchor-id="è-come-avere-delle-api">È come avere delle API</h3>
<p>Il formato <code>parquet</code> - accoppiato a <em>client</em> come DuckDB - rende <strong>facile</strong> e <strong>universale</strong> l’accesso ai dati. Questo perché, una volta che un file è pubblico sul web (in <code>HTTPS</code>, come <code>S3</code>, ecc.), si ha a disposizione un’<strong>interfaccia <code>SQL</code></strong> per interrogarlo, in <strong>modalità <code>streaming</code></strong>, ovvero rendendo disponibili solo le porzioni di dati necessarie per rispondere alle <em>query</em>, invece che tutto il file.</p>
<p>È un po’ come <strong>avere delle API</strong>, ma senza doverle creare. E, da utente, senza dovere studiare una nuova documentazione di API, perché basta conoscere l’“universale” <code>SQL</code> e accedere al file <code>parquet</code> dal linguaggio di <em>scripting</em> e/o <em>client</em> preferiti.</p>
<p>Mi spiego con un esempio, basato sui <a href="https://www.italiadomani.gov.it/content/sogei-ng/it/it/catalogo-open-data/Universo_ReGiS_Progetti.html">dati sui progetti del PNRR</a>. È un dataset “piccolo” (200.000 righe per 50 colonne), ma mi è comodo qui a fini didattici.<br> Voglio sapere per ogni Missione, il numero dei progetti e il valore del finanziamento PNRR (in euro).<br> Usando come client DuckDB, e abilitando l’estensione <code>httpfs</code> (vedi sezione estensioni), basta conoscere l’URL del file e lanciare questa <em>query</em>:</p>
<div class="sourceCode" id="cb9" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb9-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<span id="cb9-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SELECT "Descrizione Missione" missione,COUNT(*) numero_progetti,</span></span>
<span id="cb9-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SUM("Finanziamento PNRR") finanziamento_pnrr</span></span>
<span id="cb9-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">FROM "https://raw.githubusercontent.com/aborruso/aborruso.github.io//main/posts/duckdb-intro-csv/file/PNRR_Progetti-Universo_REGIS_v2.1.parquet"</span></span>
<span id="cb9-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">GROUP by "Descrizione Missione"</span></span>
<span id="cb9-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">ORDER BY finanziamento_pnrr desc;</span></span>
<span id="cb9-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span></code></pre></div>
<p>E in circa 1 secondo (al primo lancio e in molto meno dal secondo in poi) ottengo:</p>
<div id="tbl-parquet-api" class="striped responsive small quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-parquet-api-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Tabella&nbsp;3: Output della <em>query</em>
</figcaption>
<div aria-describedby="tbl-parquet-api-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="table-responsive">
<table class="table-striped small table-sm caption-top table">
<colgroup>
<col style="width: 27%">
<col style="width: 36%">
<col style="width: 36%">
</colgroup>
<thead>
<tr class="header">
<th>missione</th>
<th style="text-align: right;">numero_progetti</th>
<th style="text-align: right;">finanziamento_pnrr</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>Rivoluzione verde e transizione ecologica</td>
<td style="text-align: right;">49621</td>
<td style="text-align: right;">22688516407.240803</td>
</tr>
<tr class="even">
<td>Infrastrutture per una mobilità sostenibile</td>
<td style="text-align: right;">206</td>
<td style="text-align: right;">22563735313.390625</td>
</tr>
<tr class="odd">
<td>Istruzione e ricerca</td>
<td style="text-align: right;">65403</td>
<td style="text-align: right;">20129269029.008453</td>
</tr>
<tr class="even">
<td>Digitalizzazione, innovazione, competitività e cultura</td>
<td style="text-align: right;">63025</td>
<td style="text-align: right;">19245334466.823135</td>
</tr>
<tr class="odd">
<td>Inclusione e coesione</td>
<td style="text-align: right;">11764</td>
<td style="text-align: right;">12998257338.579054</td>
</tr>
<tr class="even">
<td>Salute</td>
<td style="text-align: right;">7527</td>
<td style="text-align: right;">8059988416.008047</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
<p>E posso farlo anche da una <a href="https://shell.duckdb.org/">pagina web</a> che includa DuckDb come <em>WebAssembly</em> (vedi Figura&nbsp;4).</p>
<div id="fig-duckdb-wasm" class="quarto-float quarto-figure quarto-figure-center anchored" width="100%">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-duckdb-wasm-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="https://shell.duckdb.org/"><img src="https://aborruso.github.io/posts/duckdb-intro-csv/images/ddb-wasm.png" class="img-fluid figure-img" style="width:100.0%"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-duckdb-wasm-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;4: Il client DuckDB come modulo WASM
</figcaption>
</figure>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Non è la soluzione definitiva
</div>
</div>
<div class="callout-body-container callout-body">
<p>Questa dei file statici in formato <code>parquet</code> non è la soluzione definitiva per abilitare l’accesso ai dati in modo programmatico, in applicazioni web. Fino ad alcuni milioni di righe ha delle <em>performance</em> buone, poi diventa un po’ lento. E ci sono modalità più ottimizzate per richieste transazionali o atomiche, per dati relazionali con schemi complessi, per dataset “privati” con controllo granulare degli accessi, e per dati in rapido cambiamento.</p>
</div>
</div>
</section>
<section id="affiancarlo-ai-file-csv" class="level3">
<h3 class="anchored" data-anchor-id="affiancarlo-ai-file-csv">Affiancarlo ai file CSV</h3>
<p>Il formato <code>parquet</code> - per alcune delle sue caratteristiche - <strong>potrebbe</strong> <strong>affiancare</strong> (e alla lunga <strong>rimpiazzare</strong>?) il <strong><code>CSV</code></strong>, come formato di <strong>pubblicazione</strong> di <strong>dati aperti</strong>.<br></p>
<p>In contesti applicativi in cui le <em>performance</em>, lo spazio di archiviazione, le modalità di accesso sono parametri da tenere in alta considerazione, è già molto usato.<br> Un esempio per tutti è quello dei dataset di <a href="https://huggingface.co/datasets">Hugging Face</a>.</p>
<p>I dati aperti globali sugli edifici del progetto <a href="https://github.com/microsoft/GlobalMLBuildingFootprints/">GlobalMLBuildingFootprints</a> (1.2 miliardi di edifici), sono in formato parquet, nella sua estensione spaziale.<br> Anche i dataset geografici del progetto <a href="https://overturemaps.org/download/">Overture Maps Foundation</a>, sono in formato parquet.<br> I dati aperti sulle <a href="https://www.nyc.gov/site/tlc/about/tlc-trip-record-data.page">corse di taxi e veicoli con conducente di New York</a>, sono anch’essi in questo formato.</p>
<p>L’ultimo esempio, per chiudere in bellezza, è quello dell’impareggiabile <a href="https://www.data.gouv.fr/"><strong>portale Open Data della Francia</strong></a>.<br> Pubblica un dataset in formato <code>parquet</code>, sono disponibili gli URL statici dei file, ed è possibile fare <em>query</em> in modo comodissimo, come se fossero disponibili delle API.<br> Ad esempio posso interrogare il <a href="https://www.data.gouv.fr/fr/datasets/bureaux-de-vote-et-adresses-de-leurs-electeurs/">file da 470 MB degli indirizzi</a>, di 15 milioni di righe, per avere il numero di indirizzi per comune con questa semplicità (vedi Lista&nbsp;4):</p>
<div id="lst-query-francia" class="bash listing quarto-float quarto-figure quarto-figure-left anchored">
<figure class="quarto-float quarto-float-lst figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-lst" id="lst-query-francia-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Lista&nbsp;4: Esempio di <em>query</em> da <em>shell</em>
</figcaption>
<div aria-describedby="lst-query-francia-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="sourceCode" id="lst-query-francia" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="lst-query-francia-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<span id="lst-query-francia-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">load httpfs;</span></span>
<span id="lst-query-francia-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SELECT code_commune_ref, sum(nb_adresses) sum</span></span>
<span id="lst-query-francia-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">FROM "https://static.data.gouv.fr/resources/bureaux-de-vote-et-adresses-de-leurs-electeurs/20230626-135723/table-adresses-reu.parquet"</span></span>
<span id="lst-query-francia-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">GROUP BY ALL ORDER by 2 DESC LIMIT 10;</span></span>
<span id="lst-query-francia-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span></code></pre></div>
</div>
</figure>
</div>
<p>E in pochi secondi si ha restituito il risultato (vedi Figura&nbsp;5).</p>
<div id="fig-portale-opendata-francia" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-portale-opendata-francia-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/duckdb-intro-csv/images/portale-opendata-francia.png" class="img-fluid figure-img" style="width:100.0%">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-portale-opendata-francia-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;5: Output da shell
</figcaption>
</figure>
</div>
</section>
</section>
<section id="duckdb" class="level2">
<h2 class="anchored" data-anchor-id="duckdb">DuckDB</h2>
<p><strong>DuckDB</strong> è lo strumento più usato in questo post, perché riesce a fare utilizzare comodamente dati <code>CSV</code> brutti, sporchi, cattivi e “grossi”, e anche renderli belli (con una conversione in formato <code>parquet</code>).</p>
<p>È un <strong>database relazionale <em>embedded</em></strong> e <strong><em>open source</em></strong> <strong>leggero</strong> e <strong>veloce</strong>, di facilissima installazione e gestione.<br> È progettato per l’<a href="https://duckdb.org/why_duckdb.html#duckdbisfast"><strong>analisi rapida di dati</strong></a> ed è basato su uno schema di archiviazione a colonne (vedi spiegazione correlata per il formato <code>parquet</code>).</p>
<p>È scritto in <code>C++</code>, ha un’interfaccia <code>SQL</code> standard, ed è <a href="https://duckdb.org/why_duckdb.html#duckdbissimple">integrabile facilmente</a> in qualsiasi ambiente di lavoro (API per Python, R, Java, Julia, Swift, ecc.).</p>
<p>Per le sue caratteristiche e per l’uso che si fa tipicamente dei dati, ha contribuito a far emergere la frase “<a href="https://motherduck.com/blog/big-data-is-dead/"><strong>Big data is dead</strong></a>” (leggilo è molto interessante):</p>
<ul>
<li>I sistemi moderni possono gestire anche dati molto grandi in modo efficace ed economico.</li>
<li>La maggior parte delle aziende ha pochi GB/TB di dati, non i PB prospettati dal marketing di alcune soluzioni.</li>
<li><em>Storage</em> e <em>computing</em> sono separati, ma lo <em>storage</em> tende ad aumentare più velocemente del <em>computing</em> richiesto.</li>
<li>Le query analitiche usano di solito solo una piccola parte dei dataset, i record più recenti.</li>
<li>Alcuni dati invecchiano velocemente, dopo poco tempo sono interrogati raramente e possono diventare un onere.</li>
<li>Bisognerebbe dimostrare che i dataset rimangono realmente rilevanti anziché accumularli senza motivo.</li>
</ul>
<p>DuckDB è “tanta roba” e sul <a href="https://duckdb.org/">sito ufficiale</a> è tutto molto ben documentato.</p>
<p>Qui voglio sottolineare alcune cose che, da piccolo utente, mi sono piaciute molto.</p>
<section id="facilità-di-installazione-e-utilizzo" class="level3">
<h3 class="anchored" data-anchor-id="facilità-di-installazione-e-utilizzo">Facilità di installazione e utilizzo</h3>
<p>La <a href="https://duckdb.org/docs/installation/index">pagina dedicata</a> è molto comoda:</p>
<ol type="1">
<li>si sceglie la versione;</li>
<li>l’ambiente e le modalità di lavoro (io lo utilizzo soprattutto a riga di comando, come <code>CLI</code>);</li>
<li>la piattaforma;</li>
<li>vengono restituite le istruzioni per l’installazione.</li>
</ol>
<p>E in pochissimo tempo si è pronti all’uso.</p>
<div id="fig-duckdb-install" class="quarto-float quarto-figure quarto-figure-center anchored" width="100%">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-duckdb-install-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<a href="https://duckdb.org/docs/installation/index"><img src="https://aborruso.github.io/posts/duckdb-intro-csv/images/duckdb_install.png" class="img-fluid figure-img" style="width:100.0%"></a>
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-duckdb-install-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;6: Pagina di installazione di DuckDB
</figcaption>
</figure>
</div>
</section>
<section id="le-estensioni" class="level3">
<h3 class="anchored" data-anchor-id="le-estensioni">Le estensioni</h3>
<p>DuckDB ha delle <a href="https://duckdb.org/docs/archive/0.8.1/extensions/overview"><strong>estensioni</strong></a> che ne estendono in modo molto interessante l’utilizzo.</p>
<p>Tre che ho trovato subito utilissime sono:</p>
<ul>
<li><a href="https://duckdb.org/docs/extensions/httpfs"><code>httpfs</code></a>, per leggere file <code>CSV</code> e <code>parquet</code> direttamente da indirizzi <code>HTTP(S)</code> (è come avere delle API) o tramite <code>S3</code>;</li>
<li><a href="https://duckdb.org/docs/extensions/json"><code>json</code></a>, che implementa funzioni per lavorare con dati in formato <code>JSON</code>;</li>
<li><a href="https://duckdb.org/docs/extensions/spatial"><code>spatial</code></a>, per usare DuckDB come motore di analisi spaziali/geografiche.</li>
</ul>
<p>E con l’estensione <code>httpfs</code> e con dati CSV pubblicati in modo “standard” (come <a href="https://github.com/pcm-dpc/COVID-19">quelli sulla COVID-19</a> pubblicati dalla Protezione Civile), è ad esempio possibile avere restituito comodamente e rapidamente la <strong>media mobile settimanale</strong> dei nuovi casi <strong>COVID-19</strong> <strong>per regione</strong>, puntando semplicemente all’URL di un file statico (DuckDB supporta una sintassi <code>SQL</code>, dove il <code>FROM</code> può essere inserito all’inizio):</p>
<div class="sourceCode" id="cb10" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb10-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span>  <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"FROM read_csv_auto('https://raw.githubusercontent.com/pcm-dpc/COVID-19/master/dati-regioni/dpc-covid19-ita-regioni.csv')</span></span>
<span id="cb10-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SELECT denominazione_regione,data,nuovi_positivi,AVG(nuovi_positivi)</span></span>
<span id="cb10-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">OVER (</span></span>
<span id="cb10-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  PARTITION BY denominazione_regione</span></span>
<span id="cb10-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  ORDER BY data</span></span>
<span id="cb10-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  RANGE BETWEEN INTERVAL 7 DAYS PRECEDING</span></span>
<span id="cb10-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  AND INTERVAL 0 DAYS FOLLOWING</span></span>
<span id="cb10-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  ) AS media_mobile</span></span>
<span id="cb10-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">ORDER BY 1,2;"</span></span></code></pre></div>
<p>Come se fosse un’API.</p>
<p>E per dare un’idea dell’<a href="https://github.com/duckdblabs/duckdb_spatial">estensione spaziale</a>, un piccolo esempio, per creare due punti, unirli in una linea, calcolare il centroide di questa ed estrarne la coordinata <code>x</code>:</p>
<div class="sourceCode" id="annotated-cell-8" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-annotation-code code-with-copy code-annotated"><code class="sourceCode bash"><button class="code-annotation-anchor" data-target-cell="annotated-cell-8" data-target-annotation="1">1</button><span id="annotated-cell-8-1" class="code-annotation-target"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'load spatial;</span></span>
<span id="annotated-cell-8-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SELECT ST_X(</span></span>
<span id="annotated-cell-8-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">  ST_Centroid(</span></span>
<span id="annotated-cell-8-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    ST_MakeLine(</span></span>
<span id="annotated-cell-8-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      ST_POINT(42.3471, 14.8454),ST_POINT(42.1471, 13.8454)</span></span>
<span id="annotated-cell-8-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">      )</span></span>
<span id="annotated-cell-8-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">    )</span></span>
<span id="annotated-cell-8-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">) test;'</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div>
<dl class="code-annotation-container-hidden code-annotation-container-grid">
<dt data-target-cell="annotated-cell-8" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-8" data-code-lines="1" data-code-annotation="1">carica l’estensione spaziale</span>
</dd>
</dl>
<p>A schermo si avrà <code>42.2471</code>.</p>
</section>
<section id="un-sql-più-comodo" class="level3">
<h3 class="anchored" data-anchor-id="un-sql-più-comodo">Un SQL più comodo</h3>
<p>DuckDB supporta un <code>SQL</code> che mette di buon umore. Alcuni esempi.</p>
<p>Se ho una tabella con 199 colonne, come quella dei progetti di OpenCoesione, e voglio selezionarle tutte tranne due, dovrei scrivere per esteso le 196 che voglio. Qui posso usare <code>EXCLUDE</code> e scrivere soltanto le due che non voglio:</p>
<div class="sourceCode" id="cb11" style="background: #f1f3f5;"><pre class="sourceCode sql code-overflow-wrap code-with-copy"><code class="sourceCode sql"><span id="cb11-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> EXCLUDE (codice_progetto, codice_progetto_originale) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> progetti;</span></code></pre></div>
<p>Lo stesso avviene nel comune <code>SQL</code>, quando devo applicare delle modifiche soltanto a una parte dei campi di una tabella. Qui ho <code>REPLACE</code>:</p>
<div class="sourceCode" id="cb12" style="background: #f1f3f5;"><pre class="sourceCode sql code-overflow-wrap code-with-copy"><code class="sourceCode sql"><span id="cb12-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">REPLACE</span> (FINANZ_TOTALE_PUBBLICO<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">/</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">100</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">AS</span> FINANZ_NORM) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> miatabella;</span></code></pre></div>
<p>Ma il <code>SQL</code> “speciale” di DuckDB che mi ha fatto più piacere usare è il <code>GROUP BY ALL</code>. Normalmente, infatti specificare le colonne sia nella clausola <code>SELECT</code> che nella clausola <code>GROUP BY</code>. Qui, con <code>GROUP BY ALL</code>, il raggruppamento viene fatto per tutte le colonne nella clausola SELECT che non sono incluse in una funzione di aggregazione.</p>
<div class="sourceCode" id="cb13" style="background: #f1f3f5;"><pre class="sourceCode sql code-overflow-wrap code-with-copy"><code class="sourceCode sql"><span id="cb13-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> missione,regione, <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">COUNT</span>(<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span>) numero_progetti</span>
<span id="cb13-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> progetti</span>
<span id="cb13-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">GROUP</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">BY</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">ALL</span></span></code></pre></div>
<p>E in modo simile funziona l’<code>ORDER BY ALL</code>.</p>
<p>In molti dialetti <code>SQL</code>, non è possibile utilizzare un alias definito nella clausola <code>SELECT</code> in nessun altro punto, tranne che nella clausola <code>ORDER BY</code> di quella stessa <em>query</em>. Questo spesso porta a lunghe <em>subquery</em>.<br>In DuckDB, un alias non di aggregazione nella clausola <code>SELECT</code> può essere immediatamente utilizzato nelle clausole <code>WHERE</code> e <code>GROUP BY</code>, mentre gli alias di aggregazione possono essere utilizzati nella clausola <code>HAVING</code>. Nessuna <em>subquery</em> necessaria!</p>
<p>È possibile fare lo <em>slicing</em> delle stringhe in modo simile ai linguaggi di scripting, senza necessariamente usare <code>SUBSTRING</code>:</p>
<div class="sourceCode" id="cb14" style="background: #f1f3f5;"><pre class="sourceCode sql code-overflow-wrap code-with-copy"><code class="sourceCode sql"><span id="cb14-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Quanto è bello DuckDB'</span>[:<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-</span><span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">7</span>] <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">as</span> slice;</span></code></pre></div>
<div class="sourceCode" id="cb15" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb15-1">┌────────────────┐</span>
<span id="cb15-2">│     slice      │</span>
<span id="cb15-3">├────────────────┤</span>
<span id="cb15-4">│ Quanto è bello │</span>
<span id="cb15-5">└────────────────┘</span></code></pre></div>
<p>E si potrebbero fare tanti altri esempi.</p>
</section>
<section id="integrazione-con-altri-ambienti" class="level3">
<h3 class="anchored" data-anchor-id="integrazione-con-altri-ambienti">Integrazione con altri ambienti</h3>
<p>Con l’estensione <code>sqlite</code>, legge un in modo diretto un <em>database</em> <code>sqlite</code>:<br></p>
<div class="sourceCode" id="cb16" style="background: #f1f3f5;"><pre class="sourceCode sql code-overflow-wrap code-with-copy"><code class="sourceCode sql"><span id="cb16-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> sqlite_scan(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'test.db'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'tbl_name'</span>);</span></code></pre></div>
<p>Con l’estensione spaziale legge file in formato <code>EXCEL</code>:</p>
<div class="sourceCode" id="cb17" style="background: #f1f3f5;"><pre class="sourceCode sql code-overflow-wrap code-with-copy"><code class="sourceCode sql"><span id="cb17-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> st_read(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'test_excel.xlsx'</span>, <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">layer</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'Sheet1'</span>);</span></code></pre></div>
<p>Con l’<a href="https://duckdb.org/docs/extensions/postgres_scanner">estensione <code>postgres</code></a>, legge un <em>database</em> <code>PostgreSQL</code>:</p>
<div class="sourceCode" id="cb18" style="background: #f1f3f5;"><pre class="sourceCode sql code-overflow-wrap code-with-copy"><code class="sourceCode sql"><span id="cb18-1"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">-- usando la stringa di connessione vuota, di default</span></span>
<span id="cb18-2"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">*</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">FROM</span> postgres_scan(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">''</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'public'</span>, <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'mytable'</span>);</span></code></pre></div>
<p>Le <a href="https://duckdb.org/docs/api/python/overview">API Python</a> portano la potenza di fuoco di DuckDB in modo molto comodo ed efficace dentro questo ambiente di lavoro.<br> E DuckDB può nativamente interrogare Pandas DataFrames, Polars DataFrames e tabelle Arrow.</p>
<div class="sourceCode" id="cb19" style="background: #f1f3f5;"><pre class="sourceCode python code-overflow-wrap code-with-copy"><code class="sourceCode python"><span id="cb19-1"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> duckdb</span>
<span id="cb19-2"></span>
<span id="cb19-3"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># directly query a Pandas DataFrame</span></span>
<span id="cb19-4"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pandas <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pd</span>
<span id="cb19-5">pandas_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pd.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'a'</span>: [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>]})</span>
<span id="cb19-6">duckdb.sql(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SELECT * FROM pandas_df'</span>)</span>
<span id="cb19-7"></span>
<span id="cb19-8"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># directly query a Polars DataFrame</span></span>
<span id="cb19-9"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> polars <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pl</span>
<span id="cb19-10">polars_df <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pl.DataFrame({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'a'</span>: [<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>]})</span>
<span id="cb19-11">duckdb.sql(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SELECT * FROM polars_df'</span>)</span>
<span id="cb19-12"></span>
<span id="cb19-13"><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"># directly query a pyarrow table</span></span>
<span id="cb19-14"><span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">import</span> pyarrow <span class="im" style="color: #00769E;
background-color: null;
font-style: inherit;">as</span> pa</span>
<span id="cb19-15">arrow_table <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> pa.Table.from_pydict({<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'a'</span>:[<span class="dv" style="color: #AD0000;
background-color: null;
font-style: inherit;">42</span>]})</span>
<span id="cb19-16">duckdb.sql(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'SELECT * FROM arrow_table'</span>)</span></code></pre></div>
<p>Ed è possibile usare DuckDB in <a href="https://duckdb.org/docs/api/r">R</a>, <a href="https://duckdb.org/docs/api/julia">Julia</a>, tramite <a href="https://duckdb.org/docs/api/odbc/overview">ODBC</a> e con tanti altri <a href="https://duckdb.org/docs/api/overview"><em>client</em></a>.</p>
</section>
<section id="duckdb-e-observable" class="level3">
<h3 class="anchored" data-anchor-id="duckdb-e-observable">DuckDB e Observable</h3>
<p>DuckDb è <a href="https://observablehq.com/@observablehq/duckdb">nativamente <strong>integrato</strong> in <strong>Observable</strong></a>. E questo gli consente di leggere in modo diretto file in formato CSV, JSON, Apache Arrow e Apache Parquet, e di sfruttare un potente motore di query SQL.</p>
<p>Prima si attiva il client, puntando alla risorsa di interesse:</p>
<div class="sourceCode" id="lst-duckdb-oservable" style="background: #f1f3f5;"><pre class="sourceCode javascript code-with-copy"><code class="sourceCode javascript"><span id="lst-duckdb-oservable-1">pnrrdb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DuckDBClient<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">of</span>({</span>
<span id="lst-duckdb-oservable-2">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">progetti</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">FileAttachment</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"PNRR_Progetti-Universo_REGIS_v2.1.parquet"</span>)</span>
<span id="lst-duckdb-oservable-3">})</span></code></pre></div>
<div class="cell">
<div class="sourceCode cell-code hidden" id="cb20" data-startfrom="681" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 680;"><span id="cb20-681">pnrrdb <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> DuckDBClient<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">of</span>({</span>
<span id="cb20-682">  <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">progetti</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">FileAttachment</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"file/PNRR_Progetti-Universo_REGIS_v2.1.parquet"</span>)</span>
<span id="cb20-683">})</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-1" data-nodetype="declaration">

</div>
</div>
</div>
<p>E poi si può usare il <em>client</em> Javascript DuckDB per fare una query <code>SQL</code>, da integrare ad esempio in una <a href="https://observablehq.com/@observablehq/input-table">tabella Observable</a>:</p>
<div class="cell responsive small">
<div class="sourceCode cell-code" id="cb21" data-startfrom="690" data-source-offset="0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 689;"><span id="cb21-690">Inputs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table</span>(</span>
<span id="cb21-691">  pnrrdb<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">sql</span><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">`SELECT Missione, SUM("Finanziamento PNRR") AS total_PNRR</span></span>
<span id="cb21-692"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  FROM progetti</span></span>
<span id="cb21-693"><span class="vs" style="color: #20794D;
background-color: null;
font-style: inherit;">  GROUP BY ALL`</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">locale</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"it-IT"</span>}</span>
<span id="cb21-694">)</span></code></pre></div>
<div class="cell-output cell-output-display">
<div id="ojs-cell-2" data-nodetype="expression">

</div>
</div>
</div>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Questa tabella
</div>
</div>
<div class="callout-body-container callout-body">
<p>Il codice Observable di esempio di sopra è eseguito al caricamento di questa pagina. E la tabella è proprio un esempio di <em>output live</em> (grazie al fatto che questo sito è basato su <a href="https://quarto.org/docs/interactive/ojs/">Quarto</a>). Questo per mostrarti quanto sia facile e diretto l’uso di DuckDB in Observable.<br> Nel codice per generare la tabella, <code>locale: "it-IT"</code> è per avere i numeri all’“italiana”, con il <code>.</code> come separatore delle migliaia e la <code>,</code> come separatore dei decimali.</p>
</div>
</div>
</section>
</section>
<section id="dati-opencoesione" class="level2">
<h2 class="anchored" data-anchor-id="dati-opencoesione">Dati OpenCoesione</h2>
<blockquote class="blockquote">
<p><a href="https://opencoesione.gov.it/"><strong>OpenCoesione</strong></a> è l’iniziativa nazionale di governo aperto (<em>open government</em>) sulle <strong>politiche di coesione</strong><sup>1</sup>, coordinata dal <strong>Dipartimento per le Politiche di Coesione</strong> della Presidenza del Consiglio dei Ministri. Nasce, nel 2012, per favorire un <strong>migliore uso</strong> delle <strong>risorse pubbliche</strong> attraverso la <strong>diffusione</strong> e il <strong>riutilizzo</strong> di <strong>dati</strong> e informazioni sugli <strong>interventi finanziati</strong> con risorse nazionali ed europee, che vengono pubblicati sul portale.</p>
</blockquote>
<p>Il portale contiene i dati “a partire dal ciclo 2000-2006 limitatamente ai programmi FSC (Fondo per lo Sviluppo e la Coesione) a titolarità regionale e dal ciclo 2007-2013 per quanto riguarda tutti i programmi nazionali ed europei, aggiornati con cadenza bimestrale”.</p>
<p>👏 È un progetto che <strong>ha fatto</strong> e <strong>fa scuola</strong>. E a proposito di “scuola”, non si può non citare il progetto “<a href="http://www.ascuoladiopencoesione.it/"><strong>A Scuola di OpenCoesione</strong></a>”, che ha coinvolto migliaia di scuole di tutta Italia, portando nelle classi, tra studenti e studentesse, insegnanti e famiglie, il tema della trasparenza e della partecipazione.</p>
<p>Nel portale è presente la <a href="https://opencoesione.gov.it/it/opendata/#!progetti_sie_section"><strong>sezione dei dati aperti</strong></a>, in cui il dataset più importante è quello dei <a href="https://opencoesione.gov.it/it/opendata/progetti_esteso.zip"><strong>Progetti con tracciato esteso</strong></a>.<br> Lo useremo come dataset di esempio, per mostrare come sia possibile lavorare comodamente con un file <code>CSV</code> di dimensioni “importanti” e di una certa complessità e ricchezza.</p>
<section id="esplorare-il-dataset" class="level3">
<h3 class="anchored" data-anchor-id="esplorare-il-dataset">Esplorare il dataset</h3>
<p>Il dataset <a href="https://opencoesione.gov.it/it/opendata/progetti_esteso.zip"><strong>Progetti con tracciato esteso</strong></a> (quello aggiornato al 30 aprile 2023) è un file <code>CSV</code> compresso in formato <code>ZIP</code> che pesa circa 200 MB; decompresso circa 4 GB e mezzo.</p>
<p>Lanciando <code>unzip -l progetti_esteso_20230430.zip</code> ottengo:</p>
<div class="sourceCode" id="cb22" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb22-1"><span class="an" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">Archive:</span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">  progetti_esteso_20230430.zip</span></span>
<span id="cb22-2">  Length      Date    Time    Name</span>
<span id="cb22-3">---------  ---------- -----   ----</span>
<span id="cb22-4">4541980767  2023-07-05 23:34   progetti_esteso_20230430.csv</span>
<span id="cb22-5">---------                     -------</span>
<span id="cb22-6">4541980767                     1 file</span></code></pre></div>
<p>È molto utile leggere qualche riga del <code>CSV</code>. Per farlo posso lanciare il comando di sotto, che invia il contenuto del file compresso all’<em>utility</em> <code>head</code>: mostra le prime 10 righe del file e si ferma.<br> Lo fa in 0.003 secondi - istantaneamente - perché <strong>il file non viene decompresso per intero</strong>, ma <strong>solo la parte che serve</strong> per mostrare le prime 10 righe.</p>
<div class="sourceCode" id="cb23" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb23-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unzip</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span> progetti_esteso_20230430.zip <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span></span></code></pre></div>
<p>Facendolo riesco a leggere che:</p>
<ul>
<li>il separatore di campo è il <code>;</code>;</li>
<li>la prima riga è una riga di intestazione;</li>
<li>che ci sono decine di campi (questo lo si può leggere anche dal <a href="https://opencoesione.gov.it/media/opendata/metadati_progetti_tracciato_esteso.xls">file dei metadati</a>).</li>
</ul>
<p>Con qualche sforzo in più di scorrimento a schermo, riesco a vedere che il separatore dei decimali è la <code>,</code> e che i campi con le date sono in un formato che sembra un numero intero, ma in realtà è <code>YYYYMMDD</code> (<code>23 agosto 2021</code> è espresso come <code>20210823</code>).</p>
<p>Modificando un po’ il comando di sopra, con <code>unzip -p progetti_esteso_20230430.zip | wc -l</code>, leggo che il file è composto da 1.936.840 righe.</p>
<p>Fatta questa prima esplorazione grezza, di solito voglio “guardare” in modo più “comodo” la tabella dei dati. Potrei salvare le prime 10 righe in un file, aggiungendo al comando di sopra <code>&gt; prime_dieci_righe.csv</code>, e infine aprirlo con un foglio elettronico; io preferisco usare lo <a href="https://ondata.github.io/guidaVisiData/">straordinario <strong>VisiData</strong></a> per farlo.<br> Con <code>unzip -p progetti_esteso_20230430.zip | head | vd -f csv --csv-delimiter=";"</code> ad esempio visualizzo le 10 righe di <em>output</em> e tutte le colonne (constatando che sono 199), ma soprattutto mi faccio una prima idea dei contenuti.</p>
<div id="fig-duckdb-preview-vd" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-duckdb-preview-vd-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/duckdb-intro-csv/images/visidata_explore.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-duckdb-preview-vd-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;7: Esempio visualizzazione con VisiData
</figcaption>
</figure>
</div>
<p>Ci sono tantissimi altri strumenti e modalità con cui potrei fare queste ed altre operazioni di esplorazione e analisi, ma questo è un <em>post</em> dedicato in modo particolare a DuckDB e alla sua applicazione a riga di comando. Quindi <strong>da qui in poi</strong>, utilizzerò <strong>soprattutto</strong> <strong>DuckDB</strong> e la sua <strong><code>cli</code></strong>.<br> Per replicare con DuckDB quanto visto sopra in Figura&nbsp;7, il comando è (metto qualche “a capo” per renderlo più leggibile):</p>
<div class="sourceCode" id="annotated-cell-22" style="background: #f1f3f5;"><pre class="sourceCode bash code-annotation-code code-with-copy code-annotated"><code class="sourceCode bash"><span id="annotated-cell-22-1"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">unzip</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-p</span> progetti_esteso_20230430.zip <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">head</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">\</span></span>
<button class="code-annotation-anchor" data-target-cell="annotated-cell-22" data-target-annotation="1">1</button><span id="annotated-cell-22-2" class="code-annotation-target"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-cmd</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'.mode box'</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<button class="code-annotation-anchor" data-target-cell="annotated-cell-22" data-target-annotation="2">2</button><span id="annotated-cell-22-3" class="code-annotation-target"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">select * from read_csv_auto("/dev/stdin");</span></span>
<button class="code-annotation-anchor" data-target-cell="annotated-cell-22" data-target-annotation="3">3</button><span id="annotated-cell-22-4" class="code-annotation-target"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">less</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-S</span></span><div class="code-annotation-gutter-bg"></div><div class="code-annotation-gutter"></div></code></pre></div>
<dl class="code-annotation-container-hidden code-annotation-container-grid">
<dt data-target-cell="annotated-cell-22" data-target-annotation="1">1</dt>
<dd>
<span data-code-cell="annotated-cell-22" data-code-lines="2" data-code-annotation="1"><code>-cmd '.mode box'</code> abilita la vista “box”</span>
</dd>
<dt data-target-cell="annotated-cell-22" data-target-annotation="2">2</dt>
<dd>
<span data-code-cell="annotated-cell-22" data-code-lines="3" data-code-annotation="2">L’<em>input</em> è lo <code>stdin</code></span>
</dd>
<dt data-target-cell="annotated-cell-22" data-target-annotation="3">3</dt>
<dd>
<span data-code-cell="annotated-cell-22" data-code-lines="4" data-code-annotation="3">L’<em>output</em> a <code>less</code> in modo che sia leggibile</span>
</dd>
</dl>
<p>A schermo ho un’anteprima leggibile e navigabile, come questa di Figura&nbsp;8.</p>
<div id="fig-duckdb-preview-box" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-duckdb-preview-box-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/duckdb-intro-csv/images/duckdb-preview-box.gif" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-duckdb-preview-box-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;8: Output in modalità <code>box</code> di DuckDB
</figcaption>
</figure>
</div>
<p>Come detto sopra DuckDB può <strong>leggere nativamente</strong> file <strong>compressi</strong> in formato <strong><code>GZIP</code></strong> (e <code>ZSTD</code>).<br> Allora per comodità, ho creato la versione <code>GZIP</code> del file <code>Progetti con tracciato esteso</code> di OpenCoesione.</p>
<p>La posso interrogare in modo diretto, applicando la funzione <code>read_csv_auto</code>, che prova a fare l’inferenza della presenza (o no) della linea di intestazione, del separatore dei campi, del separatore dei decimali, del tipo di campo, ecc.:</p>
<div class="sourceCode" id="cb24" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb24-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<span id="cb24-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SELECT * from read_csv_auto("progetti_esteso_20230430.csv.gz") LIMIT 10</span></span>
<span id="cb24-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span></code></pre></div>
<p>In output ho un’anteprima ben leggibile a schermo, in cui vedo 10 righe, alcuni dei campi e il loro tipo e il numero di colonne.</p>
<div id="fig-duckdb-standard-output" class="quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-fig figure">
<div aria-describedby="fig-duckdb-standard-output-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<img src="https://aborruso.github.io/posts/duckdb-intro-csv/images/duck-standard-output.png" class="img-fluid figure-img">
</div>
<figcaption class="quarto-float-caption-bottom quarto-float-caption quarto-float-fig" id="fig-duckdb-standard-output-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Figura&nbsp;9: DuckDb standard output
</figcaption>
</figure>
</div>
<p>Per vedere tutti i campi posso forzare l’<strong>output in <code>CSV</code></strong>, aggiungendo <code>--csv</code> e infine leggerlo con VisiData:</p>
<div class="sourceCode" id="cb25" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb25-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<span id="cb25-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SELECT * from read_csv_auto("progetti_esteso_20230430.csv.gz") LIMIT 10</span></span>
<span id="cb25-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">|</span> <span class="ex" style="color: null;
background-color: null;
font-style: inherit;">vd</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-f</span> csv</span></code></pre></div>
<p>Un comando comodissimo di DuckDB è <a href="https://duckdb.org/docs/guides/meta/summarize"><strong><code>SUMMARIZE</code></strong></a>, che restituisce una <strong>tabella esplorativa di sintesi</strong> che è una piccola gemma.<br> Per ogni campo restituisce:</p>
<ul>
<li>tipo di campo;</li>
<li>valore minimo;</li>
<li>valore massimo;</li>
<li>numero di valori univoci approssimato;</li>
<li>valore medio;</li>
<li>deviazione standard;</li>
<li>valore al 25°, 50° e 75° percentile;</li>
<li>conteggio dei valori.</li>
</ul>
<p>Qui sotto in Tabella&nbsp;4 un esempio di output per alcune delle colonne del dataset di OpenCoesione.<br> È una tabella di gran valore, perché consente di fare delle prime scelte di analisi e di trasformazione dei dati e avere restituito degli elementi di qualità dei dati.</p>
<div id="tbl-summarize-output" class="striped responsive small quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-summarize-output-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Tabella&nbsp;4: <em>Output</em> di esempio di SUMMARIZE
</figcaption>
<div aria-describedby="tbl-summarize-output-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="table-responsive">
<table class="table-striped small table-sm caption-top table">
<colgroup>
<col style="width: 6%">
<col style="width: 6%">
<col style="width: 8%">
<col style="width: 8%">
<col style="width: 8%">
<col style="width: 8%">
<col style="width: 8%">
<col style="width: 8%">
<col style="width: 8%">
<col style="width: 8%">
<col style="width: 8%">
<col style="width: 8%">
</colgroup>
<thead>
<tr class="header">
<th>column_name</th>
<th>column_type</th>
<th style="text-align: right;">min</th>
<th style="text-align: right;">max</th>
<th style="text-align: right;">approx_unique</th>
<th style="text-align: right;">avg</th>
<th style="text-align: right;">std</th>
<th style="text-align: right;">q25</th>
<th style="text-align: right;">q50</th>
<th style="text-align: right;">q75</th>
<th style="text-align: right;">count</th>
<th style="text-align: right;">null_percentage</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>OC_TOT_PAGAMENTI_RENDICONTAB_UE</td>
<td>FLOAT</td>
<td style="text-align: right;">-450519.72</td>
<td style="text-align: right;">1433693200.0</td>
<td style="text-align: right;">449379</td>
<td style="text-align: right;">48410.75611172828</td>
<td style="text-align: right;">1908955.4857718376</td>
<td style="text-align: right;">455.01105803437605</td>
<td style="text-align: right;">1815.3021594409709</td>
<td style="text-align: right;">9166.19804364237</td>
<td style="text-align: right;">1936839</td>
<td style="text-align: right;">8.22%</td>
</tr>
<tr class="even">
<td>CUP_DESCR_SETTORE</td>
<td>VARCHAR</td>
<td style="text-align: right;"></td>
<td style="text-align: right;">SERVIZI PER LA P.A. E PER LA COLLETTIVITA’</td>
<td style="text-align: right;">12</td>
<td style="text-align: right;"></td>
<td style="text-align: right;"></td>
<td style="text-align: right;"></td>
<td style="text-align: right;"></td>
<td style="text-align: right;"></td>
<td style="text-align: right;">1936839</td>
<td style="text-align: right;">0.0%</td>
</tr>
<tr class="odd">
<td>DESCR_INDICATORE_2</td>
<td>VARCHAR</td>
<td style="text-align: right;"></td>
<td style="text-align: right;">tematiche oggetto di approfondimento a favore dei beneficiari potenziale ed effettivi</td>
<td style="text-align: right;">600</td>
<td style="text-align: right;"></td>
<td style="text-align: right;"></td>
<td style="text-align: right;"></td>
<td style="text-align: right;"></td>
<td style="text-align: right;"></td>
<td style="text-align: right;">1936839</td>
<td style="text-align: right;">0.0%</td>
</tr>
<tr class="even">
<td>FINANZ_DA_REPERIRE</td>
<td>FLOAT</td>
<td style="text-align: right;">0.0</td>
<td style="text-align: right;">929000000.0</td>
<td style="text-align: right;">241</td>
<td style="text-align: right;">19124433.744656816</td>
<td style="text-align: right;">79954584.61051819</td>
<td style="text-align: right;">42872.88574218749</td>
<td style="text-align: right;">408335.86328125</td>
<td style="text-align: right;">4609128.875</td>
<td style="text-align: right;">1936839</td>
<td style="text-align: right;">99.99%</td>
</tr>
<tr class="odd">
<td>OC_FINANZ_UE_FESR_NETTO</td>
<td>FLOAT</td>
<td style="text-align: right;">-209719.28</td>
<td style="text-align: right;">1024941760.0</td>
<td style="text-align: right;">155171</td>
<td style="text-align: right;">48779.41458696303</td>
<td style="text-align: right;">2049515.9863344613</td>
<td style="text-align: right;">0.0</td>
<td style="text-align: right;">0.0</td>
<td style="text-align: right;">180.9459324096726</td>
<td style="text-align: right;">1936839</td>
<td style="text-align: right;">42.73%</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
<p><br>Il comando si lancia anteponendolo alla lista di record di cui si vuole ottenere una preziosa sintesi:</p>
<div class="sourceCode" id="cb26" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb26-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<span id="cb26-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SUMMARIZE SELECT * from read_csv_auto("progetti_esteso_20230430.csv.gz")</span></span>
<span id="cb26-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span></code></pre></div>
<p>Ma se lo faccio, ottengo un errore:</p>
<div class="sourceCode" id="cb27" style="background: #f1f3f5;"><pre class="sourceCode markdown code-with-copy"><code class="sourceCode markdown"><span id="cb27-1"><span class="an" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">Error:</span><span class="co" style="color: #5E5E5E;
background-color: null;
font-style: inherit;"> Invalid Input Error: Could not convert string 'a.001'</span></span>
<span id="cb27-2">to INT64 in column "OC_COD_ARTICOLAZ_PROGRAMMA", at line 25439.</span></code></pre></div>
<p>Questo avviene per un <strong>problema</strong> legato all’<strong>inferenza automatica</strong> del campo <code>OC_COD_ARTICOLAZ_PROGRAMMA</code> che nelle prime righe contiene valori numerici, ma che in realtà contiene anche caratteri non numerici, con una struttura molto variabile.<br> Ecco alcuni valori di esempio di questo campo: <code>01</code> ; <code>08</code> ; <code>III</code> ; <code>04</code> ; <code>02</code> ; <code>1</code> ; <code>03</code> ; <code>a</code> ; <code>2</code> ; <code>I</code> ; <code>05</code> ; <code>POCMOLISE</code> ; <code>VIII</code>.<br> Nel <a href="https://opencoesione.gov.it/media/opendata/metadati_progetti_tracciato_esteso.xls">file dei metadati</a> questo campo è dichiarato coerentemente come <code>char</code>.</p>
<p>L’<a href="https://duckdb.org/docs/data/csv/auto_detection">inferenza automatica</a> di un <code>CSV</code> in di DuckDB lavora di <em>default</em> su 20.480 righe. Quando viene fatto su un file compresso, vengono lette le prime 20.480 righe a partire dall’inizio del file.<br> È possibile aumentare il numero di righe da leggere, con il parametro <code>sample_size</code>:</p>
<div class="sourceCode" id="cb28" style="background: #f1f3f5;"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb28-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span>
<span id="cb28-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SUMMARIZE SELECT * from read_csv_auto("progetti_esteso_20230430.csv.gz",sample_size=50000)</span></span>
<span id="cb28-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'</span></span></code></pre></div>
<p>Anche se aumento l’inferenza a 50.000 righe, ho errori. Stavolta però per il campo <code>COD_TIPO_PROCED_ATTIVAZIONE</code>, che di base sembra contenere numeri, ma alle volte contiene il carattere <code>.</code>.<br> Nel <a href="https://opencoesione.gov.it/media/opendata/metadati_progetti_tracciato_esteso.xls">file dei metadati</a> questo campo è dichiarato come <code>num</code>. È un <strong>errore</strong>, dovrebbe essere <code>char</code>.</p>
<p>Portando il numero di righe a 100.000, non ho più errori. Ed è molto comodo - per un file “grande”, non ottimizzato per le <em>performance</em> e compresso - ottenere l’<em>output</em> di <code>SUMMARIZE</code> in circa 10 secondi.<br> Ma la <strong>velocità è niente senza qualità</strong>: tanti dei campi sono associati a un tipo di campo non corretto. Queste le ragioni principali:</p>
<ul>
<li>il <strong>separatore</strong> dei <strong>decimali</strong> è la <code>,</code> e non il <code>.</code> (che è un po’ uno standard). Quindi, campi che contengono valori come <code>5234,14</code> vengono interpretati come stringhe. Sono le decine di campi con suffisso <code>OC_FINANZ_</code>. Si mappano correttamente se si aggiunge il parametro <code>decimal_separator=","</code> alla funzione <code>read_csv_auto</code>, e se si definiscono tutti i campi numerici come tali.</li>
<li>C’è però una <strong>difformità</strong> nell’uso dei <strong>separatori</strong> dei <strong>decimali</strong>. Per la grandissima parte dei campi numerici è la <code>,</code>, ma in campi come <code>PROGRAMMATO_INDICATORE_1</code> è il <code>.</code>. Quindi se si aggiunge <code>decimal_separator=","</code> (è una dichiarazione globale), si dovrà per campi come <code>PROGRAMMATO_INDICATORE_1</code> definirli prima come campi di testo e fare poi il <em>casting</em> a <code>FLOAT</code>.</li>
<li>I campi con le <strong>date</strong> vengono mappati <strong>come numeri interi</strong>. Questo in realtà non è un problema ed è coerente con i metadati ufficiali. Il <code>23 agosto 2021</code> è espresso come <code>20210823</code>. Per potere però usare funzioni correlate alle date, è meglio definire i campi come <code>date</code> e non come <code>int</code>. Si fa definendo il formato dei valori delle date, aggiungendo il parametro <code>dateformat='%Y%m%d'</code> alla funzione <code>read_csv_auto</code> e dichiarando i relativi campi come <code>DATE</code>.</li>
</ul>
<p>OpenCoesione pubblica un <a href="https://opencoesione.gov.it/it/opendata/metadati/"><strong>file dei metadati</strong></a>: oltre a contenere <strong>piccoli errori</strong>, non è disponibile anche in un formato che possa essere letto automaticamente da applicazioni e librerie <em>software</em>, <strong>non è</strong> in formato <strong><em>machine readable</em></strong> (vedi sezione sulla descrizione di un <code>CSV</code>).<br> Questa mancanza rende l’<strong>uso</strong> di questo CSV <strong>non immediato</strong> e <strong>non scevro da errori</strong>.</p>
<p>Per avere un <em>output</em> del comando <code>SUMMARIZE</code> corretto, in presenza di un <code>CSV</code> non standard (in questo senso) e con alcuni problemi, è necessario scrivere un comando molto “verboso”, come quello sottostante.</p>
<div class="callout callout-style-default callout-note callout-titled">
<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-16-contents" aria-controls="callout-16" aria-expanded="false" aria-label="Toggle callout">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Procedura corretta per <code>SUMMARIZE</code>
</div>
<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div>
</div>
<div id="callout-16" class="callout-16-contents callout-collapse collapse">
<div class="callout-body-container callout-body">
<div class="sourceCode" id="cb29" style="background: #f1f3f5;"><pre class="sourceCode bash code-overflow-wrap code-with-copy"><code class="sourceCode bash"><span id="cb29-1"><span class="ex" style="color: null;
background-color: null;
font-style: inherit;">duckdb</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">--csv</span> <span class="at" style="color: #657422;
background-color: null;
font-style: inherit;">-c</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span></span>
<span id="cb29-2"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">SUMMARIZE SELECT *</span></span>
<span id="cb29-3"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">REPLACE(</span></span>
<span id="cb29-4"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_1 AS FLOAT) AS PROGRAMMATO_INDICATORE_1,</span></span>
<span id="cb29-5"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_2 AS FLOAT) AS PROGRAMMATO_INDICATORE_2,</span></span>
<span id="cb29-6"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_3 AS FLOAT) AS PROGRAMMATO_INDICATORE_3,</span></span>
<span id="cb29-7"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(PROGRAMMATO_INDICATORE_4 AS FLOAT) AS PROGRAMMATO_INDICATORE_4,</span></span>
<span id="cb29-8"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_1 AS FLOAT) AS REALIZZATO_INDICATORE_1,</span></span>
<span id="cb29-9"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_2 AS FLOAT) AS REALIZZATO_INDICATORE_2,</span></span>
<span id="cb29-10"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_3 AS FLOAT) AS REALIZZATO_INDICATORE_3,</span></span>
<span id="cb29-11"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">CAST(REALIZZATO_INDICATORE_4 AS FLOAT) AS REALIZZATO_INDICATORE_4,</span></span>
<span id="cb29-12"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb29-13"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">from read_csv_auto(</span></span>
<span id="cb29-14"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">'progetti_esteso_20230430.csv.gz',SEP=';',dateformat='%Y%m%d',decimal_separator=',',sample_size=100000,</span></span>
<span id="cb29-15"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">types={'OC_COD_ARTICOLAZ_PROGRAMMA':'VARCHAR','FINANZ_UE':'FLOAT','FINANZ_UE_FESR':'FLOAT','FINANZ_UE_FSE':'FLOAT','FINANZ_UE_FEASR':'FLOAT','FINANZ_UE_FEAMP':'FLOAT','FINANZ_UE_IOG':'FLOAT','FINANZ_STATO_FONDO_DI_ROTAZIONE':'FLOAT','FINANZ_STATO_FSC':'FLOAT','FINANZ_STATO_PAC':'FLOAT','FINANZ_STATO_COMPLETAMENTI':'FLOAT','FINANZ_STATO_ALTRI_PROVVEDIMENTI':'FLOAT','FINANZ_REGIONE':'FLOAT','FINANZ_PROVINCIA':'FLOAT','FINANZ_COMUNE':'FLOAT','FINANZ_RISORSE_LIBERATE':'FLOAT','FINANZ_ALTRO_PUBBLICO':'FLOAT','FINANZ_STATO_ESTERO':'FLOAT','FINANZ_PRIVATO':'FLOAT','FINANZ_DA_REPERIRE':'FLOAT','FINANZ_TOTALE_PUBBLICO':'FLOAT','ECONOMIE_TOTALI':'FLOAT','ECONOMIE_TOTALI_PUBBLICHE':'FLOAT','OC_FINANZ_UE_NETTO':'FLOAT','OC_FINANZ_UE_FESR_NETTO':'FLOAT','OC_FINANZ_UE_FSE_NETTO':'FLOAT','OC_FINANZ_UE_FEASR_NETTO':'FLOAT','OC_FINANZ_UE_FEAMP_NETTO':'FLOAT','OC_FINANZ_UE_IOG_NETTO':'FLOAT','OC_FINANZ_STATO_FONDO_ROT_NETTO':'FLOAT','OC_FINANZ_STATO_FSC_NETTO':'FLOAT','OC_FINANZ_STATO_PAC_NETTO':'FLOAT','OC_FINANZ_STATO_COMPL_NETTO':'FLOAT','OC_FINANZ_STATO_ALTRI_PROV_NETTO':'FLOAT','OC_FINANZ_REGIONE_NETTO':'FLOAT','OC_FINANZ_PROVINCIA_NETTO':'FLOAT','OC_FINANZ_COMUNE_NETTO':'FLOAT','OC_FINANZ_RISORSE_LIBERATE_NETTO':'FLOAT','OC_FINANZ_ALTRO_PUBBLICO_NETTO':'FLOAT','OC_FINANZ_STATO_ESTERO_NETTO':'FLOAT','OC_FINANZ_PRIVATO_NETTO':'FLOAT','OC_FINANZ_TOT_PUB_NETTO':'FLOAT','OC_COSTO_COESIONE':'FLOAT','IMPEGNI':'FLOAT','OC_IMPEGNI_GIURID_VINCOLANTI':'FLOAT','OC_IMPEGNI_TRASFERIMENTI':'FLOAT','OC_IMPEGNI_COESIONE':'FLOAT','TOT_PAGAMENTI':'FLOAT','OC_TOT_PAGAMENTI_BENEFICIARI':'FLOAT','OC_TOT_PAGAMENTI_TRASFERIMENTI':'FLOAT','COSTO_REALIZZATO':'FLOAT','COSTO_RENDICONTABILE_UE':'FLOAT','OC_TOT_PAGAMENTI_RENDICONTAB_UE':'FLOAT','OC_TOT_PAGAMENTI_FSC':'FLOAT','OC_TOT_PAGAMENTI_PAC':'FLOAT','OC_PAGAMENTI_COESIONE':'FLOAT','OC_DATA_INIZIO_PROGETTO':'DATE','OC_DATA_FINE_PROGETTO_PREVISTA':'DATE','OC_DATA_FINE_PROGETTO_EFFETTIVA':'DATE','DATA_INIZIO_PREV_STUDIO_FATT':'DATE','DATA_INIZIO_EFF_STUDIO_FATT':'DATE','DATA_FINE_PREV_STUDIO_FATT':'DATE','DATA_FINE_EFF_STUDIO_FATT':'DATE','DATA_INIZIO_PREV_PROG_PREL':'DATE','DATA_INIZIO_EFF_PROG_PREL':'DATE','DATA_FINE_PREV_PROG_PREL':'DATE','DATA_FINE_EFF_PROG_PREL':'DATE','DATA_INIZIO_PREV_PROG_DEF':'DATE','DATA_INIZIO_EFF_PROG_DEF':'DATE','DATA_FINE_PREV_PROG_DEF':'DATE','DATA_FINE_EFF_PROG_DEF':'DATE','DATA_INIZIO_PREV_PROG_ESEC':'DATE','DATA_INIZIO_EFF_PROG_ESEC':'DATE','DATA_FINE_PREV_PROG_ESEC':'DATE','DATA_FINE_EFF_PROG_ESEC':'DATE','DATA_INIZIO_PREV_AGG_BANDO':'DATE','DATA_INIZIO_EFF_AGG_BANDO':'DATE','DATA_FINE_PREV_AGG_BANDO':'DATE','DATA_FINE_EFF_AGG_BANDO':'DATE','DATA_INIZIO_PREV_STIP_ATTRIB':'DATE','DATA_INIZIO_EFF_STIP_ATTRIB':'DATE','DATA_FINE_PREV_STIP_ATTRIB':'DATE','DATA_FINE_EFF_STIP_ATTRIB':'DATE','DATA_INIZIO_PREV_ESECUZIONE':'DATE','DATA_INIZIO_EFF_ESECUZIONE':'DATE','DATA_FINE_PREV_ESECUZIONE':'DATE','DATA_FINE_EFF_ESECUZIONE':'DATE','DATA_INIZIO_PREV_COLLAUDO':'DATE','DATA_INIZIO_EFF_COLLAUDO':'DATE','DATA_FINE_PREV_COLLAUDO':'DATE','DATA_FINE_EFF_COLLAUDO':'DATE','COD_TIPO_PROCED_ATTIVAZIONE':'VARCHAR','OC_FLAG_REGIONE_UNICA':'INT','DATA_AGGIORNAMENTO':'DATE','OC_FLAG_CUP':'INT','PROGRAMMATO_INDICATORE_1':'VARCHAR','REALIZZATO_INDICATORE_1':'VARCHAR','PROGRAMMATO_INDICATORE_2':'VARCHAR','REALIZZATO_INDICATORE_2':'VARCHAR','PROGRAMMATO_INDICATORE_3':'VARCHAR','REALIZZATO_INDICATORE_3':'VARCHAR','PROGRAMMATO_INDICATORE_4':'VARCHAR','REALIZZATO_INDICATORE_4':'VARCHAR'}</span></span>
<span id="cb29-16"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">)</span></span>
<span id="cb29-17"><span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"</span> <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">&gt;</span>summarize.csv</span></code></pre></div>
</div>
</div>
</div>
<p>Con questi dati di sintesi emerge ad esempio che circa 36 campi hanno almeno il 90% dei <strong>valori nulli</strong>.<br> O che in alcuni campi con le <strong>date</strong> ci sono <strong>valori</strong> (di minimo o di massimo) <strong>strani</strong> e probabilmente errati, come quelli in Tabella&nbsp;5.</p>
<div id="tbl-strange-date" class="striped responsive small quarto-float quarto-figure quarto-figure-center anchored">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-strange-date-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Tabella&nbsp;5: Campi con valori di date “strani”
</figcaption>
<div aria-describedby="tbl-strange-date-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="table-responsive">
<table class="table-striped small table-sm caption-top table">
<thead>
<tr class="header">
<th>column_name</th>
<th>min</th>
<th>max</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>OC_DATA_INIZIO_PROGETTO</td>
<td>1899-12-30</td>
<td>2024-02-01</td>
</tr>
<tr class="even">
<td>DATA_INIZIO_EFF_STIP_ATTRIB</td>
<td>1899-12-30</td>
<td>2025-12-31</td>
</tr>
<tr class="odd">
<td>DATA_INIZIO_EFF_AGG_BANDO</td>
<td>1900-01-01</td>
<td>2030-03-03</td>
</tr>
<tr class="even">
<td>DATA_FINE_PREV_STUDIO_FATT</td>
<td>1987-07-28</td>
<td>2103-06-30</td>
</tr>
<tr class="odd">
<td>DATA_FINE_EFF_STUDIO_FATT</td>
<td>1987-07-28</td>
<td>2103-06-30</td>
</tr>
<tr class="even">
<td>OC_DATA_FINE_PROGETTO_PREVISTA</td>
<td>1899-12-30</td>
<td>2103-12-31</td>
</tr>
<tr class="odd">
<td>DATA_FINE_PREV_ESECUZIONE</td>
<td>1899-12-30</td>
<td>2103-12-31</td>
</tr>
<tr class="even">
<td>DATA_INIZIO_EFF_ESECUZIONE</td>
<td>1899-12-30</td>
<td>2211-01-20</td>
</tr>
<tr class="odd">
<td>OC_DATA_FINE_PROGETTO_EFFETTIVA</td>
<td>1899-12-30</td>
<td>2211-08-31</td>
</tr>
<tr class="even">
<td>DATA_FINE_EFF_ESECUZIONE</td>
<td>1899-12-30</td>
<td>2211-08-31</td>
</tr>
<tr class="odd">
<td>DATA_FINE_EFF_STIP_ATTRIB</td>
<td>1899-12-30</td>
<td>4014-03-07</td>
</tr>
<tr class="even">
<td>DATA_FINE_PREV_AGG_BANDO</td>
<td>1991-12-05</td>
<td>8012-10-08</td>
</tr>
</tbody>
</table>
</div>
</div>
</figure>
</div>
<p>Ma soprattutto è possibile constatare quali siano <strong>i campi “categorici”</strong>, quelli con un <strong>numero limitato di valori univoci</strong>, che possono essere usati per raggruppare e aggregare i dati e fare emergere elementi interessanti.</p>
<p>Tra i campi categorici <code>OC_MACROAREA</code>, che definisce le macroaree geografiche italiane. E per sapere ad esempio qual è il finanziamento pubblico totale per ciascuna, si può usare la query <code>SQL</code>:</p>
<div id="lst-query-macroarea" class="sql listing quarto-float quarto-figure quarto-figure-left anchored">
<figure class="quarto-float quarto-float-lst figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-lst" id="lst-query-macroarea-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Lista&nbsp;5: Query SQL: totale dei finanziamenti pubblici per macroaree
</figcaption>
<div aria-describedby="lst-query-macroarea-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="sourceCode" id="lst-query-macroarea" style="background: #f1f3f5;"><pre class="sourceCode sql code-with-copy"><code class="sourceCode sql"><span id="lst-query-macroarea-1"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">SELECT</span> OC_MACROAREA,</span>
<span id="lst-query-macroarea-2"><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">CAST</span>(<span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">SUM</span>(FINANZ_TOTALE_PUBBLICO) <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">AS</span> BIGINT) FINANZ_TOTALE_PUBBLICO</span>
<span id="lst-query-macroarea-3"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">GROUP</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">BY</span> OC_MACROAREA</span>
<span id="lst-query-macroarea-4"><span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">ORDER</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">BY</span> FINANZ_TOTALE_PUBBLICO <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">DESC</span></span></code></pre></div>
</div>
</figure>
</div>
<p>Restituirà qualcosa come in Tabella&nbsp;6.</p>
<div class="cell" data-execution_count="2">
<div id="tbl-aree-sum" class="cell quarto-float quarto-figure quarto-figure-center anchored" data-execution_count="2">
<figure class="quarto-float quarto-float-tbl figure">
<figcaption class="quarto-float-caption-top quarto-float-caption quarto-float-tbl" id="tbl-aree-sum-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
Tabella&nbsp;6: Finanziamento pubblico per macro aree
</figcaption>
<div aria-describedby="tbl-aree-sum-caption-0ceaefa1-69ba-4598-a22c-09a6ac19f8ca">
<div class="cell-output cell-output-display" data-execution_count="2">
<style type="text/css">
#T_474f4 th:nth-child(1) {
  text-align: left;
}
#T_474f4 th:nth-child(2) {
  text-align: right;
}
#T_474f4_row0_col0, #T_474f4_row1_col0, #T_474f4_row2_col0, #T_474f4_row3_col0, #T_474f4_row4_col0 {
  text-align: left;
}
#T_474f4_row0_col1, #T_474f4_row1_col1, #T_474f4_row2_col1, #T_474f4_row3_col1, #T_474f4_row4_col1 {
  text-align: right;
}
</style>

<div class="table-responsive">
<table id="T_474f4" class="table-bordered table-striped small do-not-create-environment cell caption-top table table-sm" data-quarto-postprocess="true">
<thead>
<tr class="header">
<th id="T_474f4_level0_col0" class="col_heading level0 col0" data-quarto-table-cell-role="th">Macro area</th>
<th id="T_474f4_level0_col1" class="col_heading level0 col1" data-quarto-table-cell-role="th">Finanziamento totale pubblico (€)</th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td id="T_474f4_row0_col0" class="data row0 col0">Mezzogiorno</td>
<td id="T_474f4_row0_col1" class="data row0 col1">182.919.710.550</td>
</tr>
<tr class="even">
<td id="T_474f4_row1_col0" class="data row1 col0">Centro-Nord</td>
<td id="T_474f4_row1_col1" class="data row1 col1">61.964.843.697</td>
</tr>
<tr class="odd">
<td id="T_474f4_row2_col0" class="data row2 col0">Ambito Nazionale</td>
<td id="T_474f4_row2_col1" class="data row2 col1">8.808.650.456</td>
</tr>
<tr class="even">
<td id="T_474f4_row3_col0" class="data row3 col0">Altro</td>
<td id="T_474f4_row3_col1" class="data row3 col1">3.684.521.639</td>
</tr>
<tr class="odd">
<td id="T_474f4_row4_col0" class="data row4 col0">Estero</td>
<td id="T_474f4_row4_col1" class="data row4 col1">287.153.594</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</figure>
</div>
</div>
<div class="cell hidden dataframe table-bordered striped responsive small">
<div class="sourceCode cell-code hidden" id="cb30" data-startfrom="989" data-source-offset="-0" style="background: #f1f3f5;"><pre class="sourceCode js code-with-copy"><code class="sourceCode javascript" style="counter-reset: source-line 988;"><span id="cb30-989">data <span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">=</span> <span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">FileAttachment</span>(<span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"./risorse/sum-by-region.csv"</span>)<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">csv</span>({ <span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">typed</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="kw" style="color: #003B4F;
background-color: null;
font-weight: bold;
font-style: inherit;">true</span> })</span>
<span id="cb30-990">Inputs<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">.</span><span class="fu" style="color: #4758AB;
background-color: null;
font-style: inherit;">table</span>(data<span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">,</span> {<span class="dt" style="color: #AD0000;
background-color: null;
font-style: inherit;">locale</span><span class="op" style="color: #5E5E5E;
background-color: null;
font-style: inherit;">:</span> <span class="st" style="color: #20794D;
background-color: null;
font-style: inherit;">"it-IT"</span>})</span></code></pre></div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-3-1" data-nodetype="declaration">

</div>
</div>
</div>
<div class="cell-output cell-output-display hidden">
<div>
<div id="ojs-cell-3-2" data-nodetype="expression">

</div>
</div>
</div>
</div>
<p>➡️ Purtroppo però non è possibile usare in modo comodo una query come quella di Lista&nbsp;5.<br> Perché, come scritto sopra, il <code>CSV</code> ha alcuni problemi e non è “standard”.<br> Per eseguirla allora sarebbe necessario inserire la lunghissima lista di parametri per la funzione <code>read_csv_auto</code> e definire i tipi di campo, così come nel caso di <code>SUMMARIZE</code>. Ma sarebbe molto scomodo e poco pratico.</p>
<p><strong>Due modi</strong> per <strong>risolvere</strong> il <strong>problema</strong>:</p>
<ul>
<li><strong>creare</strong> un <strong><code>CSV</code></strong> “<strong>pulito</strong>” e <strong>standard</strong>, con i tipi di campo corretti, e lavorare su questo;</li>
<li><strong>trasformare</strong> il file <strong><code>CSV</code></strong> di input in un file <strong><code>PARQUET</code></strong> e lavorare su questo.</li>
</ul>
</section>
<section id="note-sul-dataset-progetti" class="level3">
<h3 class="anchored" data-anchor-id="note-sul-dataset-progetti">Note sul dataset progetti</h3>
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Su OpenCoesione
</div>
</div>
<div class="callout-body-container callout-body">
<p>Prima di scrivere alcune note sul dataset, voglio sottolineare alcuni punti su <a href="https://opencoesione.gov.it/it/"><strong>OpenCoesione</strong></a>:</p>
<ol type="1">
<li><strong>se non ci fossero questi dati</strong>, se non fossero dei dati aperti, se non fossero di grande interesse, se non fossero “grandi”, <strong>non avrei probabilmente scritto questo <em>post</em></strong>;</li>
<li>Sono poche le banche dati aperte - come questa - che hanno portato a <strong>tanti casi di riuso</strong>, e da tanto tempo;</li>
<li>Sono <strong>pochi i gruppi di lavoro</strong> in questo contesto che <strong>rispondono</strong> a <strong>richieste</strong> di <strong>chiarimento</strong> e <strong>supporto</strong>, a <strong>suggerimenti</strong> <strong>implementativi</strong> e a <strong>progetti di collaborazione</strong>. Il gruppo di OpenCoesione lo fa;</li>
<li>Sono <strong>pochi</strong> i <strong>dataset</strong> pubblicati in Italia, <strong>corredati</strong> da <strong>metadati</strong>;</li>
<li>Apri il <a href="https://opencoesione.gov.it/it/">sito</a>, OpenCoesione è <strong>molto di più di un singolo dataset</strong>.</li>
</ol>
</div>
</div>
<p>A seguire alcune <strong>note</strong> e <strong>proposte/suggerimenti</strong> sul <strong>dataset</strong> dei progetti con tracciato esteso di OpenCoesione (nella versione di aprile 2023):</p>
<ul>
<li>nel <a href="https://opencoesione.gov.it/media/opendata/metadati_progetti_tracciato_esteso.xls">file dei metadati</a>, non si fa riferimento al campo <code>OC_MACROAREA</code>, che è però presente nel dataset. È da aggiungere;</li>
<li>il <code>COD_TIPO_PROCED_ATTIVAZIONE</code> è dichiarato come <code>num</code>, ma contiene anche stringhe. È da correggere la dichiarazione del tipo di campo;</li>
<li>c’è una <strong>difformità</strong> nell’<strong>uso</strong> dei <strong>separatori</strong> dei <strong>decimali</strong>. Per la grandissima parte dei campi numerici è la <code>,</code>, ma in campi come <code>PROGRAMMATO_INDICATORE_1</code> è il <code>.</code>;</li>
<li>ci sono alcune celle con <strong>problemi</strong> di <strong><em>encoding</em></strong> dei <strong>caratteri</strong>. OpenCoesione ci ha già scritto che su questo punto stanno lavorando e che con la prossima release del dataset, il problema sarà risolto e/o ridotto;</li>
<li>nei campi con le <strong>date</strong> ci sono a volte <strong>valori “strani”</strong>, troppo indietro nel passato o troppo avanti nel futuro (vedi Tabella&nbsp;5);</li>
<li><strong>tutti</strong> i <strong>campi</strong> <strong>numerici</strong> sono dichiarati come <strong><code>num</code></strong>, indipendentemente dal fatto che siano interi o decimali. Sarebbe preferibile avere una distinzione tra <code>int</code> e <code>float</code>.</li>
</ul>
<p>Metto a parte, infine, delle proposte/suggerimenti a cui tengo particolarmente:</p>
<ul>
<li><strong>usare</strong> come formato di compressione non lo <code>ZIP</code>, ma <strong><code>GZIP</code></strong>. Rende il dataset più pronto all’uso;</li>
<li><strong>associare</strong> ai metadati in formato <code>XLS</code> anche <strong>una descrizione <em>machine readable</em></strong>. O in uno dei formati standard descritti sopra, o anche semplicemente come schema <code>SQL</code> di creazione della tabella. Rende l’operativa sui dati molto più immediata e potenzialmente efficiente;</li>
<li><strong>affiancare</strong> al formato <code>CSV</code> il <strong>formato <code>PARQUET</code></strong>. È di per sé ben compresso, rende possibile eseguire analisi complesse in modo quasi immediato da “normali” PC e <em>laptop</em> ed è un formato intrinsecamente ben descritto;</li>
<li>produrre dei <strong><code>CSV</code></strong> che siano il più “<strong>standard</strong>” possibile.</li>
</ul>
</section>
</section>
<section id="in-conclusione" class="level2">
<h2 class="anchored" data-anchor-id="in-conclusione">In conclusione</h2>
<p>Con questo lungo post <strong>non voglio</strong> contribuire a rendere il mondo brutto e <strong>fare in modo che il formato <code>CSV</code> sia utilizzato ancora di più</strong>.<br> A parte gli scherzi, è certamente un formato con alcune problematicità, ma è ancora molto utilizzato come formato di scambio di dati in forma di testo strutturato.<br></p>
<p>Con le dovute precauzioni, con gli <strong>strumenti giusti</strong>, con un corredo informativo adeguato e per dimensioni non eccessive, può essere un formato comodo e pratico.<br> <strong>Descrivendolo</strong>, “<strong>standardizzandolo</strong>” e <strong>comprimendolo</strong>, diventa molto più usabile.<br> E questo è un invito a chiunque rende disponibili online dati in formato <code>CSV</code>.<br> Finché dura, usiamolo bene.</p>
<p>Un altro suggerimento (a me per primo) è quello di <strong>usare <code>SQL</code></strong> per costruire <strong>processi</strong> di <strong>analisi</strong> e di <strong>trasformazione</strong> dei dati. È un vecchio e diffuso linguaggio, utilizzabile da quasi qualsiasi applicazione e/o linguaggio di programmazione, correlati ai dati. È super documentato, ci sono migliaia di tutorial, messaggi sui forum, libri, ecc.</p>
<p>E ci sono strumenti come <strong>DuckDB</strong>. Ok, non è vero che i “I Big Data” sono morti, ma con strumenti come questo, è possibile <strong>lavorare</strong> in modo <strong>comodo</strong> e <strong>rapido</strong> con <strong>dati</strong> di <strong>dimensioni</strong> <strong>importanti</strong>, <strong>senza</strong> dover <strong>ricorrere</strong> a <strong>infrastrutture</strong> <strong>complesse</strong> e <strong>costose</strong>.</p>
<p>Ho voluto suggerire l’opportunità di <strong>utilizzare</strong> il <strong>formato</strong> <strong><code>Parquet</code></strong> come uno dei <strong>formati</strong> <strong>principali</strong> di <strong>scambio</strong> e di <strong>lavoro</strong> con i <strong>dati</strong>.</p>
<p>E infine voglio sottolineare ancora una volta, che <strong>senza</strong> <strong>dataset</strong> come quelli di <strong>OpenCoesione</strong>, <strong>non avrei pensato di scrivere questo post</strong> e non sarei riuscito a dargli questo sviluppo.</p>
<hr>
</section>
<section id="buone-letture-e-fonti-di-ispirazione" class="level2">
<h2 class="anchored" data-anchor-id="buone-letture-e-fonti-di-ispirazione">Buone letture e fonti di ispirazione</h2>
<ul>
<li><a href="https://motherduck.com/blog/big-data-is-dead/">Big data is dead</a></li>
<li><a href="https://www.robinlinacre.com/parquet_api/">Why parquet files are my preferred API for bulk open data</a></li>
<li><a href="https://towardsdatascience.com/a-parquet-file-is-all-you-need-962df86886bb">A Parquet File Is All You Need</a></li>
<li><a href="https://cloudnativegeo.org/blog/2023/08/performance-explorations-of-geoparquet-and-duckdb/">Performance Explorations of GeoParquet (and DuckDB)</a></li>
<li><a href="https://data-mozart.com/parquet-file-format-everything-you-need-to-know/">Parquet file format – everything you need to know!</a></li>
<li><a href="https://duckdb.org/docs/data/csv/overview.html">CSV Loading</a></li>
<li><a href="https://www.w3.org/TR/tabular-data-primer/">CSV on the Web: A Primer</a></li>
<li><a href="https://www.icem7.fr/outils/parquet-devrait-remplacer-le-format-csv/">Parquet devrait remplacer le format CSV</a></li>
<li><a href="https://tech.marksblogg.com/duckdb-geospatial-gis.html">Geospatial DuckDB</a></li>
<li><a href="https://duckdb.org/2023/08/23/even-friendlier-sql.html">Even Friendlier SQL with DuckDB</a></li>
</ul>
<hr>
</section>
<section id="il-piacere-di-vedere-questo-articolo-girare" class="level2">
<h2 class="anchored" data-anchor-id="il-piacere-di-vedere-questo-articolo-girare">Il piacere di vedere questo articolo “girare”</h2>
<div class="callout callout-style-default callout-tip callout-titled">
<div class="callout-header d-flex align-content-center">
<div class="callout-icon-container">
<i class="callout-icon"></i>
</div>
<div class="callout-title-container flex-fill">
Chi ha parlato di questo articolo
</div>
</div>
<div class="callout-body-container callout-body">
<ul>
<li><a href="https://newsletterest.com/message/185579/Data-Elixir-Issue-450"><strong>Data Elixir - Issue 450</strong></a>;</li>
<li><a href="https://buttondown.email/puntofisso/archive/532-quantum-of-sollazzo/"><strong>532: quantum of sollazzo</strong></a>, di Giuseppe Sollazzo;</li>
<li><a href="https://stefanogatti.substack.com/p/laculturadeldato-094#LaCulturaDelDato"><strong>LaCulturaDelDato #094</strong></a>, di Stefano Gatti.</li>
</ul>
</div>
</div>


</section>


<a onclick="window.scrollTo(0, 0); return false;" id="quarto-back-to-top"><i class="bi bi-arrow-up"></i> Torna in cima</a><div id="quarto-appendix" class="default"><section id="footnotes" class="footnotes footnotes-end-of-document"><h2 class="anchored quarto-appendix-heading">Note</h2>

<ol>
<li id="fn1"><p>Le politiche di coesione sono un insieme di iniziative e azioni messe in atto dall’Unione Europea per ridurre le disparità economiche, sociali e territoriali tra le diverse regioni e Stati membri.↩︎</p></li>
</ol>
</section></div> ]]></description>
  <category>duckdb</category>
  <category>csv</category>
  <category>parquet</category>
  <guid>https://aborruso.github.io/posts/duckdb-intro-csv/</guid>
  <pubDate>Sun, 20 Aug 2023 22:00:00 GMT</pubDate>
  <media:content url="https://aborruso.github.io/posts/duckdb-intro-csv/atutorial.png" medium="image" type="image/png" height="97" width="144"/>
</item>
</channel>
</rss>
