Scala 如何检测Spark数据帧是否有列
当我从Spark SQL中的JSON文件创建数据帧时,如何在调用之前判断给定列是否存在 JSON模式示例:Scala 如何检测Spark数据帧是否有列,scala,apache-spark,dataframe,apache-spark-sql,Scala,Apache Spark,Dataframe,Apache Spark Sql,当我从Spark SQL中的JSON文件创建数据帧时,如何在调用之前判断给定列是否存在 JSON模式示例: { "a": { "b": 1, "c": 2 } } 这就是我想做的: 电位_列=序号b、c、d df=sqlContext.read.jsonfilename potential_columns.mapcolumn=>ifdf.hasColumncolumn df.selectsa.$column 但是我找不到hasColumn的好函数。我得到的最接近的结果是
{
"a": {
"b": 1,
"c": 2
}
}
这就是我想做的:
电位_列=序号b、c、d
df=sqlContext.read.jsonfilename
potential_columns.mapcolumn=>ifdf.hasColumncolumn df.selectsa.$column
但是我找不到hasColumn的好函数。我得到的最接近的结果是测试列是否在这个有点笨拙的数组中:
scala> df.select("a.*").columns
res17: Array[String] = Array(b, c)
实际上,为了使用列,甚至不需要调用select,只需在数据帧本身上调用它即可
// define test data
case class Test(a: Int, b: Int)
val testList = List(Test(1,2), Test(3,4))
val testDF = sqlContext.createDataFrame(testList)
// define the hasColumn function
def hasColumn(df: org.apache.spark.sql.DataFrame, colName: String) = df.columns.contains(colName)
// then you can just use it on the DF with a given column name
hasColumn(testDF, "a") // <-- true
hasColumn(testDF, "c") // <-- false
然后您可以将其用作:
testDF.hasColumn("a") // <-- true
testDF.hasColumn("c") // <-- false
您的另一个选择是对df.columns和您的潜在_列执行一些数组操作,在这种情况下是一个交集 唉,这对上面的内部对象场景不起作用。您需要查看该模式 我要将您的潜在_列更改为完全限定的列名
val potential_columns = Seq("a.b", "a.c", "a.d")
// Our object model
case class Document( a: String, b: String, c: String)
case class Document2( a: Document, b: String, c: String)
// And some data...
val df = sc.parallelize(Seq(Document2(Document("a", "b", "c"), "c2")), 2).toDF
// We go through each of the fields in the schema.
// For StructTypes we return an array of parentName.fieldName
// For everything else we return an array containing just the field name
// We then flatten the complete list of field names
// Then we intersect that with our potential_columns leaving us just a list of column we want
// we turn the array of strings into column objects
// Finally turn the result into a vararg (: _*)
df.select(df.schema.map(a => a.dataType match { case s : org.apache.spark.sql.types.StructType => s.fieldNames.map(x => a.name + "." + x) case _ => Array(a.name) }).flatMap(x => x).intersect(potential_columns).map(df(_)) : _*).show
这只会深入一个层次,所以要使其通用化,您需要做更多的工作。只要假设它存在,并让它通过Try失败即可。简单明了,支持任意嵌套:
import scala.util.Try
import org.apache.spark.sql.DataFrame
def hasColumn(df: DataFrame, path: String) = Try(df(path)).isSuccess
val df = sqlContext.read.json(sc.parallelize(
"""{"foo": [{"bar": {"foobar": 3}}]}""" :: Nil))
hasColumn(df, "foobar")
// Boolean = false
hasColumn(df, "foo")
// Boolean = true
hasColumn(df, "foo.bar")
// Boolean = true
hasColumn(df, "foo.bar.foobar")
// Boolean = true
hasColumn(df, "foo.bar.foobaz")
// Boolean = false
或者更简单:
val columns = Seq(
"foobar", "foo", "foo.bar", "foo.bar.foobar", "foo.bar.foobaz")
columns.flatMap(c => Try(df(c)).toOption)
// Seq[org.apache.spark.sql.Column] = List(
// foo, foo.bar AS bar#12, foo.bar.foobar AS foobar#13)
Python等价物:
从pyspark.sql.utils导入AnalysisException
从pyspark.sql导入行
def具有_柱DF,柱:
尝试:
df[col]
返回真值
例外情况除外:
返回错误
df=sc.parallelize[Rowfoo=[Rowbar=Rowfoobar=3]].toDF
我有一个朋友,福巴
错误的
你有吗,福
符合事实的
我有一个专栏,foo.bar
符合事实的
有四列,foo.bar.foobar
符合事实的
有四个栏df,foo.bar.foobaz
错误的
Try不是最优的,因为它会在做出决定之前计算Try中的表达式
对于大型数据集,请在Scala中使用以下命令:
我通常使用的另一个选项是
df.columns.contains("column-name-to-check")
这将返回一个布尔值
def hasColumn(df: org.apache.spark.sql.DataFrame, colName: String) =
Try(df.select(colName)).isSuccess
使用上述函数检查是否存在包含嵌套列名的列。对于那些无意中发现此问题并寻找Python解决方案的人,我使用:
if 'column_name_to_check' in df.columns:
# do something
当我使用Python尝试@Jai Prakash对df.columns.contains的回答“column-name-to-check”时,我得到了AttributeError:“list”对象没有“contains”属性。如果在加载json时使用模式定义分解json,则无需检查该列。如果它不在json源代码中,它将显示为空列
val schemaJson = """
{
"type": "struct",
"fields": [
{
"name": field1
"type": "string",
"nullable": true,
"metadata": {}
},
{
"name": field2
"type": "string",
"nullable": true,
"metadata": {}
}
]
}
"""
val schema = DataType.fromJson(schemaJson).asInstanceOf[StructType]
val djson = sqlContext.read
.schema(schema )
.option("badRecordsPath", readExceptionPath)
.json(dataPath)
在PySpark中,df.columns提供数据帧中的列列表,因此 df.columns中的colName
将返回一个True或False。试穿一下。祝你好运 对于嵌套列,可以使用
df.schema.simpleString().find('column_name')
在pyspark中,您可以简单地运行 df列中的“字段”
这不适用于嵌套列。从json{a:{b:1,c:0}来看,这也适用于结构化字段。使用contains函数的解决方案没有+1乍一看,dfpath或df[col]看起来是一个非常昂贵的测试,但这都是懒惰的dag建筑,所以它很便宜,对吗?@Davos,这与懒惰没有什么关系。列不是数据容器,而是查询描述模型的组件。在更广泛的上下文中,若要了解有关数据集的任何信息,请处理并检查其逻辑QueryExecution.Analysized plan,这适用于col/同时应用resolve或schema/列。@10465355SaysRestoreTemonica谢谢,这正是我的意思。我指的不是Scala中的惰性指令,而是Spark如何创建逻辑计划、将其转换为物理计划,然后在集群上执行任务的分阶段方法。如果在逻辑计划阶段解决了这个问题,那么它是便宜的。是的,这是正确的,它不适用于嵌套列。我同意Try不是最佳选择。我要做的是:我用字段数组创建一列,然后用数组进行测试,数组包含:val fields=df.schema.fieldNames;df.withColumnfields,litfields.withColumnhas_column,当narray_包含$fields,field1,littrue``这种检查数据帧中的列的方法会减慢spark处理吗?@Vassista你能帮我更好地理解你的问题吗?是否有其他方法可以比较性能?df1.columns显示['bankData','reference','submissionTime'];但是df1['bankData']['userAddress'].列显示列,不显示结构,我是否缺少什么?
if 'column_name_to_check' in df.columns:
# do something
val schemaJson = """
{
"type": "struct",
"fields": [
{
"name": field1
"type": "string",
"nullable": true,
"metadata": {}
},
{
"name": field2
"type": "string",
"nullable": true,
"metadata": {}
}
]
}
"""
val schema = DataType.fromJson(schemaJson).asInstanceOf[StructType]
val djson = sqlContext.read
.schema(schema )
.option("badRecordsPath", readExceptionPath)
.json(dataPath)
df.schema.simpleString().find('column_name')