Shiny på Azure Databricks

Shiny är ett R-paket som finns på CRAN och används för att skapa interaktiva R-program och instrumentpaneler. Du kan använda Shiny i RStudio Server som finns i Azure Databricks-kluster. Du kan också utveckla, vara värd för och dela Shiny-program direkt från en Azure Databricks-notebook-fil.

Om du vill komma igång med Shiny kan du läsa de glänsande självstudierna. Du kan köra de här självstudierna i Azure Databricks-notebook-filer.

Den här artikeln beskriver hur du kör Shiny-program på Azure Databricks och använder Apache Spark i Shiny-program.

Glänsande inuti R-anteckningsböcker

Kom igång med Shiny inuti R-notebook-filer

Shiny-paketet ingår i Databricks Runtime. Du kan interaktivt utveckla och testa Shiny-program i Azure Databricks R-notebook-filer på samma sätt som värdbaserade RStudio.

Följ dessa steg för att komma igång:

  1. Skapa en R-anteckningsbok.

  2. Importera Shiny-paketet och kör exempelappen 01_hello på följande sätt:

      library(shiny)
      runExample("01_hello")
    
  3. När appen är klar innehåller utdata url:en för Shiny-appen som en klickbar länk som öppnar en ny flik. Information om hur du delar den här appen med andra användare finns i Dela glänsande app-URL.

    Exempel på glänsande app

