Azure Cosmos DB: eseguire analisi dei grafi con Spark e Apache TinkerPop Gremlin

Azure Cosmos DB è il servizio di database multimodello distribuito a livello globale di Microsoft. È possibile creare ed eseguire query su database di documenti, coppie chiave-valore e grafi sfruttando i vantaggi offerti dalle funzionalità di scalabilità orizzontale e distribuzione globale alla base di Azure Cosmos DB. Azure Cosmos DB supporta carichi di lavoro di grafi OLTP (Online Transaction Processing) basati sul linguaggio Apache TinkerPop Gremlin.

Spark è un progetto di Apache Software Foundation incentrato sull'elaborazione di dati OLAP (Online Analytical Processing) generici. Spark offre un modello di calcolo distribuito in memoria/su disco simile al modello MapReduce di Hadoop. È possibile distribuire Apache Spark nel cloud con Azure HDInsight.

Combinando Azure Cosmos DB e Spark, è possibile eseguire carichi di lavoro sia OLTP che OLAP con Gremlin. Questa guida introduttiva illustra come eseguire query Gremlin su Azure Cosmos DB in un cluster Azure HDInsight Spark.

Prerequisiti

Prima di poter eseguire questo esempio, è necessario soddisfare i prerequisiti seguenti:

  • Cluster Azure HDInsight Spark 2.0
  • JDK 1.8+ (eseguire apt-get install default-jdk se JDK non è disponibile)
  • Maven (eseguire apt-get install maven se Maven non è disponibile)
  • Una sottoscrizione di Azure (Se non si ha una sottoscrizione di Azure, creare un account gratuito prima di iniziare.)

Per informazioni su come configurare un cluster Azure HDInsight Spark, vedere Provisioning di cluster HDInsight.

Creare un account di database Azure Cosmos DB

Per prima cosa, si crea un account di database con l'API Graph seguendo questa procedura:

  1. In una nuova finestra accedere al portale di Azure.
  2. Nel riquadro a sinistra fare clic su Nuovo, quindi su Database e infine su Azure Cosmos DB.

    Riquadro Database nel portale di Azure

  3. Nel pannello Nuovo account specificare la configurazione desiderata per l'account Azure Cosmos DB.

    Con Azure Cosmos DB è possibile scegliere uno dei quattro modelli di programmazione: Gremlin (grafo), MongoDB, SQL (DocumentDB) e Tabella (chiave/valore), ognuno dei quali attualmente richiede un account separato.

    In questa guida introduttiva viene eseguita la programmazione in base all'API di DocumentDB, quindi scegliere SQL (DocumentDB) quando si compila il modulo. Se si hanno dati di grafi di un'app di social media, dati chiave/valore (tabella) o dati di cui è stata eseguita la migrazione da un'app MongoDB, tenere presente che Azure Cosmos DB può offrire una piattaforma di servizi di database con distribuzione a livello globale e a disponibilità elevata per tutte le applicazioni cruciali.

    Completare i campi nel pannello Nuovo account usando le informazioni riportate nello screenshot seguente come guida. I valori effettivi potrebbero essere diversi.

    Pannello Nuovo account per Azure Cosmos DB

    Impostazione Valore consigliato Descrizione
    ID Valore univoco Nome univoco che identifica l'account Azure Cosmos DB. Poiché alI'ID fornito viene aggiunto documents.azure.com per creare l'URI, usare un ID univoco ma facilmente identificabile. L'ID può contenere solo lettere minuscole, numeri e il segno meno (-) e deve avere una lunghezza compresa tra 3 e 50 caratteri.
    API SQL (DocumentDB) La programmazione in base all'API di DocumentDB verrà eseguita più avanti in questo articolo.
    Sottoscrizione Sottoscrizione in uso Sottoscrizione di Azure da usare per l'account Azure Cosmos DB.
    Gruppo di risorse Stesso valore di ID Nome del nuovo gruppo di risorse per l'account. Per semplicità si può usare lo stesso nome usato come ID.
    Località Area più vicina ai propri utenti Posizione geografica in cui ospitare l'account Azure Cosmos DB. Scegliere la posizione più vicina agli utenti, per offrire loro l'accesso più rapido possibile ai dati.
  4. Fare clic su Crea per creare l'account.
  5. Nella barra degli strumenti superiore fare clic sull'icona delle notifiche icona delle notifiche per monitorare il processo di distribuzione.

    Riquadro Notifiche del portale di Azure

  6. Quando la finestra Notifiche indica che la distribuzione è stata completata, chiudere la finestra di notifica e aprire il nuovo account dal riquadro Tutte le risorse nel Dashboard.

    Account DocumentDB nel riquadro Tutte le risorse

