Condividi tramite


Connettore Spark Common Data Model per Azure Synapse Analytics

Il connettore Spark Common Data Model (connettore Spark CDM) è un reader/writer di formati in Azure Synapse Analytics. Consente a un programma Spark di leggere e scrivere entità Common Data Model in una cartella Common Data Model tramite DataFrame Spark.

Per informazioni sulla definizione di documenti di Common Data Model tramite Common Data Model 1.2, vedere questo articolo sulle funzionalità di Common Data Model e su come usarli.

Funzionalità

A livello generale, il connettore supporta:

  • 3.1 e 3.2 e 3.3.
  • Lettura di dati da un'entità in una cartella Common Data Model in un DataFrame Spark.
  • Scrittura da un DataFrame Spark a un'entità in una cartella Common Data Model basata su una definizione di entità Common Data Model.
  • Scrittura da un DataFrame Spark a un'entità in una cartella Common Data Model basata sullo schema del DataFrame.

Il connettore supporta anche:

  • Lettura e scrittura in cartelle Common Data Model in Azure Data Lake Storage con uno spazio dei nomi gerarchico (HNS) abilitato.
  • Lettura da cartelle Common Data Model descritte da file manifesto o model.json.
  • Scrittura in cartelle Common Data Model descritte da un file manifesto.
  • Dati in formato CSV con o senza intestazioni di colonna e con caratteri delimitatori selezionabili dall'utente.
  • Dati in formato Apache Parquet, incluso Parquet annidato.
  • Submanifest in lettura e uso facoltativo di submanifest con ambito entità in scrittura.
  • Scrittura di dati tramite modelli di partizione modificabili dall'utente.
  • Uso di identità gestite e credenziali in Azure Synapse Analytics.
  • Risoluzione dei percorsi alias Common Data Model usati nelle importazioni tramite definizioni dell'adattatore Common Data Model descritte in un file config.json.

Limiti

Il connettore non supporta le funzionalità e gli scenari seguenti:

  • Scritture parallele. ma non è una scelta consigliata. Non esiste alcun meccanismo di blocco a livello di archiviazione.
  • Accesso a livello di codice ai metadati dell'entità dopo la lettura di un'entità.
  • Accesso a livello di codice per impostare o eseguire l'override dei metadati durante la scrittura di un'entità.
  • La deriva dello schema, in cui i dati in un DataFrame scritto includono attributi aggiuntivi non inclusi nella definizione dell'entità.
  • Evoluzione dello schema, in cui le partizioni di entità fanno riferimento a versioni diverse della definizione di entità. È possibile verificare la versione eseguendo com.microsoft.cdm.BuildInfo.version.
  • Scrivere il supporto per model.json.
  • Scrittura di dati Time in Parquet. Attualmente, il connettore supporta l'override di una colonna timestamp da interpretare come valore Common Data Model Time anziché come valorDateTime e solo per i file CSV.
  • Tipo Parquet Map, array di tipi primitivi e array di tipi di matrice. Common Data Model attualmente non li supporta, per cui non lo fa neanche il Connettore Spark CDM.

Esempi

Per iniziare a usare il connettore, vedere il codice di esempio e i file Common Data Model.

Lettura dei dati

Quando il connettore legge i dati, usa i metadati nella cartella Common Data Model per creare il DataFrame in base alla definizione di entità risolta per l'entità specificata, come indicato nel manifesto. Il connettore usa nomi di attributi di entità come nomi di colonna DataFrame. Esegue il mapping dei tipi di dati degli attributi ai tipi di dati delle colonne. Quando il DataFrame viene caricato, viene popolato dalle partizioni di entità identificate nel manifesto.

Il connettore cerca nel manifesto specificato ed eventuali submanifest di primo livello per l'entità specificata. Se l'entità richiesta si trova in un submanifest di secondo livello o inferiore o se sono presenti più entità con lo stesso nome in submanifest diversi, è necessario specificare il submanifest che contiene l'entità richiesta anziché il manifesto radice.

Le partizioni di entità possono essere in una combinazione di formati, ad esempio CSV e Parquet. Tutti i file di dati dell'entità identificati nel manifesto vengono combinati in un unico set di dati indipendentemente dal formato e caricato nel DataFrame.

Quando il connettore legge i dati CSV, usa l'opzione Spark failfast per impostazione predefinita. Se il numero di colonne non è uguale al numero di attributi nell'entità, il connettore restituisce un errore.

