日萌社
人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)
大数据组件使用 总文章
- Impala 操作/读写 Kudu,使用druid连接池
- Kudu 原理、API使用、代码
- Kudu Java API 条件查询
- spark读取kudu表导出数据为parquet文件(spark kudu parquet)
- kudu 导入/导出 数据
- Kudu 分页查询的两种方式
- Kudu 创建主键
- map、flatMap(流的扁平化)、split 的区别
- spark程序打包为jar包,并且导出所有第三方依赖的jar包
-
spark提交命令 spark-submit 的参数 executor-memory、executor-cores、num-executors、spark.default.parallelism分析
window本地版本
<dependencies>
<dependency>
<groupId>org.apache.kudu</groupId>
<artifactId>kudu-client</artifactId>
<version>1.9.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.kudu</groupId>
<artifactId>kudu-client-tools</artifactId>
<version>1.9.0</version>
</dependency>
<dependency>
<groupId>org.apache.kudu</groupId>
<artifactId>kudu-spark2_2.11</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.8</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.3.3</version>
</dependency>
<!-- Spark Core -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>2.3.3</version>
<scope>compile</scope>
</dependency>
<!-- HDFS Client -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<args>
<arg>-dependencyfile</arg>
<arg>${project.build.directory}/.scala_dependencies</arg>
</args>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.spark_kudu_parquet.spark_kudu</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
package com.spark_kudu_parquet
import org.apache.kudu.spark.kudu._
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql._
import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
object spark_kudu {
def main1(args: Array[String]): Unit = {
val sparkConf = new SparkConf()
.setAppName("spark_kudu")
//设置Master_IP并设置spark参数
.setMaster("local")
.set("spark.worker.timeout", "500")
.set("spark.cores.max", "10")
.set("spark.rpc.askTimeout", "600s")
.set("spark.network.timeout", "600s")
.set("spark.task.maxFailures", "1")
.set("spark.speculationfalse", "false")
.set("spark.driver.allowMultipleContexts", "true")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
val sparkContext = SparkContext.getOrCreate(sparkConf)
val sqlContext = SparkSession.builder().config(sparkConf).getOrCreate().sqlContext
// val users = sqlContext.read.load("file:///E:\\parquet\\part-00000-14f6796e-a932-437d-9743-86c46291429e-c000.snappy.parquet")
val usersDF = sqlContext.read.parquet("file:///E:\\parquet")
// usersDF.show()
usersDF.registerTempTable("parquetFile")
val teenagers = sqlContext.sql("SELECT user_id,day FROM parquetFile")
teenagers.show()
// teenagers.map(t => "Name: " + t(0)).collect().foreach(println)
}
def main2(args: Array[String]): Unit = {
val sparkConf = new SparkConf()
.setAppName("spark_kudu")
//设置Master_IP并设置spark参数
.setMaster("local")
.set("spark.worker.timeout", "500")
.set("spark.cores.max", "10")
.set("spark.rpc.askTimeout", "600s")
.set("spark.network.timeout", "600s")
.set("spark.task.maxFailures", "1")
.set("spark.speculationfalse", "false")
.set("spark.driver.allowMultipleContexts", "true")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
val sparkContext = SparkContext.getOrCreate(sparkConf)
val sqlContext = SparkSession.builder().config(sparkConf).getOrCreate().sqlContext
// val peopleDF = sqlContext.read.json("file:///E:\\people.json")
// peopleDF.show()
// peopleDF.write.parquet("file:///E:\\parquet")
usersDF.select("user_id", "day").write.save("hdfs://spark1:9000/namesAndFavColors.parquet")
// print("=====================")
val usersDF = sqlContext.read.parquet("file:///E:\\parquet")
print("=====================")
usersDF.printSchema()
usersDF.show()
// usersDF.createOrReplaceTempView("parquetFile")
// val teenagers = sqlContext.sql("SELECT * FROM parquetFile")
// teenagers.show()
}
def main3(args: Array[String]): Unit = {
val sparkConf = new SparkConf()
.setAppName("spark_kudu")
//设置Master_IP并设置spark参数
.setMaster("local")
.set("spark.worker.timeout", "500")
.set("spark.cores.max", "10")
.set("spark.rpc.askTimeout", "600s")
.set("spark.network.timeout", "600s")
.set("spark.task.maxFailures", "1")
.set("spark.speculationfalse", "false")
.set("spark.driver.allowMultipleContexts", "true")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
val sparkContext = SparkContext.getOrCreate(sparkConf)
val sqlContext = SparkSession.builder().config(sparkConf).getOrCreate().sqlContext
val kuduMasters = "IP,IP,IP"
val kuduContext = new KuduContext(kuduMasters, sqlContext.sparkContext)
//TODO 1:定义kudu表
val kuduTableName = "event_wos_p1"
//TODO 2:配置kudu参数
val kuduOptions: Map[String, String] = Map(
"kudu.table" -> kuduTableName,
"kudu.master" -> kuduMasters)
//TODO 3:注册kudu表作为spark的临时表
sqlContext.read.options(kuduOptions).kudu.registerTempTable(kuduTableName)
//TODO 4:执行sparkSQL语句,spark会自动将谓词推入kudu引擎
val customerNameAgeDF = sqlContext.sql(s"""SELECT user_id,day FROM $kuduTableName WHERE user_id = -3519975374177104455""")
//TODO 5:展示结果
customerNameAgeDF.show()
customerNameAgeDF.printSchema()
//TODO 6:使用sparkSQL的查询计划
customerNameAgeDF.explain()
// customerNameAgeDF.toDF("user_id","day")
//spark默认会根据分区来决定输出文件的多少。所以我们可以用repartition来设置 输出文件的个数。
// customerNameAgeDF.repartition(1).write.parquet("file:///E:\\parquet")
// customerNameAgeDF.select("user_id","day").write.format("parquet").save("E:\\parquet")
customerNameAgeDF.select("user_id", "day").write.format("parquet").save("hdfs://node1:8020//user/hive/warehouse/test_parquet_kudu/")
/*
create table test_parquet_kudu(user_id bigint,day int) stored as parquet;
show create table test_parquet_kudu;
*/
// val usersDF = sqlContext.read.parquet("file:///E:\\parquet")
// usersDF.printSchema()
// usersDF.show()
// usersDF.registerTempTable("parquetFile")
// val teenagers = sqlContext.sql("SELECT user_id,day FROM parquetFile")
// teenagers.show()
}
def main4(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("test").setMaster("local")
val sc = new SparkContext(conf)
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
val parquet: DataFrame = sqlContext.read.parquet("file:///E:\\parquet")
parquet.printSchema()
parquet.show()
// parquet.select(parquet("name"), parquet("age")).show()
// parquet.select(parquet("user_id"), parquet("day") + 1).show()
}
def main5(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("test").setMaster("local")
val sc = new SparkContext(conf)
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
// 读取文件生成RDD
val file = sc.textFile("file:///E:\\people.txt")
//定义parquet的schema,数据字段和数据类型需要和hive表中的字段和数据类型相同,否则hive表无法解析
val schema = (new StructType)
.add("name", StringType, true)
.add("age", IntegerType, false)
val rowRDD = file.map(_.split(" ")).map(p => Row(p(0), Integer.valueOf(p(1).trim)))
// 将RDD装换成DataFrame
val peopleDataFrame = sqlContext.createDataFrame(rowRDD, schema)
peopleDataFrame.printSchema()
peopleDataFrame.show()
// peopleDataFrame.registerTempTable("people")
peopleDataFrame.createOrReplaceTempView("people")
val teenagers = sqlContext.sql("SELECT name,age FROM people")
teenagers.printSchema()
teenagers.show()
//spark默认会根据分区来决定输出文件的多少。所以我们可以用repartition来设置 输出文件的个数。
// peopleDataFrame.repartition(1).write.mode(SaveMode.Overwrite).parquet("")
peopleDataFrame.write.parquet("file:///E:\\parquet")
// peopleDataFrame.write.parquet("hdfs://node1:9000//user/hive/warehouse/test_parquet/")
/*
create table test_parquet(name string,age int) stored as parquet;
show create table test_parquet;
*/
}
def main6(args: Array[String]): Unit = {
val conf = new SparkConf().setAppName("test").setMaster("local")
val sc = new SparkContext(conf)
val sqlContext = new SQLContext(sc)
val users = sqlContext.read.format("parquet").load("file:///E:\\parquet")
users.printSchema()
users.show()
users.createOrReplaceTempView("people")
val teenagers = sqlContext.sql("SELECT name,age FROM people")
teenagers.printSchema()
teenagers.show()
// users.registerTempTable("usersTempTab")
// users.createOrReplaceTempView("usersTempTab")
// val usersRDD =sqlContext.sql("select * from usersTempTab").rdd
// usersRDD.foreach(t=>println("name:"+t(0)+" age:"+t(1)))
}
}
linux CDH版本
<packaging>jar</packaging>
<repositories>
<repository>
<id>cdh.repo</id>
<name>Cloudera Repositories</name>
<url>https://repository.cloudera.com/artifactory/cloudera-repos</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>scala-tools.org</id>
<name>Scala-tools Maven2 Repository</name>
<url>http://scala-tools.org/repo-releases</url>
</repository>
<repository>
<id>maven-hadoop</id>
<name>Hadoop Releases</name>
<url>https://repository.cloudera.com/content/repositories/releases/</url>
</repository>
</repositories>
<dependencies>
<!-- ========================CDH 6.1.1版本 =======================-->
<dependency>
<groupId>org.apache.kudu</groupId>
<artifactId>kudu-client</artifactId>
<version>1.8.0-cdh6.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.kudu</groupId>
<artifactId>kudu-client-tools</artifactId>
<version>1.8.0-cdh6.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.kudu</groupId>
<artifactId>kudu-spark2_2.11</artifactId>
<version>1.8.0-cdh6.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-sql_2.11</artifactId>
<version>2.4.0-cdh6.1.1</version>
</dependency>
<!-- Spark Core -->
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.11</artifactId>
<version>2.4.0-cdh6.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-hive_2.11</artifactId>
<version>2.4.0-cdh6.1.1</version>
</dependency>
<!-- HDFS Client -->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.0.0-cdh6.1.1</version>
</dependency>
<!-- ========================非CDH 6.1.1版本 =======================-->
<!--<dependency>-->
<!--<groupId>org.apache.kudu</groupId>-->
<!--<artifactId>kudu-client</artifactId>-->
<!--<version>1.9.0</version>-->
<!--<scope>test</scope>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.apache.kudu</groupId>-->
<!--<artifactId>kudu-client-tools</artifactId>-->
<!--<version>1.9.0</version>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.apache.kudu</groupId>-->
<!--<artifactId>kudu-spark2_2.11</artifactId>-->
<!--<version>1.7.0</version>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.apache.spark</groupId>-->
<!--<artifactId>spark-sql_2.11</artifactId>-->
<!--<version>2.3.3</version>-->
<!--</dependency>-->
<!--<!– Spark Core –>-->
<!--<dependency>-->
<!--<groupId>org.apache.spark</groupId>-->
<!--<artifactId>spark-core_2.11</artifactId>-->
<!--<version>2.3.3</version>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>org.apache.spark</groupId>-->
<!--<artifactId>spark-hive_2.11</artifactId>-->
<!--<version>2.3.3</version>-->
<!--<scope>compile</scope>-->
<!--</dependency>-->
<!--<!– HDFS Client –>-->
<!--<dependency>-->
<!--<groupId>org.apache.hadoop</groupId>-->
<!--<artifactId>hadoop-client</artifactId>-->
<!--<version>3.0.0</version>-->
<!--</dependency>-->
<!-- ===============================通用===============================-->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.11.8</version>
</dependency>
</dependencies>
<!--
添加以下build信息的话,会把src\main\scala中的scala文件都到一个jar包
-->
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<args>
<arg>-dependencyfile</arg>
<arg>${project.build.directory}/.scala_dependencies</arg>
</args>
</configuration>
</execution>
</executions>
</plugin>
<!--
-->
<!--
添加以下plugin信息的话,会把所有jar包中的文件解压缩后都集中压缩到一个jar包
-->
<!--<plugin>-->
<!--<groupId>org.apache.maven.plugins</groupId>-->
<!--<artifactId>maven-shade-plugin</artifactId>-->
<!--<version>2.3</version>-->
<!--<executions>-->
<!--<execution>-->
<!--<phase>package</phase>-->
<!--<goals>-->
<!--<goal>shade</goal>-->
<!--</goals>-->
<!--<configuration>-->
<!--<filters>-->
<!--<filter>-->
<!--<artifact>*:*</artifact>-->
<!--<excludes>-->
<!--<exclude>META-INF/*.SF</exclude>-->
<!--<exclude>META-INF/*.DSA</exclude>-->
<!--<exclude>META-INF/*.RSA</exclude>-->
<!--</excludes>-->
<!--</filter>-->
<!--</filters>-->
<!--<transformers>-->
<!--<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">-->
<!--<mainClass>com.spark_kudu_parquet.spark_kudu</mainClass>-->
<!--</transformer>-->
<!--</transformers>-->
<!--</configuration>-->
<!--</execution>-->
<!--</executions>-->
<!--</plugin>-->
</plugins>
</build>
import org.apache.kudu.spark.kudu._
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.sql._
import org.apache.spark.sql.types.{IntegerType, StringType, StructField, StructType}
import java.util.Date
import java.text.SimpleDateFormat
import java.util.Calendar
object spark_kudu
{
val sparkConf = new SparkConf()
//设置Master_IP并设置spark参数
.setAppName("spark_kudu")
//-----------------------------------------------------
/*
本地模式 才需要以下配置
*/
//集群模式 不使用 setMaster("local[数字]")。local[数字] 表示本地运行多少个个线程
// .setMaster("local[50]")
// //测试环境3台机器硬件:每台机器有2个CPU,每个CPU有8个核,那么每台机器一共有16个核
// //spark.cores.max / spark.executor.cores = 48 / 2 = 24个executor。每个 executor 占用 2 个core 和 1g 内存。24个executor一共占用 48个core 和 24g 内存
// .set("spark.cores.max", "48")
// .set("spark.executor.cores", "2")
// .set("spark.executor.memory", "2g")
//-----------------------------------------------------
.set("spark.worker.timeout", "1000")
//spark.sql.shuffle.partitions(对sparks SQL专用的设置) 默认值:200 含义:当shuffle数据时,配置joins联接或aggregations聚合时要使用的分区数,提高shuffle并行度
.set("spark.sql.shuffle.partitions", "400")
//自动重新分区,每个stage[阶段]运行时分区并不尽相同,使用此配置可优化计算后分区数,避免分区数过大导致单个分区数据量过少,每个task运算分区数据时时间过短,
// 从而导致task频繁调度消耗过多时间
.set("spark.sql.auto.repartition", "true")
//每个stage的默认task数量,计算公式为num-executors * executor-cores 系统默认值分区为40,这是导致executor并行度上不去的罪魁祸首,
// 之所以这样计算是为了尽量避免计算最慢的task决定整个stage的时间,将其设置为总核心的2-3倍,让运行快的task可以继续领取任务计算直至全部任务计算完毕
.set("spark.default.parallelism", "600")
.set("spark.rpc.askTimeout", "1000s")
.set("spark.network.timeout", "1000s")
.set("spark.task.maxFailures", "4")
.set("spark.speculationfalse", "false")
.set("spark.driver.allowMultipleContexts", "true")
.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
val sparkContext = SparkContext.getOrCreate(sparkConf)
val sqlContext = SparkSession.builder().config(sparkConf).getOrCreate().sqlContext
//测试环境 外网 "xxx,xxx,xxx" 默认使用端口7051
// val kuduMasters = "xxx,xxx,xxx"
//测试环境 内网 "xxx,xxx,xxx" 默认使用端口7051
val kuduMasters = "xxx,xxx,xxx"
//生产环境 外网 "xxx,xxx,xxx" 默认使用端口7051
// val kuduMasters ="xxx,xxx,xxx"
//生产环境 内网 "xxx,xxx,xxx" 默认使用端口7051
//val kuduMasters = "xxx,xxx,xxx"
val kuduContext = new KuduContext(kuduMasters, sqlContext.sparkContext)
//TODO 1:定义kudu表
val kuduTableName = "event_wos_p1"
//TODO 2:配置kudu参数
val kuduOptions: Map[String, String] = Map(
"kudu.table" -> kuduTableName,
"kudu.master" -> kuduMasters)
//TODO 3:注册kudu表作为spark的临时表
sqlContext.read.options(kuduOptions).kudu.registerTempTable(kuduTableName)
//SELECT * FROM rawdata.event_wos_p1 where user_id = -8867208521423675794;
// val customerNameAgeDF = sqlContext.sql("SELECT * FROM event_wos_p1 where user_id = -8867208521423675794" )
//SELECT * FROM rawdata.event_wos_p1 where time BETWEEN '2019-06-01 00:00:00' AND '2019-06-01 00:00:01'
// val customerNameAgeDF = sqlContext.sql("SELECT * FROM event_wos_p1 where time BETWEEN '2019-06-01 00:00:00' AND '2019-06-01 00:00:01'" )
//SELECT count(*) FROM rawdata.event_wos_p1 where time > '2019-06-01 00:00:00.744000000' and time < '2019-06-01 00:00:03.492000000'
val customerNameAgeDF = sqlContext.sql("SELECT * FROM event_wos_p1 where time > '2019-06-01 00:00:00.744000000' and time < '2019-06-01 00:00:03.492000000'" )
// val customerNameAgeDF = sqlContext.sql(s"""SELECT * FROM $kuduTableName where day= $x""" )
// val customerNameAgeDF = sqlContext.sql(s"""SELECT * FROM $kuduTableName where user_id = -8867208521423675794""" )
// val customerNameAgeDF = sqlContext.sql(s"""SELECT count(*) FROM $kuduTableName where user_id = -8867208521423675794""" ) //2583
// val customerNameAgeDF = sqlContext.sql(s"""SELECT count(*) FROM $kuduTableName where time > from_unixtime(1559318400,'yyyy-MM-dd HH:mm:ss') and time < from_unixtime(1559318401,'yyyy-MM-dd HH:mm:ss')""" )
// val customerNameAgeDF = sqlContext.sql(s"""SELECT * FROM $kuduTableName where time > '2019-06-01 00:00:00' and time < '2019-06-01 00:00:01'""" )
// val customerNameAgeDF = sqlContext.sql(s"""SELECT count(*) FROM $kuduTableName where time > '2019-06-01 00:00:00.744000000' and time < '2019-06-01 00:00:03.492000000'""" )
// val customerNameAgeDF = sqlContext.sql(s"""SELECT * FROM $kuduTableName where time BETWEEN '2019-06-01 00:00:00' AND '2019-06-01 00:00:01'""" )
//TODO 4:执行sparkSQL语句,spark会自动将谓词推入kudu引擎
// val customerNameAgeDF = sqlContext.sql(s"""SELECT * FROM $kuduTableName WHERE user_id = -8867208521423675794""")
//TODO 5:展示结果
// customerNameAgeDF.show()
// customerNameAgeDF.printSchema()
//TODO 6:使用sparkSQL的查询计划
// customerNameAgeDF.explain()
// customerNameAgeDF.select("day","user_id" ).show()
// val day_user_id_DF = customerNameAgeDF.select("day","user_id" )
// customerNameAgeDF.toDF("user_id","day")
/*
SparkSql 控制输出文件数量且大小均匀(distribute by rand())
Q:Spark如何控制文件你输出数量?
A:这个简单,用 coalesce或者repartition,num=(1.0*(df.count())/7000000).ceil.toInt
Q:Spark让输出文件大小均匀?
A:在sparksql的查询最后加上distribute by rand()
本文重点:distribute by 关键字控制map输出结果的分发,相同字段的map输出会发到一个reduce节点处理,如果字段是rand()一个随机数,能能保证每个分区的数量基本一致
val num = (1.0 * (df.count()) / 100).ceil.toInt
df.coalesce(num).createOrReplaceTempView("res")
*/
//spark默认会根据分区来决定输出文件的多少。所以我们可以用repartition来设置 输出文件的个数。
// val num = (1.0 * (customerNameAgeDF.count()) / 100).ceil.toInt
// customerNameAgeDF.coalesce(num).write.parquet("file:///E:\\parquet")
// day_user_id_DF.coalesce(num).write.parquet("file:///E:\\parquet")
//此处表是在 hdfs文件系统下 创建 /home/gzp/parquet目录
//hadoop fs -rm -R /home 递归删除目录和文件 。hadoop fs -rm -R /user/gzp/out。 hadoop fs -chown -R gzp:gzp /user/gzp/out
// customerNameAgeDF.repartition(1).write.parquet("/home/gzp/parquet")
customerNameAgeDF.repartition(1).write.parquet("/user/gzp/out")
// customerNameAgeDF.repartition(1).write.parquet("file:///E:\\parquet")
// customerNameAgeDF.select("user_id","day").write.format("parquet").save("E:\\parquet")
// customerNameAgeDF.select("user_id", "day").write.format("parquet").save("hdfs://node1:8020//user/hive/warehouse/test_parquet_kudu/")
/*
create table test_parquet_kudu(user_id bigint,day int) stored as parquet;
show create table test_parquet_kudu;
*/
// val usersDF = sqlContext.read.parquet("file:///E:\\parquet")
// usersDF.printSchema()
// usersDF.show()
// usersDF.registerTempTable("parquetFile")
// val teenagers = sqlContext.sql("SELECT user_id,day FROM parquetFile")
// teenagers.show()
}
1.Kudu:测试环境下的 rawdata.event_wos_p1表 根据查询条件day=18048 可以查询出 8148210 条数据
SELECT * FROM rawdata.event_wos_p1 WHERE day=18048;
SELECT count(*) FROM rawdata.event_wos_p1 WHERE day=18048;
2.Kudu:分页查询的两种方式
1.第一种:可以直接使用“limit 行数” 表示直接从 select 的查询结果中 获取出一定的行数。
“limit 行数”的用法 可以通过 kudu api 或者 spark sql 对 Kudu 进行查询。
2.第二种:必须使用impala的api才可以进行分页条件(“limit 开始 offset 结束”)的sql查询,spark sql 本身不支持对 Kudu直接进行 分页条件(“limit 开始 offset 结束”)的sql查询。
而且还必须先使用“order by 排序字段”之后才能使用“limit 开始 offset 结束”,否则语法错误。
排序+分页的 缺点:数据量大的时候 非常耗时不可取。
例子:select * from 表名 where 字段 = xx order by 排序字段 limit 开始 offset 结束;
1.Hive支持索引,但是Hive的索引与关系型数据库中的索引并不相同,比如,Hive不支持主键或者外键。
Hive索引可以建立在表中的某些列上,以提升一些操作的效率,例如减少MapReduce任务中需要读取的数据块的数量。
在可以预见到分区数据非常庞大的情况下,索引常常是优于分区的。
需要时刻记住的是,Hive并不像事物数据库那样针对个别的行来执行查询、更新、删除等操作。这些操作依赖高效的索引来实现高性能。
Hive是一种批处理工具,通常用在多任务节点的场景下,快速地扫描大规模数据。关系型数据库则适用于典型的单机运行、I/O密集型的场景。
Hive通过并行化来实现性能,因此Hive更适用于全表扫描这样的操作,而不是像使用关系型数据库一样操作。
2.Hive的索引目的是提高Hive表指定列的查询速度。
没有索引时,类似'WHERE tab1.col1 = 10' 的查询,Hive会加载整张表或分区,然后处理所有的rows,
但是如果在字段col1上面存在索引时,那么只会加载和处理文件的一部分。
与其他传统数据库一样,增加索引在提升查询速度时,会消耗额外资源去创建索引和需要更多的磁盘空间存储索引。
Hive 0.7.0版本中,加入了索引。Hive 0.8.0版本中增加了bitmap索引。
3.Hive里的分区、分桶、视图、索引
1.分桶是细粒度的,分桶是不同的文件。桶在对指定列进行哈希计算时,会根据哈希值切分数据,使每个桶对应一个文件。里面的id是哈希值,分过来的。
分桶,一般用作数据倾斜和数据抽样方面。由此,可看出是细粒度。
2.分区是粗粒度的,即相当于,表下建立文件夹。分区是不同的文件夹。
Hive 中创建分区表没有什么复杂的分区类型(范围分区、列表分区、hash分区,混合分区等)。
分区列也不是表中的一个实际的字段,而是一个或者多个伪列。意思是说,在表的数据文件中实际并不保存分区列的信息与数据。
3.注意:普通表(外部表、内部表)、分区表这三个都是对应HDFS上的目录,桶表对应是目录里的文件
4.索引是为了提高查询速度的,视图是在查询sql的基础上的。
对一个表来说,视图是横向的,一般创建视图查询语句都要加条件的
索引是作用列上面的。拿索引来说,在某列上建立索引,得到的这个索引表,其实是原来的表而已。只是取了个新名字,因为在建立了索引,包装了一下。
视图是指计算机数据库中的视图,是一个虚拟表,即不是实实在在的,其内容由查询定义。
同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。
行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。
一般情况,是多表关联查询的时候,才用视图。
对一个表来说,视图是横向的,一般创建视图查询语句都要加条件的,索引是作用列上面的。
索引是为了提高查询速度的,视图是在查询sql的基础上的。
比如一个表很多字段,你查询的时候,只是想取得其中一部分字段,并且包含一些特定条件的数据 ,这个时候最好用视图。
4.Hive 和 HBase 查询步骤,图看 D:\气盖世\笔记\Hive 和 HBase\Hive 和 HBase 查询步骤
1.Hive里的2维坐标系统(第一步定位行键 -> 第二步定位列修饰符)
2.HBase里的4维坐标系统(第一步定位行键 -> 第二步定位列簇 -> 第三步定位列修饰符 -> 第四步定位时间戳)
实际上,HBase的存储值,即一个键值对,是 { row key,column family,column name,timestamp } -> value
行键,相当于第一步级索引。
列簇,相当于第二步级索引。
列修饰符,相当于第三步级索引。
时间戳,相当于第四步级索引。
5.例子1:
1.原表是user。创建索引后的表是user_index_table。索引是user_index
2.在原表user上创建索引user_index,得到创建索引后的表user_index_table
3.先创建原表user:create table user(id int,name string) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE;
往原表user里导入数据:LOAD DATA LOCAL INPATH '/export1/tmp/wyp/row.txt' OVERWRITE INTO TABLE user;
给原表user做个测试
SELECT * FROM user where id =500000;
Total MapReduce CPU Time Spent: 5 seconds 630 msec
OK
500000 wyp.
Time taken: 14.107 seconds, Fetched: 1 row(s)
可以看出,一共用了14.107s。
4.创建 临时索引表user_index_table,说明:临时索引表是table user_index_table,索引名称为user_index,索引字段为user表中的id字段
CREATE INDEX user_index ON TABLE user(id) AS 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' WITH deferred REBUILD IN TABLE user_index_table;
或者如下写都是一样的,建议如下写
create index user_index on table user(id) as 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' with deferred rebuild IN TABLE user_index_table;
给原表user更新数据(填充 原表user 的索引数据):ALTER INDEX user_index on user REBUILD;
删除索引:DROP INDEX user_index on user;
查看索引(查看 原表user 的创建的索引):SHOW INDEX on user;
6.例子2:
1.步骤一:创建 索引测试表 index_test,后面需要给id字段做一个索引字段
CREATE TABLE index_test( id INT, name STRING ) PARTITIONED BY (dt STRING) ROW FORMAT DELIMITED FILEDS TERMINATED BY ',';
说明:创建一个索引测试表 index_test,而 dt作为分区属性,
“ROW FORMAT DELIMITED FILEDS TERMINATED BY ','” 表示用逗号分割字符串,默认为‘\001’。
2.步骤二:创建 临时索引表 index_tmp
create table index_tmp(id INT, name STRING, dt STRING) ROW FORMAT DELIMITED FILEDS TERMINATED BY ',';
说明:临时索引表是table index_tmp
3.步骤三:加载数据到 临时索引表 index_tmp 中
load data local inpath '/home/hadoop/djt/test.txt' into table index_tmp;
4.步骤四:设置 Hive 的索引属性来优化索引查询
set hive.exec.dynamic.partition.mode=nonstrict;----设置所有列为 dynamic partition
set hive.exec.dynamic.partition=true;----使用动态分区
5.步骤五:查询 临时索引表index_tmp 中的数据,然后再把 临时索引表index_tmp 中的数据 插入到 索引测试表index_test 中。
insert overwrite table index_test partition(dt) select id,name,dt from index_tmp;
6.步骤六:使用 索引测试表 index_test,在属性 id 上创建一个索引,索引名称为 index1_index_test
create index index1_index_test on table index_test(id) as 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' WITH DEFERERD REBUILD;
建议如下写
create index index1_index_test on table index_test(id) as 'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler' WITH DEFERERD REBUILD;
索引是index1_index_test
索引测试表是 index_test
在索引测试表的属性id上创建的索引
7.步骤七:填充 索引测试表 index_test 的索引数据
alter index index1_index_test on index_test rebuild;
8.步骤八:查看 索引测试表 index_test 的创建的索引
show index on index_test
9.步骤九:查看 索引测试表 index_test 的分区信息
show partitions index_test;
10.步骤十:查看 索引测试表 index_test 的索引数据(/usr/hive/warehouse/default_表名_索引名_)
$ hadoop fs -ls /usr/hive/warehouse/default_index_test_index1_index_test_
11.步骤十一:删除 索引测试表 index_test 的索引
drop index index1_index_test on index_test;
show index on index_test;
12.步骤十二:索引测试表的索引数据也被删除(/usr/hive/warehouse/default_表名_索引名_)
$ hadoop fs -ls /usr/hive/warehouse/default_index_test_index1_index_test_
no such file or directory
13.步骤十三:修改配置文件信息
1.hive.optimize.index.filter 和 hive.optimize.index.groupby 参数默认是 false。使用索引的时候必须把这两个参数开启,才能起到作用。
hive.optimize.index.filter:自动使用索引,默认不开启false;
hive.optimize.index.groupby:是否使用聚集索引优化group-by查询,默认关闭false;
2.hive.optimize.index.filter.compact.minsize
为输入一个紧凑的索引将被自动采用最小尺寸、默认5368709120(以字节为单位)。
压缩索引自动应用的最小输入大小,默认是5368709120;
3.hive.optimize.ppd:是否支持谓词下推,默认开启;所谓谓词下推,将外层查询块的 WHERE 子句中的谓词移入所包含的较低层查询块(例如视图),从而能够提早进行数据过滤以及有可能更好地利用索引。
4.hive.index.compact.file.ignore.hdfs:在索引文件中存储的hdfs地址将在运行时被忽略,如果开启的话;如果数据被迁移,那么索引文件依然可用,默认是false;
5.hive.optimize.index.filter.compact.maxsize:同上,相反含义,如果是负值代表正无穷,默认是-1;
6.hive.index.compact.query.max.size:一个使用压缩索引做的查询能取到的最大数据量,默认是10737418240 个byte;负值代表无穷大;
7.hive.index.compact.query.max.entries:使用压缩索引查询时能读到的最大索引项数,默认是10000000;负值代表无穷大;
8.hive.index.compact.binary.search:在索引表中是否开启二分搜索进行索引项查询,默认是true;
9.hive.exec.concatenate.check.index:如果设置为true,那么在做ALTER TABLE tbl_name CONCATENATE on a table/partition(有索引) 操作时,抛出错误;
可以帮助用户避免index的删除和重建;
报错:
A read-only user or a user in a read-only database is not permitted to disable read-only mode on a connection
不允许只读用户或只读数据库中的用户禁用连接的只读模式。
原因1:
作为(do'whoami')登录的用户对hive使用的derby元存储数据库目录没有写访问权。因此,请转到/var/lib/hive/metastore/metastore_db(在大多数情况下这是默认值),
并通过执行anls验证您的用户ID是否具有权限。如果您的用户ID没有权限,您应该要求目录所有者授予您写权限。因此,作为所有者/超级用户登录并执行
解决1:
cd /var/lib/hive/metastore/metastore_db
chmod a+rwx . --recursive
cd /var/lib/hive/metastore
chmod 777 metastore_db
原因2:
另一个可能的原因是Derby是一个单用户数据库。所以,请转到 /var/lib/hive/metastore/metastore_db
解决2:
请注意,这将授予所有用户权限。但是相应地调整r-w-x位。
cd /var/lib/hive/metastore/metastore_db
rm *.lck
报错:
Error executing SQL query "select "DB_ID" from "DBS""
原因:
查看hive初始化的元数据库是默认的derby,还是musql,如果hive-site.xml配置的还是默认的derby连接信息的话,
修改为mysql的连接信息,然后进行初始化hive的元数据库到mysql中
解决:
cd /opt/cloudera/parcels/CDH/lib/hive/conf
hive-site.xml 中删除掉derby连接信息,增加mysql的连接信息,然后 执行命令 schematool -initSchema -dbType mysql 初始化hive的元数据库,
最终mysql中的hive数据库自动生成出一系列对应的hive相关表
报错:
Permission denied: user=gzp, access=WRITE, inode="/":hdfs:supergroup:drwxr-xr-x
解决:
1.方式一:
hadoop fs -ls / (默认以当前用户身份执行hadoop命令) 或 sudo -u hdfs hadoop fs -ls / (sudo -u hdfs表示以hdfs的身份执行命令)
“sudo -u hdfs 命令”:执行命令,可以用 hdfs dfs 代替 hadoop fs
2.方式二:
su hdfs 进入hdfs用户命令界面:bash-4.2$ 命令
3.方式三:
关闭hdfs的权限检查:dfs.permissions 检查 HDFS 权限,操作:关闭权限检查,选择不勾选
4.方式四:
使用属于自己当前用的 hdfs目录。比如“/user/当前用户名”的hdfs目录 其 Owner 和 Group 都是当前用户名,那么便不会产生任何权限问题
如果这个文件夹或文件的Group是自己用户名,但是Owner是hdfs用户的话,那么自己用户仍然没有权限修改该文件夹或文件,必须要使用Owner所属的hdfs用户才能修改该文件夹或文件
比如说 可以通过 “sudo -u hdfs 命令” 或者 设置环境变量:export HADOOP_USER_NAME=hdfs 的方式来 修改 Owner所属的hdfs用户的 文件夹或文件
5.对于hadoop程序而言
如果hadoop没有启用Kerberos或者从Kerberos获取的用户为null,那么获取HADOOP_USER_NAME环境变量,并将它的值作为Hadoop执行用户。
如果我们没有设置HADOOP_USER_NAME环境变量,那么程序将调用whoami来获取当前用户,并用groups来获取用户所在组。
whoami:linux命令,即当前操作命令的用户
1.方式一:设置环境变量:export HADOOP_USER_NAME=hdfs
设置用户名的作用之一是:程序输出的文件/文件夹的所有人Owner属于该用户hdfs
比如说 直接执行命令 export HADOOP_USER_NAME=hdfs
比如说 修改某个用户目录下的环境变量 vim .bash_profile 添加 export HADOOP_USER_NAME=hdfs。然后刷新 source .bash_profile
比如说 修改系统环境变量 vim /etc/profile 添加 export HADOOP_USER_NAME=hdfs。然后刷新 source /etc/profile
2.方式二:程序中设置:System.setProperty("HADOOP_USER_NAME", "hdfs");
设置用户名的作用之一是:程序输出的文件/文件夹的所有人Owner属于该用户hdfs
6.对于Spark程序而言
Spark默认将用户程序运行所在系统的当前登录用户作为用户程序的关联用户。
所以可以采用以下两种方法:
1.方式一:su hdfs 进入 hdfs 用户执行命令 或 sudo -u hdfs 以hdfs的身份执行命令。
设置用户名的作用之一是:程序输出的文件/文件夹的所有人Owner属于该用户hdfs
2.代码中添加:System.setProperty("user.name", "hdfs");
spark程序 或 mr程序 在hdfs生成文件的时候 需要注意 生成的最后一级的文件夹必须不存在,否则报错 path hdfs://cdh01:8020/文件路径 already exists
解决:比如说 spark程序 或 mr程序 数据输出的hdfs路径 配置为 /user/root/out 时,/user/root是可以已经存在的,但是要保证最后一级的文件夹out 是不存在的 即可
1.impala查询Kudu:测试环境下的 rawdata.event_wos_p1表 根据查询条件user_id = -8867208521423675794 可以查询出 2583 条数据
SELECT * FROM rawdata.event_wos_p1 WHERE user_id = -8867208521423675794;
SELECT count(*) FROM rawdata.event_wos_p1 WHERE user_id = -8867208521423675794;
2.Hive查询:创建的 hive表 要使用 row format delimited fields terminated by '\t' stored as parquet
SELECT count(*) FROM `event_database`.`event_tmp` ;
SELECT * FROM `event_database`.`event_tmp` ;
3.impala查询Kudu 和 Hive查询 都可以
//秒为单位的时间戳 2019-06-01 02:13:23.400000000
select distinct from_unixtime(1559351246,'yyyy-MM-dd HH:mm:ss') from `rawdata`.`event_wos_p1`;
日期时间比较:以下sql语法在impala查询kudu和hive查询两种方式都可实现
kudu表中和hive表中的time字段的类型:timestamp 类型
kudu表中和hive表中的time字段的值:2019-06-01 00:00:00.360000000
1.第一种方式: where time字段 > from_unixtime(秒单位时间戳,'yyyy-MM-dd HH:mm:ss') and time字段 < from_unixtime(秒单位时间戳,'yyyy-MM-dd HH:mm:ss')
2.第二种方式:where time字段 > '2019-06-01 00:00:00' and time字段 < '2019-06-01 00:00:01'
3.第三种方式:where time字段 BETWEEN '2019-06-01 00:00:00' AND '2019-06-01 00:00:01';
4.注意:
1.kudu表中的time字段:
此处time字段建立为主键,因此查询时比较快
例子:通过java kudu api 创建联合主键 val hashKeys: ImmutableList[String] = ImmutableList.of("id", "user_id")
2.hive表中的time字段:
1.如果time字段没有建立索引的话,那么查询很慢,注意Hive不支持主键或者外键,并且hive sql都是需要转换为mr执行的,所以会更慢
2.如果time字段建立有索引的话,那么查询比较快
//2019-06-01 00:00:00 < time < 2019-06-01 01:00:00
select time from `rawdata`.`event_wos_p1` where time > from_unixtime(1559318400,'yyyy-MM-dd HH:mm:ss') and time < from_unixtime(1559322000,'yyyy-MM-dd HH:mm:ss');
//2019-06-01 00:00:00 < time < 2019-06-01 01:00:00
select time from `rawdata`.`event_wos_p1` where time > '2019-06-01 00:00:00' and time < '2019-06-01 01:00:00';
//2019-06-01 00:00:00 < time < 2019-06-01 00:00:01
select time from `rawdata`.`event_wos_p1` where time > from_unixtime(1559318400,'yyyy-MM-dd HH:mm:ss') and time < from_unixtime(1559318401,'yyyy-MM-dd HH:mm:ss');
//2019-06-01 00:00:00 < time < 2019-06-01 00:00:01
select time from `rawdata`.`event_wos_p1` where time > '2019-06-01 00:00:00' and time < '2019-06-01 00:00:01';
//2019-06-01 00:00:00 < time < 2019-06-01 01:00:00
select count(time) from `rawdata`.`event_wos_p1` where time > from_unixtime(1559318400,'yyyy-MM-dd HH:mm:ss') and time < from_unixtime(1559322000,'yyyy-MM-dd HH:mm:ss');
//2019-06-01 00:00:00 < time < 2019-06-01 01:00:00
select count(time) from `rawdata`.`event_wos_p1` where time > '2019-06-01 00:00:00' and time < '2019-06-01 01:00:00';
//2019-06-01 00:00:00 < time < 2019-06-01 00:00:01
select count(time) from `rawdata`.`event_wos_p1` where time > from_unixtime(1559318400,'yyyy-MM-dd HH:mm:ss') and time < from_unixtime(1559318401,'yyyy-MM-dd HH:mm:ss');
//2019-06-01 00:00:00 < time < 2019-06-01 00:00:01
select count(time) from `rawdata`.`event_wos_p1` where time > '2019-06-01 00:00:00' and time < '2019-06-01 00:00:01';
select time from `rawdata`.`event_wos_p1` where time BETWEEN '2019-06-01 00:00:00.744000000' AND '2019-06-01 00:00:03.492000000';
select count(time) from `rawdata`.`event_wos_p1` where time BETWEEN '2019-06-01 00:00:00' AND '2019-06-01 00:00:01';
hdfs文件的相关操作主要使用hadoop fs、hadoop dfs、hdfs dfs 命令,以下对最常用的相关命令进行简要说明。
hadoop fs -ls 显示当前目录结构,-ls -R 递归显示目录结构
hadoop fs -mkdir 创建目录
hadoop fs -mkdir -p 递归创建目录
hadoop fs -rm 删除文件
hadoop fs -rm -R 递归删除目录和文件,要注意的是只会删除最后一级文件夹和该文件夹下的文件,并不会删除最后一级文件夹之外的文件夹和文件
例子: hadoop fs -rm -R /home/gzp/parquet 只会删除 parquet 文件夹和其下的文件,并不会删除 /home/gzp文件夹和其下的文件
hadoop fs -put [localsrc] [dst] 从本地加载文件到HDFS
hadoop fs -get [dst] [localsrc] 从HDFS导出文件到本地
hadoop fs - copyFromLocal [localsrc] [dst] 从本地加载文件到HDFS,与put一致
hadoop fs -copyToLocal [dst] [localsrc] 从HDFS导出文件到本地,与get一致
hadoop fs -test -e 检测目录和文件是否存在,存在返回值$?为0,不存在返回1
hadoop fs -text 查看文件内容
hadoop fs -du 统计目录下各文件大小,单位字节。-du -s 汇总目录下文件大小,-du -h 显示单位
hadoop fs -tail 显示文件末尾
hadoop fs -cp [src] [dst] 从源目录复制文件到目标目录
hadoop fs -mv [src] [dst] 从源目录移动文件到目标目录
hadoop fs -chmod [-R] 755 URI#改变用户访问权限
hadoop fs -chgrp [-R] GROUP URI#改变文件的所属组
hadoop fs -chmod [-R] 755 URI#改变用户访问权限
hadoop fs -chown [-R] [OWNER][:[GROUP]] URI [URI ] #修改文件的所有者,即修改OWNER和GROUP。例子:hadoop fs -chown [-R] root:root 目录路径
迭代删除(只删除最后一级目录此处为out下所有的文件/文件夹):hadoop fs -rm -R /user/gzp/out
修改OWNER和GROUP:hadoop fs -chown -R gzp:gzp /user/gzp/out
移动文件的同时重命名:hadoop fs -mv /user/gzp/out/part-00000-68f51c41-3a8c-4692-bd6e-42428766bc12-c000.snappy.parquet /user/hive/warehouse/event_database.db/event_tmp/part-00000-68f51c41-3a8c-4692-bd6e-42428766bc12-c000.snappy.parquet
首先创建hive表,数据用tab分隔
create table test(name string,age int) row format delimited fields terminated by '\t';
加载数据
load data local inpath '/home/work/test/ddd.txt' into table test;
数据样例格式:
hive> select * from test limit 5;
OK
leo 27
jim 38
leo 15
jack 22
jay 7
Time taken: 0.101 seconds, Fetched: 5 row(s)
创建parquet格式表
create table test_parquet(name string,age int) stored as parquet
查看表结构
可以看到数据的inputFormat是MapredParquetInputFormat,之后我们将用这个类来解析数据文件
hive> show create table test_parquet;
OK
CREATE TABLE `test_parquet`(
`name` string,
`age` int)
ROW FORMAT SERDE
'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe'
STORED AS INPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat'
OUTPUTFORMAT
'org.apache.hadoop.hive.ql.io.parquet.MapredParquetOutputFormat'
LOCATION
'hdfs://localhost:9000/user/hive/warehouse/test_parquet'
TBLPROPERTIES (
'transient_lastDdlTime'='1495038003')
往parquet格式表中插入数据
insert into table test_parquet select * from test;
用spark中hadoopFile api解析hive中parquet格式文件
如果是用spark-shell中方式读取文件一定要将hive-exec-0.14.0.jar加入到启动命令行中(MapredParquetInputFormat在这个jar中),
还有就是要指定序列化的类,启动命令行如下
spark-shell --master spark://xiaobin:7077
--jars /home/xiaobin/soft/apache-hive-0.14.0-bin/lib/hive-exec-0.14.0.jar
--conf spark.serializer=org.apache.spark.serializer.KryoSerializer
具体读取代码如下
用MapredParquetInputFormat解析hive中parquet格式文件,每行数据将会解析成一个key和value,这里的key是空值,value是一个ArrayWritable,
value的长度和表的列个数一样,value各个元素对应hive表中行各个字段的值
scala> import org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat
import org.apache.hadoop.hive.ql.io.parquet.MapredParquetInputFormat
scala> import org.apache.hadoop.io.{ArrayWritable, NullWritable, Text}
import org.apache.hadoop.io.{ArrayWritable, NullWritable, Text}
scala> val file =sc.hadoopFile("hdfs://localhost:9000/user/hive/warehouse/test_parquet/000000_0",classOf[MapredParquetInputFormat],classOf[Void],classOf[ArrayWritable])
file: org.apache.spark.rdd.RDD[(Void, org.apache.hadoop.io.ArrayWritable)] = hdfs://localhost:9000/user/hive/warehouse/test_parquet/000000_0 HadoopRDD[0] at hadoopFile at <console>:29
scala> file.take(10).foreach{case(k,v)=>
| val writables = v.get()
| val name = writables(0)
| val age = writables(1)
| println(writables.length+" "+name+" "+age)
| }
==================================================================================
用spark DataFrame 解析parquet文件
val conf = new SparkConf().setAppName("test").setMaster("local")
val sc = new SparkContext(conf)
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
val parquet: DataFrame = sqlContext.read.parquet("hdfs://192.168.1.115:9000/user/hive/warehouse/test_parquet")
parquet.printSchema()
parquet.select(parquet("name"), parquet("age") + 1).show()
root
|-- name: string (nullable = true)
|-- age: integer (nullable = true)
+----+---------+
|name|(age + 1)|
+----+---------+
| leo| 28|
| jim| 39|
| leo| 16|
|jack| 23|
| jay| 8|
| jim| 38|
|jack| 37|
| jay| 12|
==================================================================================
用hivesql直接读取hive表
在local模式下没有测试成功,打包用spark-submit测试
提交任务命令行:spark-submit --class quickspark.QuickSpark02 --master spark://192.168.1.115:7077 sparkcore-1.0-SNAPSHOT.jar
val conf = new SparkConf().setAppName("test")
val sc = new SparkContext(conf)
val hiveContext = new HiveContext(sc)
val sql: DataFrame = hiveContext.sql("select * from test_parquet limit 10")
sql.take(10).foreach(println)
[leo,27]
[jim,38]
[leo,15]
[jack,22]
[jay,7]
[jim,37]
[jack,36]
[jay,11]
[leo,35]
[leo,33]
==================================================================================
用spark写parquet文件
val conf = new SparkConf().setAppName("test").setMaster("local")
val sc = new SparkContext(conf)
val sqlContext = new org.apache.spark.sql.SQLContext(sc)
// 读取文件生成RDD
val file = sc.textFile("hdfs://192.168.1.115:9000/test/user.txt")
//定义parquet的schema,数据字段和数据类型需要和hive表中的字段和数据类型相同,否则hive表无法解析
val schema = (new StructType)
.add("name", StringType, true)
.add("age", IntegerType, false)
val rowRDD = file.map(_.split("\t")).map(p => Row(p(0), Integer.valueOf(p(1).trim)))
// 将RDD装换成DataFrame
val peopleDataFrame = sqlContext.createDataFrame(rowRDD, schema)
peopleDataFrame.registerTempTable("people")
peopleDataFrame.write.parquet("hdfs://192.168.1.115:9000/user/hive/warehouse/test_parquet/")
用hive sql读取用spark DataFrame生成的parquet文件
hive> select * from test_parquet limit 10;
OK
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
leo 27
jim 38
leo 15
jack 22
jay 7
jim 37
jack 36
jay 11
leo 35
leo 33