Scala 在Spark上运行Tika的类路径问题

Scala 在Spark上运行Tika的类路径问题,scala,jar,apache-spark,classpath,apache-tika,Scala,Jar,Apache Spark,Classpath,Apache Tika,我试图在Tika处理一堆文件。文件的数量有数千个,所以我决定构建一个RDD文件,让Spark来分配工作负载。不幸的是,我发现了多个NoClassDefFound异常 这是我的sbt文件: name := "TikaFileParser" version := "0.1" scalaVersion := "2.11.7" libraryDependencies += "org.apache.spark" %% "spark-core" % "1.5.1" % "provided" library

我试图在Tika处理一堆文件。文件的数量有数千个,所以我决定构建一个RDD文件,让Spark来分配工作负载。不幸的是,我发现了多个
NoClassDefFound
异常

这是我的sbt文件:

name := "TikaFileParser"
version := "0.1"
scalaVersion := "2.11.7"

libraryDependencies += "org.apache.spark" %% "spark-core" % "1.5.1" % "provided"
libraryDependencies += "org.apache.tika" % "tika-core" % "1.11"
libraryDependencies += "org.apache.tika" % "tika-parsers" % "1.11"
libraryDependencies += "org.apache.hadoop" % "hadoop-client" % "2.7.1" % "provided"
这是我的汇编

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.1")
这是源文件:

import org.apache.spark.SparkContext
import org.apache.spark.SparkContext._
import org.apache.spark.SparkConf
import org.apache.spark.input.PortableDataStream
import org.apache.tika.metadata._
import org.apache.tika.parser._
import org.apache.tika.sax.WriteOutContentHandler
import java.io._

object TikaFileParser {

  def tikaFunc (a: (String, PortableDataStream)) = {

    val file : File = new File(a._1.drop(5))
    val myparser : AutoDetectParser = new AutoDetectParser()
    val stream : InputStream = new FileInputStream(file)
    val handler : WriteOutContentHandler = new WriteOutContentHandler(-1)
    val metadata : Metadata = new Metadata()
    val context : ParseContext = new ParseContext()

    myparser.parse(stream, handler, metadata, context)

    stream.close

    println(handler.toString())
    println("------------------------------------------------")
  }


  def main(args: Array[String]) {

    val filesPath = "/home/user/documents/*"
    val conf = new SparkConf().setAppName("TikaFileParser")
    val sc = new SparkContext(conf)
    val fileData = sc.binaryFiles(filesPath)
    fileData.foreach( x => tikaFunc(x))
  }
}
我正在和你一起做这件事

spark-submit --driver-memory 2g --class TikaFileParser --master local[4]
             /path/to/TikaFileParser-assembly-0.1.jar
并获取
java.lang.NoClassDefFoundError:org/apache/cxf/jaxrs/ext/multipart/ContentDisposition
,这是解析器的依赖项。出于好奇,我将包含此类的jar添加到Spark的--jars选项中,然后再次运行。这次我得到了一个新的
NoClassDefFoundError
(记不清是哪一个,还记得Tika依赖项)

我已经在这里发现了一个类似的问题(),解决方案是构建一个胖罐子。但我想知道是否有其他方法可以解决依赖性问题

顺便说一句:我在没有Spark的情况下尝试了这个代码段(所以只需使用一个带有文件名和foreach循环的数组,并相应地更改了tikaFunc签名)。我在没有任何参数的情况下运行了它,它工作得非常好

编辑:现在更新代码段以用于sbt程序集

我已经在这里发现了一个类似的问题(Spark NoClassDeftFoundError上的ApacheTika 1.11),解决方案是构建一个胖jar。但是我想知道是否有其他方法可以解决依赖性问题

找到所有的依赖项并将它们添加到
--jars
。你可以用它来完成。但是我不明白为什么你更喜欢用它来构建一个jar,而不是将它们全部组合起来

我在没有任何争论的情况下运行了它,它运行得非常完美


SBT已经确保您拥有类路径上的所有依赖项,但Spark不使用SBT运行程序。

问题来自JAR中的版本不匹配。我决定使用以下SBT文件解决我的问题:

name := "TikaFileParser"
version := "0.1"
scalaVersion := "2.11.7"

libraryDependencies += "org.apache.spark" %% "spark-core" % "1.5.1" % "provided"
libraryDependencies += "org.apache.tika" % "tika-core" % "1.11"
libraryDependencies += "org.apache.tika" % "tika-parsers" % "1.11"
libraryDependencies += "org.apache.hadoop" % "hadoop-client" % "2.7.1" % "provided"

mergeStrategy in assembly <<= (mergeStrategy in assembly) { (old) =>
  {
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard
    case _     => MergeStrategy.first
  }
}
name:=“TikaFileParser”
版本:=“0.1”
规模规避:=“2.11.7”
libraryDependencies+=“org.apache.spark”%%“spark核心”%%“1.5.1”%”已提供
libraryDependencies+=“org.apache.tika”%“tika核心”%“1.11”
libraryDependencies+=“org.apache.tika”%“tika解析器”%“1.11”
libraryDependencies+=“org.apache.hadoop”%“hadoop客户端”%“2.7.1”%“已提供”
程序集mergeStrategy.discard中的mergeStrategy
案例=>MergeStrategy.first
}
}

我想更正@flowit的答案,因为它让我投入了漫长的一天调查

答案的问题是合并策略,它丢弃了每个
META-INF
目录。然而,这也将丢弃Tika注册i.a.及其解析器的
META-INF/services
目录

使用合并策略(您可以在已接受的答案或其他四处飞来飞去的Stackoverflow答案中找到),您将得到空内容,因为Tika将默认为
EmptyParser
。因此,如果您尝试解析任何内容,Tika将无法解析解析器。请参阅

我的解决方案是(我想是使用了更新的sbt语法):


我希望类路径中JAR的依赖项会自动添加到类路径中。但显然不是这样。这是不可能的,因为JAR对它们的依赖项一无所知:这是SBT(或Maven,或Ivy,等等)责任。我成功地构建了一个胖jar,但我仍然得到了相同的缺少类错误。一些文档被正确解析,其他文档仍然产生
java.lang.NoClassDefFoundError:org/apache/cxf/jaxrs/ext/multipart/ContentDisposition
。我相应地更新了问题。
assemblyMergeStrategy in assembly := {
  case PathList("META-INF", xs @ _*) =>
    (xs map {_.toLowerCase}) match {
      case "services" :: xs => MergeStrategy.concat // Tika uses the META-INF/services to register its parsers statically, don't discard it
      case _ => MergeStrategy.discard
    }
  case x => MergeStrategy.first
}