In alternativa, a partire dalla versione 0.19, il connettore supporta la modalità permissiva (solo per i file CSV). Con la modalità permissiva, quando una riga CSV ha un numero inferiore di colonne rispetto allo schema di entità, il connettore assegna valori Null per le colonne mancanti. Quando una riga CSV contiene più colonne rispetto allo schema di entità, le colonne maggiori del numero di colonne dello schema di entità vengono troncate al numero di colonne dello schema. L'utilizzo è il seguente:

.option("mode", "permissive") or .option("mode", "failfast")

Scrittura dei dati

Quando il connettore scrive in una cartella Common Data Model, se l'entità non esiste già in tale cartella, il connettore crea una nuova entità e una nuova definizione. Aggiunge l'entità e la definizione alla cartella Common Data Model e vi fa riferimento nel manifesto.

Il connettore supporta due modalità di scrittura:

  • Scrittura esplicita: la definizione di entità fisica si basa su una definizione di entità Common Data Model logica specificata.

    Il connettore legge e risolve la definizione di entità logica specificata per creare la definizione di entità fisica usata nella cartella Common Data Model. Se le istruzioni di importazione in qualsiasi file di definizione Common Data Model a cui si fa riferimento direttamente o indirettamente includono alias, è necessario fornire un file config.json che esegue il mapping di questi alias agli adattatori Common Data Model e ai percorsi di archiviazione.

    • Se lo schema del DataFrame non corrisponde alla definizione di entità a cui si fa riferimento, il connettore restituisce un errore. Assicurarsi che i tipi di dati della colonna nel DataFrame corrispondano ai tipi di dati dell'attributo nell'entità, inclusi per i dati decimali, la precisione e il set di scalabilità tramite tratti in Common Data Model.
    • Se il DataFrame non è coerente con la definizione di entità, il connettore restituisce un errore.
    • Se il DataFrame è coerente:
      • Se l'entità esiste già nel manifesto, il connettore risolve la definizione di entità fornita e la convalida rispetto alla definizione nella cartella Common Data Model. Se le definizioni non corrispondono, il connettore restituisce un errore. In caso contrario, il connettore scrive i dati e aggiorna le informazioni sulla partizione nel manifesto.
      • Se l'entità non esiste nella cartella Common Data Model, il connettore scrive una copia risolta della definizione di entità nel manifesto nella cartella Common Data Model. Il connettore scrive i dati e aggiorna le informazioni sulla partizione nel manifesto.
  • Scrittura implicita: la definizione dell'entità è derivata dalla struttura DataFrame.

    • Se l'entità non esiste nella cartella Common Data Model, il connettore usa la definizione implicita per creare la definizione di entità risolta nella cartella Common Data Model di destinazione.

    • Se l'entità esiste nella cartella Common Data Model, il connettore convalida la definizione implicita rispetto alla definizione di entità esistente. Se le definizioni non corrispondono, il connettore restituisce un errore. In caso contrario, il connettore scrive i dati e le definizioni di entità logiche derivate in una sottocartella della cartella dell'entità.

      Il connettore scrive i dati nelle cartelle di dati all'interno di una sottocartella di entità. Una modalità di salvataggio determina se i nuovi dati sovrascrivono o vengono accodati ai dati esistenti o se vengono restituiti un errore se sono presenti dati. L'impostazione predefinita consiste nel restituire un errore se i dati esistono già.

Integrazione dell'alias Common Data Model

I file di definizione di Common Data Model usano alias nelle istruzioni di importazione per semplificare le suddette e consentire il percorso del contenuto importato in fase di esecuzione. Uso degli alias:

  • Semplifica l'organizzazione dei file Common Data Model in modo che le definizioni di Common Data Model correlate possano essere raggruppate in percorsi differenti.
  • Consente l'accesso al contenuto Common Data Model da percorsi distribuiti differenti in fase di esecuzione.

Il frammento di codice seguente illustra l'uso degli alias nelle istruzioni di importazione in un file di definizione Common Data Model:

"imports": [  
{     
  "corpusPath": "cdm:/foundations.cdm.json"
},  
{       
  "corpusPath": "core:/TrackedEntity.cdm.json"  
},  
{      
  "corpusPath": "Customer.cdm.json"  
} 
]

