读取mysql数据写入parquet文件

读取mysql数据写入parquet文件

创建表

create table tbs1(
id int,
name varchar(50),
address varchar(50),
countryid int);

写入数据

package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"strconv"
)

func main() {
	dsn := "root:123456@tcp(192.168.230.71:3306)/fxdb"
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// 准备INSERT语句
	stmt, err := db.Prepare("INSERT INTO tbs1 (id,name,address,countryid) VALUES (?,?,?,?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

	// 执行INSERT语句
	for i := 1; i <= 1000; i++ {
		stmt.Exec(i, "tom"+strconv.Itoa(i), "wuhan"+strconv.Itoa(i), 1000+i)
	}

	fmt.Println("Data inserted successfully")
}

读取数据写入parquet文件

go.mod文件内容如下:

module parquetdemo

go 1.20

require (
	github.com/go-sql-driver/mysql v1.5.0
	github.com/xitongsys/parquet-go v1.6.2
	github.com/xitongsys/parquet-go-source v0.0.0-20200817004010-026bad9b25d0
)

require (
	github.com/apache/arrow/go/arrow v0.0.0-20200730104253-651201b0f516 // indirect
	github.com/apache/thrift v0.16.0 // indirect
	github.com/golang/snappy v0.0.4 // indirect
	github.com/google/flatbuffers v2.0.8+incompatible // indirect
	github.com/klauspost/compress v1.15.9 // indirect
	github.com/pierrec/lz4/v4 v4.1.15 // indirect
	github.com/stretchr/testify v1.8.0 // indirect
	golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
)

main.go内容:

package main

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/xitongsys/parquet-go-source/local"
	"github.com/xitongsys/parquet-go/writer"
	"log"
)

func main() {
	// DSN(数据源名称)
	dsn := "root:123456@tcp(192.168.230.71:3306)/fxdb"

	// 打开数据库连接
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// 验证连接
	err = db.Ping()
	if err != nil {
		log.Fatal(err)
	}

	sSql := "SELECT * FROM tbs1"
	stmt, err := db.Prepare(sSql)
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

	// 查询
	rows, err := stmt.Query()
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()
	// 数据列
	columns, err := rows.Columns()
	if err != nil {
		log.Fatal(err)
	}

	// 列的个数
	count := len(columns)

	types, _ := rows.ColumnTypes()

	/* 构建如下字符串数组,写入需要按照这个数组顺序
	md := []string{
		"name=id, type=INT64",
		"name=Name, type=BYTE_ARRAY, convertedtype=UTF8, encoding=PLAIN",
	}*/

	// 构建md
	var md []string
	// 需要按顺序
	for i := 0; i < len(types); i++ {
		sqltype := *types[i]
		// 列名
		vname := sqltype.Name()
		// 列的数据类型
		vtype := sqltype.DatabaseTypeName()
		item := fmt.Sprintf("name=%s,type=%s", vname, getType(vtype))
		md = append(md, item)
	}

	//write,创建一个ParquetFile
	fw, err := local.NewLocalFileWriter("csv.parquet")
	if err != nil {
		log.Println("Can't open file", err)
		return
	}
	// 创建一个CSV writer,np为parallel number
	pw, err := writer.NewCSVWriter(md, fw, 4)
	if err != nil {
		log.Println("Can't create csv writer", err)
		return
	}

	// 用于存储表数据
	mData := make([]map[string]interface{}, 0)
	// 一条数据的各列的值(需要指定长度为列的个数,以便获取地址)
	values := make([]interface{}, count)
	// 存储values的地址
	valPointers := make([]interface{}, count)
	// 取values地址放入valPointers
	for i := 0; i < count; i++ {
		valPointers[i] = &values[i]
	}
	// 遍历数据
	for rows.Next() {
		// 获取各列的值,放到对应的地址中
		rows.Scan(valPointers...)
		// 一条数据的Map (列名和值的键值对)
		entry := make(map[string]interface{})

		// Map 赋值
		for i, col := range columns {
			var v interface{}
			val := values[i]
			b, ok := val.([]byte)
			if ok {
				v = string(b)
			} else {
				v = val
			}
			entry[col] = v
		}

		mData = append(mData, entry)
	}

	for i, _ := range mData {
		data := make([]interface{}, 0)
		// 按列顺序
		for j := 0; j < len(types); j++ {
			sqltype := *types[j]
			data = append(data, mData[i][sqltype.Name()])
		}

		if err = pw.Write(data); err != nil {
			log.Println("WriteString error:", err)
		}
	}

	if err = pw.WriteStop(); err != nil {
		log.Println("WriteStop error", err)
	}
	log.Println("Write Finished")
	fw.Close()
}

func getType(colType string) string {
	if colType == "INT" {
		return "INT64"
	}
	if colType == "VARCHAR" {
		return "BYTE_ARRAY, convertedtype=UTF8, encoding=PLAIN"
	}
	return ""
}
### 回答1: Spark SQL可以通过DataFrame API或SQL语句来操作外部数据源,包括parquet、hive和mysql等。其中,parquet是一种列式存储格式,可以高效地存储和查询大规模数据;hive是一种基于Hadoop的数据仓库,可以通过Spark SQL来查询和分析;而mysql是一种常见的关系型数据库,可以通过Spark SQL来读取写入数据。在使用Spark SQL操作外部数据源时,需要先创建DataFrame或注册表,然后通过API或SQL语句来进行数据读取、过滤、聚合等操作。同时,还可以通过Spark SQL的连接器来实现不同数据源之间的数据传输和转换。 ### 回答2: Spark SQL 是 Apache Spark 中的一个模块,用于在大规模数据集上进行结构化数据处理。它支持多种数据源,并提供了访问、查询和操作这些数据源的功能。 对于外部数据源的操作,Spark SQL 提供了适配器和驱动程序来连接不同的数据源。下面简单介绍一下对于三种常见的数据源(Parquet、Hive、MySQL)的操作方式: 1. ParquetParquet 是一种列式存储格式,适用于大规模数据存储和分析。对于 Parquet 数据源,Spark SQL 提供了原生的支持,你可以直接使用 `spark.read.parquet()` 方法读取 Parquet 文件,并通过 `write.parquet()` 方法写入 Parquet 文件。Spark SQL 会自动推断 Parquet 文件的模式(schema),你也可以通过指定模式参数来指定具体的模式。 2. Hive:Hive 是一个数据仓库基础设施,可以在 Hadoop 上进行数据仓库的处理和查询。Spark SQL 可以与 Hive 结合使用,使用 Hive 提供的 metastore 来管理表和模式,通过 HiveQL(Hive 查询语言)来查询和操作 Hive 数据。你可以通过 `spark.sql()` 方法来执行 HiveQL 查询,也可以使用 `registerTempTable()` 方法将一个 Spark DataFrame 注册为一个临时表,然后通过 SQL 语句查询这个临时表。 3. MySQLMySQL 是一种关系型数据库管理系统,Spark SQL 也可以与 MySQL 进行集成。首先,需要在 Spark 中导入相应的 MySQL 驱动程序,例如 "com.mysql.jdbc.Driver"。然后,通过 `spark.read.format("jdbc")` 方法来读取 MySQL 数据库中的表,你需要指定连接 URL、表名、用户名和密码等参数。使用相同的方式,你也可以将 Spark DataFrame 写入MySQL 数据库中。 总结起来,Spark SQL 对于 Parquet、Hive 和 MySQL 这些外部数据源都提供了直接的支持和集成。通过适配器和驱动程序,你可以使用 Spark SQL 的 API 和功能来读取写入、查询和操作这些外部数据源中的数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shulu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值