【问题标题】:Spark SQL's where clause excludes null valuesSpark SQL 的 where 子句排除空值
【发布时间】:2015-12-06 22:33:46
【问题描述】:

我正在尝试在 Apache spark sql 上运行查询。第一个查询工作正常,但第二个查询也会删除空值。

代码:

def main(args: Array[String]) {

    val sc = new SparkContext("local[*]", "Spark")
    val sqlContext = new SQLContext(sc)

    val pageViewsDF = getDataframe(sc, sqlContext)

    println("RUNNING SQL QUERIES ")

    sqlContext.sql("select name , count(*) from pageviews_by_second group by name").show(10)

    sqlContext.sql("select name , count(*) from pageviews_by_second where name not in (\"Rose\") group by name").show(10)

  }

  def getDataframe(sc: SparkContext, sqlContext: SQLContext): DataFrame = {

    Logger.getLogger("org").setLevel(Level.OFF);
    Logger.getLogger("akka").setLevel(Level.OFF);

    val dataArray = List(List("David", null),
      List("David", null),
      List("Charlie", "23"),
      List("Rose", null),
      List("Ben", null),
      List("Harry", "43"),
      List(null, "25"),
      List(null, "21"),
      List("David", "15"),
      List("Rose", null),
      List("Alan", "26"))
    val separator = ","

    // Create an RDD
    val dataRDD = sc.parallelize(dataArray)

    // The schema is encoded in a string
    val header = "name,age"

    // Import Spark SQL data types and Row.
    import org.apache.spark.sql._

    // Generate the schema based on the string of schema
    val schema =
      StructType(
        header.split(separator).map { fieldName =>
          StructField(fieldName, StringType, true)
        })

    val rowRDD =
      dataRDD
        .map(p => Row(p(0), p(1)))

    // Apply the schema to the RDD.
    var df = sqlContext.createDataFrame(rowRDD, schema)

    df.registerTempTable("pageviews_by_second")

    df
  }

第一次查询的结果是:

+-------+---+
|   name|_c1|
+-------+---+
|   Alan|  1|
|    Ben|  1|
|  David|  3|
|Charlie|  1|
|   Rose|  2|
|  Harry|  1|
|   null|  2|
+-------+---+

第二个查询的输出:

+-------+---+
|   name|_c1|
+-------+---+
|   Alan|  1|
|    Ben|  1|
|  David|  3|
|Charlie|  1|
|  Harry|  1|
+-------+---+

在第二个查询中,我只排除了“Rose”,但也排除了“null”。

如果我的查询有误,请帮助我正确查询。

【问题讨论】:

    标签: sql apache-spark apache-spark-sql


    【解决方案1】:

    这是因为 SQL 中的NULL 相当于“未知”。这意味着与NULL 的任何比较,除了IS NULL / IS NOT NULL 是未定义的并返回NULL

    case class Record(id: Integer, value: String)
    
    val df = sc.parallelize(Seq(Record(1, "foo"), Record(2, null))).toDF
    df.registerTempTable("df")
    
    sqlContext.sql("""SELECT value = "foo" FROM df""").show
    // +----+
    // | _c0|
    // +----+
    // |true|
    // |null|
    // +----+
    
    sqlContext.sql("""SELECT value != "foo" FROM df""").show
    // +-----+
    // |  _c0|
    // +-----+
    // |false|
    // | null|
    // +-----+
    

    因为IN / NOT IN 也未定义:

    sqlContext.sql("""SELECT value IN ("foo", "bar")  FROM df""").show
    // +----+
    // | _c0|
    // +----+
    // |true|
    // |null|
    // +----+
    

    这是一种标准的 SQL 行为,正确实现 SQL 标准的系统应该以相同的方式运行。如果您要过滤并保留NULLs,则必须明确说明:

    sqlContext.sql(
      """SELECT value IN ("foo", "bar") OR value IS NULL FROM df""").show
    // +----+
    // | _c0|
    // +----+
    // |true|
    // |true|
    // +----+
    

    【讨论】:

    • 谢谢,回答很有帮助,但是我的 where 子句应该如何在结果中也获得空值?
    • 查看最后一个sn-p。
    【解决方案2】:

    如果你想切换回两种状态逻辑,你需要将coalesce 可空列(这是专有NVL 的标准术语)转换为一些不存在的值。

    使用与@zero323 相同的设置

     sqlContext.sql("""SELECT value, coalesce(value,'other baz') = "foo" FROM df""").show
    

    .

    value c1
    foo   true
    null  false
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-27
      • 1970-01-01
      相关资源
      最近更新 更多