学习 Apache Nifi 的心路历程

本文档介绍了使用NiFi进行数据处理的详细步骤,包括从数据源读取、转换、分割JSON、提取特定字段、日期转换以及自定义开发的ExtractDateType Processor,用于将文本日期转换为毫秒值。最后通过ConvertJSONToSQL生成SQL语句并执行插入操作。此外,还分享了自定义Processor的Maven项目配置、打包和NiFi中的部署使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写在前面:本文为个人学习过程,仅限于学习使用。学习使我快乐,大家加油

一、准备工作

  1. 首先,Nifi自行官网下载,我使用的是Nifi-1.9.2。
  2. 自行修改相关配置,并启动。(其实并没有修改什么配置,就修改了IP和端口号)
  3. 可以通过浏览器打开Nifi工作空间。
  4. 配置好相关数据源地址信息。(数据库配置如图配置,基本的填写好这5项)
    数据库连接配置(这是Oracle数据库)

二、大概流程

流程总览:
流程概览
此过程大概意思是:

  1. 读取数据源A中的一张表中的两个字段TableName、Json_Data(TableName对应的是数据源B中的一张表,且Json_Data中的Key对应表的相应字段)
  2. 从数据源A查询出来的结果,将其转化为JSON格式,同时保证为数组形式(例如:[{"":"","":""},{"":"","":""}])
  3. 将JSON格式的数组切割成单个JSON格式字符串
  4. 提取TableName的Key将其放入到Nifi中,实在可以成为一个Nifi流中的属性,流向之后的Porcess组件
  5. 提取Json_Data属性,将其提取出来,并放入流中,当作流的内容向下传递
  6. 由于在我的Json_Data中含有时间类型的字符串,例如:"2020-01-01 12:12:12"这样会在之后的Json转SQL中报错,从源码描述中可知:应传入毫秒值类型可以转化使用
  7. 将Json转化成INSERT的SQL,执行插入
    Nifi ConvertJSONToSQL 描述

三、详细说明

1、GenerateTableFetch
此功能模块可以生成分页查询的SQL语句
GenerateTableFetch
2、ExecuteSQLRecord
此功能执行提供的SQL选择查询。查询结果将转换为Record Writer指定的格式。
ExecuteSQLRecord
3、ConvertAvroToJSON
此模块将Binary Avro记录转换为JSON对象。该处理器提供了一个Avro字段到JSON字段的直接映射,这样生成的JSON将具有与Avro文档相同的层次结构。
ConvertAvroToJSON
4、SplitJson
此模块将JsonPath表达式指定的数组元素的JSON文件拆分为多个单独的FlowFiles。
SplitJson
5、EvaluateJsonPath
此模块可以匹配文件流中的内容,并可以选择将其设置为文件流中的属性,或者设置为流文件内容向下传递。
EvaluateJsonPath
提取为流文件属性
EvaluateJsonPath
提取为流文件内容
5、ExtractDateType
此模块是我自定义开发的模块,功能为使用正则表达式匹配文本日期内容并将其替换为对应的毫秒值文本。
(对于自定义开发的流程以及相关配置,在文章末尾)

package com.test.nifi.processor;

import org.apache.commons.io.IOUtils;
import org.apache.nifi.annotation.behavior.*;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.annotation.lifecycle.OnScheduled;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.SeeAlso;
import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processor.AbstractProcessor;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.ProcessorInitializationContext;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.util.StandardValidators;

import java.io.InputStreamReader;
import java.io.StringWriter;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Tags({"example"})
@CapabilityDescription("Provide a description")
@SeeAlso({})
@ReadsAttributes({@ReadsAttribute(attribute = "", description = "")})
@WritesAttributes({@WritesAttribute(attribute = "", description = "")})
public class ExtractDateType extends AbstractProcessor {

    public static final PropertyDescriptor MY_PROPERTY = new PropertyDescriptor
            .Builder().name("MY_PROPERTY")
            .displayName("My property")
            .description("Example Property")
            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
            .build();

    public static final Relationship MY_RELATIONSHIP_SUCCESS = new Relationship.Builder()
            .name("sucess")
            .description("Example relationship Success")
            .build();

    public static final Relationship MY_RELATIONSHIP_FAILURE = new Relationship.Builder()
            .name("failure")
            .description("Example relationship Failure")
            .build();

    private List<PropertyDescriptor> descriptors;

    private Set<Relationship> relationships;

