使用正则表达式进行Spark过滤

3
我正在尝试按日期筛选文件数据,将其分为好数据和坏数据,因此将获得2个结果文件。从测试文件中,前4行需要进入好数据文件,最后2行进入坏数据文件。
我有两个问题:
1. 我没有得到任何好的数据,结果文件为空。 2. 坏数据结果看起来像下面这样 - 只取名字字符 (,C,h) (,J,u) (,T,h) (,J,o) (,N,e) (,B,i) 测试文件
Christopher|Jan 11, 2017|5 
Justin|11 Jan, 2017|5 
Thomas|6/17/2017|5 
John|11-08-2017|5 
Neli|2016|5 
Bilu||5

加载和RDD

scala> val file = sc.textFile("test/data.txt")
scala> val fileRDD = file.map(x => x.split("|"))

正则表达式

scala> val singleReg = """(\w(3))\s(\d+)(,)\s(\d(4))|(\d+)\s(\w(3))(,)\s(\d(4))|(\d+)(\/)(\d+)(\/)(\d(4))|(\d+)(-)(\d+)(-)(\d(4))""".r

这里的三个"(双引号)和.r是否重要?

过滤器 问题区域

scala> val validSingleRecords = fileRDD.filter(x => (singleReg.pattern.matcher(x(1)).matches))
scala> val badSingleRecords = fileRDD.filter(x => !(singleReg.pattern.matcher(x(1)).matches))

将数组转换为字符串

scala> val validSingle = validSingleRecords.map(x => (x(0),x(1),x(2)))
scala> val badSingle = badSingleRecords.map(x => (x(0),x(1),x(2)))

写文件

scala> validSingle.repartition(1).saveAsTextFile("data/singValid")
scala> badSingle.repartition(1).saveAsTextFile("data/singBad")

更新1 我之前的正则表达式有误,已做修正。在Scala中反斜杠是转义字符,需要进行重复。

val singleReg = """\\w{3}\\s\\d+,\\s\\d{4}|\\d+\\s\\w{3},\\s\\d{4}|\\d+\/\\d+\/\\d{4}|\\d+-\\d+-\\d{4}""".r

在regex101上检查正则表达式,前4行的日期都经过了验证。

我已经再次运行测试,但仍然得到相同的结果。


请问您能否提供好数据和坏数据的预期输出? - himanshuIIITian
前4行需要放在好的数据中,最后2行按照正则表达式放在坏的数据中。 - learning...
你认为为什么你的正则表达式匹配了前4行?你认为\w(3)是什么意思?不加花括号,出现次数肯定不是3。你的正则表达式只匹配了数字3。你可以在网上测试正则表达式,例如在这里https://regex101.com/。 - UninformedUser
我已更新正则表达式,正在测试... 待会儿会更新。 - learning...
在问题中添加了更新1。 - learning...
有人有这个的Python版本吗? - Pedro Alves
1个回答

5

以下是代码存在的两个问题:

  1. 您用于分割data.txt行的字符是错误的,应该使用'|'而不是"|"
  2. singleReg正则表达式是错误的。

正确的代码如下所示:

加载和RDD

scala> val file = sc.textFile("test/data.txt")
scala> val fileRDD = file.map(x => x.split('|'))

正则表达式

scala> val singleReg = """\w{3}\s\d{2},\s\d{4}|\d{2}\s\w{3},\s\d{4}|\d{1}\/\d{2}\/\d{4}|\d{2}-\d{2}-\d{4}""".r

过滤器

scala> val validSingleRecords = fileRDD.filter(x => (singleReg.pattern.matcher(x(1)).matches))
scala> val badSingleRecords = fileRDD.filter(x => !(singleReg.pattern.matcher(x(1)).matches))

将数组转换为字符串

scala> val validSingle = validSingleRecords.map(x => (x(0),x(1),x(2)))
scala> val badSingle = badSingleRecords.map(x => (x(0),x(1),x(2)))

写文件

scala> validSingle.repartition(1).saveAsTextFile("data/singValid")
scala> badSingle.repartition(1).saveAsTextFile("data/singBad")

上述代码将会给你以下输出 -
(Christopher,Jan 11, 2017,5 )
(Justin,11 Jan, 2017,5 )
(Thomas,6/17/2017,5 )
(John,11-08-2017,5 )

data/singBad

(Neli,2016,5 )
(Bilu,,5)

用逗号或空格进行分割时,我们使用“,”或“ ”,为什么使用管道符号时要用单引号“|”? - learning...
你的问题答案在这里 - https://stackoverflow.com/questions/47867743/scala-splitting-with-double-quotes-vs-single-quotes - himanshuIIITian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接