目录
3.1 hive
3.1.1 flink sql
3.1.2 数据源准备
3.1.3 sql-client
3.1.4 代码
3.1.5 采坑
3.1.6 配置 (点击参考)
3.1.7 hive的demo(点击参考) ******
这里解释几个对于hive 数据访问比较关键的点.
***HiveCatalog 的作用
***hive的兼容表和非兼容表 is_generic=true
***Dialect的作用
SET table.sql-dialect=hive;
flink对hive的读写操作
1. 分区表
(1)创建hive的分区表
(2)准备数据kafka的数据
将kafka的数据sink到hive分区表中
(3)查询数据
2.对非分区表
(1)创建
(2)准备数据 略,和上面分区表一致
(3)先设置 Sql Hint的方式(点击参考) ,管理非分区表
jar
wget https://repo.maven.apache.org/maven2/org/apache/flink/flink-sql-connector-hive-3.1.2_2.11/1.12.0/flink-sql-connector-hive-3.1.2_2.11-1.12.0.jar
flink-sql-connector-hive-2.3.6
flink-connector-hive_2.11-1.12.0.jar
hive-exec-2.3.4.jar
配置
add hive-site.xml sql-client-default.xml
hive-site.xml (需要添加password )
javax.jdo.option.ConnectionPassword
xxxx
password for connecting to mysql server
javax.jdo.option.ConnectionUserName
hive
hive.metastore.schema.verification
true
sql-client-default.yml 中修改 name+ type+ hive-conf-dir
catalogs:
# A typical catalog definition looks like:
- name: myhive
type: hive
hive-conf-dir: /data/flink/flink-1.12.0/conf
execution:
# select the implementation responsible for planning table programs
# possible values are 'blink' (used by default) or 'old'
planner: blink
# 'batch' or 'streaming' execution
type: streaming
public static void main(String[] args) {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
EnvironmentSettings settings = EnvironmentSettings.newInstance().useBlinkPlanner().build();
StreamTableEnvironment tableEnv = StreamTableEnvironment .create(env,settings);
String name = "myhive";
String defaultDatabase = "default";
String hiveConfDir = "src/main/resources";
HiveCatalog hive = new HiveCatalog(name, defaultDatabase, hiveConfDir);
tableEnv.registerCatalog("myhive", hive);
// 使用注册的catalog
tableEnv.useCatalog("myhive");
// 向Hive表中写入一条数据
String insertSQL = " select * from temp_db.stu11 ";
Table table = tableEnv.sqlQuery(insertSQL);
DataStream rowDataStream = tableEnv.toAppendStream(table, Row.class);
rowDataStream.map(new MapFunction() {
@Override
public Row map(Row row) throws Exception {
System.out.println(row);
return row;
}
}).print("sql==").setParallelism(1);
//任务启动,这行必不可少!
try {
env.execute("test");
} catch (Exception e) {
e.printStackTrace();
}
}
(2)pom
org.apache.hive
hive-exec
3.1.0
org.apache.flink
flink-connector-hive_2.11
1.12.0
(1)hive 写的配置:
- partition.time-extractor.timestamp-pattern
- 默认值:(none)
- 解释:分区时间抽取器,与 DDL 中的分区字段保持一致,如果是按天分区,则可以是**year-day dt $hour:00:00`;
- sink.partition-commit.trigger
- process-time:不需要时间提取器和水位线,当当前时间大于分区创建时间 + sink.partition-commit.delay 中定义的时间,提交分区;
- partition-time:需要 Source 表中定义 watermark,当 watermark > 提取到的分区时间 +sink.partition-commit.delay 中定义的时间,提交分区;
- 默认值:process-time
- 解释:分区触发器类型,可选 process-time 或partition-time。
- sink.partition-commit.delay
- 默认值:0S
- 解释:分区提交的延时时间,如果是按天分区,则该属性的值为:1d,如果是按小时分区,则该属性值为1h;
- sink.partition-commit.policy.kind
- metastore:添加分区的元数据信息,仅Hive表支持该值配置
- success-file:在表的存储路径下添加一个_SUCCESS文件
- 默认值:(none)
- 解释:提交分区的策略,用于通知下游的应用该分区已经完成了写入,也就是说该分区的数据可以被访问读取。可选的值如下:
可以同时配置上面的两个值,比如metastore,success-file
(2) hive读的配置
- streaming-source.enable
- 默认值:false
- 解释:是否开启流式读取 Hive 表,默认不开启。
- streaming-source.partition.include
- 默认值:all
- 解释:配置读取Hive的分区,包括两种方式:all和latest。all意味着读取所有分区的数据,latest表示只读取最新的分区数据。值得注意的是,latest方式只能用于开启了流式读取Hive表,并用于维表JOIN的场景。
- streaming-source.monitor-interval
- 默认值:None
- 解释:持续监控Hive表分区或者文件的时间间隔。值得注意的是,当以流的方式读取Hive表时,该参数的默认值是1m,即1分钟。当temporal join时,默认的值是60m,即1小时。另外,该参数配置不宜过短 ,最短是1 个小时,因为目前的实现是每个 task 都会查询 metastore,高频的查可能会对metastore 产生过大的压力。
- streaming-source.partition-order
- 默认值:partition-name
- 解释:streaming source的分区顺序。默认的是partition-name,表示使用默认分区名称顺序加载最新分区,也是推荐使用的方式。除此之外还有两种方式,分别为:create-time和partition-time。其中create-time表示使用分区文件创建时间顺序。partition-time表示使用分区时间顺序。指的注意的是,对于非分区表,该参数的默认值为:create-time。
- streaming-source.consume-start-offset
- 默认值:None
- 解释:流式读取Hive表的起始偏移量。
- partition.time-extractor.kind
- 默认值:default
- 分区时间提取器类型。用于从分区中提取时间,支持default和自定义。如果使用default,则需要通过参数partition.time-extractor.timestamp-pattern配置时间戳提取的正则表达式。
在 SQL Client 中需要显示地开启 SQL Hint 功能
Temporal Join最新表
lookup.join.cache.ttl
尖叫提示:
当使用此种方式时,Hive表必须是有界的lookup表,即非Streaming Source的时态表,换句话说,该表的属性streaming-source.enable = false。
如果要使用Streaming Source的时态表,记得配置streaming-source.monitor-interval的值,即数据更新的时间间隔。
- 默认值:60min
- 解释:表示缓存时间。由于 Hive 维表会把维表所有数据缓存在 TM 的内存中,当维表数据量很大时,很容易造成 OOM。当然TTL的时间也不能太短,因为会频繁地加载数据,从而影响性能
Flink SQL> set table.dynamic-table-options.enabled= true;
这里主要是demo为主,阐述现象.这篇文章写得太赞了,让我彻底的理解了flink sql和hive的集成方式
use catalog myhive;
export HADOOP_CLASSPATH=`hadoop classpath`;
./bin/sql-client.sh embedded
use catalog myhive;
---查询hive外表,
select * from ods_gbl.ods_phone limit 3; -
---查询内表
select * from stu ;
select * from temp_db.stu11;
向默认的内表中插入数据
insert into `default`.stu select 33,'lara2';
Flink利用 Hive 的 MetaStore 作为持久化的 Catalog
1. 区别兼容表和非兼容表的区别> 在hive中能否查询真实数据.
2. 利用hive的catalog 都可以在hive中查找到元数据的信息
举例说明:
请分别在hive 客户端和flink sql client 观察这样执行的效果
describe formatted user_behavior;
describe formatted user_kafka ;
通过hive元数据查询到在flink sql中已经生成的user_behavior表
SELECT
a.tbl_id, -- 表id
from_unixtime(create_time) AS create_time, -- 创建时间
a.db_id, -- 数据库id
b.name AS db_name, -- 数据库名称
a.tbl_name -- 表名称
FROM sys.tbls AS a
LEFT JOIN sys.DBS AS b ON a.db_id =b.db_id
WHERE a.tbl_name = "user_behavior";
CREATE TABLE user_kafka (
`user_id` BIGINT,
`item_id` BIGINT,
`category_id` BIGINT,
`behavior` STRING,
`ts` STRING
) WITH (
'connector' = 'kafka',
'topic' = 'user_test',
'scan.startup.mode' = 'latest-offset',
'properties.group.id' = 'local-sql-test',
'scan.topic-partition-discovery.interval' = '10000',
'properties.bootstrap.servers'= 'localhost:9200',
'format' = 'json',
'json.fail-on-missing-field' = 'true',
'json.ignore-parse-errors' = 'false'
);
--构建kafka的兼容hive表 在元数据中
CREATE TABLE user_generic (
`user_id` BIGINT,
`item_id` BIGINT,
`category_id` BIGINT,
`behavior` STRING,
`ts` STRING
) WITH (
'connector' = 'kafka',
'topic' = 'user_test',
'scan.startup.mode' = 'latest-offset',
'properties.group.id' = 'local-sql-test',
'properties.bootstrap.servers' = 'localhost:9200',
'format' = 'json',
'json.fail-on-missing-field' = 'true',
'json.ignore-parse-errors' = 'false',
'is_generic' = 'false'
);
insert into user_generic select 2020,1221,100,'buy','2017-11-26T01:10:40';
---select * from user_generic
insert into user_kafka select 2020,1221,100,'buy','2017-11-
6T01:00:00';
---select * from user_kafka
只要利用了这个dialect ,自动将是兼容表,并且flink可以进行可读可写.
CREATE TABLE IF NOT EXISTS `hive_dialect` (
`id` int COMMENT 'id',
`name` string COMMENT '名称',
`age` int COMMENT '年龄'
)
COMMENT 'hive dialect表测试'
ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';
set execution.type=streaming;
SET table.sql-dialect=hive;
CREATE TABLE user_behavior_hive (
`user_id` BIGINT, -- 用户id
`item_id` BIGINT, -- 商品id
`cat_id` BIGINT, -- 品类id
`action` STRING, -- 用户行为
`province` INT, -- 用户所在的省份
`ts` BIGINT -- 用户行为发生的时间戳
) PARTITIONED BY (dt STRING,hr STRING,mi STRING) STORED AS parquet TBLPROPERTIES (
'partition.time-extractor.timestamp-pattern'='$dt $hr:$mi:00',
'sink.partition-commit.trigger'='partition-time',
'sink.partition-commit.delay'='0S',
'sink.partition-commit.policy.kind'='metastore,success-file'
);
{"user_id": "54462", "item_id":"1715", "cat_id": "1464116", "action": "pv", "province":1,"ts": 1612166100 }
SET table.sql-dialect=default;
TABLE user_behavior (
`user_id` BIGINT, -- 用户id
`item_id` BIGINT, -- 商品id
`cat_id` BIGINT, -- 品类id
`action` STRING, -- 用户行为
`province` INT, -- 用户所在的省份
`ts` BIGINT, -- 用户行为发生的时间戳
`proctime` AS PROCTIME(), -- 通过计算列产生一个处理时间列
`eventTime` AS TO_TIMESTAMP(FROM_UNIXTIME(ts, 'yyyy-MM-dd HH:mm:ss')), -- 事件时间
WATERMARK FOR eventTime AS eventTime - INTERVAL '5' SECOND -- 定义watermark
) WITH (
'connector' = 'kafka', -- 使用 kafka connector
'topic' = 'user_behavior', -- kafka主题
'scan.startup.mode' = 'latest-offset', -- 偏移量
'properties.group.id' = 'local-sql-test', -- 消费者组
'properties.bootstrap.servers' = 'localhost:9200',
'format' = 'json', -- 数据源格式为json
'json.fail-on-missing-field' = 'true',
'json.ignore-parse-errors' = 'false'
);
INSERT INTO user_behavior_hive
SELECT
user_id,
item_id,
cat_id,
action,
province,
ts,
FROM_UNIXTIME(ts, 'yyyy-MM-dd'),
FROM_UNIXTIME(ts, 'HH'),
FROM_UNIXTIME(ts, 'mm')
FROM user_behavior;
set table.dynamic-table-options.enabled= true;
SELECT * FROM user_behavior_hive /*+ OPTIONS('streaming-source.enable'='true', 'streaming-source.consume-start-offset'='1') */;
streaming-source.consume-start-offset 这里的参数可以点击参考
SET table.sql-dialect=hive;
CREATE TABLE dimension_table (
product_id STRING,
product_name STRING,
unit_price DECIMAL(10, 4),
pv_count BIGINT,
like_count BIGINT,
comment_count BIGINT,
update_time TIMESTAMP(3),
update_user STRING,
) TBLPROPERTIES (
'streaming-source.enable' = 'false', -- 关闭streaming source
'streaming-source.partition.include' = 'all', -- 读取所有数据
'lookup.join.cache.ttl' = '12 h'
);
set table.dynamic-table-options.enabled= true;
SELECT
fact.item_id,
dim.item_name,
count(*) AS buy_cnt
FROM fact_user_behavior AS fact
LEFT JOIN dim_item1
/*+ OPTIONS('streaming-source.enable'='false',
'streaming-source.partition.include' = 'all',
'lookup.join.cache.ttl' = '12 h') */
FOR SYSTEM_TIME AS OF fact.proctime AS dim
ON fact.item_id = dim.item_id
WHERE fact.action = 'buy'
GROUP BY fact.item_id,dim.item_name;