Shiny no Azure Databricks

Shiny é um pacote R, disponível no CRAN, usado para construir aplicativos e painéis interativos R. Você pode usar o Shiny dentro do RStudio Server hospedado em clusters do Azure Databricks. Você também pode desenvolver, hospedar e compartilhar aplicativos Shiny diretamente de um bloco de anotações do Azure Databricks.

Para começar a usar o Shiny, consulte os tutoriais do Shiny. Você pode executar esses tutoriais em blocos de anotações do Azure Databricks.

Este artigo descreve como executar aplicativos Shiny no Azure Databricks e usar o Apache Spark dentro de aplicativos Shiny.

Brilhante dentro de notebooks R

Introdução aos notebooks Shiny inside R

O pacote Shiny está incluído no Databricks Runtime. Você pode desenvolver e testar interativamente aplicativos Shiny dentro de notebooks do Azure Databricks R de forma semelhante ao RStudio hospedado.

Siga estes passos para começar:

  1. Crie um bloco de anotações R.

  2. Importe o pacote Shiny e execute o aplicativo 01_hello de exemplo da seguinte maneira:

      library(shiny)
      runExample("01_hello")
    
  3. Quando o aplicativo estiver pronto, a saída incluirá o URL do aplicativo Shiny como um link clicável que abre uma nova guia. Para partilhar esta aplicação com outros utilizadores, consulte Partilhar URL da aplicação Shiny.

    Exemplo de aplicação Shiny

Nota

  • As mensagens de log aparecem no resultado do comando, semelhante à mensagem de log padrão (Listening on http://0.0.0.0:5150) mostrada no exemplo.
  • Para parar o aplicativo Shiny, clique em Cancelar.
  • A aplicação Shiny utiliza o processo R do notebook. Se você desanexar o bloco de anotações do cluster ou cancelar a célula que executa o aplicativo, o aplicativo Shiny será encerrado. Não é possível executar outras células enquanto o aplicativo Shiny está em execução.

Execute aplicativos Shiny a partir de pastas Databricks Git

Você pode executar aplicativos Shiny que são verificados em pastas Databricks Git.

  1. Clone um repositório Git remoto.

  2. Execute a aplicação.

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

Executar aplicações Shiny a partir de ficheiros

Se o código do aplicativo Shiny fizer parte de um projeto gerenciado pelo controle de versão, você poderá executá-lo dentro do bloco de anotações.

Nota

Você deve usar o caminho absoluto ou definir o diretório de trabalho com setwd().

  1. Confira o código de um repositório usando um código semelhante a:

      %sh git clone https://github.com/rstudio/shiny-examples.git
      cloning into 'shiny-examples'...
    
  2. Para executar o aplicativo, insira um código semelhante ao seguinte em outra célula:

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

Partilhar o URL da aplicação Shiny

O URL do aplicativo Shiny gerado quando você inicia um aplicativo é compartilhável com outros usuários. Qualquer usuário do Azure Databricks com permissão CAN ATTACH TO no cluster pode exibir e interagir com o aplicativo, desde que o aplicativo e o cluster estejam em execução.

Se o cluster no qual o aplicativo está sendo executado for encerrado, o aplicativo não estará mais acessível. Você pode desabilitar a terminação automática nas configurações do cluster.

Se você anexar e executar o bloco de anotações que hospeda o aplicativo Shiny em um cluster diferente, o URL Shiny será alterado. Além disso, se você reiniciar o aplicativo no mesmo cluster, o Shiny poderá escolher uma porta aleatória diferente. Para garantir uma URL estável, você pode definir a shiny.port opção ou, ao reiniciar o aplicativo no mesmo cluster, especificar o port argumento.

Brilhante no servidor RStudio hospedado

Requisitos

Importante

Com o RStudio Server Pro, você deve desativar a autenticação por proxy. Certifique-se de que auth-proxy=1 não está presente no interior /etc/rstudio/rserver.conf.

Introdução ao Shiny no RStudio Server hospedado

  1. Abra o RStudio no Azure Databricks.

  2. No RStudio, importe o pacote Shiny e execute o aplicativo 01_hello de exemplo da seguinte maneira:

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

    Uma nova janela aparece, exibindo o aplicativo Shiny.

    Primeiro aplicativo Shiny

Executar um aplicativo Shiny a partir de um script R

Para executar um aplicativo Shiny a partir de um script R, abra o script R no editor RStudio e clique no botão Executar aplicativo no canto superior direito.

Aplicativo de execução brilhante

Use o Apache Spark dentro de aplicativos Shiny

Você pode usar o Apache Spark dentro de aplicativos Shiny com SparkR ou sparklyr.

Usar o SparkR com Shiny em um notebook

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)