Nell'esempio precedente si usa cdm come alias per il percorso del file foundations di Common Data Model. Usa core come alias per il percorso del file di definizione TrackedEntity.

Gli alias sono etichette di testo corrispondenti a un valore dello spazio dei nomi in una voce dell'adattatore in un file Common Data Model config.json. Una voce dell'adattatore specifica il tipo di adattatore (ad esempio, adls, CDNGitHub, o local) e un URL che definisce un percorso. Alcune schede supportano altre opzioni di configurazione, ad esempio un timeout di connessione. Mentre gli alias sono etichette di testo arbitrarie, l'alias cdm viene trattato in modo speciale.

Il connettore Spark CDM cerca nel percorso radice del modello della definizione dell'entità per il caricamento del file config.json. Se il file config.json si trova in un'altra posizione o si desidera eseguire l'override del file config.json nella radice del modello, è possibile specificare il percorso di un file config.json usando l'opzione configPath. Il file config.json deve contenere voci di adattatore per tutti gli alias usati nel codice Common Data Model risolto, altrimenti il connettore segnala un errore.

La possibilità di eseguire l'override del file config.json significa che è possibile fornire percorsi accessibili dal runtime per le definizioni di Common Data Model. Assicurarsi che il contenuto a cui viene fatto riferimento in fase di esecuzione sia coerente con le definizioni usate quando Common Data Model è stato originariamente creato.

Per convenzione, l'alias cdm fa riferimento al percorso delle definizioni di Common Data Model standard a livello radice, incluso il file foundations.cdm.json. Il file include i tipi di dati primitivi Common Data Model e un set di base di definizioni di tratto necessarie per la maggior parte delle definizioni di entità Common Data Model.

È possibile risolvere l'alias cdm come qualsiasi altro alias usando una voce dell'adattatore nel file config.json. Se non si specifica una scheda o si specifica una voce Null, l'alias cdm viene risolto per impostazione predefinita nella rete per la distribuzione di contenuti (CDN) di Common Data Model all'indirizzo https://cdm-schema.microsoft.com/logical/.

È anche possibile usare l'opzione cdmSource per eseguire l'override del modo in cui viene risolto l'alias cdm. L'uso dell'opzione cdmSource è utile se l'alias cdm è l'unico alias usato nelle definizioni di Common Data Model risolte, perché può evitare la necessità di creare o fare riferimento a un file config.json.

Parametri, opzioni e modalità di salvataggio

Sia per le letture che per le scritture, specificare il nome della libreria del connettore Spark CDM come parametro. Si usa un set di opzioni per parametrizzare il comportamento del connettore. Durante la scrittura, il connettore supporta anche una modalità di salvataggio.

Il nome, le opzioni e la modalità di salvataggio della libreria del connettore sono formattati come segue:

  • dataframe.read.format("com.microsoft.cdm") [.option("option", "value")]*
  • dataframe.write.format("com.microsoft.cdm") [.option("option", "value")]* .mode(savemode.\<saveMode\>)

Di seguito è riportato un esempio che mostra alcune delle opzioni disponibili nell'uso del connettore per le letture:

val readDf = spark.read.format("com.microsoft.cdm")
  .option("storage", "mystorageaccount.dfs.core.windows.net")
  .option("manifestPath", "customerleads/default.manifest.cdm.json")
  .option("entity", "Customer")
  .load()

Opzioni comuni di lettura e scrittura

Le opzioni seguenti identificano l'entità nella cartella Common Data Model in cui si sta leggendo o scrivendo.

Opzione Descrizione Modello e utilizzo di esempio
storage URL dell'endpoint per l'account azure Data Lake Storage, con HNS abilitato, che contiene la cartella Common Data Model.
Usare l'URL dfs.core.windows.net.
<accountName>.dfs.core.windows.net "myAccount.dfs.core.windows.net"
manifestPath Percorso relativo del manifesto o del file model.json nell'account di archiviazione. Per le letture, può essere un manifesto radice o un submanifest o un file model.json. Per le scritture, deve essere un manifesto radice. <container>/{<folderPath>}<manifestFileName>,
"mycontainer/default.manifest.cdm.json" "models/hr/employees.manifest.cdm.json"
"models/hr/employees/model.json" (sola lettura)
entity Nome dell'entità di origine o di destinazione nel manifesto. Quando si scrive un'entità per la prima volta in una cartella, il connettore assegna il nome alla definizione di entità risolta. Il nome dell'entità fa distinzione tra maiuscole e minuscole. <entityName>
"customer"
maxCDMThreads Numero massimo di letture simultanee mentre il connettore risolve una definizione di entità. Qualsiasi numero intero valido, ad esempio 5