Kommentar

  • Loggmeddelanden visas i kommandoresultatet, ungefär som standardloggmeddelandet (Listening on http://0.0.0.0:5150) som visas i exemplet.
  • Om du vill stoppa Shiny-programmet klickar du på Avbryt.
  • Shiny-programmet använder notebook R-processen. Om du kopplar från anteckningsboken från klustret, eller om du avbryter cellen som kör programmet, avslutas Shiny-programmet. Du kan inte köra andra celler medan Shiny-programmet körs.

Köra Shiny-appar från Databricks Git-mappar

Du kan köra Shiny-appar som är incheckade i Databricks Git-mappar.

  1. Klona en fjärransluten Git-lagringsplats.

  2. Kör programmet.

    library(shiny)
    runApp("006-tabsets")
    

Köra Shiny-appar från filer

Om din Shiny-programkod ingår i ett projekt som hanteras av versionskontrollen kan du köra den i notebook-filen.

Kommentar

Du måste använda den absoluta sökvägen eller ange arbetskatalogen med setwd().

  1. Kolla in koden från en lagringsplats med hjälp av kod som liknar:

      %sh git clone https://github.com/rstudio/shiny-examples.git
      cloning into 'shiny-examples'...
    
  2. Om du vill köra programmet anger du kod som liknar följande i en annan cell:

    library(shiny)
    runApp("/databricks/driver/shiny-examples/007-widgets/")
    

Dela glänsande app-URL

Url:en för shiny-appen som genereras när du startar en app kan delas med andra användare. Alla Azure Databricks-användare med CAN ATTACH TO-behörighet i klustret kan visa och interagera med appen så länge både appen och klustret körs.

Om klustret som appen körs på avslutas är appen inte längre tillgänglig. Du kan inaktivera automatisk avslutning i klusterinställningarna.

Om du bifogar och kör notebook-filen som är värd för Shiny-appen i ett annat kluster ändras shiny-URL:en. Om du startar om appen i samma kluster kan Shiny också välja en annan slumpmässig port. För att säkerställa en stabil URL kan du ange shiny.port alternativet, eller när du startar om appen i samma kluster kan du ange port argumentet.

Shiny på värdbaserad RStudio Server

Krav

Viktigt!

Med RStudio Server Pro måste du inaktivera proxierad autentisering. Se till att auth-proxy=1 inte finns i /etc/rstudio/rserver.conf.

Kom igång med Shiny på värdbaserade RStudio Server

  1. Öppna RStudio på Azure Databricks.

  2. Importera Shiny-paketet i RStudio och kör exempelappen 01_hello på följande sätt:

    > library(shiny)
    > runExample("01_hello")
    
    Listening on http://127.0.0.1:3203
    

    Ett nytt fönster visas med shiny-programmet.

    First Shiny-app

Köra en Shiny-app från ett R-skript

Om du vill köra en Shiny-app från ett R-skript öppnar du R-skriptet i RStudio-redigeraren och klickar på knappen Kör app längst upp till höger.

Glänsande körningsapp

Använda Apache Spark i Shiny-appar

Du kan använda Apache Spark i Shiny-program med antingen SparkR eller sparklyr.

Använda SparkR med Shiny i en notebook-fil

library(shiny)
library(SparkR)
sparkR.session()

ui <- fluidPage(
  mainPanel(
    textOutput("value")
  )
)

server <- function(input, output) {
  output$value <- renderText({ nrow(createDataFrame(iris)) })
}

shinyApp(ui = ui, server = server)

Använd sparklyr med Shiny i en notebook-fil

library(shiny)
library(sparklyr)

sc <- spark_connect(method = "databricks")

ui <- fluidPage(
  mainPanel(
    textOutput("value")
  )
)

server <- function(input, output) {
  output$value <- renderText({
    df <- sdf_len(sc, 5, repartition = 1) %>%
      spark_apply(function(e) sum(e)) %>%
      collect()
    df$result
  })
}

shinyApp(ui = ui, server = server)
library(dplyr)
library(ggplot2)
library(shiny)
library(sparklyr)

sc <- spark_connect(method = "databricks")
diamonds_tbl <- spark_read_csv(sc, path = "/databricks-datasets/Rdatasets/data-001/csv/ggplot2/diamonds.csv")

# Define the UI
ui <- fluidPage(
  sliderInput("carat", "Select Carat Range:",
              min = 0, max = 5, value = c(0, 5), step = 0.01),
  plotOutput('plot')
)

# Define the server code
server <- function(input, output) {
  output$plot <- renderPlot({
    # Select diamonds in carat range
    df <- diamonds_tbl %>%
      dplyr::select("carat", "price") %>%
      dplyr::filter(carat >= !!input$carat[[1]], carat <= !!input$carat[[2]])

    # Scatter plot with smoothed means
    ggplot(df, aes(carat, price)) +
      geom_point(alpha = 1/2) +
      geom_smooth() +
      scale_size_area(max_size = 2) +
      ggtitle("Price vs. Carat")
  })
}

# Return a Shiny app object
shinyApp(ui = ui, server = server)

Spark Shiny-app

Vanliga frågor och svar

Varför är min Shiny-app nedtonad efter en tid?

Om det inte finns någon interaktion med Shiny-appen stängs anslutningen till appen efter cirka 4 minuter.

Om du vill återansluta uppdaterar du shiny-appsidan. Instrumentpanelens tillstånd återställs.

Varför försvinner mitt glänsande visningsfönster efter ett tag?

Om shiny viewer-fönstret försvinner efter tomgång i flera minuter beror det på samma timeout som scenariot "gray out".

Varför kommer långa Spark-jobb aldrig tillbaka?

Detta beror också på tidsgränsen för inaktivitet. Alla Spark-jobb som körs längre än de tidigare nämnda tidsgränserna kan inte återge resultatet eftersom anslutningen stängs innan jobbet returneras.

Hur undviker jag tidsgränsen?

  • Det finns en lösning som föreslås i funktionsbegäran: Be klienten skicka keep alive-meddelande för att förhindra TCP-timeout på vissa lastbalanserare på Github. Lösningen skickar pulsslag för att hålla WebSocket-anslutningen vid liv när appen är inaktiv. Men om appen blockeras av en tidskrävande beräkning fungerar inte den här lösningen.

  • Shiny stöder inte tidskrävande uppgifter. Ett shiny-blogginlägg rekommenderar att du använder löften och framtider för att köra långa uppgifter asynkront och hålla appen avblockerad. Här är ett exempel som använder pulsslag för att hålla Shiny-appen vid liv och kör ett långvarigt Spark-jobb i en future konstruktion.

    # Write an app that uses spark to access data on Databricks
    # First, install the following packages:
    install.packages(‘future’)
    install.packages(‘promises’)
    
    library(shiny)
    library(promises)
    library(future)
    plan(multisession)
    
    HEARTBEAT_INTERVAL_MILLIS = 1000  # 1 second
    
    # Define the long Spark job here
    run_spark <- function(x) {
      # Environment setting
      library("SparkR", lib.loc = "/databricks/spark/R/lib")
      sparkR.session()
    
      irisDF <- createDataFrame(iris)
      collect(irisDF)
      Sys.sleep(3)
      x + 1
    }
    
    run_spark_sparklyr <- function(x) {
      # Environment setting
      library(sparklyr)
      library(dplyr)
      library("SparkR", lib.loc = "/databricks/spark/R/lib")
      sparkR.session()
      sc <- spark_connect(method = "databricks")
    
      iris_tbl <- copy_to(sc, iris, overwrite = TRUE)
      collect(iris_tbl)
      x + 1
    }
    
    ui <- fluidPage(
      sidebarLayout(
        # Display heartbeat
        sidebarPanel(textOutput("keep_alive")),
    
        # Display the Input and Output of the Spark job
        mainPanel(
          numericInput('num', label = 'Input', value = 1),
          actionButton('submit', 'Submit'),
          textOutput('value')
        )
      )
    )
    server <- function(input, output) {
      #### Heartbeat ####
      # Define reactive variable
      cnt <- reactiveVal(0)
      # Define time dependent trigger
      autoInvalidate <- reactiveTimer(HEARTBEAT_INTERVAL_MILLIS)
      # Time dependent change of variable
      observeEvent(autoInvalidate(), {  cnt(cnt() + 1)  })
      # Render print
      output$keep_alive <- renderPrint(cnt())
    
      #### Spark job ####
      result <- reactiveVal() # the result of the spark job
      busy <- reactiveVal(0)  # whether the spark job is running
      # Launch a spark job in a future when actionButton is clicked
      observeEvent(input$submit, {
        if (busy() != 0) {
          showNotification("Already running Spark job...")
          return(NULL)
        }
        showNotification("Launching a new Spark job...")
        # input$num must be read outside the future
        input_x <- input$num
        fut <- future({ run_spark(input_x) }) %...>% result()
        # Or: fut <- future({ run_spark_sparklyr(input_x) }) %...>% result()
        busy(1)
        # Catch exceptions and notify the user
        fut <- catch(fut, function(e) {
          result(NULL)
          cat(e$message)
          showNotification(e$message)
        })
        fut <- finally(fut, function() { busy(0) })
        # Return something other than the promise so shiny remains responsive
        NULL
      })
      # When the spark job returns, render the value
      output$value <- renderPrint(result())
    }
    shinyApp(ui = ui, server = server)
    
  • Det finns en hård gräns på 12 timmar sedan den första sidinläsningen varefter alla anslutningar, även om de är aktiva, avslutas. Du måste uppdatera Shiny-appen för att återansluta i dessa fall. Den underliggande WebSocket-anslutningen kan dock när som helst stängas av en mängd olika faktorer, inklusive nätverks-instabilitet eller datorns viloläge. Databricks rekommenderar att du skriver om Shiny-appar så att de inte kräver en långvarig anslutning och inte överlitar sig på sessionstillstånd.

Min app kraschar direkt efter starten, men koden verkar vara korrekt. Vad är det som händer?

Det finns en gräns på 50 MB för den totala mängden data som kan visas i en Shiny-app i Azure Databricks. Om programmets totala datastorlek överskrider den här gränsen kraschar den omedelbart efter start. För att undvika detta rekommenderar Databricks att du minskar datastorleken, till exempel genom att koppla ned de data som visas eller minska bildupplösningen.

Databricks rekommenderar upp till 20.

Kan jag använda en annan version av Shiny-paketet än den som installerades i Databricks Runtime?

Ja. Se Åtgärda versionen av R-paket.

Hur kan jag utveckla ett Shiny-program som kan publiceras till en Shiny-server och få åtkomst till data i Azure Databricks?

Även om du kan komma åt data naturligt med Hjälp av SparkR eller sparklyr under utveckling och testning på Azure Databricks, kan det inte direkt komma åt data och tabeller i Azure Databricks när ett Shiny-program har publicerats till en fristående värdtjänst.

Om du vill att programmet ska fungera utanför Azure Databricks måste du skriva om hur du kommer åt data. Det finns några alternativ:

  • Använd JDBC/ODBC för att skicka frågor till ett Azure Databricks-kluster.
  • Använd Databricks Anslut.
  • Direktåtkomst till data i objektlagring.

Databricks rekommenderar att du arbetar med ditt Azure Databricks-lösningsteam för att hitta den bästa metoden för din befintliga data- och analysarkitektur.

Kan jag utveckla ett Shiny-program i en Azure Databricks-notebook-fil?

Ja, du kan utveckla ett Shiny-program i en Azure Databricks-notebook-fil.

Hur kan jag spara shiny-program som jag utvecklade på värdbaserade RStudio Server?

Du kan antingen spara programkoden på DBFS eller kontrollera koden i versionskontrollen.