Aggiungere una raccolta

È ora possibile usare lo strumento Esplora dati nel portale di Azure per creare un database e una raccolta.

  1. Nel menu di navigazione a sinistra del portale di Azure fare clic su Esplora dati (anteprima).

  2. Nel pannello Esplora dati (anteprima) fare clic su Nuova raccolta e quindi specificare le informazioni seguenti:

    Pannello Esplora dati nel portale di Azure

    Impostazione Valore consigliato Descrizione
    ID database Attività Nome del nuovo database. I nomi dei database devono avere una lunghezza compresa tra 1 e 255 caratteri e non possono contenere /, \, #, ? o spazi finali.
    ID raccolta Items Nome della nuova raccolta. I nomi delle raccolte prevedono requisiti per i caratteri uguali a quelli degli ID dei database.
    Capacità di archiviazione Fissa (10 GB) Usare il valore predefinito. Questo valore indica la capacità di archiviazione del database.
    Velocità effettiva 400 UR Usare il valore predefinito. Se si vuole ridurre la latenza, è possibile aumentare la velocità effettiva in un secondo momento.
    UR/min Off Lasciare il valore predefinito. Se in seguito sarà necessario gestire carichi di lavoro di picco, sarà possibile attivare la funzionalità UR/min al momento.
    Chiave di partizione /category Chiave di partizione che distribuisce i dati in modo uniforme a ogni partizione. Quando si crea una raccolta ad alte prestazioni è importante selezionare la chiave di partizione corretta. Per altre informazioni, vedere Progettazione per il partizionamento.
  3. Dopo aver completato il modulo, fare clic su OK.

Esplora dati mostrerà il nuovo database e la nuova raccolta.

Ottenere Apache TinkerPop

Ottenere Apache TinkerPop seguendo questa procedura:

  1. Accedere in remoto al nodo master del cluster HDInsight ssh tinkerpop3-cosmosdb-demo-ssh.azurehdinsight.net.

  2. Clonare il codice sorgente di TinkerPop3, compilarlo in locale ed eseguirne l'installazione nella cache di Maven.

    git clone https://github.com/apache/tinkerpop.git
    cd tinkerpop
    mvn clean install
    
  3. Installare il plug-in Spark-Gremlin

    a. L'installazione del plug-in viene gestita da Grape. Inserire le informazioni relative ai repository per Grape in modo da consentire il download del plug-in e delle relative dipendenze.

    Creare il file di configurazione di Grape, se non è presente in ~/.groovy/grapeConfig.xml. Usare le seguenti impostazioni:

    <ivysettings>
    <settings defaultResolver="downloadGrapes"/>
    <resolvers>
        <chain name="downloadGrapes">
        <filesystem name="cachedGrapes">
            <ivy pattern="${user.home}/.groovy/grapes/[organisation]/[module]/ivy-[revision].xml"/>
            <artifact pattern="${user.home}/.groovy/grapes/[organisation]/[module]/[type]s/[artifact]-[revision].[ext]"/>
        </filesystem>
        <ibiblio name="codehaus" root="http://repository.codehaus.org/" m2compatible="true"/>
        <ibiblio name="central" root="http://central.maven.org/maven2/" m2compatible="true"/>
        <ibiblio name="jitpack" root="https://jitpack.io" m2compatible="true"/>
        <ibiblio name="java.net2" root="http://download.java.net/maven/2/" m2compatible="true"/>
        <ibiblio name="apache-snapshots" root="http://repository.apache.org/snapshots/" m2compatible="true"/>
        <ibiblio name="local" root="file:${user.home}/.m2/repository/" m2compatible="true"/>
        </chain>
    </resolvers>
    </ivysettings>
    

    b. Avviare la console Gremlin bin/gremlin.sh.

    c. Installare il plug-in Spark-Gremlin con la versione 3.3.0-SNAPSHOT compilata nei passaggi precedenti:

    $ bin/gremlin.sh
    
            \,,,/
            (o o)
    -----oOOo-(3)-oOOo-----
    plugin activated: tinkerpop.server
    plugin activated: tinkerpop.utilities
    plugin activated: tinkerpop.tinkergraph
    gremlin> :install org.apache.tinkerpop spark-gremlin 3.3.0-SNAPSHOT
    ==>loaded: [org.apache.tinkerpop, spark-gremlin, 3.3.0-SNAPSHOT] - restart the console to use [tinkerpop.spark]
    gremlin> :q
    $ bin/gremlin.sh
    
            \,,,/
            (o o)
    -----oOOo-(3)-oOOo-----
    plugin activated: tinkerpop.server
    plugin activated: tinkerpop.utilities
    plugin activated: tinkerpop.tinkergraph
    gremlin> :plugin use tinkerpop.spark
    ==>tinkerpop.spark activated
    
  4. Controllare se Hadoop-Gremlin è attivato con :plugin list. Disabilitare questo plug-in perché potrebbe interferire con il plug-in Spark-Gremlin :plugin unuse tinkerpop.hadoop.