Nota

Non è più necessario specificare una definizione di entità logica oltre alla definizione di entità fisica nella cartella Common Data Model in lettura.

Opzioni di scrittura esplicite

Le opzioni seguenti identificano la definizione di entità logica per l'entità scritta. La definizione di entità logica viene risolta in una definizione fisica che definisce la modalità di scrittura dell'entità.

Opzione Descrizione Modello o utilizzo di esempio
entityDefinitionStorage Account di Azure Data Lake Storage che contiene la definizione di entità. Obbligatorio se è diverso dall'account di archiviazione che ospita la cartella Common Data Model. <accountName>.dfs.core.windows.net
"myAccount.dfs.core.windows.net"
entityDefinitionModelRoot Posizione della radice o del corpus del modello all'interno dell'account. <container>/<folderPath>
"crm/core"
entityDefinitionPath Posizione dell'entità. Si tratta del percorso del file di definizione Common Data Model relativo alla radice del modello, incluso il nome dell'entità in tale file. <folderPath>/<entityName>.cdm.json/<entityName>
"sales/customer.cdm.json/customer"
configPath Il percorso del contenitore e della cartella di un file config.json che contiene le configurazioni dell'adattatore per tutti gli alias inclusi nel file di definizione dell'entità e qualsiasi file Common Data Model a cui si fa riferimento direttamente o indirettamente.

Questa opzione non è necessaria se config.json si trova nella cartella radice del modello.
<container><folderPath>
useCdmStandardModelRoot Indica che la radice del modello si trova in https://cdm-schema.microsoft.com/CDM/logical/. Usato per fare riferimento ai tipi di entità definiti nella rete CDN Common Data Model. Esegue l'override entityDefinitionStorage di e entityDefinitionModelRoot (se specificato).
"useCdmStandardModelRoot"
cdmSource Definisce la modalità di risoluzione dell'alias cdm (se presente nei file di definizione common data model). Se si utilizza questa opzione, esegue l'override di qualsiasi adattatore cdm specificato nel file config.json. I valori validi sono builtin o referenced. Il valore predefinito è referenced.

Se si imposta questa opzione su referenced, il connettore usa le definizioni più recenti di Common Data Model pubblicate in https://cdm-schema.microsoft.com/logical/. Se si imposta questa opzione su builtin, il connettore usa le definizioni di base Common Data Model incorporate nel modello a oggetti common data model usato dal connettore.

Nota:
*Il connettore Spark CDM potrebbe non usare la versione più recente di Common Data Model SDK, quindi potrebbe non contenere le definizioni standard pubblicate più recenti.
*Le definizioni predefinite includono solo il contenuto Common Data Model di primo livello, ad esempio foundations.cdm.json o primitives.cdm.json. Se si desidera usare definizioni di Common Data Model standard di livello inferiore, usare referenced o includere un adattatore cdm in config.json.
"builtin"|"referenced"

Nell'esempio precedente il percorso completo dell'oggetto definizione dell'entità cliente è https://myAccount.dfs.core.windows.net/models/crm/core/sales/customer.cdm.json/customer. In questo percorso i modelli sono il contenitore in Azure Data Lake Storage.

Opzioni di scrittura implicite

Se non si specifica una definizione di entità logica in scrittura, l'entità viene scritta in modo implicito, in base allo schema del DataFrame.

Quando si scrive in modo implicito, una colonna timestamp viene in genere interpretata come un tipo di dati Common Data Model DateTime. È possibile eseguire l'override di questa interpretazione per creare un attributo del tipo di dati Common Data Model Time fornendo un oggetto metadati associato alla colonna che specifica il tipo di dati. Per informazioni dettagliate, vedere Gestione dei dati temporali di Common Data Model più avanti in questo articolo.

Il supporto per la scrittura dei dati temporali è disponibile solo per i file CSV. Il supporto attualmente non si estende a Parquet.

Opzioni per la struttura delle cartelle e il formato dei dati

È possibile usare le opzioni seguenti per modificare l'organizzazione della cartella e il formato di file.

