写在前面:本文为个人学习过程,仅限于学习使用。学习使我快乐,大家加油
一、准备工作
- 首先,Nifi自行官网下载,我使用的是Nifi-1.9.2。
- 自行修改相关配置,并启动。(其实并没有修改什么配置,就修改了IP和端口号)
- 可以通过浏览器打开Nifi工作空间。
- 配置好相关数据源地址信息。(数据库配置如图配置,基本的填写好这5项)
二、大概流程
流程总览:
此过程大概意思是:
- 读取数据源A中的一张表中的两个字段TableName、Json_Data(TableName对应的是数据源B中的一张表,且Json_Data中的Key对应表的相应字段)
- 从数据源A查询出来的结果,将其转化为JSON格式,同时保证为数组形式(例如:[{"":"","":""},{"":"","":""}])
- 将JSON格式的数组切割成单个JSON格式字符串
- 提取TableName的Key将其放入到Nifi中,实在可以成为一个Nifi流中的属性,流向之后的Porcess组件
- 提取Json_Data属性,将其提取出来,并放入流中,当作流的内容向下传递
- 由于在我的Json_Data中含有时间类型的字符串,例如:"2020-01-01 12:12:12"这样会在之后的Json转SQL中报错,从源码描述中可知:应传入毫秒值类型可以转化使用
- 将Json转化成INSERT的SQL,执行插入
三、详细说明
1、GenerateTableFetch
此功能模块可以生成分页查询的SQL语句
2、ExecuteSQLRecord
此功能执行提供的SQL选择查询。查询结果将转换为Record Writer指定的格式。
3、ConvertAvroToJSON
此模块将Binary Avro记录转换为JSON对象。该处理器提供了一个Avro字段到JSON字段的直接映射,这样生成的JSON将具有与Avro文档相同的层次结构。
4、SplitJson
此模块将JsonPath表达式指定的数组元素的JSON文件拆分为多个单独的FlowFiles。
5、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语句。
7、PutSQL
此模块可以执行一个SQL UPDATE或INSERT命令。
最后,连接各个共能模块,将其串联成整个流程,开始执行~
注意:数据源和相关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~
至此内容,干货满满~
最后的最后:希望文章可以帮到大家,路过大神不喜勿喷,我们共同学习,加油吧!!!!