如何将撇号添加到字符串类型的列?

时间:2017-05-21 08:57:22

标签: apache-spark apache-spark-sql

我有一个简单的数据框,其中包含一些字符串cloumns:

Name      age address
micheal   21  Washington
Jhon      10 San Franciso

我希望在每个字符串类型列中添加撇号,我需要检查 列类型并相应地更改它,结果将是:

Name       age  address
'micheal'  21   'Washington'
'Jhon'     20   'San Francisco'

我没有多少列,所以我需要动态查询列类型。

2 个答案:

答案 0 :(得分:1)

然后有两个要求:

  

我希望将撇号添加到每个字符串类型列

     

我不会有多少列

// load the dataset from a CSV file
val names = spark.
  read.
  option("header", true).
  option("inferSchema", true).
  csv("names.txt")
scala> names.show
+-------+---+------------+
|   Name|age|     address|
+-------+---+------------+
|micheal| 21|  Washington|
|   Jhon| 10|San Franciso|
+-------+---+------------+

对于这种特殊情况,架构如下:

scala> names.printSchema
root
 |-- Name: string (nullable = true)
 |-- age: integer (nullable = true)
 |-- address: string (nullable = true)

我们有两个字符串类型的字段,但是要求我们不知道我们将拥有多少列并不重要。

用于Scala的Spark SQL的DataFrame API实际上可以帮助行Dataset[Row]类型的行。

import org.apache.spark.sql.Row
scala> names.collect.head.isInstanceOf[Row]
res0: Boolean = true

来自org.apache.spark.sql.Row's scaladoc

  

表示关系运算符的一行输出。允许通过序数进行通用访问,这将导致原语的装箱开销,以及本机原语访问。

尽管如此,解决方案可能如下:

import org.apache.spark.sql.DataFrame
def quoteStringColumns(df: DataFrame) = {

  import org.apache.spark.sql.types.{StringType, StructType}
  def stringFieldNames(schema: StructType) = {
    schema.filter(_.dataType == StringType).map(_.name)
  }
  val columns = stringFieldNames(names.schema)

  val quoteUDF = udf { s: String => s"'$s'" }
  columns.foldLeft(df) { case (resultDF, c) => resultDF.withColumn(c, quoteUDF(col(c))) }
}

val r = quoteStringColumns(names)
scala> r.show
+---------+---+--------------+
|     Name|age|       address|
+---------+---+--------------+
|'micheal'| 21|  'Washington'|
|   'Jhon'| 10|'San Franciso'|
+---------+---+--------------+

答案 1 :(得分:1)

快速而简单的解决方案是map超过dtypesselect

import org.apache.spark.sql.functions.{col, concat, lit}

val exprs = df.dtypes.map {
 // if column is a string concat with quotes and alias
  case (c, "StringType") => concat(lit("'"), col(c), lit("'")).alias(c)
  // otherwise keep as is.
  case (c, _) => col(c)
}

df.select(exprs: _*).show
+---------+---+---------------+
|     Name|age|        address|
+---------+---+---------------+
|'michael'| 21|   'Washington'|
|   'Jhon'| 20|'San Francisco'|
+---------+---+---------------+