<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Untitled Publication]]></title><description><![CDATA[Untitled Publication]]></description><link>https://marcopozzan.it</link><generator>RSS for Node</generator><lastBuildDate>Thu, 10 Sep 2026 04:22:28 GMT</lastBuildDate><atom:link href="https://marcopozzan.it/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Gestione SCD con Delta Change Data Feed in Fabric]]></title><description><![CDATA[All'interno di Microsoft Fabric, le tabelle Delta trovano applicazione sia nel Data Warehouse che come tabelle gestite all'interno della Lakehouse. La loro versatilità si estende a diverse caratteristiche e funzionalità, rendendoli indispensabili in ...]]></description><link>https://marcopozzan.it/gestione-scd-con-delta-change-data-feed-in-fabric</link><guid isPermaLink="true">https://marcopozzan.it/gestione-scd-con-delta-change-data-feed-in-fabric</guid><dc:creator><![CDATA[Marco Pozzan]]></dc:creator><pubDate>Fri, 22 Mar 2024 10:12:13 GMT</pubDate><content:encoded><![CDATA[<p>All'interno di Microsoft Fabric, le tabelle Delta trovano applicazione sia nel Data Warehouse che come tabelle gestite all'interno della Lakehouse. La loro versatilità si estende a diverse caratteristiche e funzionalità, rendendoli indispensabili in vari casi d'uso. Una di queste funzionalità è il <strong>delta change data feed</strong></p>
<p>In questo articolo voglio mostrare come sfruttare il <strong>delta change data feed</strong> per facilitare la sincronizzazione continua dei dati tra diverse tabelle in lakehouse diversi all' interno della architettura a medaglione.</p>
<h3 id="heading-che-cosa-sono-i-data-feed">Che cosa sono i data feed?</h3>
<p>I data feed consentono di tenere traccia delle modifiche a livello di riga tra le versioni di una tabella Delta. Se vengono abilitati su una tabella Delta vengono tracciate le modifiche con dei metadati che indicano se la riga specificata è stata inserita, eliminata o aggiornata.</p>
<h3 id="heading-scenario-di-utilizzo">Scenario di utilizzo</h3>
<p>Lo scenario seguente illustra la procedura dettagliata per abilitare i data feed di modifica su una tabella delta in un livello silver. Successivamente simuleremo la modifica delle righe di questa tabella silver e vedremo come con una logica di tipo SCD 2 le modifiche saranno riportate nella tabella nel livello gold.</p>
<p>Per semplicità, lavoreremo solo con 2 Lakehouse (Silver e Gold) evitando di partire dal livello bronze per semplicità. Il codice seguente caricherà i nostri dati grezzi in una tabella Delta, "DimProducts", nella "SilverLayer" (la nostra Lakehouse predefinita).</p>
<p><img src="https://media.licdn.com/dms/image/D4E12AQE2A5WnlznMNw/article-inline_image-shrink_1500_2232/0/1711036648638?e=1716422400&amp;v=beta&amp;t=w8SqBCpphTRdH4nt95v6cVciZQ68feFNPDMvaiPafFA" alt /></p>
<p>Creiamo ora la tabella con il seguente script</p>
<pre><code class="lang-plaintext">DimProducts= [("EC-R098", 10000, "Silver"),  
              ("EC-T209", 1000, "Silver"),
              ("FW-1000", 7000, "Red"),
              ("FL-2301", 500, "Black") ]
columns = ["ProductAlternateKey","SafetyStockLevel","Color", ]
spark.createDataFrame(data=DimProducts, schema = columns).write.format("delta").mode("overwrite").saveAsTable("DimProducts")
</code></pre>
<p>Il risultato dello script si può vedere nell'immagine sotto</p>
<p><img src="https://media.licdn.com/dms/image/D4D12AQFsV27l3vv9UA/article-inline_image-shrink_1500_2232/0/1711050892382?e=1716422400&amp;v=beta&amp;t=l26lyW0dKBYgiWAGjg69XYN_tH7x9XNEq59uVt03O4k" alt /></p>
<p>Ora popoliamo la tabdella nel layer gold utilizzando il seguente script di copia dati dal silver layer al gold layer</p>
<pre><code class="lang-plaintext">import pyspark.sql.functions as F
spark.read.format("delta").table("SilverLayer.DimProducts").withColumn("DeletedFlag", F.lit("N"))  \
     .write.format("delta").mode("overwrite").save("abfss://dcfbd0ab-da78-491a-8a60-1ace7dd434fb@onelake.dfs.fabric.microsoft.com/0420a87e-4462-4952-a987-5f572a96bf49/Tables/DimProducts")
