Cómo pasar funciones a Spark
Los operadores de Spark se implementan en gran medida pasando funciones al controlador en el clúster. La clave para escribir aplicaciones Spark es utilizar operadores (o transformaciones) para pasar funciones a Spark. Hay dos formas comúnmente utilizadas de transferir funciones a Spark (de la documentación oficial de Spark, Guía de programación de Spark):
La primera: función anónima Cuando el código a procesar es relativamente pequeño, se pueden usar funciones anónimas. utilizado Escriba directamente en el operador:
1
myrdd.map(x =gt; x 1)
Segundo tipo: en el objeto singleton global Estático. Método: primero defina el objeto MyFunctions y el método estático: funcOne, y luego pase MyFunctions.funcOne al operador RDD.
1
2
3
4
5
6 p> p>
7
8
objeto MisFunciones {
def funcOne(s: String): String = { ... } p>
}
myRdd.map(MyFunctions.funcOne)
En el desarrollo de vendedores, debe pasar la referencia de RDD a un método de una instancia de una determinada clase. , pase La función dada a RDD es el método de instancia de la instancia de clase:
1
2
3
4 p>
5
6
7
clase MiClase {
def funcOne(s: Cadena): Cadena = { ... }
def hacerCosas(rdd: RDD[String]): RDD[String] = { rdd.map(funcOne }
}
En En este ejemplo, hemos definido una clase MyClass y se pasa un RDD al método de instancia doStuff de la clase. El operador RDD
llama a otro método de instancia funcOne de la clase.
Cuando llamas al método doStuff en una instancia, necesitas enviar el objeto de instancia completo al clúster, por lo que la clase MyClass debe ser serializable y debe extenderse
Serializable.
De manera similar, acceder a variables de objeto fuera del método también hará referencia al objeto completo, y el objeto completo debe enviarse al clúster:
1
2
3
4
5
6
clase MiClase {
val campo = "Hola "
def hacerCosas(rdd: RDD[String]): RDD[String] = { rdd.map(x =gt; campo
x) lt; span style="font -size: 9pt; line-height: 1.5; "gt;}lt;/spangt
1
}
En orden Para evitar que se envíe todo el objeto a un clúster, puede definir una variable local para guardar una referencia a un campo de objeto externo. Esto es especialmente cierto en algunos objetos grandes, lo que puede evitar enviar el objeto completo al clúster y mejorar la eficiencia. .
1
2
3
4
5
6 p> p>
7
def hacerCosas(rdd: RDD[String]): RDD[String] = {
val field_ = this.field
rdd.map(x =gt; field_ x)
}
Las aplicaciones Spark eventualmente se ejecutarán en un clúster. Muchos problemas no se pueden exponer en un solo entorno local. A menudo nos encontramos con el problema de la inconsistencia entre los resultados de ejecución local y los resultados de ejecución del clúster. Esto requiere que utilicemos un estilo de programación más funcional al desarrollar e intentemos escribir las funciones como funciones puras. Las ventajas de las funciones puras son: sin estado, seguras para subprocesos y sin necesidad de sincronización de subprocesos. Las aplicaciones o entornos en ejecución (tiempo de ejecución) pueden almacenar en caché los resultados de las funciones puras para acelerar las operaciones.
Entonces, ¿qué es una función pura?
Una función pura es una función donde los flujos de datos de entrada y salida son todos explícitos. Explícito
significa que solo hay un canal para que la función intercambie datos con el mundo exterior: los parámetros y valores de retorno toda la información de entrada recibida por la función desde fuera de la función se pasa al interior de la misma; la función a través de parámetros; toda la información enviada por la función al exterior de la función se pasa al exterior de la función a través del valor de retorno. Si una función obtiene datos del mundo exterior o envía datos al mundo exterior de forma implícita, entonces la función no es una función pura y se denomina función impura.
Implícito significa que la función intercambia datos con el mundo exterior a través de canales distintos de los parámetros y los valores de retorno. Por ejemplo, leer variables globales y modificar variables globales se denominan intercambios de datos implícitos con el mundo exterior, por ejemplo, usar la API de E / S (biblioteca de funciones del sistema de entrada y salida) para leer archivos de configuración o generar archivos e imprimir. En la pantalla, los datos se intercambian con el mundo exterior de forma implícita.
Cuando la interacción de objetos está involucrada en el proceso de cálculo, intente usar objetos sin estado. Por ejemplo, para un bean, las variables miembro son todas val y se usa una nueva cuando se requiere interacción de datos. .
Acerca de las leyes conmutativas y asociativas (conmutativas y asociativas).
Las funciones pasadas para reducir, reducirByKey y otras operaciones de fusión y agregación deben satisfacer las leyes conmutativas y asociativas. Las leyes conmutativas y asociativas son las que hemos aprendido en matemáticas:
a b = b a , a b c = a (. b c)
Las funciones func(a, b) y f(b, a) definidas deberían obtener el mismo resultado, f(f(a, b), c) y f( a,f(b ,c)) debería dar el mismo resultado.
Finalmente, hablemos del uso de variables de difusión y acumuladores. No defina una variable global en el programa. Si necesita compartir datos entre varios nodos, puede utilizar el método de variable de transmisión. Si necesita algunos cálculos agregados globales, puede utilizar acumuladores.