Opzione Descrizione Modello o utilizzo di esempio
useSubManifest Se true, fa sì che l'entità di destinazione venga inclusa nel manifesto radice tramite una submanifest. Il submanifest e la definizione dell'entità vengono scritti in una cartella di entità sotto la radice. Il valore predefinito è false. "true"|"false"
format Definisce il formato di file. I formati di file supportati correnti sono CSV e Parquet. Il valore predefinito è csv. "csv"|"parquet"
delimiter Solo CSV. Definisce il delimitatore in uso. Il valore predefinito è la virgola. "|"
columnHeaders Solo CSV. Se true, aggiunge una prima riga ai file di dati con intestazioni di colonna. Il valore predefinito è true. "true"|"false"
compression Sola scrittura. Solo Parquet. Definisce il formato di compressione in uso. Il valore predefinito è snappy. "uncompressed" | "snappy" | "gzip" | "lzo"
dataFolderFormat Consente una struttura di cartelle di dati definibile dall'utente all'interno di una cartella di entità. Consente di sostituire i valori di data e ora in nomi di cartelle usando la formattazione DateTimeFormatter. Il contenuto non formattatore deve essere racchiuso tra virgolette singole. Il formato predefinito è "yyyy"-"MM"-"dd", che produce nomi di cartelle come 2020-07-30. year "yyyy" / month "MM"
"Data"

Save mode

La modalità di salvataggio specifica il modo in cui il connettore gestisce i dati di entità esistenti nella cartella Common Data Model durante la scrittura di un DataFrame. Le opzioni devono sovrascrivere, aggiungere o restituire un errore se i dati esistono già. La modalità di salvataggio predefinita è ErrorIfExists.

Modalità Descrizione
SaveMode.Overwrite Sovrascrive la definizione di entità esistente se viene modificata e sostituisce le partizioni di dati esistenti con le partizioni di dati in fase di scrittura.
SaveMode.Append Aggiunge i dati scritti in nuove partizioni insieme alle partizioni esistenti.

Questa modalità non supporta la modifica dello schema. Se lo schema dei dati scritti non è compatibile con la definizione di entità esistente, il connettore genera un errore.
SaveMode.ErrorIfExists Restituisce un errore se sono già presenti partizioni.

Per informazioni dettagliate sul modo in cui i file di dati sono denominati e organizzati in fase di scrittura, vedere la sezione Cartella e denominazione e organizzazione più avanti in questo articolo.

Autenticazione

È possibile usare tre modalità di autenticazione con il connettore Spark CDM per leggere o scrivere i metadati e le partizioni di dati di Common Data Model: passthrough delle credenziali, token di firma di accesso condiviso (SAS) e registrazione dell'app.

Pass-through delle credenziali

In Azure Synapse Analytics il connettore Spark CDM supporta l'uso di identità gestite per le risorse di Azure per mediare l'accesso all'account di Azure Data Lake Storage che contiene la cartella Common Data Model. Un'identità gestita viene creata automaticamente per ogni area di lavoro di Azure Synapse Analytics. Il connettore usa l'identità gestita dell'area di lavoro che contiene il notebook in cui viene chiamato il connettore per l'autenticazione negli account di archiviazione.

È necessario assicurarsi che l'identità scelta abbia accesso agli account di archiviazione appropriati:

  • Concedere le autorizzazioni Collaboratore ai dati del BLOB di archiviazione per consentire alla libreria di scrivere nelle cartelle Common Data Model.
  • Concedere le autorizzazioni di lettura dei dati dei BLOB di archiviazione per consentire solo l'accesso in lettura.

In entrambi i casi non sono necessarie opzioni aggiuntive per il connettore.

Opzioni per il controllo degli accessi in base al token SAS

Le credenziali del token SAS sono un'opzione aggiuntiva per l'autenticazione agli account di archiviazione. Con l'autenticazione con token SAS, il token SAS può essere a livello di contenitore o di cartella. Sono necessarie le autorizzazioni appropriate:

  • Le autorizzazioni di lettura per un manifesto o una partizione richiedono solo il supporto a livello di lettura.
  • Le autorizzazioni di scrittura richiedono sia il supporto di lettura che scrittura.
Opzione Descrizione Modello e utilizzo di esempio
sasToken Token SAS per accedere all'account di archiviazione relativo con le autorizzazioni corrette <token>

Opzioni per il controllo degli accessi in base alle credenziali