Use o sparklyr com Shiny em um notebook

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)

Aplicação Spark Shiny

Perguntas mais frequentes (FAQ)

Por que meu aplicativo Shiny está acinzentado depois de algum tempo?

Se não houver interação com o aplicativo Shiny, a conexão com o aplicativo será fechada após cerca de 4 minutos.

Para se reconectar, atualize a página do aplicativo Shiny. O estado do painel é redefinido.

Por que minha janela do visualizador Shiny desaparece depois de um tempo?

Se a janela do visualizador Shiny desaparecer depois de ficar ociosa por vários minutos, é devido ao mesmo tempo limite que o cenário "gray out".

Por que os trabalhos longos do Spark nunca voltam?

Isso também ocorre por causa do tempo limite ocioso. Qualquer trabalho do Spark em execução por mais tempo do que os tempos limite mencionados anteriormente não é capaz de renderizar seu resultado porque a conexão fecha antes que o trabalho retorne.

Como posso evitar o tempo limite?

  • Há uma solução alternativa sugerida em Solicitação de recurso: fazer com que o cliente envie a mensagem keep alive para evitar o tempo limite de TCP em alguns balanceadores de carga no Github. A solução alternativa envia pulsações para manter a conexão WebSocket ativa quando o aplicativo está ocioso. No entanto, se o aplicativo estiver bloqueado por um cálculo de longa execução, essa solução alternativa não funcionará.

  • Shiny não suporta tarefas de longa duração. Uma postagem de blog Shiny recomenda o uso de promessas e futuros para executar tarefas longas de forma assíncrona e manter o aplicativo desbloqueado. Aqui está um exemplo que usa pulsações para manter o aplicativo Shiny vivo e executa um trabalho Spark de longa duração em uma future construção.

    # 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)
    
  • Há um limite rígido de 12 horas desde o carregamento inicial da página, após o qual qualquer conexão, mesmo que ativa, será encerrada. Você deve atualizar o aplicativo Shiny para se reconectar nesses casos. No entanto, a conexão WebSocket subjacente pode fechar a qualquer momento por uma variedade de fatores, incluindo instabilidade de rede ou modo de suspensão do computador. O Databricks recomenda reescrever aplicativos Shiny para que eles não exijam uma conexão de longa duração e não confiem demais no estado da sessão.

Meu aplicativo falha imediatamente após a inicialização, mas o código parece estar correto. O que é que se passa?

Há um limite de 50 MB na quantidade total de dados que podem ser exibidos em um aplicativo Shiny no Azure Databricks. Se o tamanho total de dados do aplicativo exceder esse limite, ele falhará imediatamente após a inicialização. Para evitar isso, o Databricks recomenda reduzir o tamanho dos dados, por exemplo, reduzindo a resolução dos dados exibidos ou reduzindo a resolução das imagens.

A Databricks recomenda até 20.

Posso usar uma versão do pacote Shiny diferente da instalada no Databricks Runtime?

Sim. Consulte Corrigir a versão dos pacotes R.

Como posso desenvolver um aplicativo Shiny que pode ser publicado em um servidor Shiny e acessar dados no Azure Databricks?

Embora você possa acessar dados naturalmente usando o SparkR ou o sparklyr durante o desenvolvimento e o teste no Azure Databricks, depois que um aplicativo Shiny é publicado em um serviço de hospedagem autônomo, ele não pode acessar diretamente os dados e as tabelas no Azure Databricks.

Para permitir que seu aplicativo funcione fora do Azure Databricks, você deve reescrever como acessa os dados. Existem algumas opções:

  • Use JDBC/ODBC para enviar consultas a um cluster do Azure Databricks.
  • Use o Databricks Connect.
  • Acesse diretamente os dados no armazenamento de objetos.

A Databricks recomenda que você trabalhe com sua equipe de soluções do Azure Databricks para encontrar a melhor abordagem para sua arquitetura de dados e análises existente.

Posso desenvolver um aplicativo Shiny dentro de um bloco de anotações do Azure Databricks?

Sim, você pode desenvolver um aplicativo Shiny dentro de um bloco de anotações do Azure Databricks.

Como posso guardar as aplicações Shiny que desenvolvi no RStudio Server alojado?

Você pode salvar o código do aplicativo no DBFS ou verificar seu código no controle de versão.