Preparare le dipendenze di TinkerPop3

Durante la compilazione di TinkerPop3 nel passaggio precedente sono state estratte nella directory di destinazione anche tutte le dipendenze in formato JAR per Spark e Hadoop. Usare i file JAR preinstallati con HDI ed effettuare il pull delle dipendenze aggiuntive solo se necessario.

  1. Passare alla directory di destinazione della console Gremlin in tinkerpop/gremlin-console/target/apache-tinkerpop-gremlin-console-3.3.0-SNAPSHOT-standalone.

  2. Spostare tutti i file JAR da ext/ a lib/: find ext/ -name '*.jar' -exec mv {} lib/ \;.

  3. Rimuovere tutte le librerie JAR in lib/ che non sono incluse nell'elenco seguente:

    # TinkerPop3
    gremlin-console-3.3.0-SNAPSHOT.jar
    gremlin-core-3.3.0-SNAPSHOT.jar       
    gremlin-groovy-3.3.0-SNAPSHOT.jar     
    gremlin-shaded-3.3.0-SNAPSHOT.jar     
    hadoop-gremlin-3.3.0-SNAPSHOT.jar     
    spark-gremlin-3.3.0-SNAPSHOT.jar      
    tinkergraph-gremlin-3.3.0-SNAPSHOT.jar
    
    # Gremlin depedencies
    asm-3.2.jar                                
    avro-1.7.4.jar                             
    caffeine-2.3.1.jar                         
    cglib-2.2.1-v20090111.jar                  
    gbench-0.4.3-groovy-2.4.jar                
    gprof-0.3.1-groovy-2.4.jar                 
    groovy-2.4.9-indy.jar                      
    groovy-2.4.9.jar                           
    groovy-console-2.4.9.jar                   
    groovy-groovysh-2.4.9-indy.jar             
    groovy-json-2.4.9-indy.jar                 
    groovy-jsr223-2.4.9-indy.jar               
    groovy-sql-2.4.9-indy.jar                  
    groovy-swing-2.4.9.jar                     
    groovy-templates-2.4.9.jar                 
    groovy-xml-2.4.9.jar                       
    hadoop-yarn-server-nodemanager-2.7.2.jar   
    hppc-0.7.1.jar                             
    javatuples-1.2.jar                         
    jaxb-impl-2.2.3-1.jar                      
    jbcrypt-0.4.jar                            
    jcabi-log-0.14.jar                         
    jcabi-manifests-1.1.jar                    
    jersey-core-1.9.jar                        
    jersey-guice-1.9.jar                       
    jersey-json-1.9.jar                        
    jettison-1.1.jar                           
    scalatest_2.11-2.2.6.jar                   
    servlet-api-2.5.jar                        
    snakeyaml-1.15.jar                         
    unused-1.0.0.jar                           
    xml-apis-1.3.04.jar                        
    