In alternativa all'uso di un'identità gestita o di un'identità utente, è possibile fornire credenziali esplicite per consentire al connettore Spark CDM di accedere ai dati. In Microsoft Entra ID creare una registrazione dell'app. Concedere quindi all'app l'accesso alla registrazione all'account di archiviazione usando uno dei ruoli seguenti:

  • Collaboratore ai dati del BLOB di archiviazione per consentire alla libreria di scrivere in cartelle Common Data Model
  • Lettore di dati BLOB di archiviazione per consentire solo le autorizzazioni di lettura

Dopo aver creato le autorizzazioni, è possibile passare l'ID app, la chiave dell'app e l'ID tenant al connettore in ogni chiamata usando le opzioni seguenti. È consigliabile usare Azure Key Vault per archiviare questi valori per assicurarsi che non siano archiviati in testo non crittografato nel file del notebook.

Opzione Descrizione Modello e utilizzo di esempio
appId ID di registrazione dell'app per l'autenticazione nell'account di archiviazione <guid>
appKey Chiave o segreto dell'app registrata <encrypted secret>
tenantId ID tenant di Microsoft Entra con cui viene registrata l'app <guid>

Esempi

Negli esempi seguenti vengono usate tutte le variabili appId, appKey e tenantId. Queste variabili sono state inizializzate in precedenza nel codice, in base a una registrazione dell'app di Azure: autorizzazioni Collaboratore ai dati del BLOB di archiviazione per l'archiviazione per la scrittura e autorizzazioni di lettura dei dati del BLOB di archiviazione per la lettura.

Lettura

Questo codice legge l'entità Person dalla cartella Common Data Model con un manifesto in mystorage.dfs.core.windows.net/cdmdata/contacts/root.manifest.cdm.json:

val df = spark.read.format("com.microsoft.cdm")
 .option("storage", "mystorage.dfs.core.windows.net")
 .option("manifestPath", "cdmdata/contacts/root.manifest.cdm.json")
 .option("entity", "Person")
 .load()

Scrittura implicita usando solo uno schema DataFrame

Il codice seguente scrive il DataFrame df in una cartella Common Data Model con un manifesto in mystorage.dfs.core.windows.net/cdmdata/Contacts/default.manifest.cdm.json con un'entità evento.

Il codice scrive i dati dell'evento come file Parquet, lo comprime con gzip e lo aggiunge alla cartella. (il codice aggiunge nuovi file senza eliminare i file esistenti).


df.write.format("com.microsoft.cdm")
 .option("storage", "mystorage.dfs.core.windows.net")
 .option("manifestPath", "cdmdata/Contacts/default.manifest.cdm.json")
 .option("entity", "Event")
 .option("format", "parquet")
 .option("compression", "gzip")
 .mode(SaveMode.Append)
 .save()

Scrittura esplicita usando una definizione di entità archiviata in Data Lake Storage

Il codice seguente scrive il DataFrame df in una cartella Common Data Model con un manifesto in https://_mystorage_.dfs.core.windows.net/cdmdata/Contacts/root.manifest.cdm.json con l'entità Person. Il codice scrive i dati delle persone come nuovi file CSV (per impostazione predefinita) che sovrascrivono i file esistenti nella cartella.

Il codice recupera la definizione dell’entità Person da https://_mystorage_.dfs.core.windows.net/models/cdmmodels/core/Contacts/Person.cdm.json.

df.write.format("com.microsoft.cdm")
 .option("storage", "mystorage.dfs.core.windows.net")
 .option("manifestPath", "cdmdata/contacts/root.manifest.cdm.json")
 .option("entity", "Person")
 .option("entityDefinitionModelRoot", "cdmmodels/core")
 .option("entityDefinitionPath", "/Contacts/Person.cdm.json/Person")
 .mode(SaveMode.Overwrite)
 .save()

Scrittura esplicita usando un'entità definita nel repository GitHub Common Data Model

Il codice seguente scrive il DataFrame df in una cartella Common Data Model con:

  • Manifesto in https://_mystorage_.dfs.core.windows.net/cdmdata/Teams/root.manifest.cdm.json.
  • Submanifest che contiene l'entità TeamMembership creata in una sottodirectory TeamMembership.

I dati TeamMembership vengono scritti in file CSV (impostazione predefinita) che sovrascrivono eventuali file di dati esistenti. Il codice recupera la definizione di TeamMembership entità dall'rete CDN Common Data Model in Team Membership in applicationCommon.

