Spark的数据读取,SparkCore连接MySQL及HBase的数据读取

Spark的数据读取即数据保存可以从两个维度来做区分:文件格式以及文件系统。

文件格式分为:Text文件,Json文件,Csv文件,Sequence文件以及Object文件;

文件系统分为:本地文件系统,HDFS,HBase以及数据库。

1. 文件类数据读取与保存

1.1 Text文件
  1. 数据读取:textFile(String)

    var hdfsFile = sc.textFile("hdfs://hadoop01:8020/fruit.txt")

  2. 数据保存:saveAsTextFile(String)

    hdfsFile.saveAsTextFile("/fruitOut")

1.2 Json文件

如果JSON文件中每一行就是一个JSON记录,那么可以通过将JSON文件当做文本文件来读取,然后利用相关的JSON库对每一条数据进行JSON解析。

注意:使用RDD读取JSON文件处理很复杂,同时SparkSql集成了很好的处理JSON文件的方式,所以应用中多采用SparkSql处理JSON文件。

object JsonTest {
  def main(args: Array[String]): Unit = {
    //控制日志输出
    Logger.getLogger("org").setLevel(Level.ERROR)
    
    // 创建spark配置信息
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
    // 创建SparkContext
    val sc = new SparkContext(conf)
  
    // 读取文件
    val lineRdd = sc.textFile("D://sparkData/students.json")

    // 解析json数据
    val result = lineRdd.map(JSON.parseFull).collect()
    result.foreach(println(_))

    sc.stop()
  }
}
1.3 Sequence文件

SequenceFile文件是Hadoop用来存储二进制形式的key-value对而设计的一种平面文件(Flat File)。

Spark有专门用来读取SequenceFile的接口,在SparkContext中,可以调用sequenceFile[keyClass, valueClass] (path)。

注意:SequenceFile文件只针对PairRDD

object SequenceTest {
  def main(args: Array[String]): Unit = {
    //控制日志输出
    Logger.getLogger("org").setLevel(Level.ERROR)
    
    // 创建spark配置信息
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
    // 创建SparkContext
    val sc = new SparkContext(conf)
  
    // 读取文件
    val lineRdd = sc.textFile("D://sparkData/students.json")

    // 将RDD保存为Sequence文件
    lineRdd.map((_, 1)).saveAsSequenceFile("D://sparkData/seq")

    // 读取Sequence文件
    val seq = sc.sequenceFile[String, Int]("D://sparkData/seq")

    // 打印读取后的Sequence文件
    seq.collect().foreach(println(_))
    
    sc.stop()
  }
}
1.4 对象文件

对象文件是将对象序列化后保存的文件,采用Java的序列化机制。

可以通过objectFile[k, v] (path)函数接收一个路径,读取对象文件,返回对应的RDD,也可以通过调用saveAsObjectFile()实现对对象文件的输出。

因为是序列化所以要指定类型。

object ObjectTest {
  def main(args: Array[String]): Unit = {
    //控制日志输出
    Logger.getLogger("org").setLevel(Level.ERROR)
    
    // 创建spark配置信息
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
    // 创建SparkContext
    val sc = new SparkContext(conf)
  
    // 读取文件
    val lineRdd = sc.textFile("D://sparkData/students.json")

    // 将文件保存为Object文件
    lineRdd.saveAsObjectFile("D://sparkData/obj")

    // 读取Object文件
    val result = sc.objectFile[String]("D://sparkData/obj")
    result.collect().foreach(println(_))
    
    sc.stop()
  }
}

2. 文件系统类数据读取与保存

2.1 HDFS

Spark的整个生态系统与Hadoop是完全兼容的,所以对于Hadoop所支持的文件类型或者数据库类型,Spark也同样支持。另外,由于Hadoop的API有新旧两个版本,所以Spark为了能够兼容Hadoop所有的版本,也提供了两套创建操作接口。对于外部存储创建操作而言,hadoopRDD和newHadoopRDD是最为抽象的两个函数接口,主要包含以下四个参数。

  1. 输入格式(InputFormat):制定数据输入的类型,如TextInputFormat等,新旧两个版本所引用的版本分别是org.apache.hadoop.mapred.InputFormat和
    org.apache.hadoop.mapreduce.InputFormat(NewInputFormat)
  2. 键类型:指定[K, V]键值对中K的类型
  3. 值类型:指定[K, V]键值对中V的类型
  4. 分区值:指定由外部存储生成的RDD的partition数量的最小值,如果没有指定,系统会使用默认值 defaultMinSplits

注意:其他创建操作的API接口都是为了方便最终的Spark程序开发者而设置的,是这两个接口的高效实现版本。例如,对于textFile而言,只有path这个指定文件路径的参数,其他参数在系统内部指定了默认值。

  1. 在Hadoop中以压缩形式存储的数据,不需要指定解压方式就能够进行读取,因为Hadoop本身有一个解压器会根据压缩文件的后缀推断解压算法进行解压。
  2. 如果用Spark从Hadoop中读取某种类型的数据不知道怎么读取的时候,上网查找一个使用map-reduce的时候是怎么读取这种这种数据的,然后再将对应的读取方式改写成上面的hadoopRDD和newAPIHadoopRDD两个类就行了。
2.2 MySQL数据库连接

支持通过Java JDBC访问关系型数据库。需要通过JdbcRDD进行,示例如下:

添加依赖

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>8.0.18</version>
</dependency>

MySql读取

import java.sql.DriverManager
import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkConf, SparkContext}

object MysqlSelect {
  def main(args: Array[String]): Unit = {
    //控制日志输出
    Logger.getLogger("org").setLevel(Level.ERROR)
    
    // 创建spark配置信息
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
    // 创建SparkContext
    val sc = new SparkContext(conf)
  
    // 定义连接mysql的参数
    val driver = "com.mysql.cj.jdbc.Driver"
    val url = "jdbc:mysql://127.0.0.1:3306/mybatis?serverTimezone=GMT%2B8"
    val userName = "root"
    val passWd = "123456"

    // 创建JdbcRDD
    val rdd = new JdbcRDD(sc, () => {
      Class.forName(driver)
      DriverManager.getConnection(url, userName, passWd)
    },
      "select * from dynasty where id >= ? and id <= ?;",
      1,
      10,
      1,
      r => (r.getInt(1), r.getString(2))
    ).cache()

    // 打印最后结果
    println(rdd.count())
    println("-----------------")
    rdd.foreach(print(_))

    sc.stop()
  }
}

MySql写入

import java.sql.DriverManager
import org.apache.log4j.{Level, Logger}
import org.apache.spark.{SparkConf, SparkContext}

object MysqlInsert {
  def main(args: Array[String]): Unit = {
    //控制日志输出
    Logger.getLogger("org").setLevel(Level.ERROR)
    
    // 创建spark配置信息
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
    // 创建SparkContext
    val sc = new SparkContext(conf)
  
    // 创建要插入的数据
    val data = sc.parallelize(List("Female", "Male", "Female"))

    // 往mysql中添加数据,调用foreachPartition针对每一个分区进行操作
    data.foreachPartition(insertData)

    def insertData(iterator: Iterator[String]): Unit = {
      // 定义连接mysql的参数
      val driver = "com.mysql.cj.jdbc.Driver"
      val url = "jdbc:mysql://127.0.0.1:3306/mybatis?serverTimezone=GMT%2B8"
      val userName = "root"
      val passWd = "123456"
      // 注册数据库驱动
      Class.forName(driver).newInstance()
      // 获取数据库连接
      val conn = DriverManager.getConnection(url, userName, passWd)

      iterator.foreach(data => {
        val sql = "insert into emp(name) values (?);"
        // 将数据存入到mysql
        val ps = conn.prepareStatement(sql)
        // 封装数据
        ps.setString(1, data)
        // 执行
        ps.execute()
      })
      conn.close()
    }
  }
}
2.3 HBase数据库

由于org.apache.hadoop.hbase.mapreduce.TableInputFormat类的实现,Spark可以通过Hadoop输入格式访问HBase。这个输入格式会返回键值对数据,其中键的类型为org.apache.hadoop.hbase.io.ImmutableBytesWritable,而值的类型为org.apache.hadoop.hbase.client.Result。

添加依赖

<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-server</artifactId>
    <version>2.2.5</version>
</dependency>
<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-client</artifactId>
    <version>2.2.5</version>
</dependency>
<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-mapreduce</artifactId>
    <version>2.2.5</version>
</dependency>
<dependency>
    <groupId>org.apache.hbase</groupId>
    <artifactId>hbase-common</artifactId>
    <version>2.2.5</version>
