Scala 使用作为字符串数组的行字段筛选spark数据帧
使用Spark 1.5和Scala 2.10.6 我试图通过一个字符串数组字段“tags”来过滤数据帧。正在查找标记为“private”的所有行Scala 使用作为字符串数组的行字段筛选spark数据帧,scala,apache-spark,Scala,Apache Spark,使用Spark 1.5和Scala 2.10.6 我试图通过一个字符串数组字段“tags”来过滤数据帧。正在查找标记为“private”的所有行 val report = df.select("*") .where(df("tags").contains("private")) 获取: 线程“main”org.apache.spark.sql.AnalysisException中的异常: 由于数据类型不匹配,无法解析“Contains(tags,private)”: 参数1需要字符串类型,
val report = df.select("*")
.where(df("tags").contains("private"))
获取:
线程“main”org.apache.spark.sql.AnalysisException中的异常:
由于数据类型不匹配,无法解析“Contains(tags,private)”:
参数1需要字符串类型,但“tags”是数组类型
类型
过滤法更合适吗
更新:
数据来自cassandra adapter,但一个最简单的示例显示了我正在尝试做什么,并且也得到了上述错误:
def testData (sc: SparkContext): DataFrame = {
val stringRDD = sc.parallelize(Seq("""
{ "name": "ed",
"tags": ["red", "private"]
}""",
"""{ "name": "fred",
"tags": ["public", "blue"]
}""")
)
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
import sqlContext.implicits._
sqlContext.read.json(stringRDD)
}
def run(sc: SparkContext) {
val df1 = testData(sc)
df1.show()
val report = df1.select("*")
.where(df1("tags").contains("private"))
report.show()
}
更新:标记数组可以是任意长度,“private”标记可以位于任意位置
更新:一个有效的解决方案:UDF
val filterPriv = udf {(tags: mutable.WrappedArray[String]) => tags.contains("private")}
val report = df1.filter(filterPriv(df1("tags")))
您可以使用ordinal来引用json数组的,例如在您的示例中
df(“标记”)(0)
。这是一个工作样本
scala> val stringRDD = sc.parallelize(Seq("""
| { "name": "ed",
| "tags": ["private"]
| }""",
| """{ "name": "fred",
| "tags": ["public"]
| }""")
| )
stringRDD: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[87] at parallelize at <console>:22
scala> import sqlContext.implicits._
import sqlContext.implicits._
scala> sqlContext.read.json(stringRDD)
res28: org.apache.spark.sql.DataFrame = [name: string, tags: array<string>]
scala> val df=sqlContext.read.json(stringRDD)
df: org.apache.spark.sql.DataFrame = [name: string, tags: array<string>]
scala> df.columns
res29: Array[String] = Array(name, tags)
scala> df.dtypes
res30: Array[(String, String)] = Array((name,StringType), (tags,ArrayType(StringType,true)))
scala> val report = df.select("*").where(df("tags")(0).contains("private"))
report: org.apache.spark.sql.DataFrame = [name: string, tags: array<string>]
scala> report.show
+----+-------------+
|name| tags|
+----+-------------+
| ed|List(private)|
+----+-------------+
scala>val stringRDD=sc.parallelize(Seq(“”)
|{“姓名”:“ed”,
|“标签”:[“专用”]
| }""",
|“{”姓名“:“弗雷德”,
|“标签”:[“公共”]
| }""")
| )
stringRDD:org.apache.spark.rdd.rdd[String]=ParallelCollectionRDD[87]位于parallelize at:22
scala>导入sqlContext.implicits_
导入sqlContext.implicits_
scala>sqlContext.read.json(stringRDD)
res28:org.apache.spark.sql.DataFrame=[名称:字符串,标记:数组]
scala>val df=sqlContext.read.json(stringRDD)
df:org.apache.spark.sql.DataFrame=[名称:字符串,标记:数组]
scala>df.columns
res29:Array[String]=数组(名称、标记)
scala>df.dtypes
res30:Array[(String,String)]=数组((名称,StringType),(标记,ArrayType(StringType,true)))
scala>val report=df.select(“*”)。其中(df(“tags”)(0)。包含(“private”))
报告:org.apache.spark.sql.DataFrame=[名称:字符串,标记:数组]
scala>report.show
+----+-------------+
|名称|标签|
+----+-------------+
|教育署名单(私人)|
+----+-------------+
我认为如果您使用where(array_contains(…))
它会起作用。以下是我的结果:
scala> import org.apache.spark.SparkContext
import org.apache.spark.SparkContext
scala> import org.apache.spark.sql.DataFrame
import org.apache.spark.sql.DataFrame
scala> def testData (sc: SparkContext): DataFrame = {
| val stringRDD = sc.parallelize(Seq
| ("""{ "name": "ned", "tags": ["blue", "big", "private"] }""",
| """{ "name": "albert", "tags": ["private", "lumpy"] }""",
| """{ "name": "zed", "tags": ["big", "private", "square"] }""",
| """{ "name": "jed", "tags": ["green", "small", "round"] }""",
| """{ "name": "ed", "tags": ["red", "private"] }""",
| """{ "name": "fred", "tags": ["public", "blue"] }"""))
| val sqlContext = new org.apache.spark.sql.SQLContext(sc)
| import sqlContext.implicits._
| sqlContext.read.json(stringRDD)
| }
testData: (sc: org.apache.spark.SparkContext)org.apache.spark.sql.DataFrame
scala>
| val df = testData (sc)
df: org.apache.spark.sql.DataFrame = [name: string, tags: array<string>]
scala> val report = df.select ("*").where (array_contains (df("tags"), "private"))
report: org.apache.spark.sql.DataFrame = [name: string, tags: array<string>]
scala> report.show
+------+--------------------+
| name| tags|
+------+--------------------+
| ned|[blue, big, private]|
|albert| [private, lumpy]|
| zed|[big, private, sq...|
| ed| [red, private]|
+------+--------------------+
scala>import org.apache.spark.SparkContext
导入org.apache.spark.SparkContext
scala>import org.apache.spark.sql.DataFrame
导入org.apache.spark.sql.DataFrame
scala>DefTestData(sc:SparkContext):数据帧={
|val stringRDD=sc.parallelize(顺序
|(“{”name:“ned”,“tags:[“blue”,“big”,“private”]}”“,
|“{”name:“albert”,“tags:[“private”,“lumpy”]}”“,
|“{”name:“zed”,“tags:[“big”,“private”,“square”]}”“,
|“{”name:“jed”,“tags:[“green”,“small”,“round”]}”“,
|“{”name:“ed”,“tags:[“red”,“private”]}”“,
|“{”name:“fred”,“tags:[“public”,“blue”]}”“)
|val sqlContext=new org.apache.spark.sql.sqlContext(sc)
|导入sqlContext.implicits_
|sqlContext.read.json(stringRDD)
| }
testData:(sc:org.apache.spark.SparkContext)org.apache.spark.sql.DataFrame
斯卡拉>
|val df=测试数据(sc)
df:org.apache.spark.sql.DataFrame=[名称:字符串,标记:数组]
scala>val report=df.select(“*”)。其中(数组_包含(df(“标记”),“private”))
报告:org.apache.spark.sql.DataFrame=[名称:字符串,标记:数组]
scala>report.show
+------+--------------------+
|名称|标签|
+------+--------------------+
|ned |[蓝色,大,私人]|
|阿尔伯特|[私人,笨重]|
|zed |[大的,私人的,方形的]|
|ed |[红色,私人]|
+------+--------------------+
请注意,如果您编写
where(array_包含(df(“tags”),“private”)
,但如果您编写where(df(“tags”)。array_包含(“private”)
(更直接地类似于您最初编写的内容)它失败于数组\u contains不是org.apache.spark.sql.Column
的成员。查看Column
的源代码,我发现有一些东西需要处理contains
(为此构建contains
实例)但不是array\u contains
。这可能是一个疏忽。发布数据示例以及创建dfOne选项的方法是构建一个UDF。好吧,在查看源代码之后(因为列的scaladoc.contains
只说“包含其他元素”,这不是很有启发性),我看到Column.contains
构造了org.apache.spark.sql.catalyst.expressions.contains的一个实例,该实例表示“如果字符串left
包含字符串right
,则返回true的函数”。因此似乎df1(“标记”).contains
在这种情况下不能执行我们希望它执行的操作。我不知道建议使用什么替代方法。在中也有数组contains
…expressions
但是列
似乎没有使用它。事实上,在将数据更改为字符串而不是字符串数组后,我发现查询成功。@DavidMaust,我有一个UDF来工作:val filterPriv=UDF{(tags:mutable.WrappedArray[String])=>tags.contains(“private”)};val report=df1.filter(filterPriv(df1(“tags”))
仍在寻找更好的东西,但至少我没有被阻止。thx!谢谢。如果pos是固定的,那么它可以工作,但它不是。我应该让测试数据更复杂一点,数组中可以有任意数量的标记,位置是任意的。@navicore那么你的代码应该可以工作。检查我的updateinteresting,我遗漏了一些东西,看起来像实际上,我正在做什么,但得到了错误。现在仔细检查spark版本…@navicore这是在1.5.4thx上。我一定是在什么地方交叉了手。我尝试了1.5.1和1.6并且val report=df.select(“*”)。其中(df(“tags”).contains(“private”)
在orig post中给了我那个错误。挖掘…。选择(“*”)
不需要=>df.where(…)…
在使用此方法之前,需要导入org.apache.spark.sql.functions.array\u包含的内容。