start standalone spark run locally docs cluster r scala apache-spark apache-spark-sql sparkr

standalone - spark docs



Usando SparkR JVM para llamar a métodos desde un archivo jar Scala (1)

Quería poder empaquetar DataFrames en un archivo jar Scala y acceder a ellos en R. El objetivo final es crear una forma de acceder a tablas de bases de datos específicas y de uso frecuente en Python, R y Scala sin escribir una biblioteca diferente para cada .

Para hacer esto, hice un archivo jar en Scala con funciones que usan la biblioteca SparkSQL para consultar la base de datos y obtener los DataFrames que quiero. Quería poder llamar a estas funciones en R sin crear otra JVM, ya que Spark ya se ejecuta en una JVM en R. Sin embargo, los usos de JVM Spark no están expuestos en la API de SparkR. Para que sea accesible y hacer que los métodos Java sean accesibles, modifiqué "backend.R", "generics.R", "DataFrame.R" y "NAMESPACE" en el paquete SparkR y reconstruí el paquete:

En "backend.R" hice los métodos formales "callJMethod" y "createJObject":

setMethod("callJMethod", signature(objId="jobj", methodName="character"), function(objId, methodName, ...) { stopifnot(class(objId) == "jobj") if (!isValidJobj(objId)) { stop("Invalid jobj ", objId$id, ". If SparkR was restarted, Spark operations need to be re-executed.") } invokeJava(isStatic = FALSE, objId$id, methodName, ...) }) setMethod("newJObject", signature(className="character"), function(className, ...) { invokeJava(isStatic = TRUE, className, methodName = "<init>", ...) })

Modifiqué "generic.R" para que también contenga estas funciones:

#'' @rdname callJMethod #'' @export setGeneric("callJMethod", function(objId, methodName, ...) { standardGeneric("callJMethod")}) #'' @rdname newJobject #'' @export setGeneric("newJObject", function(className, ...) {standardGeneric("newJObject")})

Luego agregué exportaciones para estas funciones al archivo NAMESPACE:

export("cacheTable", "clearCache", "createDataFrame", "createExternalTable", "dropTempTable", "jsonFile", "loadDF", "parquetFile", "read.df", "sql", "table", "tableNames", "tables", "uncacheTable", "callJMethod", "newJObject")

Esto me permitió llamar a las funciones de Scala que escribí sin iniciar una nueva JVM.

Los métodos scala que escribí devuelven DataFrames, que son "jobj" s en R cuando se devuelven, pero un SparkR DataFrame es un entorno + un trabajoj. Para convertir estos jobj DataFrames en SparkR DataFrames, utilicé la función dataFrame () en "DataFrame.R", que también pude acceder siguiendo los pasos anteriores.

Pude acceder entonces al DataFrame que "construí" en Scala desde R y uso todas las funciones de SparkR en ese DataFrame. Me preguntaba si había una mejor manera de crear una biblioteca de idiomas cruzados, o si hay alguna razón por la cual Spark JVM no debería ser pública.


¿Alguna razón por la cual Spark JVM no debería ser público?

Probablemente más de uno. Los desarrolladores de Spark hacen serios esfuerzos para proporcionar una API pública estable. Los detalles bajos de la implementación, incluida la forma en que los idiomas de los invitados se comunican con JVM, simplemente no forman parte del contrato. Podría ser completamente reescrito en cualquier punto sin ningún impacto negativo en los usuarios. Si decides usarlo y hay cambios incompatibles hacia atrás, estás solo.

Mantener las funciones internas privadas reduce el esfuerzo de mantener y admitir software. Simplemente no te molestes con todas las formas posibles en que el usuario puede abusar de estos.

una mejor manera de hacer una biblioteca de lenguaje cruzado

Es difícil de decir sin saber más acerca de su caso de uso. Veo al menos tres opciones:

  • Para los principiantes, R proporciona solo un mecanismo de control de acceso débil. Si alguna parte de la API es interna, siempre puedes usar la función ::: para acceder a ella. Como dicen las personas inteligentes:

    Normalmente, es un error de diseño utilizar ::: en su código, ya que probablemente el objeto correspondiente se haya guardado internamente por una buena razón.

    pero una cosa es segura, es mucho mejor que modificar la fuente de chispa. Como beneficio adicional, marca claramente partes de su código que son particularmente frágiles y potencialmente inestables.

  • si todo lo que quiere es crear DataFrames, lo más simple es usar SQL sin formato. Es limpio, portátil, no requiere compilación, embalaje y simplemente funciona. Suponiendo que tiene una cadena de consulta como la siguiente almacenada en la variable llamada q

    CREATE TEMPORARY TABLE foo USING org.apache.spark.sql.jdbc OPTIONS ( url "jdbc:postgresql://localhost/test", dbtable "public.foo", driver "org.postgresql.Driver" )

    se puede usar en R:

    sql(sqlContext, q) fooDF <- sql(sqlContext, "SELECT * FROM foo")

    Pitón:

    sqlContext.sql(q) fooDF = sqlContext.sql("SELECT * FROM foo")

    Scala:

    sqlContext.sql(q) val fooDF = sqlContext.sql("SELECT * FROM foo")

    o directamente en Spark SQL.

  • finalmente puede usar la API de fuentes de datos Spark para un acceso compatible y multiplataforma.

De estos tres, preferiría el SQL sin formato, seguido de la API de Fuentes de datos para casos complejos y dejo internos como último recurso.

Editar (2016-08-04) :

Si está interesado en el acceso de bajo nivel a JVM, hay un paquete relativamente nuevo rstudio / sparkapi que expone el protocolo SparkR RPC interno. Es difícil predecir cómo evolucionará, así que úsala bajo tu propio riesgo.