</code></pre>
<p><img src="https://media.licdn.com/dms/image/D4D12AQHtqFhHvV9jjQ/article-inline_image-shrink_1500_2232/0/1711055594392?e=1716422400&amp;v=beta&amp;t=2tk4vksEvmjDVghlKsGabfsneNjDYRgQ8QGevsLY5Wo" alt /></p>
<p>Ora le tabelle sono state create ed essendo una la copia dell'altra sono anche sono sincronizzate. Il prossimo passo è abilitare il Change Data Feed sulla tabella DimProduct del livello Silver su cui poi faremo le modifiche dei dati. Per abilitare usiamo il seguente script</p>
<pre><code class="lang-plaintext">%%sql
ALTER TABLE SilverLayer.DimProducts SET TBLPROPERTIES (delta.enableChangeDataFeed = true)
</code></pre>
<p>Con Change Data Feed abilitato sulla nostra tabella, possiamo iniziare a tenere traccia delle nostre modifiche. Quindi, apporteremo 3 modifiche alla tabella "DimProduct" (1 aggiornamento, 1 eliminazione e 1 inserimento). L'obiettivo è identificare cosa è cambiato nella tabella del livello sylver ed essere in grado di replicare tali cambiamenti nella versione "DimProducts" del livello gold proprio come fosse una SCD di tipo 2 di un nostro ipotetico Data warehouse.</p>
<pre><code class="lang-plaintext">%%sql
-- Inserimento di un record
INSERT INTO SilverLayer.DimProducts  VALUES ('BK-R93R-44", 550, "Silver")

-- Aggiornamento di un record
UPDATE SilverLayer.DimProducts SET SafetyStockLevel = '1500' WHERE ProductAlternateKey = 'EC-T209'

-- delete a record
DELETE from SilverLayer.DimProducts WHERE ProductAlternateKey  = 'FL-2301'
</code></pre>
<p>prima delle modifiche</p>
<p><img src="https://media.licdn.com/dms/image/D4D12AQHErwbxk54aug/article-inline_image-shrink_1500_2232/0/1711052535625?e=1716422400&amp;v=beta&amp;t=yHU1-exF9We8oMF_5dxwo_awhpwD5onku3NX44No1XQ" alt /></p>
<p>nuova situazione dopo le modifiche ai dati</p>
<p><img src="https://media.licdn.com/dms/image/D4D12AQGlpLsvNP_zdQ/article-inline_image-shrink_1500_2232/0/1711053109746?e=1716422400&amp;v=beta&amp;t=siUarADYVim_RJj15By2ITiQ42rs8YtnI9G749GPozs" alt /></p>
<p>Per visualizzare i Data Feed di modifica e per vedere esattamente cosa è successo possiamo usare la funzione DESCRIBE. Nell'immagine sotto dopo l'eseguzione dello script si possono vedere che sono presenti un buon numero di colonne di metadati associate alle modifiche, ma per semplicità ci concentreremo su "<strong>version</strong>", "<strong>operation</strong>" e "<strong>operationparameters</strong>" della colonna. Eseguiamo allora lo script per vedere questa funzionalità</p>
<pre><code class="lang-plaintext">%%sql 
describe history SilverLayer.DimProducts;
</code></pre>
<p><img src="https://media.licdn.com/dms/image/D4D12AQEdftYiJyzJxA/article-inline_image-shrink_1500_2232/0/1711053481413?e=1716422400&amp;v=beta&amp;t=nmmN_DwDd_7VfjFtYWb_ujKT4bc2PIm_gWRMgA05WlI" alt /></p>
<p>Queste informazioni sono utili, ma per ottenere un risultato più intuitivo e informativo che indichi chiaramente i valori modificati, le diverse versioni di tali modifiche o anche una versione o un commit specifico, possiamo utilizzare la funzione "table_changes" cui si passa la tabella e il valore che indica la prima versione del cambiamento che si vuole visualizzare. Di seguito lo script</p>
<pre><code class="lang-plaintext">%%sql
SELECT * FROM table_changes('SilverLayer.DimProducts', 1) order by _commit_timestamp DESC;
</code></pre>
<p><img src="https://media.licdn.com/dms/image/D4D12AQFWlcjD5LiZMg/article-inline_image-shrink_1500_2232/0/1711053883337?e=1716422400&amp;v=beta&amp;t=HqIjZOX8RscGj4LjVYrc--Wpn1QnxYWf9F3Zn-fGouI" alt /></p>
<p>Nell'immagine sopra possiamo vedere i valori prima e dopo dei nostri 3 cambiamenti infatti la riga 1 e 2 rappresentano il prima e il dopo dell'aggiornamento del codice EC-T209 la riga 3 mostra la cancellazione della riga con codice FL-2301 e la riga 4 mostra l'inserimento del codice BK-R93R-44</p>
<p>Queste informazioni sono estremamente preziose, quindi per realizzare la SCD 2 sul livello gold. Creaimo una vista temporanea che prende in considerazione solo le ultime versioni di ogni codice</p>
<pre><code class="lang-plaintext">%%sql
CREATE OR REPLACE TEMPORARY VIEW DimProducts_latest_version as
SELECT * 
    FROM 
         (SELECT *, rank() over (partition by ProductAlternateKey  order by _commit_version desc) as rank
          FROM table_changes('SilverLayer.DimProducts', 1)
          WHERE _change_type !='update_preimage')
    WHERE rank=1
</code></pre>
<p>Sotto il risultato nell'immagine</p>
<p><img src="https://media.licdn.com/dms/image/D4D12AQHuxP4oPql7UA/article-inline_image-shrink_1500_2232/0/1711054920904?e=1716422400&amp;v=beta&amp;t=O_28giYJnq8hqrcpoTRmxJp2Pdds6qkuWSUAvN3celk" alt /></p>
<p>Ora utilizzeremo un'istruzione SQL MERGE per allineare la tabella del livello gold con le modifiche della tablle del livello silver in modo tale che siano allineate. L'obiettivo di questa istruzione MERGE è :</p>
<ul>
<li><p>Inserisci eventuali nuove righe nella tabella GoldLakehouse.</p>
</li>
<li><p>Aggiorna una riga esistente in base ai criteri di unione e alla corrispondenza dei valori.</p>
</li>
<li><p>Aggiorna la nostra colonna "DeletedFlag" per le righe che sono state eliminate.</p>
</li>
</ul>
<p>Di seguito lo script per la realizzazione della Merge</p>
<pre><code class="lang-plaintext">%%sql
MERGE INTO GoldLayer.DimProducts t 
USING DimProducts_latest_version  s ON s.ProductAlternateKey  = t.ProductAlternateKey   
WHEN MATCHED AND s._change_type='update_postimage' THEN UPDATE SET SafetyStockLevel = s.SafetyStockLevel 
WHEN MATCHED AND s._change_type='delete' THEN UPDATE SET DeletedFlag = 'Y' 
WHEN NOT MATCHED THEN INSERT (ProductAlternateKey, SafetyStockLevel, Color,DeletedFlag) VALUES (s.ProductAlternateKey, s.SafetyStockLevel,s.Color, 'N')
</code></pre>
<p>Il risultato della merge lo si può vedere sotto</p>
<p><img src="https://media.licdn.com/dms/image/D4D12AQGoKVmB67upSA/article-inline_image-shrink_1500_2232/0/1711056040021?e=1716422400&amp;v=beta&amp;t=2V-4yhH39z4ZX5Z29ueXSdlJ7bOPkJ4dV8rAbpl3hS0" alt /></p>
]]></content:encoded></item><item><title><![CDATA[Semantic Link]]></title><description><![CDATA[Fabric Semantic Link è stato finalmente annunciato ed è disponibile per tutti. Il semantik link permette di accedere facilmente al modello semantico di Power BI utilizzando Python/R/Spark in un notebook in modo da poter arricchire/aumentare i report ...]]></description><link>https://marcopozzan.it/semantic-link</link><guid isPermaLink="true">https://marcopozzan.it/semantic-link</guid><dc:creator><![CDATA[Marco Pozzan]]></dc:creator><pubDate>Thu, 21 Mar 2024 13:01:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1711026665943/21fb225a-7ba9-4afb-bd8b-99fe1e31561c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Fabric Semantic Link è stato finalmente annunciato ed è disponibile per tutti. Il semantik link permette di accedere facilmente al modello semantico di Power BI utilizzando Python/R/Spark in un notebook in modo da poter arricchire/aumentare i report di Power BI con i dati provenienti da altri mondi come ad esempio quello della data science.</p>
<p>Con il collegamento semantico è possibile usare modelli semantici di Power BI all'interno di un progetto di data science per eseguire attività come analisi statistiche approfondite e modellazione predittiva con tecniche di machine learning. L'output può essere archiviato in OneLake utilizzando Apache Spark e inserito in Power BI utilizzando Direct Lake.</p>
<p>Il Semantic Link include una semplice libreria Python (<a target="_blank" href="https://learn.microsoft.com/en-us/python/api/semantic-link-sempy/sempy?view=semantic-link-python">sampy</a>) che può essere utilizzata nel notebook Fabric per accedere a qualsiasi set di dati Power BI (ovvero modello semantico), incluse tutte le relazioni, i dati, le misure, le colonne calcolate, le gerarchie, DMV ed eseguire DAX rispetto nei notebook utilizzando Python o Spark.</p>
<pre><code class="lang-plaintext">#Configurazione libreria
!pip install semantic-link --q 

