Shell脚本
1、日期格式化
DT=`date -d'-1 day' +%Y-%m-%d`
echo $DT
2021-03-04
2、if判断 $1 $2 是参数
if [ $1 -eq 0 ]
then echo '1'
else echo '2'
fi
if [[ $1 && $2 ]] // 两个参数
3、单引号(强制字符化),双引号(可以$引用变量),漂号(会被作为命令执行)的区别
[root@dream1 ~]# n=3
[root@dream1 ~]# echo '$n'
$n
[root@dream1 ~]# echo "$n"
3
[root@dream1 ~]# echo `$n`
-bash: 3: command not found
4、shell脚本中,配置环境变量
export HIVE_HOME=/opt/apps/hive
5、命令操作替换jar包中的文件:
显示jar中的文件列表: jar -tvf xx.jar
解压jar中的指定文件: jar -xvf xx.jar yy.properties
更新jar中的指定文件: jar -uvf xx.jar yy.properties
端口
hadoop
namenode 9000/8020(看配置)
kafka
broker 9092
zookeeper
2181
hbase
regionserver 16010
case class
package jn.ws.util
import jn.ws.bean.LogBean
import org.apache.spark.sql.Row
/**
* row => bean
*/
object EtlUtils {
def row2Logbean(row: Row): LogBean = {
row match {
case Row(
account: String
, appId: String
, appVersion: String
, carrier: String
) =>
LogBean(
account
, appId
, appVersion
, carrier
)
case _ => null
}
}
}
pt.map(EtlUtils.row2Logbean)
frame.rdd.map {
case Row(
repAdviceDealMethod: String,
repAdviceTitle: String,
repAdviceNumberOther: Int
) => Advice(
repAdviceDealMethod,
repAdviceTitle,
repAdviceNumberOther
)
case _ => null
}
java -cp 如何依赖外部jar包
在线分析平台
布隆过滤器
val filter = new BloomFilter(200000000, 4, 1)
// 字典数据
for(id <- hisIds){
filter.add(new Key(id.getBytes()))
}
// 广播
val bc = spark.sparkContext.broadcast(filter)
val res = log.map(s=>{
val f = bc.value
var isnew = 1
// 查询是否存在
if(f.membershipTest(new Key(s.getBytes()))) isnew = 0
}
经纬度计算 GeoHash,相同区域内根据lng,lat和GeoHash方法得出的结果相同
<dependency>
<groupId>ch.hsr</groupId>
<artifactId>geohash</artifactId>
<version>1.3.0</version>
</dependency>
GeoHash.geoHashStringWithCharacterPrecision(lat,lng,5)
spark广播变量
val dbByte = spark.sparkContext.broadcast(db2Bin) // 发送广播变量
val db = dbByte.value // 读取广播变量
Ip2Region,根据ip获取省市(无法获取区)
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
val searcher = new DbSearcher(new DbConfig(), db)
val block = searcher.memorySearch(ip).toString
保存、读取parquet文件
resGeo.write.parquet("dataware/data/geo")
spark.read.parquet("dataware/data/geo")
按照指定分区 生成paquet文件
frame.write.partitionBy("provincename","cityname").parquet(parquetPath)
设置parquet的压缩格式
val config = Map[String,String](
"spark.serializer" -> classOf[KryoSerializer].getName,
"spark.sql.parquet.compression.codec" -> "snappy"
)
创建dataSet 一般模拟数据较为常用 seq需要引入
import spark.implicits._
val dt: Dataset[String] = spark.createDataset(Seq("60.208.118.18", "60.108.118.18", "60.215.77.35"))
spark读取资源目录
props.load(GeoHashDict.getClass.getClassLoader.getResourceAsStream("db.properties"))
saprk加载配置文件
方式一
package com.ws.conf
import java.io.InputStream
import java.util.Properties
object ConfigHelper {
val application = new Properties()
val config: InputStream = ConfigHelper.getClass.getClassLoader.getResourceAsStream("application.properties")
application.load(config)
val master: String = application.getProperty("app.comm.master")
val jdbc_driver: String = application.getProperty("app.mysql.driver")
val jdbc_url: String = application.getProperty("app.mysql.url")
val jdbc_username: String = application.getProperty("app.mysql.username")
val jdbc_password: String = application.getProperty("app.mysql.password")
val properties = new Properties()
properties.setProperty("driver",jdbc_driver)
properties.setProperty("user",jdbc_username)
properties.setProperty("password",jdbc_password)
}
方式二 采用typesafe包的ConfigFacory
<dependency>
<groupId>com.typesafe</groupId>
<artifactId>config</artifactId>
<version>1.3.0</version>
</dependency>
package com.ws.conf
import java.util.Properties
import com.typesafe.config.ConfigFactory
object ConfigHelper {
private lazy val application = ConfigFactory.load()
val master: String = application.getString("app.comm.master")
val jdbc_driver: String = application.getString("app.mysql.driver")
val jdbc_url: String = application.getString("app.mysql.url")
val jdbc_username: String = application.getString("app.mysql.username")
val jdbc_password: String = application.getString("app.mysql.password")
val properties = new Properties()
properties.setProperty("driver",jdbc_driver)
properties.setProperty("user",jdbc_username)
properties.setProperty("password",jdbc_password)
}
spark读取hdfs
spark读取mysql
val props = new Properties() props.load(GeoHashDict.getClass.getClassLoader.getResourceAsStream("db.properties"))
val dataFrame = spark.read.jdbc("jdbc:mysql://dream3:3306/realtimedw?useUnicode=true&characterEncoding=utf8", "t_md_areas", props)
spark自定义函数的使用
方式一
import org.apache.spark.sql.functions._
val geoMap: UserDefinedFunction = udf((lng:Double, lat:Double) => {
GeoHash.geoHashStringWithCharacterPrecision(lat,lng,5)
})
val resGeo: DataFrame = res.select('province, 'city, 'region, geoMap('lng, 'lat) as "geohash")
方式二
DataSet转DataFrame
val DataFrame = dataset.toDF("ip", "region")
创建dataFrame
spark读取csv文件指定schema,默认都是string
val schema = new StructType()
.add("countid", DataTypes.StringType)
.add("deviceid", DataTypes.StringType)
.add("sessionid", DataTypes.StringType)
.add("ts", DataTypes.LongType)
val logdf: DataFrame = spark.read.option("header",true).schema(schema).csv("dataware/data/idBind/day1/event_app_action_log")
相对路径使用
val logdf: DataFrame = spark.read.schema(schema).csv("dataware/data/idBind/event_app_action_log")
sqoop迁移注意事项

Hive开启日志
cp hive-log4j2.properties.template hive-log4j2.properties
修改日志目录
Hive报错
hive -hiveconf hive.root.logger=DEBUG,console
进入hive命令行,执行报错的语句
hive本地模式开启
hive.exec.mode.local.auto | false | 让Hive确定是否自动启动本地模式运行 |
hive.exec.mode.local.auto.inputbytes.max | 134217728(128MB) | 当第一个参数为true时,输入字节小于此值时才能启动本地模式 |
hive.exec.mode.local.auto.input.files.max | 4 | 当一个参数为true时,任务个数小于此值时才能启动本地模式 |
hive> SET hive.exec.mode.local.auto=true; hive> SET hive.exec.mode.local.auto.inputbytes.max=50000000; hive> SET hive.exec.mode.local.auto.input.files.max=5;
hiveserver2 的默认运行jvm 最多为256M 复杂的mr程序会报错无法执行,
修改hive-config.sh 调整Jvm参数
hive full join
hive explode 行转列
select(explode(array(did,uid)) as ids) from xx
spark 整合hive
hive desc 获取建表语句和表结构
show create table app_log; // 获取建表语句
hive时间戳转换
注意 hive中的时间戳是精确到秒的,而我们的代码中一般是精确到毫秒的,所以处理我们的时间戳需要除以1000在运算
0: jdbc:hive2://dream4:10000> select unix_timestamp();
+-------------+--+
| _c0 |
+-------------+--+
| 1614832733 |
+-------------+--+
1 row selected (0.06 seconds)
0: jdbc:hive2://dream4:10000> select from_unixtime(1614832638,'yyyy-MM-dd');
+-------------+--+
| _c0 |
+-------------+--+
| 2021-03-04 |
+-------------+--+
1 row selected (0.056 seconds)
0: jdbc:hive2://dream4:10000>
insert 指定分区
spark.sql(
"""
|insert into ipbind(deviceid,countid,ts,score) partition(dt='2020-03-08')
|select
| deviceid,countid,min(ts) ts,count(distinct sessionid) * 100 as score
|from
| logs
|group by
| deviceid,countid
|""".stripMargin)
创建表指定分区
create table dwd17.idbind(deviceid string,accountid string,ts bigint,score double) partitioned by (dt string);
导入数据指定分区
load data local inpath '/root/rng.11' into table test.act_range partiton('2020-10-11')
hive 高阶聚合函数 cube 多维立方体
With cube(所有维度自由组合)
grouping sets(按照指定维度组合)

一个字段join两个字段,两列合成一列处理
select explode(array(deviceid,account)) as ids from idbind;
Permission denied: user=Wsong, access=WRITE, inode=
启动flume
bin/flume-ng agent -c conf/ -f agentconf/yiee_log.properties -n a1 -Dflume.root.logger=DEBUG,console
删除处于ACCEPTED状态的任务
for i in `yarn application -list | grep -w ACCEPTED | awk '{print $1}' | grep application_`; do yarn application -kill $i; done
spark-yarn的资源配置
yarn的nodemanager的 容器 的工作目录
// 模式匹配
val Array(bzipPath:String,parquetPath:String) = args
隐式转换
package com.ws.etl.bean
class RichString(str: String) {
// 定义方法
def toRichInt: Int = {
try {
str.toInt
} catch {
case _: Exception => 0
}
}
def toRichDouble: Double = try {
str.toDouble
} catch {
case _:Exception => 0.0
}
}
object RichString {
// 定义隐式转换
implicit def string2RichString(str:String): RichString = new RichString(str)
}
导入隐式转换,然后使用
def main(args: Array[String]): Unit = {
// 导入隐式转换
import com.ws.etl.bean.RichString._
val a = "10"
// 使用隐式转换
println(a.toRichInt-1)
}
解决caseClass 只能装22个属性
package cn.ws.bean
/**
* scala 2.10 版本之前 caseClass 只能装22个属性,为了解决这个问题,我们可以实现Product接口解决这个问题
*/
class Psn extend Product(
val name: String, // 会话标识
val age: Int
) extends Product {
/**
* @param n 角标
*/
override def productElement(n: Int): Any = n match {
case 0 => name
case 1 => age
}
/**
* 成员属性个数
*
* @return
*/
override def productArity: Int = 2
/**
* 是否一个同一类型
*
* @param that
* @return
*/
override def canEqual(that: Any): Boolean = that.isInstanceOf[Psn]
}
object Psn {
def apply(arr: Array[String]): Psn = new Psn(
arr(0),
arr(1).toInt
)
}
spark删除文件的方法,通用于hdfs、本地环境、或其他文件系统
package com.ws.etl.utils
import org.apache.hadoop.fs.{FileSystem, Path}
import org.apache.spark.SparkContext
object FileHelper {
/**
* 为了解决运行环境不一定的情况下(本地 hdfs),删除文件的问题
*
* @param dirPath 文件路径
* @param sc sparkContext
*/
def deleteDir(dirPath: String, sc: SparkContext): AnyVal = {
// spark 集成了 hadoop,所以我们能拿到他的core-site配置文件
val conf = sc.hadoopConfiguration
// 根据配置文件,获取文件系统
val system = FileSystem.get(conf)
val path = new Path(dirPath)
// 根据文件系统来判断文件是否存在
if (system.exists(path)) {
// 是否递归删除
system.delete(path, true)
}
}
}
dataFrame 过滤简单写法
1、map+= 2、match case
SparkGraph
命令行创建kafka-consumer
如何指定offset:--offset,如果指定--offset之后必须指定分区号 --partition
bin/kafka-console-consumer.sh --bootstrap-server dream1:9092,dream2:9092,dream3:9092 --topic test --offset earliest --partition 0
spark序列化及优化方式
spark默认的序列化方式是ObjectOutputStream,比较臃肿
可以指定spark的序列化方式,org.apache.spark.serializer.kryoSerializer,这个序列化方式会少一些元数据信息,但是必须要携带类的信息,因为driver端和executor端序列化、反序列化必须要携带类的属性,是哪个类,以便于反序列化。
我们可以指定kryoSerializer所需要序列化的所有类,这样就不需要带元数据信息了。
conf.registerKryoClasses(***)
scala解构赋值
val Array(today:String,yearstoday: String) = args
xmail
yum install mailx
vi /etc/mail.rc
set from=dream1@qq.com #(需修改)收件人显示的发件人名称,可填写你的名字等
set smtp=smtp.qq.com #(需修改)你所使用的外部邮箱的smtp服务器地址
set smtp-auth-user=957830825@qq.com #(需修改)你所使用的外部邮箱的用户名
set smtp-auth-password=nxyvstujuxebbbjj #(需修改)你所使用的外部邮箱密码
set smtp-auth=login
测试
echo 123 | mailx -v -s "test" xxxx@qq.com
sql-client flinkcdc
# 启动flink本地集群
${FLINK_HOME}/bin/start-cluster.sh
# 启动sql-client
${FLINK_HOME}/bin/sql-client.sh
# 需要往flink lib中放入flink-cdc.jar
# 执行完成后 看flink本地模式的webui,http://xxx:8081/#/overview
# 来源脚本1,cdc字典流
CREATE TABLE cdc_dict (
id STRING,
name STRING,
age BIGINT,
create_time timestamp,
PRIMARY KEY(id) NOT ENFORCED ) WITH (
'connector' = 'mysql-cdc',
'hostname' = 'xxxx',
'port' = '3306',
'username' = 'root',
'password' = 'xxxx',
'database-name' = 'dwd',
'table-name' = 'cdc_dict'
);
# 来源脚本1,kafka主流,包含sasl配置
create table cdc_main (
id STRING,
addr STRING
)
with (
'connector' = 'kafka',
'topic' = 'flink_test',
'properties.bootstrap.servers' = 'xxxx:6667',
'properties.group.id' = 'park_test_group',
'scan.startup.mode' = 'latest-offset',
'value.format'='json',
'value.json.fail-on-missing-field' = 'false',
'value.json.ignore-parse-errors' = 'true','properties.security.protocol' = 'SASL_PLAINTEXT','properties.sasl.mechanism' = 'PLAIN','properties.sasl.jaas.config' ='org.apache.kafka.common.security.plain.PlainLoginModule required username="admin" password="Dmp@xx";');
-- 去向脚本
CREATE TABLE cdc_res (
id STRING,
name STRING,
age BIGINT,
create_time timestamp,
addr STRING,
PRIMARY KEY(id) NOT ENFORCED
) WITH (
'connector' = 'jdbc',
'url' = 'jdbc:mysql://xxxx:3306/dwd?characterEncoding=UTF-8',
'table-name' = 'cdc_res',
'username' = 'root',
'password' = 'xxxx'
);
# 操作脚本
insert into cdc_res(id,name,age,addr) select m.id,d.name,d.age,m.addr from cdc_main m left join cdc_dict d on d.id=m.id;