在简单的正则表达式替换上获取 NPE(Spark 上的 Scala)

Getting NPE on simple Regex Replacing (Scala on Spark)

我使用 Apache Spark 编写了一个简单的代码来解析大型 XML 文件(提取行、清理文本并从中删除任何 html 标记)。

我在非空字符串上调用 .replaceAllIn 时看到 NullPointerException。

有趣的是,当我 运行 在本地 代码时,我没有错误,使用磁盘输入,但我得到 NullPointerException 时我 运行 AWS EMR 上的相同代码,从 S3 加载输入文件。

相关代码如下:

val HTML_TAGS_PATTERN = """<[^>]+>""".r

// other code here...

spark
.sparkContext
.textFile(pathToInputFile, numPartitions)
.filter { str => str.startsWith("  <row ") }
.toDS()
.map { str =>

  Locale.setDefault(new Locale("en", "US"))

  val parts = str.split(""""""")

  var title: String = ""
  var body: String = ""

  // some code ommitted here

  title = StringEscapeUtils.unescapeXml(title).toLowerCase.trim
  body = StringEscapeUtils.unescapeXml(body).toLowerCase // decode xml entities


  println("before replacing, body is: "+body)

  // NEXT LINE TRIGGERS NPE
  body = HTML_TAGS_PATTERN.replaceAllIn(body, " ") // take out htmltags

}

我尝试过的事情:

我的本地设置与 AWS EMR 之间的不同之处:


我的机器和 AWS EMR 上的其他所有内容都相同:Scala 版本、Spark 版本、Java 版本、集群配置...

几个小时以来我一直在努力解决这个问题,但我想不出还有什么可以尝试的。

编辑

我已将对 r() 的调用移动到 map{} 正文中,如下所示:

val HTML_TAGS_PATTERN = """<[^>]+>"""

// code ommited

.map{

   body = HTML_TAGS_PATTERN.r.replaceAllIn(body, " ")    

 }

这也会产生一个 NPE,具有以下 stracktrace:

java.lang.NullPointerException
    at java.util.regex.Pattern.<init>(Pattern.java:1350)
    at java.util.regex.Pattern.compile(Pattern.java:1028)
    at scala.util.matching.Regex.<init>(Regex.scala:191)
    at scala.collection.immutable.StringLike$class.r(StringLike.scala:255)
    at scala.collection.immutable.StringOps.r(StringOps.scala:29)
    at scala.collection.immutable.StringLike$class.r(StringLike.scala:244)
    at scala.collection.immutable.StringOps.r(StringOps.scala:29)
    at ReadSOStanfordTokenize$$anonfun.apply(ReadSOStanfordTokenize.scala:102)
    at ReadSOStanfordTokenize$$anonfun.apply(ReadSOStanfordTokenize.scala:72)
    at org.apache.spark.sql.catalyst.expressions.GeneratedClass$GeneratedIterator.processNext(Unknown Source)
    at org.apache.spark.sql.execution.BufferedRowIterator.hasNext(BufferedRowIterator.java:43)
    at org.apache.spark.sql.execution.WholeStageCodegenExec$$anonfun$$anon.hasNext(WholeStageCodegenExec.scala:377)
    at org.apache.spark.sql.execution.datasources.FileFormatWriter$SingleDirectoryWriteTask.execute(FileFormatWriter.scala:243)
    at org.apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$org$apache$spark$sql$execution$datasources$FileFormatWriter$$executeTask.apply(FileFormatWriter.scala:190)
    at org.apache.spark.sql.execution.datasources.FileFormatWriter$$anonfun$org$apache$spar

我认为你应该尝试像下面这样内联正则表达式。

这是一个有点蹩脚的解决方案,你应该能够定义一个常量,也许把它放在全局 object 之类的地方。我不确定你在哪里定义它会是一个问题。但请记住,spark 序列化代码并 运行 将其发送到分布式工作人员上,因此可能会出现问题。

rdd.map { _ =>
   ...

   body = """<[^>]+>""".r.replaceAllIn(body, " ")    

 }

当我对空字符串 运行 .r 时,我得到了一个非常相似的错误。

val x: String = null 
x.r 
java.lang.NullPointerException
  java.util.regex.Pattern.<init>(Pattern.java:1350)
  java.util.regex.Pattern.compile(Pattern.java:1028)
  scala.util.matching.Regex.<init>(Regex.scala:223)
  scala.collection.immutable.StringLike.r(StringLike.scala:281)
  scala.collection.immutable.StringLike.r$(StringLike.scala:281)
  scala.collection.immutable.StringOps.r(StringOps.scala:29)
  scala.collection.immutable.StringLike.r(StringLike.scala:270)
  scala.collection.immutable.StringLike.r$(StringLike.scala:270)
  scala.collection.immutable.StringOps.r(StringOps.scala:29)

该错误的行号略有不同,我想是因为 Scala 版本的原因。我在 2.12.2.

多亏了 Stephen 的回答,我找到了为什么我的 UDF 上出现了 NPE...我是这样做的(在我的案例中找到一个匹配项):

def findMatch(word: String): String => Boolean = { s =>
    Option(s) match {
      case Some(validText) => if (word.toLowerCase.r.findAllIn(validText.toLowerCase).nonEmpty) true else false
      case None            => false
    }
  }

“<[^>]+>”很棒,但我的 HTML 中只有一类东西。它由样式名称和花括号之间的参数组成:

p { margin-top: 0px;margin-bottom: 0px;line-height: 1.15; }
body { font-family: 'Arial';font-style: Normal;font-weight: normal;font-size: 14.6666666666667px; }.Normal { telerik-style-type: paragraph;telerik-style-name: Normal;border-collapse: collapse; }.TableNormal { telerik-style-type: table;telerik-style-name: TableNormal;border-collapse: collapse; }.s_4C87DD5E { telerik-style-type: local;font-family: 'Arial';font-size: 14.6666666666667px;color: #000000; }.s_8D20FCAB { telerik-style-type: local;font-family: 'Arial';font-size: 14.6666666666667px;color: #000000;text-decoration: underline; }.p_53E06EE5 { telerik-style-type: local;margin-left: 0px; } 

我尝试使用以下方法提取它们,但没有成功:

"\{[^\}]+\}"