SparkSQL DataFrame:使用缓存时sql查询不起作用

时间:2015-10-19 09:03:16

标签: apache-spark apache-spark-sql

我开始使用spark来学习。我根据this document创建了一个简单的程序。

我的程序从文件(在HDFS集群上)读取付款日志,将其传输到数据帧并在某些SQL查询中使用此数据帧。我在两种情况下运行我的程序:with和without cache()方法。我遇到了一个奇怪的问题,如下所述:

  1. 不使用cache():
  2. 我尝试运行一些查询,一切都很好。 (log_zw是我的表名)

    val num_records =  sqlContext.sql("select * from log_zw").count
    val num_acc1 =  sqlContext.sql("select * from log_zw where ACN = 'acc1' ").count
    
    1. 使用缓存()
    2. 我上面也使用了两个查询。第一个查询返回了正确的值,但第二个查询返回,它返回 0

      然而,当我用另一种方法查询它时:

      val num_acc1 = log_zw.filter(log_zw("ACN").contains("acc1")).count
      

      它返回了正确的结果。

      我是Spark和集群计算系统的新手,我不知道它为什么会那样工作。任何人都可以向我解释这个问题,特别是在使用sql查询和spark方法时的不同。

      编辑:这是架构,非常简单。

      root 
       |-- PRODUCT_ID: string (nullable = true) 
       |-- CHANNEL: string (nullable = true) 
       |-- ACN: string (nullable = true) 
       |-- AMOUNT_VND: double (nullable = false) 
       |-- TRANS_ID: string (nullable = true)
      

      Edit2 :这是我使用cache()时的代码:(我运行了一些查询,结果显示在代码中的注释中)

      // read tsv files
      case class LogZW(
        PRODUCT_ID: String,
        PLATFORM: String,
        CHANNEL: String,
        ACN: String,
        AMOUNT_VND: Double,
        TRANS_ID: String)
      
      def loadLog(filename: String): DataFrame = {
        sc.textFile(filename).map(line => line.split("\t")).map(p =>
        LogZW(p(1), p(3), p(4), p(5), p(9).toDouble, p(10).substring(0,8))).toDF()
      }
      
      // generate schema
      val schemaString = "PRODUCT_ID PLATFORM CHANNEL ACN AMOUNT_VND TRANS_ID"
      val schema = StructType(schemaString.split(" ").map(fieldName => StructField(fieldName, StringType, true)))
      
      // read all files
      val HDFSFolder = "hdfs://master:54310/user/lqthang/data/*"
      val log = loadLog(HDFSFolder)
      
      // register table
      log.registerTempTable("log")
      log.show()
      
      // select a subset of log table
      val log_zw =  sqlContext.sql("select PRODUCT_ID, CHANNEL, ACN, AMOUNT_VND, TRANS_ID from log where PLATFORM = 'zingwallet' and CHANNEL not in ('CBZINGDEAL', 'VNPT') and PRODUCT_ID not in ('ZingCredit', 'zingcreditdbg') ")
      
      // register new table
      log_zw.show()
      log_zw.registerTempTable("log_zw")
      
      // cache table
      log_zw.cache()
      
      // this query returns incorrect value!!
      val num_acc1 =  sqlContext.sql("select * from log_zw where ACN = 'acc1' ").count
      
      // this query returns correct value!
      val num_acc2 =  sqlContext.sql("select * from log_zw where trim(ACN) = 'acc1' ").count
      
      // uncache data and try another query
      log_zw.unpersist()
      
      // this query also returns the correct value!!!
      val num_acc2 =  sqlContext.sql("select * from log_zw where ACN = 'acc1' ").count
      

      Edit3 :我尝试将另一个cache()方法添加到log数据帧:

      // register table
      log.registerTempTable("log")
      log.show()
      log.cache()
      

      以下代码与上述代码相同(log_zw.cache())。所以重要的结果是:

      // this query returns the CORRECT value!!
      val num_acc1 =  sqlContext.sql("select * from log_zw where ACN = 'acc1' ").count
      

1 个答案:

答案 0 :(得分:0)

我们没有关于数据的详细信息,但我注意到您的两个代码部分做了不同的事情。

首先,您执行ACN = 'acc1'但在第二步中检查ACN 是否包含'acc1'。

因此,如果ACN为'acc1',或'acc1',或'acc1'

,第二位(带滤波器)将匹配

换句话说,我敢打赌,如果你在SQL查询中添加一个修剪,你会得到不同的结果。

试试这个:
val num_records = sqlContext.sql("select * from log_zw").count val num_acc1 = sqlContext.sql("select * from log_zw where trim(ACN) = 'acc1' ").count