Как Scala обрабатывает isnull или ifnull в запросе с помощью sqlContext

У меня есть два файла данных, как показано ниже:

course.txt 
id,course 
1,Hadoop
2,Spark
3,HBase
5,Impala

Fee.txt 
id,amount 
2,3900
3,4200
4,2900

Мне нужно перечислить всю информацию о курсе с их оплатой:

sqlContext.sql("select c.id, c.course, f.amount from course c left outer join fee f on f.id = c.id").show
+---+------+------+
| id|course|amount|
+---+------+------+
|  1|Hadoop|  null|
|  2| Spark|3900.0|
|  3| HBase|4200.0|
|  5|Impala|  null|
+---+------+------+

если курс не указан в таблице Fee, то вместо того, чтобы показывать null, я хочу показать «N/A».

Я пробовал следующее и еще не получил:

команда 1:

sqlContext.sql("select c.id, c.course, ifnull(f.amount, 'N/A') from course c left outer join fee f on f.id = c.id").show

Ошибка: org.apache.spark.sql.AnalysisException: неопределенная функция ifnull; строка 1 поз. 40

команда 2:

sqlContext.sql("select c.id, c.course, isnull(f.amount, 'N/A') from course c left outer join fee f on f.id = c.id").show

Ошибка: org.apache.spark.sql.AnalysisException: нет обработчика для класса Hive udf org.apache.hadoop.hive.ql.udf.generic.GenericUDFOPNull, потому что: оператор «IS NULL» принимает только 1 аргумент.. ; строка 1 поз. 40

Как правильно справиться с этим в sqlContext в Scala? Большое спасибо.


person Choix    schedule 10.03.2018    source источник


Ответы (5)


Используя Spark DataFrame API, вы можете использовать when/otherwise с условием isNull:

val course = Seq(
  (1, "Hadoop"),
  (2, "Spark"),
  (3, "HBase"),
  (5, "Impala")
).toDF("id", "course")

val fee = Seq(
  (2, 3900),
  (3, 4200),
  (4, 2900)
).toDF("id", "amount")

course.join(fee, Seq("id"), "left_outer").
  withColumn("amount", when($"amount".isNull, "N/A").otherwise($"amount")).
  show
// +---+------+------+
// | id|course|amount|
// +---+------+------+
// |  1|Hadoop|   N/A|
// |  2| Spark|  3900|
// |  3| HBase|  4200|
// |  5|Impala|   N/A|
// +---+------+------+

Если вы предпочитаете использовать Spark SQL, вот эквивалентный SQL:

course.createOrReplaceTempView("coursetable")
fee.createOrReplaceTempView("feetable")

val result = spark.sql("""
  select
    c.id, c.course,
    case when f.amount is null then 'N/A' else f.amount end as amount
  from
    coursetable c left outer join feetable f on f.id = c.id
""")
person Leo C    schedule 10.03.2018
comment
Спасибо, Лео, это то, что мне нужно. - person Choix; 10.03.2018

Если это искровой SQL, используйте объединение UDF

select 
  c.id, 
  c.course, 
  coalesce(f.amount, 'N/A') as amount 
from c 
left outer join f 
on f.id = c.id"
person maxmithun    schedule 12.09.2018

Вы можете сделать это в простом запросе sql следующим образом, используя функции if, isnull и литерал N/A.

course.createOrReplaceTempView("c")
fee.createOrReplaceTempView("f")
sqlContext.sql("select c.id, c.course, if(isnull(f.amount), 'N/A', f.amount) as amount from c left outer join f on f.id = c.id").show

У вас должен быть следующий вывод

+---+------+------+
| id|course|amount|
+---+------+------+
|  1|Hadoop|   N/A|
|  2| Spark|  3900|
|  3| HBase|  4200|
|  5|Impala|   N/A|
+---+------+------+

надеюсь ответ будет полезен

person Ramesh Maharjan    schedule 10.03.2018

Используйте функции DataFrameNA. После того, как соединение было выполнено, вы можете заменить все нули строкой, используя функцию заполнения DataFrameNA.

https://spark.apache.org/docs/1.4.0/api/java/org/apache/spark/sql/DataFrameNaFunctions.html

person Knows Not Much    schedule 10.03.2018

В sqlContext используйте "NVL"

sqlContext.sql("""   
   SELECT c.id
      ,c.course
      ,NVL(f.amount, 'N/A')
      FROM course c
      LEFT OUTER
      JOIN fee f 
      ON f.id = c.id
    """).show()
person kennyut    schedule 29.10.2018