df.write.format("com.microsoft.cdm")
 .option("storage", "mystorage.dfs.core.windows.net")
 .option("manifestPath", "cdmdata/Teams/root.manifest.cdm.json")
 .option("entity", "TeamMembership")
 .option("useCdmStandardModelRoot", true)
 .option("entityDefinitionPath", "core/applicationCommon/TeamMembership.cdm.json/TeamMembership")
 .option("useSubManifest", true)
 .mode(SaveMode.Overwrite)
 .save()

Altre considerazioni

Mapping dei tipi di dati da Spark a Common Data Model

Il connettore applica i mapping dei tipi di dati seguenti quando si converte Common Data Model in o da Spark.

Spark Common Data Model
ShortType SmallInteger
IntegerType Integer
LongType BigInteger
DateType Date
Timestamp DateTime (facoltativamente Time)
StringType String
DoubleType Double
DecimalType(x,y) Decimal (x,y) (la scala e la precisione predefinite sono 18,4)
FloatType Float
BooleanType Boolean
ByteType Byte

Il connettore non supporta il tipo di dati Common Data Model Binary.

Gestione dei dati di Common Data Model Date, DateTime e DateTimeOffset

Il connettore Spark CDM gestisce tipi di dati Common Data Model Date e DateTime come di consueto per Spark e Parquet. In CSV il connettore legge e scrive tali tipi di dati in formato ISO 8601.

Il connettore interpreta i valori del tipo di dati Common Data Model DateTime come UTC. In CSV il connettore scrive tali valori in formato ISO 8601. Un esempio è 2020-03-13 09:49:00Z.

I valori di Common Data Model DateTimeOffset destinati alla registrazione di istantanee dell'ora locale vengono gestiti in modo diverso in Spark e Parquet da CSV. CSV e altri formati possono esprimere un istante dell'ora locale come struttura che comprende un valore datetime, ad esempio 2020-03-13 09:49:00-08:00. Parquet e Spark non supportano tali strutture. Usano invece un tipo di dati TIMESTAMP che consente di registrare un istante in formato UTC (o in un fuso orario non specificato).

Il connettore Spark CDM converte un valore DateTimeOffset in CSV in un timestamp UTC. Questo valore viene salvato in modo permanente come timestamp in Parquet. Se il valore viene reso persistente in un secondo momento in CSV, verrà serializzato come valore DateTimeOffset con un offset +00:00. Non c'è alcuna perdita di accuratezza temporale. I valori serializzati rappresentano lo stesso istante dei valori originali, anche se l'offset viene perso.

I sistemi Spark usano il tempo di sistema come baseline e in genere esprimono il tempo usando l'ora locale. È sempre possibile calcolare le ore UTC tramite l'applicazione dell'offset del sistema locale. Per i sistemi di Azure in tutte le aree, l'ora di sistema è sempre UTC, per cui tutti i valori del timestamp sono normalmente in formato UTC. Quando si usa una scrittura implicita, in cui una definizione Common Data Model è derivata da un DataFrame, le colonne timestamp vengono convertite in attributi con il tipo di dati Common Data Model DateTime, che implica un'ora UTC.

Se è importante rendere persistente un'ora locale e i dati verranno elaborati in Spark o salvati in modo permanente in Parquet, è consigliabile usare un attributo DateTime e mantenere l'offset in un attributo separato. Ad esempio, è possibile mantenere l'offset come valore intero con segno che rappresenta i minuti. In Common Data Model i valori DateTime sono in formato UTC, per cui è necessario applicare l'offset per calcolare l'ora locale.

Nella maggior parte dei casi, la persistenza dell'ora locale non è importante. Gli orari locali sono spesso necessari solo in un'interfaccia utente per praticità dell'utente e in base al fuso orario dell'utente, per cui l'archiviazione di un'ora UTC è spesso una soluzione migliore.

Gestione dei dati temporali di Common Data Model

Spark non supporta un tipo di dati esplicito Time. Un attributo con il tipo di dati Common Data Model Time è rappresentato in un DataFrame Spark come colonna con un tipo di dati Timestamp. Quando il connettore Spark CDM legge un valore di ora, il timestamp nel DataFrame viene inizializzato con la data Spark epoch 01/01/1970 più il valore di ora come letto dall'origine.

