改進版基於Spark2.2使用Spark SQL和mysql數據庫進行詩歌查詢及自動集句

       上一篇博客中,使用的Spark版本是1.6,有點過時了,所以就採用最新的Spark2.2版本,並使用MySql數據庫,

對詩歌查詢和自動集句的功能進行了改進。

        在Spark2.2中,最顯著的變化是同樣基於SparkConf構建的SparkSession取代了原來的SparkContext:

 //初始化spark
  def initSpark(appName:String){
      val conf = new SparkConf().setMaster("local").setAppName(appName)
      ss = SparkSession.builder().appName("Spark大數據集句").config(conf).getOrCreate()
  }

     然後就可以直接使用jdbc的load方法把數據庫的數據加載到DataFrame:
     @transient
     var df = ss.read.format("jdbc")
        .option("url", com.magicstudio.db.Constants.DB_URL)
        .option("dbtable", "poem_list") //必須寫表名
        .load()
     而不像在1.6版中,要先創建一個根據數據庫ResultSet創建JdbcRDD row的函數,然後把數據加載到JdbcRDD中,
然後根據數據庫欄位先定義出StructType(),再利用這個StructType把JdbcRDD轉換爲DataFrame。
     相比之下,Spark2.2的做法簡潔多了。
     但是要注意的是有兩點:
     第一,此時獲取id之類的數據整型的方法,由getString變成了row.getInt(0).toString();
     第二,DataFrame join時,被join的參數由DataFrame變成了DataSet:
     dfPoem.join(dfContent.asInstanceOf[Dataset[_]], dfPoem("id") === dfContent("poem_id"))
     另外,Spark1.6時,可以使用Scala10.6編譯,Scala 語言library自動引入scala-libray.jar,scala-reflect.jar和scala-swing.jar,
並且提供了SparkSql在內的統一的spark-assembly-1.6.0-hadoop2.6.0.jar,所以只需再引入sqlite數據庫的驅動sqlite-jdbc-3.7.2.jar
就可以了:
    
    但是使用Spark2.2,就沒那麼幸運了。首先要使用Scala2.11.8,語言自帶的library只有library和reflect兩個,swing需要
自己手工瀏覽添加;然後就是沒有了統一的spark-assembly的jar檔,需要把spark-2.2.0-bin-hadoop2.7解壓目錄中jars裏面的
jar檔全部 加入,纔不會出現jar檔的依賴引用缺失。當然要使用mysql數據庫,mysql的驅動jar必不可少:


       另外,還要注意的是,spark2.2應該是在jdk1.8的版本下編譯的,所以,需要安裝jdk1.8,並設定Java Compiler和
Scala Compiler都使用1.8的版本:



        否則,會出現java.lang.UnsupportedClassVersionError: PR/Sort : Unsupported major.minor version 52.0這個錯誤。
       另外的改進,是在導入數據到mysql中時,提前獲取詩句的叶韻和句式,這樣在集句時效率會好一些,因而
實際的集句功能的代碼也有相應修改。但是由於導入了全唐詩和全宋詩,數據量比較大,所以其實改進的效果
並不明顯。而且在查詢或集句時,如果結果數據量過多,會出現不能連接到數據庫的錯誤:
       根據錯誤提示的信息:
Driver stacktrace:
 at java.security.AccessController.doPrivileged(Native Method)
 at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:80)
 at java.awt.EventQueue.dispatchEvent(EventQueue.java:728)
 at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:201)
 at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:116)
 at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:105)
 at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
 at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
 at java.awt.EventDispatchThread.run(EventDispatchThread.java:82)
Caused by: java.security.PrivilegedActionException: org.apache.spark.SparkException: Job aborted due to stage failure: Task 0 in stage 8717.0 failed 1 times, most recent failure: Lost task 0.0 in stage 8717.0 (TID 9312, localhost, executor driver): com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
 at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
 at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
 at com.mysql.jdbc.Util.getInstance(Util.java:386)
 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1015)
 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:989)
 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:975)
 at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:920)
 at com.mysql.jdbc.ConnectionImpl.connectWithRetries(ConnectionImpl.java:2395)
 at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2316)
 at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:834)
 at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)
 at sun.reflect.GeneratedConstructorAccessor36.newInstance(Unknown Source)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
 at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
 at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
 at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:416)
 at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:347)
 at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anonfun$createConnectionFactory$1.apply(JdbcUtils.scala:61)
 at org.apache.spark.sql.execution.datasources.jdbc.JdbcUtils$$anonfun$createConnectionFactory$1.apply(JdbcUtils.scala:52)
 at org.apache.spark.sql.execution.datasources.jdbc.JDBCRDD.compute(JDBCRDD.scala:286)
 at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323)
 at org.apache.spark.rdd.RDD.iterator(RDD.scala:287)
 at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
 at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323)
 at org.apache.spark.rdd.RDD.iterator(RDD.scala:287)
 at org.apache.spark.rdd.MapPartitionsRDD.compute(MapPartitionsRDD.scala:38)
 at org.apache.spark.rdd.RDD.computeOrReadCheckpoint(RDD.scala:323)
 at org.apache.spark.rdd.RDD.iterator(RDD.scala:287)
 at org.apache.spark.scheduler.ResultTask.runTask(ResultTask.scala:87)
 at org.apache.spark.scheduler.Task.run(Task.scala:108)
 at org.apache.spark.executor.Executor$TaskRunner.run(Executor.scala:335)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
 at java.lang.Thread.run(Thread.java:748)
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
 at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
 at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
 at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
 at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
 at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
 at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:1129)
 at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:358)
 at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2489)
 at com.mysql.jdbc.ConnectionImpl.connectWithRetries(ConnectionImpl.java:2334)
 ... 26 more
Caused by: java.net.SocketException: Permission denied: connect
 at java.net.DualStackPlainSocketImpl.connect0(Native Method)
 at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketImpl.java:79)
 at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
 at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
 at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
 at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
 at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
 at java.net.Socket.connect(Socket.java:589)
 at java.net.Socket.connect(Socket.java:538)
 at java.net.Socket.<init>(Socket.java:434)
 at java.net.Socket.<init>(Socket.java:244)
 at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:256)
 at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:308)
 ... 28 more
        修改mysql連接的等待時間,或者調大max connections的數量設置,都無法解決這個問題。爲了避免出現這個問題,後來只導入了唐詩三百,全唐詩和宋詩三百,並且加上了集句數量的限制:
數據過少,會導致集句不完整;數據太多又會導致性能無法忍受,而且可能報錯。這個mysql connection的問題還希望精通SparkSQL的同好能給以指導解決。
      當然,要使用mysql數據庫,首先本地要安裝mysql數據庫,我選擇的是mysql-5.6.16-winx64.msi,創建的數據庫是spark_poet:
      可以使用導出的文件直接導入數據,也可以使用DataManager中的方法,從文本文件生成數據庫。
      工程代碼已經上傳到CSDN:下載源碼
       歡迎各位Spark高手不吝賜教。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章