• Flink读写Hive文档


    Flink读写Hive文档

    Flink 支持在 BATCH 和 STREAMING 两种模式下从 Hive 读取数据。 当作为 BATCH 应用程序运行时,Flink 将在执行查询的时间点对表的状态执行其查询。 STREAMING 读取将持续监视表并在新数据可用时增量获取。 Flink 会默认读取有界的表。

    STREAMING 读取支持使用分区表和非分区表。 对于分区表,Flink 会监控新分区的生成,并在可用时增量读取。 对于非分区表,Flink 会监控文件夹中新文件的生成,并增量读取新文件。

    Hive 表还支持 SQL Hints ,比如:

    SELECT * 
    FROM hive_table 
    /*+ 
    OPTIONS(
    	'streaming-source.enable'='true', 
    	'streaming-source.consume-start-offset'='2020-05-20'
    ) 
    */;
    

    配置表

    Hive 读配置

    Key Default Type Description
    streaming-source.enable false Boolean 是否开启 streaming source 读取
    streaming-source.partition.include all String 设置读取哪些分区,用来作为 temporal join 时设置,可选项有 alllatestall表示读取所有分区;
    latest表示按streaming-source.partition.order的顺序读取最新的分区。
    streaming-source.monitor-interval None String 连续监控分区/文件的时间间隔。 注意:hive 流读取的默认间隔是 '1 m' ,hive streaming temporal join 的默认间隔是'60 m',这是因为有一个框架限制,每个 TM 在当前的 hive streaming temporal join 中都会访问 Hive metaStore 可能会对 metaStore 产生压力的实现,这将在未来改进。
    streaming-source.partition-order partition-name String 读取分区的顺序, 可选项有create-timepartition-timepartition-name.
    create-time 比较分区/文件创建时间,这不是 Hive metaStore 中的分区创建时间,而是文件系统中的文件夹/文件修改时间。
    partition-time 比较从分区名称中提取的时间。
    partition-name 比较分区名称的字母顺序。
    对于非分区表,此值应始终为 create-time。 默认情况下,该值为分区名称。
    streaming-source.consume-start-offset None String 从哪里开始读取数据。如何解析和比较偏移量取决于 streaming-source.partition-order
    对于create-timepartition-time,格式是时间戳字符串 (yyyy-[m]m-[d]d [hh:mm:ss])。
    对于partition-time,将使用分区时间提取器从分区中提取时间。
    对于 partition-name,是分区名称字符串(例如 'pt_year=2020/pt_mon=10/pt_day=01')。
    table.exec.hive.fallback-mapred-reader false Boolean 如果为false,则使用flink native vectorized reader读取orc文件;如果是true,则使用hadoop mapred record reader读取orc文件。
    当满足以下条件时,Flink 将自动使用 Hive 表的map reduce 读取:
    1. 数据格式是ORCparquet
    2. 没有复杂数据类型的列,如 hive 类型:List、Map、Struct、Union。
    默认情况下启用此功能。 可以设置为true以禁用
    table.exec.hive.infer-source-parallelism true Boolean 是否开启自动设置source并行度如。
    果为 false,则源的并行度由配置设置。如果为true,则根据拆分数推断source并行度。
    table.exec.hive.infer-source-parallelism.max 1000 Integer 自动推断source的最大并行度
    lookup.join.cache.ttl 60 min Duration 维表 join 时的缓存 TTL(例如 10 分钟)。 默认情况下,TTL 为 60 分钟。 注意:该选项仅在与有界 hive 表 join时有效,如果是用流的方式 join 请使用 'streaming-source.monitor-interval' 配置数据更新的间隔。

    NOTE:

    • 流式读取不支持 watermark 语法。 这些数据不能作为开窗计算。

    Hive 写配置

    一. 文件滚动策略

    Key Default Type Description
    sink.rolling-policy.file-size 128MB MemorySize 写HDFS文件滚动策略,文件多大把inprogress文件rename成 part文件
    sink.rolling-policy.rollover-interval 30 min Duration part文件在滚动前可以保持打开的最长时间(默认为 30 分钟,以避免出现许多小文件)。检查频率由sink.rolling-policy.check-interval选项控制。
    sink.rolling-policy.check-interval 1 min Duration 以此值来生成一个定时器,定时检查是否满足sink.rolling-policy.rollover-interval的条件。注意这个不是用于检查非活跃文件的配置,sql里没有检查非活跃文件的配置

    NOTE: 对于bulk(桶) 格式的数据(parquet, orc, avro),文件滚动由 checkpoint 的时间间隔控制,但在一个 checkpoint 内,也会受以上参数控制。也就是说每次 checkpoint 必定会把 inprogress 文件变成 part 文件,不管有没有满足以上策略。

    NOTE: 对于按行格式写入的数据(csv,json),在没有设置自动压缩小文件的配置的情况下,文件滚动完全由以上策略控制。也就是说这种数据格式的 inprogress 文件可能跨越了多个 checkpoint 周期,在这种情况下恢复任务,如果 hadoop 版本小于 2.7, 会报Flink Truncation is not available in hadoop version < 2.7 , You are on Hadoo的错误,因为 hadoop2.7之前的版本不支持 truncate 。

    二. 小文件合并设置

    Key Default Type Description
    auto-compaction false Boolean 是否开启小文件合并。 数据将写入临时文件。 checkpoint 完成后,临时文件将被压缩。 临时文件在压缩前是不可见的。如果启用,文件压缩将根据目标文件大小将多个小文件合并为更大的文件。
    compaction.file-size (none) MemorySize 压缩文件的大小,默认为sink.rolling-policy.file-size设置的大小.

    NOTE:

    • 仅压缩单个 checkpoint 中的文件,即至少生成与 checkpoint 数量相同的文件。
    • 合并前的文件是不可见的,所以文件的时效性是:checkpoint 间隔 + 压缩时间。
    • 如果压缩时间过长,作业会产生背压并增加 checkpoint 的时间。

    三. 分区提交设置

    写入分区文件后,通常需要通知下游应用程序。 例如,将分区添加到 Hive metastore 或在目录中写入 _SUCCESS 文件。 Flink内置了分区提交功能,用户也可以自定义策略分区提交。分区提交主要包括 triggerspolicies

    1. 分区提交trigger配置

    Key Default Type Description
    sink.partition-commit.trigger process-time String 分区提交触发类型:
    process-time:基于机器时间,既不需要分区时间提取,也不需要 watermark 生成。 “当前系统时间”大于“分区创建系统时间” + “延迟(sink.partition-commit.delay)”,就提交分区。
    partition-time:基于分区时间,从分区值中提取,需要生成 watermark。 watermark 大于 “从分区值中提取的时间” + “延迟(sink.partition-commit.delay)”,就提交分区。
    sink.partition-commit.delay 0 s Duration 分区提交延迟。 如果是以天分区,应该是'1 d',如果是以小时分区,应该是'1 h'。
    sink.partition-commit.watermark-time-zone UTC String 设置 watermark 的时区,会根据这个时区把 watermark (long类型的时间戳)转换为 TIMESTAMP , 用于与分区时间进行比较来决定分区是否提交。仅在 sink.partition-commit.trigger 设置为 partition-time 时生效。 如果此选项配置不正确,例如 source rowtime 定义成 TIMESTAMP_LTZ (local time zone),但未配置此配置,用户可能会在几个小时后看到提交的分区。 默认值为UTC,表示 watermark 在 TIMESTAMP 类型的列上定义或未定义。 如果在 TIMESTAMP_LTZ 类型的列上定义了watermark,则watermark的时区为会话时区。 选项值可以是全名(例如“America/Los_Angeles”)或自定义时区 ID(例如“GMT-08:00”)。

    process-timepartition-time:

    • process-time. 不需要提取分区值也不需要 watermark。分区提交根据当前时间和分区创建时间来定。这种是比较通用的触发器,但数据不够准确,可能会发生数据漂移。
    • partition-time.根据分区时间和 watermark 来触发分区提交. 需要 watermark 生成和分区提取。

    如果你只想让下游立马看到数据,不管数据是否已经完成,可以设置成:

    • 'sink.partition-commit.trigger'='process-time'
    • 'sink.partition-commit.delay'='0s' (Default value) Once there is data in the partition, it will immediately commit. Note: the partition may be committed multiple times.

    如果想数据完成时(假设以小时作为分区)才让下游看到数据,并且 source 有 watermark,可以设置成:

    • 'sink.partition-commit.trigger'='partition-time'
    • 'sink.partition-commit.delay'='1h'

    NOTE:

    1. 迟到数据的处理:当一条记录应该写入一个已经提交的分区时,该记录就会被写入到它对应的分区中,然后再次触发该分区的提交。
    2. 分区提交其实是跟着 checkpoint 走的,分区提交是在 writer 之后的一个算子,writer 会在 checkpoint 时,把分区信息传给下游的分区提交的 commiter 算子。

    2. 分区提取器

    Key Default Type Description
    partition.time-extractor.kind default String 支持defaultcustom
    default类型,需要配置partition.time-extractor.timestamp-pattern
    custom类型,需要指定partition.time-extractor.class
    partition.time-extractor.class none String 分区提取类,需要实现PartitionTimeExtractor接口
    partition.time-extractor.timestamp-pattern none String default方式支持来自第一个字段的 'yyyy-MM-dd HH:mm:ss'。
    如果只从单个分区字段'dt'中提取,可以配置:'\(dt'。 <br/>如果多个分区字段中提取,比如'year'、'month'、'day'和'hour',可以配置:'\)year-\(month-\)day \(hour:00:00'。<br/>如果从两个分区字段'dt'和'hour'中提取,可以配置:'\)dt $hour:00:00'。

    3. 分区提交策略

    分区提交策略指的是分区提交后做的操作

    • 第一种是写到 metastore, 只有 hive 表支持 metastore policy, file system 通过目录结构管理分区。
    • 第二种是生成 success file, 在分区对应的目录中写入一个空文件。
    Key Default Type Description
    sink.partition-commit.policy.kind (none) String 提交分区的策略是通知下游应用该分区已完成写入,该分区已准备好被读取。可选值为 metastore 和 success-file,也可以同时设置 'metastore,success-file'
    metastore:把分区加到 hive metastore。 只有 hive 表支持这种策略。
    success-file: 生成一个 '_success' 空文件。
    custom: 自定义实现。
    sink.partition-commit.policy.class (none) String 自定义的分区提交策略类,需要实现PartitionCommitPolicy接口
    sink.partition-commit.success-file.name _SUCCESS String success-file策略下,生成的文件名,默认是_SUCCESS

    可以自定义提交分区策略,如下:

    public class AnalysisCommitPolicy implements PartitionCommitPolicy {
        private HiveShell hiveShell;
    	
        @Override
    	public void commit(Context context) throws Exception {
    	    if (hiveShell == null) {
    	        hiveShell = createHiveShell(context.catalogName());
    	    }
    	    
            hiveShell.execute(String.format(
                "ALTER TABLE %s ADD IF NOT EXISTS PARTITION (%s = '%s') location '%s'",
    	        context.tableName(),
    	        context.partitionKeys().get(0),
    	        context.partitionValues().get(0),
    	        context.partitionPath()));
    	    hiveShell.execute(String.format(
    	        "ANALYZE TABLE %s PARTITION (%s = '%s') COMPUTE STATISTICS FOR COLUMNS",
    	        context.tableName(),
    	        context.partitionKeys().get(0),
    	        context.partitionValues().get(0)));
    	}
    }
    

    四. Sink 并行度

    Sink的并行度,批和流都支持。 默认情况下,并行度配置为其上游的并行度。 当配置了不同于上游并行度的并行度时,写入文件和压缩文件(如果使用)将使用该值并行度。

    Key Default Type Description
    sink.parallelism (none) Integer

    完整例子

    一. 维表关联

    1. Temporal Join 最新分区

    对于随时间变化的分区表,我们可以将其作为无界流读出,如果每个分区都包含一个版本的完整数据,则该分区可以充当时态表的一个版本,时态表的版本保留数据 的分区。

    Flink 支持 processing time 的 temporal join,自动跟踪临时表的最新分区(版本),最新分区(版本)由 'streaming-source.partition-order' 选项定义。

    NOTE:此功能仅在 STREAMING 模式下支持。

    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,
      ...
    ) PARTITIONED BY (pt_year STRING, pt_month STRING, pt_day STRING) TBLPROPERTIES (
      -- 这些属性也可以通过  SQL Hits 动态指定
      -- 用 partition-name 的顺序加载最新分区, 每12h刷新一次 (官方推荐)
      'streaming-source.enable' = 'true',
      'streaming-source.partition.include' = 'latest',
      'streaming-source.monitor-interval' = '12 h',
      'streaming-source.partition-order' = 'partition-name'
    
      -- 用分区文件的创建时间 create-time 的顺序加载最新分区, 每12h刷新一次 (官方推荐)
      'streaming-source.enable' = 'true',
      'streaming-source.partition.include' = 'latest',
      'streaming-source.monitor-interval' = '12 h',
      'streaming-source.partition-order' = 'create-time'
    
      -- 用分区时间 partition-time 的顺序加载最新分区, 每12h刷新一次 (官方推荐)
      'streaming-source.enable' = 'true',
      'streaming-source.partition.include' = 'latest',
      'streaming-source.monitor-interval' = '12 h',
      'streaming-source.partition-order' = 'partition-time',
      'partition.time-extractor.kind' = 'default',
      'partition.time-extractor.timestamp-pattern' = '$pt_year-$pt_month-$pt_day 00:00:00' 
    );
    
    CREATE TABLE orders_table (
      order_id STRING,
      order_amount DOUBLE,
      product_id STRING,
      log_ts TIMESTAMP(3),
      proctime as PROCTIME()
    ) WITH (...);
    
    SELECT * FROM orders_table AS o 
    JOIN dimension_table FOR SYSTEM_TIME AS OF o.proctime AS dim
    ON o.product_id = dim.product_id;
    
    

    2. Temporal Join 最新表数据

    对于 Hive 表,我们也可以将其作为有界流读出。 在这种情况下,Hive 表只能在我们查询时跟踪其最新版本。 最新版本的表保留了 Hive 表的所有数据。

    使用最新版本表的 Temporal Join 时,Hive 表数据将缓存在 Slot 内存中。 不需要任何额外的配置。 或者,您可以使用以下属性配置 Hive 表缓存的 TTL。 缓存过期后,会再次扫描 Hive 表以加载最新数据。

    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.partition.include' = 'all',
      'lookup.join.cache.ttl' = '12 h'
    );
    
    SET table.sql-dialect=default;
    CREATE TABLE orders_table (
      order_id STRING,
      order_amount DOUBLE,
      product_id STRING,
      log_ts TIMESTAMP(3),
      proctime as PROCTIME()
    ) WITH (...);
    
    SELECT * FROM orders_table AS o 
    JOIN dimension_table FOR SYSTEM_TIME AS OF o.proctime AS dim
    ON o.product_id = dim.product_id;
    
    

    Note:

    1. 每个 join 的subtask 都需要保留自己的 Hive 表缓存。 请确保 TM 有足够的内存。
    2. 建议为streaming-source.monitor-interval 或 lookup.join.cache.ttl 设置一个相对较大的值。 否则,作业很容易出现性能问题,因为表需要过于频繁地更新和重新加载。
    3. 目前只是在缓存需要刷新时加载整个 Hive 表。 因为没有办法区分新数据和旧数据。

    二. 写 Hive 表

    Flink 支持 BATCH 和 STREAMING 两种模式的Hive表写入。 当作为 BATCH 应用程序运行时,Flink 将写入 Hive 表,仅在作业完成时使这些记录可见。 BATCH 写入支持追加和覆盖现有表。

    INSERT INTO mytable SELECT 'Tom', 25;
    INSERT OVERWRITE mytable SELECT 'Tom', 25;
    

    数据也可以插入到特定的分区中。

    # ------ 写入静态分区 ------ 
    INSERT OVERWRITE myparttable PARTITION (my_type='type_1', my_date='2019-08-08') SELECT 'Tom', 25;
    
    # ------ 写入动态分区 ------ 
    INSERT OVERWRITE myparttable SELECT 'Tom', 25, 'type_1', '2019-08-08';
    
    # ------ 静态和动态混合写入 ------ 
    INSERT OVERWRITE myparttable PARTITION (my_type='type_1') SELECT 'Tom', 25, '2019-08-08';
    

    STREAMING 不断地向 Hive 添加新数据。 用户可以动态的使用属性来控制提交行为。 STREAMING 不支持INSERT OVERWRITE

    CREATE TABLE hive_table (
      user_id STRING,
      order_amount DOUBLE
    ) PARTITIONED BY (dt STRING, hr STRING) STORED AS parquet TBLPROPERTIES (
      'partition.time-extractor.timestamp-pattern'='$dt $hr:00:00',
      'sink.partition-commit.trigger'='partition-time',
      'sink.partition-commit.delay'='1 h',
      'sink.partition-commit.policy.kind'='metastore,success-file'
    );
    CREATE TABLE kafka_table (
      user_id STRING,
      order_amount DOUBLE,
      log_ts TIMESTAMP(3),
      WATERMARK FOR log_ts AS log_ts - INTERVAL '5' SECOND
    ) WITH (...);
    
    -- stream sql, insert into hive table
    INSERT INTO TABLE hive_table 
    SELECT user_id, order_amount, DATE_FORMAT(log_ts, 'yyyy-MM-dd'), DATE_FORMAT(log_ts, 'HH')
    FROM kafka_table;
    
    -- batch sql, select with partition pruning
    SELECT * FROM hive_table WHERE dt='2020-05-20' and hr='12';
    
  • 相关阅读:
    [算法] 神秘数
    教你在Access数据库中如何使用SQL
    亚宇工资管理系统早年制作的一个很小的商业软件[源码和软件截图]
    亚宇工资管理系统早年制作的一个很小的商业软件[源码和软件截图]
    getkeyTw
    一个硬盘的感人的爱情故事!只此一篇
    码农如何快速打造一个有设计感的网站
    NK.bin和NK.nb0学习
    WINCE6.0 + S3C2443的启动过程nboot篇
    S3C2443时钟管理
  • 原文地址:https://www.cnblogs.com/quyf/p/16370921.html
Copyright © 2020-2023  润新知