我正在尝试将现有的Python(PySpark)脚本移植到Scala,以提高性能。
我遇到了一些麻烦的问题 - 如何解析Scala中的json列?
这是Python版本
# Each row in file is tab separated, example:
# 2015-10-10 149775392 {"url": "http://example.com", "id": 149775392, "segments": {"completed_segments": [321, 4322, 126]}}
action_files = sc.textFile("s3://my-s3-bucket/2015/10/10/")
actions = (action_files
.map(lambda row: json.loads(row.split('\t')[-1]))
.filter(lambda a: a.get('url') != None and a.get('segments') != None and a.get('segments').get('completed_segments') != None)
.map(lambda a: (action['url'], {"url": action['url'], "action_id": action["id"], "completed_segments": action["segments"]["completed_segments"],}))
.partitionBy(100)
.persist())
基本上,我只是试图解析json列,然后将其转换为简化版本,我可以在SparkSQL
进一步处理
作为一个新的Scala用户,我发现有很多库json解析库来完成这个简单的任务。看起来stdlib中没有一个。从我到目前为止所看到的,看起来强大的键入语言使得这个简单的任务变成了一件苦差事。
我很欣赏任何正确的方向!
PS。顺便说一句,如果我遗漏了一些明显让PySpark版本爬行的东西,我很想知道它!我正在从Hadoop / MR移植一个Pig脚本,性能从17分钟下降到MR超过5个半小时!我猜它是Python的序列化开销......
答案 0 :(得分:0)
如果您的目标是将数据传递给SparkSQL,并且您确定没有格式错误的字段(我的代码中没有看到任何异常处理)我根本不会手动解析:
val raw = sqlContext.read.json(action_files.flatMap(_.split("\t").takeRight(1)))
val df = raw
.withColumn("completed_segments", $"segments.completed_segments")
.where($"url".isNotNull && $"completed_segments".isNotNull)
.select($"url", $"id".alias("action_id"), $"completed_segments")
关于Python代码:
!=
与None
进行比较。一种正确的方法是使用is
/ is not
。它在语义上是正确的(None
是单身)并且明显更快。另请参阅PEP8 url
两次意味着更高的内存使用量和后续网络流量另一方面,我很怀疑序列化在这里是一个真正的问题。有一个开销,但真正的影响不应该接近你所描述的。