Quando si usa la scrittura esplicita, è possibile eseguire il mapping di una colonna timestamp a un attributo DateTime o Time. Se si esegue il mapping di un timestamp a un attributo Time, la parte relativa alla data del timestamp viene rimossa.

Quando si usa la scrittura implicita, per impostazione predefinita viene mappata una colonna timestamp a un attributo DateTime. Per eseguire il mapping di una colonna timestamp a un attributo Time, è necessario aggiungere un oggetto metadati alla colonna nel DataFrame che indica che il timestamp deve essere interpretato come valore di ora. Nel codice seguente viene illustrato come eseguire questa operazione in Scala:

val md = new MetadataBuilder().putString(“dataType”, “Time”)
val schema = StructType(List(
StructField(“ATimeColumn”, TimeStampType, true, md))

Accuratezza dei valori temporali

Il connettore Spark CDM supporta i valori di ora in DateTime o Time. I secondi hanno fino a sei numeri decimali, in base al formato dei dati nel file da leggere (CSV o Parquet) o come definito nel DataFrame. L'uso di sei numeri decimali consente l'accuratezza da singoli secondi a microsecondi.

Denominazione e organizzazione di cartelle e file

Quando si scrive nelle cartelle Common Data Model, è presente un'organizzazione di cartelle predefinita. Per impostazione predefinita, i file di dati vengono scritti in cartelle create per la data corrente, denominate come 2010-07-31. È possibile personalizzare la struttura e i nomi delle cartelle usando l'opzione dateFolderFormat.

I nomi dei file di dati sono basati sul modello seguente: <entity>-<jobid>-*.<fileformat>.

È possibile controllare il numero di partizioni di dati scritte usando il metodo sparkContext.parallelize(). Il numero di partizioni è determinato dal numero di executor nel cluster Spark o specificato in modo esplicito. L'esempio Scala seguente crea un DataFrame con due partizioni:

val df= spark.createDataFrame(spark.sparkContext.parallelize(data, 2), schema)

Di seguito è riportato un esempio di scrittura esplicita definita da una definizione di entità a cui si fa riferimento:

+-- <CDMFolder>
     |-- default.manifest.cdm.json     << with entity reference and partition info
     +-- <Entity>
          |-- <entity>.cdm.json        << resolved physical entity definition
          |-- <data folder>
          |-- <data folder>
          +-- ...                            

Ecco un esempio di scrittura esplicita con un submanifest:

+-- <CDMFolder>
    |-- default.manifest.cdm.json       << contains reference to submanifest
    +-- <Entity>
         |-- <entity>.cdm.json
         |-- <entity>.manifest.cdm.json << submanifest with partition info
         |-- <data folder>
         |-- <data folder>
         +-- ...

Di seguito è riportato un esempio di scrittura implicita in cui la definizione di entità è derivata da uno schema DataFrame:

+-- <CDMFolder>
    |-- default.manifest.cdm.json
    +-- <Entity>
         |-- <entity>.cdm.json          << resolved physical entity definition
         +-- LogicalDefinition
         |   +-- <entity>.cdm.json      << logical entity definitions
         |-- <data folder>
         |-- <data folder>
         +-- ...

Ecco un esempio di scrittura implicita con un submanifest:

+-- <CDMFolder>
    |-- default.manifest.cdm.json       << contains reference to submanifest
    +-- <Entity>
        |-- <entity>.cdm.json           << resolved physical entity definition
        |-- <entity>.manifest.cdm.json  << submanifest with reference to the entity and partition info
        +-- LogicalDefinition
        |   +-- <entity>.cdm.json       << logical entity definitions
        |-- <data folder>
        |-- <data folder>
        +-- ...

Risoluzione dei problemi e problemi noti

  • Assicurarsi che la precisione decimale e la scala dei campi del tipo di dati decimali usati nel DataFrame corrispondano al tipo di dati nella definizione di entità Common Data Model. Se la precisione e la scala non sono definite in modo esplicito in Common Data Model, il valore predefinito è Decimal(18,4). Per i file model.json, si presuppone che Decimal sia Decimal(18,4).
  • I nomi di file e cartelle nelle opzioni seguenti non devono includere spazi o caratteri speciali, ad esempio un segno di uguale (=): manifestPath, entityDefinitionModelRoot, entityDefinitionPath, dataFolderFormat.

Passaggi successivi

È ora possibile esaminare gli altri connettori Apache Spark: