Узкое место SparkR в createDataFrame?

Я новичок в Spark, SparkR и вообще во всех технологиях, связанных с HDFS. Недавно я установил Spark 1.5.0 и запустил простой код с помощью SparkR:

Sys.setenv(SPARK_HOME="/private/tmp/spark-1.5.0-bin-hadoop2.6")
.libPaths("/private/tmp/spark-1.5.0-bin-hadoop2.6/R/lib")
require('SparkR')
require('data.table')

sc <- sparkR.init(master="local")
sqlContext <- sparkRSQL.init(sc)
hiveContext <- sparkRHive.init(sc)

n = 1000
x = data.table(id = 1:n, val = rnorm(n))

Sys.time()
xs <- createDataFrame(sqlContext, x)
Sys.time()

Код выполняется немедленно. Однако, когда я меняю его на n = 1000000, это занимает около 4 минут (время между двумя вызовами Sys.time()). Когда я проверяю эти задания в консоли на порту: 4040, задание для n = 1000 имеет продолжительность 0,2 с, а задание для n = 1000000 0,3 с. Я делаю что-то неправильно?


person Krzysztof Jędrzejewski    schedule 01.10.2015    source источник
comment
Это заняло у меня некоторое время из-за некоторых неожиданных проблем (по пути я столкнулся с некоторыми другими ошибками, не говоря уже о том, что я постоянно забываю, какие странные вещи вы можете поместить в качестве столбца фрейма данных), но это должно быть решено в 1.6.0: SPARK-11086   -  person zero323    schedule 16.11.2015


Ответы (1)


Вы не делаете ничего особенно плохого. Это просто эффект сочетания разных факторов:

  1. createDataFrame в том виде, в каком он реализован в настоящее время (Spark 1.5.1), работает медленно. Это известная проблема, описанная в SPARK-8277.
  2. Текущая реализация плохо работает с data.table.
  3. База R относительно медленная. Умные люди говорят, что это функция, а не ошибка, но ее все же следует учитывать.

Пока SPARK-8277 не будет разрешен, вы мало что можете сделать, но есть два варианта, которые вы можете попробовать:

  • используйте старый добрый data.frame вместо data.table. Используя набор данных о рейсах (227496 строк, 14 столбцов):

    df <- read.csv("flights.csv")
    microbenchmark::microbenchmark(createDataFrame(sqlContext, df), times=3)
    
    ## Unit: seconds
    ##                             expr      min       lq     mean   median
    ##  createDataFrame(sqlContext, df) 96.41565 97.19515 99.08441 97.97465
    ##        uq      max neval
    ##  100.4188 102.8629     3
    

    по сравнению с data.table

    dt <- data.table::fread("flights.csv")
    microbenchmark::microbenchmark(createDataFrame(sqlContext, dt), times=3)
    
    ## Unit: seconds        
    ##                             expr      min       lq     mean  median
    ##  createDataFrame(sqlContext, dt) 378.8534 379.4482 381.2061 380.043
    ##        uq     max neval
    ##  382.3825 384.722     3
    
  • Запишите на диск и используйте spark-csv для загрузки данных непосредственно в Spark DataFrame без прямого взаимодействия с R. Как бы безумно это ни звучало:

    dt <- data.table::fread("flights.csv")
    
    write_and_read <- function() {
        write.csv(dt, tempfile(), row.names=FALSE)
        read.df(sqlContext, "flights.csv",
            source = "com.databricks.spark.csv",
            header = "true",
            inferSchema = "true"
        )
    }
    
    ## Unit: seconds
    ##              expr      min       lq     mean   median
    ##  write_and_read() 2.924142 2.959085 2.983008 2.994027
    ##       uq      max neval
    ##  3.01244 3.030854     3
    

Я не совсем уверен, действительно ли имеет смысл передавать данные, которые могут быть обработаны в R, в Spark, в первую очередь, но давайте не будем останавливаться на этом.

Изменить:

Эта проблема должна быть решена с помощью SPARK-11086 в Spark 1.6.0.

person zero323    schedule 13.10.2015
comment
Мне нравится твой последний комментарий! :) - person eliasah; 14.10.2015
comment
Да... Я могу быть предвзятым, но мне кажется, что SparkR берет большую часть удовольствия от R и дает очень мало взамен. Scala API достаточно мощный, чтобы его можно было рассматривать даже на относительно небольших данных, особенно когда нет идиоматической альтернативы, кроме Breeze. В Питоне это 50-50. Но SparkR кажется немного неуклюжим драйвером базы данных :) - person zero323; 14.10.2015
comment
Не могли бы вы уточнить свой 2-й пункт, почему? Data.table — это data.frame, и есть способы доступа к столбцам, аналогичные data.frame. Отсюда небольшое недоумение. Кроме того, по вашему 3-му пункту, относительно медленно к чему? И на какой операции в этом контексте? - person Arun; 14.10.2015
comment
@Arun Конечно, но давайте переместим его в чат. - person zero323; 15.10.2015