import pandas as pd
import sempy.fabric as fabric
</code></pre>
<h3 id="heading-alcuni-esempi-di-utilizzo">Alcuni esempi di utilizzo</h3>
<p>Eseguire una misura di un modello semantico di power bi da un notebook spark in Fabric</p>
<pre><code class="lang-plaintext">import requests
import pandas as pd
import sempy.fabric as fabric

TotalSales= (fabric.evaluate_measure(workspace="Modelli-Demo",dataset = "FinancialAnalytics", measure='Total Sales'))

TotalSales
</code></pre>
<p>risultato è nell'immagine sottostante</p>
<p><img src="https://media.licdn.com/dms/image/D4D12AQFawV3LypMcOQ/article-inline_image-shrink_1500_2232/0/1710973767317?e=1716422400&amp;v=beta&amp;t=h1U4uT3TvlOu5_tt4b6R8BSIwWVYzqufgmS5JHrXdi4" alt /></p>
<p>Eseguire un codice DAX in un modello semantico di power bi da un notebook spark in Fabric</p>
<pre><code class="lang-plaintext">import requests
import pandas as pd
import sempy.fabric as fabric

fabric.evaluate_dax(workspace="Modelli-Demo",dataset = "FinancialAnalytics", dax_string="""EVALUATE SUMMARIZE('Sales Orders','Sales Orders'[OrderStatus])""")
</code></pre>
<p>Il risultato è nell'immagine sottostante</p>
<p><img src="https://media.licdn.com/dms/image/D4D12AQF2A2-Z9Gu6cg/article-inline_image-shrink_1500_2232/0/1710974553726?e=1716422400&amp;v=beta&amp;t=OPNf5bAetVYHH8Ad4oFEFZ-nRVfVdqh6DpCfgCYkAxk" alt /></p>
<p>Oltre a comandi di eseguzione di comandi per ottenere dei dati è possibile anche eseguire l'aggiornamento dei dataset di power bi attraverso il seguente script.</p>
<pre><code class="lang-plaintext">import sempy.fabric as fabric 

script = [
    {
        "table": "Sales Orders"
    }
]

fabric.refresh_dataset(
    workspace="Modelli-Demo",
    dataset="FinancialAnalytics", 
    objects=script,
)
</code></pre>
<p><a target="_blank" href="https://github.com/microsoft/fabric-samples/tree/main/docs-samples/data-science/semantic-link-samples">Qui</a> trovate un set di interessanti notebook</p>
]]></content:encoded></item></channel></rss>