2017-12-21 51 views
2

sbt 1.0.4를 sbt-assembly 0.14.6과 함께 사용하여 Spark 응용 프로그램을 어셈블하려고합니다. 하게 IntelliJ IDEA 또는 spark-submit 출시 때sbt 어셈블리가있는 uber-jar로 "ClassNotFoundException : 데이터 소스를 찾을 수 없습니다 : jdbc"로 인해 Spark 어플리케이션이 실패하는 이유는 무엇입니까?

스파크 응용 프로그램이 잘 작동하지만 내가 (윈도우 10에 cmd) 명령 줄을 사용하여 조립 동네 짱 항아리를 실행하는 경우 :

java -Xmx1024m -jar my-app.jar 

나는 다음과 같은 예외를 얻을 :

스레드 "main"의 예외 java.lang.ClassNotFoundException : 데이터 소스를 찾을 수 없습니다 : jdbc. 패키지를 찾으십시오. http://spark.apache.org/third-party-projects.html

Spark 응용 프로그램은 다음과 같습니다.

package spark.main 

import java.util.Properties  
import org.apache.spark.sql.SparkSession 

object Main { 

    def main(args: Array[String]) { 
     val connectionProperties = new Properties() 
     connectionProperties.put("user","postgres") 
     connectionProperties.put("password","postgres") 
     connectionProperties.put("driver", "org.postgresql.Driver") 

     val testTable = "test_tbl" 

     val spark = SparkSession.builder() 
      .appName("Postgres Test") 
      .master("local[*]") 
      .config("spark.hadoop.fs.file.impl", classOf[org.apache.hadoop.fs.LocalFileSystem].getName) 
      .config("spark.sql.warehouse.dir", System.getProperty("java.io.tmpdir") + "swd") 
      .getOrCreate() 

     val dfPg = spark.sqlContext.read. 
      jdbc("jdbc:postgresql://localhost/testdb",testTable,connectionProperties) 

     dfPg.show() 
    } 
} 

다음은 build.sbt입니다.

name := "apache-spark-scala" 

version := "0.1-SNAPSHOT" 

scalaVersion := "2.11.8" 

mainClass in Compile := Some("spark.main.Main") 

libraryDependencies ++= { 
    val sparkVer = "2.1.1" 
    val postgreVer = "42.0.0" 
    val cassandraConVer = "2.0.2" 
    val configVer = "1.3.1" 
    val logbackVer = "1.7.25" 
    val loggingVer = "3.7.2" 
    val commonsCodecVer = "1.10" 
    Seq(
     "org.apache.spark" %% "spark-sql" % sparkVer, 
     "org.apache.spark" %% "spark-core" % sparkVer, 
     "com.datastax.spark" %% "spark-cassandra-connector" % cassandraConVer, 
     "org.postgresql" % "postgresql" % postgreVer, 
     "com.typesafe" % "config" % configVer, 
     "commons-codec" % "commons-codec" % commonsCodecVer, 
     "com.typesafe.scala-logging" %% "scala-logging" % loggingVer, 
     "org.slf4j" % "slf4j-api" % logbackVer 
    ) 
} 

dependencyOverrides ++= Seq(
    "io.netty" % "netty-all" % "4.0.42.Final", 
    "commons-net" % "commons-net" % "2.2", 
    "com.google.guava" % "guava" % "14.0.1" 
) 

assemblyMergeStrategy in assembly := { 
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard 
    case x => MergeStrategy.first 
} 

누구에게 어떤 아이디어가 있습니까?

[업데이트] GitHub의 저장소가 속임수를 썼는지 offical 한에서 촬영

구성 :

assemblyMergeStrategy in assembly := { 
    case PathList("META-INF", xs @ _*) => 
    xs map {_.toLowerCase} match { 
     case ("manifest.mf" :: Nil) | ("index.list" :: Nil) | ("dependencies" :: Nil) => 
     MergeStrategy.discard 
     case ps @ (x :: xs) if ps.last.endsWith(".sf") || ps.last.endsWith(".dsa") => 
      MergeStrategy.discard 
     case "services" :: _ => MergeStrategy.filterDistinctLines 
     case _ => MergeStrategy.first 
    } 
    case _ => MergeStrategy.first 
} 

답변

1

문제는 거의 Why does format("kafka") fail with "Failed to find data source: kafka." with uber-jar? 아파치 메이븐 사용되는 다른 OP는 uber-를 만들 수 있다는 차이점이있다 jar 그리고 여기는 sbt에 관한 것입니다 (정확하게 말하면 sbt-assembly 플러그인 구성입니다).


짧은 이름 데이터 소스 (일명 별명), 예를 들어 jdbc 또는 kafka은 해당 META-INF/services/org.apache.spark.sql.sources.DataSourceRegisterDataSourceRegister 인 경우에만 사용할 수 있습니다.

jdbc를 들어 별명이 점화 SQL은 다음 항목에 META-INF/services/org.apache.spark.sql.sources.DataSourceRegister을 사용하는 일을 (다른 사람이 있습니다) :

org.apache.spark.sql.execution.datasources.jdbc.JdbcRelationProvider 

That's what ties jdbc alias

데이터 소스 최대.

그리고 다음과 같이 uber-jar에서 제외했습니다. assemblyMergeStrategy.

assemblyMergeStrategy in assembly := { 
    case PathList("META-INF", xs @ _*) => MergeStrategy.discard 
    case x => MergeStrategy.first 
} 

참고 단순히 MergeStrategy.discardcase PathList("META-INF", xs @ _*). 그것은 근본 원인입니다. 그냥

는 "인프라"를 사용할 수 있는지 확인하고 당신은 그것의 완전한 이름 (별명)에 의해 jdbc 데이터 소스를 사용할 수 있습니다,이 시도 :

spark.read. 
    format("org.apache.spark.sql.execution.datasources.jdbc.JdbcRelationProvider"). 
    load("jdbc:postgresql://localhost/testdb") 

당신 때문에 다른 문제를 볼 수 있습니다 url과 같은 누락 된 옵션에 ... 우리는을 우회합니다.

해결책은 jdbc 데이터 소스를 비롯한 모든 데이터 소스가있는 uber-jar를 생성하는 MergeStrategy.concat 모두입니다.

case "META-INF/services/org.apache.spark.sql.sources.DataSourceRegister" => MergeStrategy.concat 
+0

감사합니다. 사실 [여기] (https://github.com/sbt/sbt-assembly)에서 가져온 기본 설정이이 트릭을 수행했습니다. 업데이트 된 질문을 참조하십시오. – korbee82

+0

'case "services":: _ => MergeStrategy.filterDistinctLines'만으로도 작동하는지 확인할 수 있습니까? 'META-INF/services/*'에만 관심이 있기 때문에 라인만으로 충분하다. 업데이트 해 주셔서 감사 드리며 (내 답변 수락)! –

+1

시도했지만 작동하지 않았습니다. – korbee82