Ottenere il connettore Spark per Azure Cosmos DB

  1. Ottenere il connettore Spark per Azure Cosmos DB azure-documentdb-spark-0.0.3-SNAPSHOT.jar e Cosmos DB Java SDK azure-documentdb-1.10.0.jar dalla relativa pagina in Github.

  2. In alternativa, è possibile eseguirne la compilazione in locale. Dato che l'ultima versione di Spark-Gremlin è stata compilata con Spark 1.6.1 e non è compatibile con la versione Spark 2.0.2 attualmente usata nel connettore Spark per Azure Cosmos DB, è possibile compilare il codice di TinkerPop3 più recente e installare i file JAR manualmente. Eseguire le operazioni seguenti:

    a. Clonare il connettore Spark per Azure Cosmos DB.

    b. Compilare TinkerPop3 (operazione già eseguita nei passaggi precedenti) e installare tutti i file JAR di TinkerPop 3.3.0-SNAPSHOT in locale.

    mvn install:install-file -Dfile="gremlin-core-3.3.0-SNAPSHOT.jar" -DgroupId=org.apache.tinkerpop -DartifactId=gremlin-core -Dversion=3.3.0-SNAPSHOT -Dpackaging=jar
    mvn install:install-file -Dfile="gremlin-groovy-3.3.0-SNAPSHOT.jar" -DgroupId=org.apache.tinkerpop -DartifactId=gremlin-groovy -Dversion=3.3.0-SNAPSHOT -Dpackaging=jar`
    mvn install:install-file -Dfile="gremlin-shaded-3.3.0-SNAPSHOT.jar" -DgroupId=org.apache.tinkerpop -DartifactId=gremlin-shaded -Dversion=3.3.0-SNAPSHOT -Dpackaging=jar`
    mvn install:install-file -Dfile="hadoop-gremlin-3.3.0-SNAPSHOT.jar" -DgroupId=org.apache.tinkerpop -DartifactId=hadoop-gremlin -Dversion=3.3.0-SNAPSHOT -Dpackaging=jar`
    mvn install:install-file -Dfile="spark-gremlin-3.3.0-SNAPSHOT.jar" -DgroupId=org.apache.tinkerpop -DartifactId=spark-gremlin -Dversion=3.3.0-SNAPSHOT -Dpackaging=jar`
    mvn install:install-file -Dfile="tinkergraph-gremlin-3.3.0-SNAPSHOT.jar" -DgroupId=org.apache.tinkerpop -DartifactId=tinkergraph-gremlin -Dversion=3.3.0-SNAPSHOT -Dpackaging=jar`
    

    c. Aggiornare tinkerpop.version azure-documentdb-spark/pom.xml a 3.3.0-SNAPSHOT.

    d. Eseguire la compilazione con Maven. I file JAR necessari vengono inseriti in target e target/alternateLocation.

    git clone https://github.com/Azure/azure-cosmosdb-spark.git
    cd azure-documentdb-spark
    mvn clean package
    
  3. Copiare i file JAR elencati in precedenza in una directory locale in ~/azure-documentdb-spark:

    $ azure-documentdb-spark:
    mkdir ~/azure-documentdb-spark
    cp target/azure-documentdb-spark-0.0.3-SNAPSHOT.jar ~/azure-documentdb-spark
    cp target/alternateLocation/azure-documentdb-1.10.0.jar ~/azure-documentdb-spark
    

Distribuire le dipendenze nei nodi di lavoro Spark

  1. Dato che la trasformazione dei dati dei grafi dipende da TinkerPop3, è necessario distribuire le relative dipendenze in tutti i nodi di lavoro Spark.

  2. Copiare le dipendenze Gremlin elencate in precedenza, il file JAR del connettore Spark per CosmosDB e CosmosDB Java SDK nei nodi di lavoro seguendo questa procedura:

    a. Copiare tutti i file JAR in ~/azure-documentdb-spark.

    $ /home/sshuser/tinkerpop/gremlin-console/target/apache-tinkerpop-gremlin-console-3.3.0-SNAPSHOT-standalone:
    cp lib/* ~/azure-documentdb-spark
    

    b. Ottenere l'elenco di tutti i nodi di lavoro Spark, disponibile nel dashboard Ambari, nell'elenco Spark2 Clients della sezione Spark2.

    c. Copiare la directory in ogni nodo.

    scp -r ~/azure-documentdb-spark sshuser@wn0-cosmos:/home/sshuser
    scp -r ~/azure-documentdb-spark sshuser@wn1-cosmos:/home/sshuser
    ...
    

Configurare le variabili di ambiente

  1. Trovare la versione HDP del cluster Spark, corrispondente al nome di directory in /usr/hdp/ (ad esempio, 2.5.4.2-7).

  2. Configurare hdp.version per tutti i nodi. Nel dashboard Ambari passare a YARN section > Configs > Advanced (Sezione YARN > Configurazioni > Avanzate) e seguire questa procedura:

    a. In Custom yarn-site aggiungere una nuova proprietà hdp.version con il valore della versione di HDP nel nodo master.

    b. Salvare le configurazioni. Verranno visualizzati avvisi che è possibile ignorare.

    c. Riavviare i servizi Oozie e YARN come indicato dalle icone di notifica.

  3. Impostare le variabili di ambiente seguenti nel nodo master, sostituendo i valori in base alle esigenze:

    export HADOOP_GREMLIN_LIBS=/home/sshuser/tinkerpop/gremlin-console/target/apache-tinkerpop-gremlin-console-3.3.0-SNAPSHOT-standalone/ext/spark-gremlin/lib
    export CLASSPATH=$CLASSPATH:$HADOOP_CONF_DIR:/usr/hdp/current/spark2-client/jars/*:/home/sshuser/azure-documentdb-spark/*
    export HDP_VERSION=2.5.4.2-7
    export HADOOP_HOME=${HADOOP_HOME:-/usr/hdp/current/hadoop-client}
    

Preparare la configurazione per i grafi

  1. Creare un file di configurazione con i parametri di connessione di Azure Cosmos DB e le impostazioni di Spark e inserirlo in tinkerpop/gremlin-console/target/apache-tinkerpop-gremlin-console-3.3.0-SNAPSHOT-standalone/conf/hadoop/gremlin-spark.properties.

    gremlin.graph=org.apache.tinkerpop.gremlin.hadoop.structure.HadoopGraph
    gremlin.hadoop.jarsInDistributedCache=true
    gremlin.hadoop.defaultGraphComputer=org.apache.tinkerpop.gremlin.spark.process.computer.SparkGraphComputer
    
    gremlin.hadoop.graphReader=com.microsoft.azure.documentdb.spark.gremlin.DocumentDBInputRDD
    gremlin.hadoop.graphWriter=com.microsoft.azure.documentdb.spark.gremlin.DocumentDBOutputRDD
    
    ####################################
    # SparkGraphComputer Configuration #
    ####################################
    spark.master=yarn
    spark.executor.memory=3g
    spark.executor.instances=6
    spark.serializer=org.apache.spark.serializer.KryoSerializer
    spark.kryo.registrator=org.apache.tinkerpop.gremlin.spark.structure.io.gryo.GryoRegistrator
    gremlin.spark.persistContext=true
    
    # Classpath for the driver and executors
    spark.driver.extraClassPath=/usr/hdp/current/spark2-client/jars/*:/home/sshuser/azure-documentdb-spark/*
    spark.executor.extraClassPath=/usr/hdp/current/spark2-client/jars/*:/home/sshuser/azure-documentdb-spark/*
    
    ######################################
    # DocumentDB Spark connector         #
    ######################################
    spark.documentdb.connectionMode=Gateway
    spark.documentdb.schema_samplingratio=1.0
    spark.documentdb.Endpoint=https://FILLIN.documents.azure.com:443/
    spark.documentdb.Masterkey=FILLIN
    spark.documentdb.Database=FILLIN
    spark.documentdb.Collection=FILLIN
    spark.documentdb.preferredRegions=FILLIN
    
  2. Aggiornare spark.driver.extraClassPath e spark.executor.extraClassPath in modo da includere la directory dei file JAR distribuiti nel passaggio precedente, in questo caso /home/sshuser/azure-documentdb-spark/*.

  3. Specificare i dettagli seguenti per Azure Cosmos DB:

    spark.documentdb.Endpoint=https://FILLIN.documents.azure.com:443/
    spark.documentdb.Masterkey=FILLIN
    spark.documentdb.Database=FILLIN
    spark.documentdb.Collection=FILLIN
    # Optional
    #spark.documentdb.preferredRegions=West\ US;West\ US\ 2
    

Caricare il grafo TinkerPop e salvarlo in Azure Cosmos DB

Per illustrare come è possibile salvare in modo permanente un grafo in Azure Cosmos DB, si usa come esempio il grafo modern predefinito di TinkerPop. Il grafo è stato archiviato in formato Kryo ed è disponibile nel repository TinkerPop.

  1. Dato che si esegue Gremlin in modalità YARN, è necessario rendere disponibili i dati del grafo nel file system Hadoop. Usare i comandi seguenti per creare una directory e copiare al suo interno il file del grafo locale.

    $ tinkerpop:
    hadoop fs -mkdir /graphData
    hadoop fs -copyFromLocal ~/tinkerpop/data/tinkerpop-modern.kryo /graphData/tinkerpop-modern.kryo
    
  2. Aggiornare temporaneamente il file gremlin-spark.properties in modo da usare GryoInputFormat per la lettura del grafo. Indicare anche inputLocation come directory creata, come illustrato di seguito:

    gremlin.hadoop.graphReader=org.apache.tinkerpop.gremlin.hadoop.structure.io.gryo.GryoInputFormat
    gremlin.hadoop.inputLocation=/graphData/tinkerpop-modern.kryo
    
  3. Avviare la console Gremlin e creare questi passaggi di calcolo per salvare in modo permanente i dati nella raccolta Azure Cosmos DB configurata:

    a. Creare il grafo: graph = GraphFactory.open("conf/hadoop/gremlin-spark.properties").

    b. Usare SparkGraphComputer per la scrittura graph.compute(SparkGraphComputer.class).result(GraphComputer.ResultGraph.NEW).persist(GraphComputer.Persist.EDGES).program(TraversalVertexProgram.build().traversal(graph.traversal().withComputer(Computer.compute(SparkGraphComputer.class)),"gremlin-groovy","g.V()").create(graph)).submit().get().

    gremlin> graph = GraphFactory.open("conf/hadoop/gremlin-spark.properties")
    ==>hadoopgraph[gryoinputformat->documentdboutputrdd]
    gremlin> hg = graph.
                compute(SparkGraphComputer.class).
                result(GraphComputer.ResultGraph.NEW).
                persist(GraphComputer.Persist.EDGES).
                program(TraversalVertexProgram.build().
                    traversal(graph.traversal().withComputer(Computer.compute(SparkGraphComputer.class)), "gremlin-groovy", "g.V()").
                    create(graph)).
                submit().
                get() 
    ==>result[hadoopgraph[documentdbinputrdd->documentdboutputrdd],memory[size:1]]
    
  4. In Esplora dati è possibile verificare che i dati siano stati salvati in modo permanente in Azure Cosmos DB.

Caricare il grafo da Azure Cosmos DB ed eseguire query Gremlin.

  1. Per caricare il grafo, modificare gremlin-spark.properties per impostare graphReader su DocumentDBInputRDD:

    gremlin.hadoop.graphReader=com.microsoft.azure.documentdb.spark.gremlin.DocumentDBInputRDD
    
  2. Caricare il grafo, attraversare i dati ed eseguire query Gremlin seguendo questa procedura:

    a. Avviare la console Gremlin bin/gremlin.sh.

    b. Creare il grafo con la configurazione graph = GraphFactory.open('conf/hadoop/gremlin-spark.properties').

    c. Creare un attraversamento del grafo con SparkGraphComputer g = graph.traversal().withComputer(SparkGraphComputer).

    d. Eseguire le query Gremlin seguenti sul grafo:

    gremlin> graph = GraphFactory.open("conf/hadoop/gremlin-spark.properties")
    ==>hadoopgraph[documentdbinputrdd->documentdboutputrdd]
    gremlin> g = graph.traversal().withComputer(SparkGraphComputer)
    ==>graphtraversalsource[hadoopgraph[documentdbinputrdd->documentdboutputrdd], sparkgraphcomputer]
    gremlin> g.V().count()
    ==>6
    gremlin> g.E().count()
    ==>6
    gremlin> g.V(1).out().values('name')
    ==>josh
    ==>vadas
    ==>lop
    gremlin> g.V().hasLabel('person').coalesce(values('nickname'), values('name'))
    ==>josh
    ==>peter
    ==>vadas
    ==>marko
    gremlin> g.V().hasLabel('person').
            choose(values('name')).
                option('marko', values('age')).
                option('josh', values('name')).
                option('vadas', valueMap()).
                option('peter', label())
    ==>josh
    ==>person
    ==>[name:[vadas],age:[27]]
    ==>29
    
Nota

Per visualizzare una registrazione più dettagliata, impostare un livello di log più dettagliato in conf/log4j-console.properties.

Passaggi successivi

In questa guida introduttiva si è appreso come usare i grafi combinando Azure Cosmos DB e Spark.