    private String reg = "\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}";
    private Pattern r = Pattern.compile(reg);
    private DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override
    protected void init(final ProcessorInitializationContext context) {
        final List<PropertyDescriptor> descriptors = new ArrayList<PropertyDescriptor>();
        descriptors.add(MY_PROPERTY);
        this.descriptors = Collections.unmodifiableList(descriptors);

        final Set<Relationship> relationships = new HashSet<Relationship>();
        relationships.add(MY_RELATIONSHIP_SUCCESS);
        relationships.add(MY_RELATIONSHIP_FAILURE);
        this.relationships = Collections.unmodifiableSet(relationships);
    }

    @Override
    public Set<Relationship> getRelationships() {
        return this.relationships;
    }

    @Override
    public final List<PropertyDescriptor> getSupportedPropertyDescriptors() {
        return descriptors;
    }

    @OnScheduled
    public void onScheduled(final ProcessContext context) {

    }

    @Override
    public void onTrigger(final ProcessContext context, final ProcessSession session) throws ProcessException {
        FlowFile flowFile = session.get();
        if (flowFile == null) {
            return;
        }
        // TODO 以下是处理数据的关键代码
        final AtomicReference<String> value = new AtomicReference<>();
        session.read(flowFile, in -> {
            try {
                StringWriter sw = new StringWriter();
                InputStreamReader inr = new InputStreamReader(in);
                char[] buffer = new char[1024];
                int n = 0;
                while (-1 != (n = inr.read(buffer))) {
                    sw.write(buffer, 0, n);
                }
                String str = sw.toString();
                Matcher m = r.matcher(str);
                while (m.find()) {
                    String time = m.group(0);
                    long l = LocalDateTime.parse(time, dtf2).toInstant(ZoneOffset.of("+8")).toEpochMilli();
                    str = str.replaceFirst(reg, Long.toString(l));
                }
                value.set(str);
            } catch (Exception ex) {
                ex.printStackTrace();
                getLogger().error("Failed to read json string.");
            }
        });
        String results = value.get();
        if (results != null && !results.isEmpty()) {
            flowFile = session.putAttribute(flowFile, "match", results);
        }
        flowFile = session.write(flowFile, out -> out.write(value.get().getBytes()));
        session.transfer(flowFile, MY_RELATIONSHIP_SUCCESS);
    }
}

6、ConvertJSONToSQL
此模块将JSON格式的FlowFile转换为UPDATE,INSERT或DELETE SQL语句。
ConvertJSONToSQL
7、PutSQL
此模块可以执行一个SQL UPDATE或INSERT命令。
PutSQL
最后,连接各个共能模块,将其串联成整个流程,开始执行~

注意:数据源和相关Avro读写器要设置为开启(闪电标志)

相关学习资料可以去查看官方文档,或者此中文文档~

NiFi官方文档

NiFi中文文档

本地文档

四、自定义Process

1、创建Maven项目,添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.test.nifi</groupId>
    <artifactId>test_nifi</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>nar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <nifi.version>1.9.2</nifi.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-api</artifactId>
            <version>${nifi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-framework-api</artifactId>
            <version>${nifi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-mock</artifactId>
            <version>${nifi.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-processor-utils</artifactId>
            <version>${nifi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-utils</artifactId>
            <version>${nifi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-lookup-service-api</artifactId>
            <version>${nifi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-avro-record-utils</artifactId>
            <version>${nifi.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-dbcp-service-api</artifactId>
            <version>${nifi.version}</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-record-sink-api</artifactId>
            <version>1.11.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-distributed-cache-client-service-api</artifactId>
            <version>1.11.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.nifi</groupId>
            <artifactId>nifi-load-distribution-service-api</artifactId>
            <version>1.11.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.nifi</groupId>
                <artifactId>nifi-nar-maven-plugin</artifactId>
                <version>1.3.2</version>
                <extensions>true</extensions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
            </plugin>
        </plugins>
    </build>
</project>

2、在resources文件夹中创建一个文件夹命名为META_INF.service,并创建一个文件名为org.apache.nifi.processor.Processor,此文件内容中是你要编译打包成nar包的类文件路径
在这里插入图片描述
3、编写好内容后,用Maven工具执行package
在这里插入图片描述

4、将打包好后的nar包,上传至NiFi程序目录下的extensions文件夹中
5、重启NiFi
6、在添加Processor中即可看到自定义的Process
在这里插入图片描述

OK~
至此内容,干货满满~

最后的最后:希望文章可以帮到大家,路过大神不喜勿喷,我们共同学习,加油吧!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值