</dependency>

从HBase读取数据

import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.HBaseConfiguration
import org.apache.hadoop.hbase.client.{Put, Result}
import org.apache.hadoop.hbase.io.ImmutableBytesWritable
import org.apache.hadoop.hbase.mapreduce.TableInputFormat
import org.apache.hadoop.hbase.util.Bytes
import org.apache.log4j.{Level, Logger}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object HbaseSelect {
  def main(args: Array[String]): Unit = {
    //控制日志输出
    Logger.getLogger("org").setLevel(Level.ERROR)
    
    // 创建spark配置信息
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
    // 创建SparkContext
    val sc = new SparkContext(conf)
  
    // 建立HBase的连接
    val config:Configuration = HBaseConfiguration.create()
    config.set("hbase.zookeeper.quorum", "node7-1:2181,node7-2:2181,node7-3:2181")
    // 设置查询的表明mydata:psn_1
    config.set(TableInputFormat.INPUT_TABLE, "mydata:psn_1")

    // 通过SparkContext将mydata:psn_1表中数据创建一个RDD
    val hbaseRDD: RDD[(ImmutableBytesWritable, Result)] = sc.newAPIHadoopRDD(
      config,
      classOf[TableInputFormat],
      classOf[ImmutableBytesWritable],
      classOf[Result]
    )

    // 计算数据条数
    val count: Long = hbaseRDD.count()
    println(count)

    // 遍历输出
    // 当建立RDD的时候,前面全部是参数信息,后面的resul才是保存数据的数据集
    hbaseRDD.foreach {
      case (_, result) =>
        // 通过result.getRow来获取行键
        val key: String = Bytes.toString(result.getRow)
        // 通过result.getValue("列族", "列名")来获取值
        // 注意这里需要使用getBytes将字符流转化成字节流
        val name: String = Bytes.toString(result.getValue("cf".getBytes, "name".getBytes))
        val age: String = Bytes.toString(result.getValue("cf".getBytes, "age".getBytes))
        // 打印结果
        println("RowKey:" + key + ",Name:" + name + ",Age:" + age)
    }

    // 关闭连接
    sc.stop()
  }
}

往HBase写入数据

import org.apache.hadoop.conf.Configuration
import org.apache.hadoop.hbase.HBaseConfiguration
import org.apache.hadoop.hbase.client.{Put, Result}
import org.apache.hadoop.hbase.io.ImmutableBytesWritable
import org.apache.hadoop.hbase.mapred.TableOutputFormat
import org.apache.hadoop.hbase.util.Bytes
import org.apache.hadoop.mapred.JobConf
import org.apache.log4j.{Level, Logger}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}

object HbaseInsert {
  def main(args: Array[String]): Unit = {
    //控制日志输出
    Logger.getLogger("org").setLevel(Level.ERROR)
    
    // 创建spark配置信息
    val conf: SparkConf = new SparkConf().setAppName(this.getClass.getSimpleName).setMaster("local[*]")
    // 创建SparkContext
    val sc = new SparkContext(conf)
  
    // 连接hbase
    val conf = HBaseConfiguration.create()
    conf.set("hbase.zookeeper.quorum", "node7-1:2181,node7-2:2181,node7-3:2181")

    // 读取文件(文件中是要写入Hbase中的数据)
    val textFile: RDD[String] = sc.textFile("D://sparkData/info.txt")
    val put: RDD[(ImmutableBytesWritable, Put)] = textFile.map {
      case line => {
        // 将文件中的数据按,切分
        val datas = line.split(",")
        // 行键的值
        val rowkey = Bytes.toBytes(datas(0))
        val put = new Put(rowkey)
        // // 依次给列族cf的列添加值
        put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("name"), Bytes.toBytes(datas(1)))
        put.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("price"), Bytes.toBytes(datas(2)))
        // // 必须有这两个返回值,put为要传入的数据
        (new ImmutableBytesWritable(rowkey), put)
      }
    }
    val jobConf = new JobConf(conf)
    jobConf.setOutputFormat(classOf[TableOutputFormat])
    // 与HBase的fruit_spark表建立连接
    jobConf.set(TableOutputFormat.OUTPUT_TABLE, "fruit_spark")
    put.saveAsHadoopDataset(jobConf)
    println("spark向hbase写入数据成功")
  }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值