Saltar al contenido

seleccionar una gama de elementos en una array chispa sql

Intenta interpretar el código de forma correcta antes de adaptarlo a tu proyecto y si tdeseas aportar algo puedes dejarlo en los comentarios.

Solución:

Desde Spark 2.4 puedes usar slice función. En Pitón):

pyspark.sql.functions.slice(x, start, length)

Función de colección: devuelve un array que contiene todos los elementos en x desde el inicio del índice (o desde el final si el inicio es negativo) con la longitud especificada.

Nuevo en la versión 2.4.

from pyspark.sql.functions import slice

df = spark.createDataFrame([
    (10, "Finance", ["Jon", "Snow", "Castle", "Black", "Ned"]),
    (20, "IT", ["Ned", "is", "no", "more"])
], ("dept_id", "dept_nm", "emp_details"))

df.select(slice("emp_details", 1, 3).alias("empt_details")).show()
+-------------------+
|       empt_details|
+-------------------+
|[Jon, Snow, Castle]|
|      [Ned, is, no]|
+-------------------+

En Scala

def slice(x: Column, start: Int, length: Int): Column

Devuelve un array que contiene todos los elementos en x desde el inicio del índice (o desde el final si el inicio es negativo) con la longitud especificada.

import org.apache.spark.sql.functions.slice

val df = Seq(
    (10, "Finance", Seq("Jon", "Snow", "Castle", "Black", "Ned")),
    (20, "IT", Seq("Ned", "is", "no", "more"))
).toDF("dept_id", "dept_nm", "emp_details")

df.select(slice($"emp_details", 1, 3) as "empt_details").show
+-------------------+
|       empt_details|
+-------------------+
|[Jon, Snow, Castle]|
|      [Ned, is, no]|
+-------------------+

Por supuesto, se puede hacer lo mismo en SQL

SELECT slice(emp_details, 1, 3) AS emp_details FROM df

Importante:

Tenga en cuenta que, a diferencia de Seq.slice, los valores se indexan desde cero y el segundo argumento es la longitud, no la posición final.

Aquí hay una solución que utiliza una función definida por el usuario que tiene la ventaja de funcionar para cualquier tamaño de rebanada que desee. Simplemente construye una función UDF alrededor del scala incorporado. slice método:

import sqlContext.implicits._
import org.apache.spark.sql.functions._

val slice = udf((array : Seq[String], from : Int, to : Int) => array.slice(from,to))

Ejemplo con una muestra de sus datos:

val df = sqlContext.sql("select array('Jon', 'Snow', 'Castle', 'Black', 'Ned') as emp_details")
df.withColumn("slice", slice($"emp_details", lit(0), lit(3))).show

Produce la salida esperada

+--------------------+-------------------+
|         emp_details|              slice|
+--------------------+-------------------+
|[Jon, Snow, Castl...|[Jon, Snow, Castle]|
+--------------------+-------------------+

También puede registrar la UDF en su sqlContext y úsalo así

sqlContext.udf.register("slice", (array : Seq[String], from : Int, to : Int) => array.slice(from,to))
sqlContext.sql("select array('Jon','Snow','Castle','Black','Ned'),slice(array('Jon‌​','Snow','Castle','Black','Ned'),0,3)")

No necesitaras lit más con esta solución

Edit2: Para quién quiere evitar udf a expensas de la legibilidad 😉

Si realmente desea hacerlo en un solo paso, tendrá que usar Scala para crear una función lambda que devuelva una secuencia de Column y envuélvelo en un array. Esto es un poco complicado, pero es un paso:

val df = List(List("Jon", "Snow", "Castle", "Black", "Ned")).toDF("emp_details")

df.withColumn("slice", array((0 until 3).map(i => $"emp_details"(i)):_*)).show(false)    


+-------------------------------+-------------------+
|emp_details                    |slice              |
+-------------------------------+-------------------+
|[Jon, Snow, Castle, Black, Ned]|[Jon, Snow, Castle]|
+-------------------------------+-------------------+

los _:* funciona un poco de magia para pasar una lista a una función llamada variadic (array en este caso, que construyen el sql array). Pero aconsejaría no usar esta solución tal como está. poner la función lambda en una función nombrada

def slice(from: Int, to: Int) = array((from until to).map(i => $"emp_details"(i)):_*))

para la legibilidad del código. Tenga en cuenta que, en general, seguir Column Las expresiones (sin usar `udf) tienen mejores resultados.

Editar: para hacerlo en una declaración sql (como pregunta en su pregunta …), siguiendo la misma lógica, generaría la consulta sql usando la lógica scala (sin decir que sea la más legible)

def sliceSql(emp_details: String, from: Int, to: Int): String = "Array(" + (from until to).map(i => "emp_details["+i.toString+"]").mkString(",") + ")"
val sqlQuery = "select emp_details,"+ sliceSql("emp_details",0,3) + "as slice from emp_details"

sqlContext.sql(sqlQuery).show

+-------------------------------+-------------------+
|emp_details                    |slice              |
+-------------------------------+-------------------+
|[Jon, Snow, Castle, Black, Ned]|[Jon, Snow, Castle]|
+-------------------------------+-------------------+

tenga en cuenta que puede reemplazar until por to para proporcionar el último elemento tomado en lugar del elemento en el que se detiene la iteración.

Puedes añadir valor a nuestro contenido dando tu veteranía en las reseñas.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *