Нулевой сейф "между" Spark оператором - PullRequest
1 голос
/ 04 февраля 2020

TL; DR: есть ли в Spark нулевой безопасный оператор between?


Я знаю о <=>, но он становится немного многословным и менее читаемым, когда мне нужно выполнить between операция.

Если дать немного контекста, у меня есть оценка в таблице A, а также верхние и нижние пределы оценки в таблице B. Мне нужно объединить их, когда оценка в таблице A находится между пределами оценки. в таблице B. Дело в том, что когда оценка в таблице A равна нулю, ее следует сравнить с нулевым верхним и нижним пределами в таблице B.

Немного кода для уточнения:

import org.apache.spark.sql.types._

/* Helper function to generate DataFrames the verbose way, which was
chosen because I wasn't able to mock these DataFrames containing null
values in numeric columns without specifying the schema - Scala was 
sending the data as "AnyVal", and Spark wasn't happy about it */


def generateDataFrame(data: List[Row], schema: List[StructField]): DataFrame = {
  spark.createDataFrame(
    sc.parallelize(data),
    StructType(schema)
  )
}


/************************* DataFrame mocking *********************/
val tableASchema = List(
  StructField("player", StringType), 
  StructField("score", DoubleType)
)
val tableAData = List(
  Row("player1", 450.0),
  Row("player2", null)
)
val tableA = generateDataFrame(tableAData, tableASchema)

val tableBSchema = List(
  StructField("lower_limit", IntegerType),
  StructField("upper_limit", IntegerType),
  StructField("band", StringType)
)
val tableBData = List(
  Row(null, null, "noScore"),
  Row(400, 500, "400-500")
)
val tableB = generateDataFrame(tableBData, tableBSchema)


/************************* Join - the problem itself *********************/
val currentSolution = tableA.join(
  tableB, 
  when($"score".isNull, $"score" <=> $"lower_limit" and $"score" <=> $"upper_limit")
  .otherwise($"score" between($"lower_limit", $"upper_limit")),
  "left"
)

val intendedSolution = tableA.join(
  tableB, 
  $"score" safeBetween($"lower_limit", $"upper_limit")
  "left"
)

Разница между предполагаемой и текущей является только читаемость. Есть ли такой метод, как safeBetween?

1 Ответ

2 голосов
/ 04 февраля 2020

Нет, нет safeBetween, но это легко определить самостоятельно. Обратите внимание, что я также реорганизовал генерацию данных:

import spark.implicits._

val tableA = List(
  ("player1", Some(450.0)),
  ("player2", None)
).toDF("player","score")

val tableB = List(
  (None, None, "noScore"),
  (Some(400), Some(500), "400-500")
).toDF("lower_limit","upper_limit","band")

implicit class ColumnExt(c:Column) {
   def safeBetween(c1: Column,c2: Column) = coalesce(c between(c1,c2),c.isNull and c1.isNull and c2.isNull)
}


val solution: DataFrame = tableA.join(
  tableB,
  $"score" safeBetween($"lower_limit",$"upper_limit"),
  "left"
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...