Flink SQL1.12 三 Hive 内表和外表读写

目录

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的方式(点击参考) ,管理非分区表


3.1 hive

3.1.1 flink sql 

3.1.2 数据源准备 

3.1.3  sql-client

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

3.1.4 代码

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

3.1.5 采坑

3.1.6 配置 (点击参考)

(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;

3.1.7 hive的demo(点击参考) ******

这里主要是demo为主,阐述现象.这篇文章写得太赞了,让我彻底的理解了flink sql和hive的集成方式

  • 执行hive 之前,必须引入的hadoop环境变量

use catalog myhive;

export HADOOP_CLASSPATH=`hadoop classpath`;

  • 启动

./bin/sql-client.sh embedded  

  • 在查询hive 元数据之前,必须用hive的catalog;

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';

这里解释几个对于hive 数据访问比较关键的点.

***HiveCatalog 的作用

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";

***hive的兼容表和非兼容表 is_generic=true

  • 构建kafka的表 非兼容hive表 (在元数据中, 默认不兼容, is_generic=true)
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'
);
  • 对于以上的兼容表和非兼容表,可以尝试在 hive 客户端进行查询和数据的插入,就能瞬间清晰
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的作用

SET table.sql-dialect=hive;

只要利用了这个dialect ,自动将是兼容表,并且flink可以进行可读可写.

  • --构建hive的非分区表
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 ',';

flink对hive的读写操作

1. 分区表

(1)创建hive的分区表

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'
);

(2)准备数据kafka的数据

{"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'
);

将kafka的数据sink到hive分区表中

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;

(3)查询数据

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 这里的参数可以点击参考

2.对非分区表

(1)创建

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'
);

(2)准备数据 略,和上面分区表一致 

(3)先设置 Sql Hint的方式(点击参考) ,管理非分区表

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;

你可能感兴趣的:(sql,flink,flink)