1.设置共享DB连接

设置DB连接共享后,可以避免每次创建转换时,重复创建相同数据源的窘境。

kettle配置javascript环境 kettle javascript_服务器

2.Kettle引入自定义java的工具jar包

2.1.编写Java工具类

2.2.将项目打成jar包

kettle配置javascript环境 kettle javascript_java_02

2.3.将jar包拷贝到Kettle的lib目录下,然后启动kettle工具

kettle配置javascript环境 kettle javascript_java_03

2.4.kettle创建JavaScript脚本,引入并使用自定义jar包类;

//Script here

var utl = new Packages.com.pga.pky.FormatUtils();

var optTime = utl.char2Date(OPT_TIME);

kettle配置javascript环境 kettle javascript_服务器_04

建议使用兼容模式对变量进行取值,赋值操作。(图示没有使用兼容模式)

3.Kettle引入自定义js文件

代码示例如下:

//Script here
//js文件相对于kettle工具根目录的路径
var path =getVariable("Internal.Transformation.Filename.Directory", "相对路径");

LoadScriptFile(path +"/common_Functions.js");
//-----------------------------------------------------------------------------------

var mpType =  getVariable("MPTYPE","");
var cycleCount = str2num(getVariable("COLLECT_CYCLE_COUNT","1"));
var prevCycle = str2num(getVariable("CYCLE_PREV_VALUE","0"));

//调用js文件中的方法
var colInfo = initCycleTime(mpType, prevCycle, cycleCount);
var startTime = date2str(colInfo[0], "yyyy-MM-dd HH:mm:ss");
var endTime = date2str(colInfo[1], "yyyy-MM-dd HH:mm:ss");
writeToLog("m","时间:"+startTime+" -> "+endTime);

3.1.获取js的路径参数

kettle配置javascript环境 kettle javascript_资源库_05

3.2.从StartScript加载文件

注意kettle调用示例:将一个javascript文件加载到实际的运行上下文中。应该从定义的StartScript调用此函数,否则,每次处理都会加载javascript文件行。

kettle配置javascript环境 kettle javascript_资源库_06

4.Linux服务器安装kettle

4.1.kettle程序解压到指定目录即可

#查看jdk版本
java -version
#进入/pdi-ce-7.1.0.0-12/data-integration/目录下
ls -l
#查看*.sh文件是否为可执行状态
#如果为不可执行状态,则执行
chmod +x *.sh
#测试是否赋权成功
./kitchen.sh

./kitchen.sh输出信息如下:

#######################################################################
WARNING:  no libwebkitgtk-1.0 detected, some features will be unavailable
    Consider installing the package with apt-get or yum.
    e.g. 'sudo apt-get install libwebkitgtk-1.0-0'
#######################################################################
OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
Options:
  -rep            = Repository name
  -user           = Repository username
  -pass           = Repository password
  -job            = The name of the job to launch
  -dir            = The directory (dont forget the leading /)
  -file           = The filename (Job XML) to launch
  -level          = The logging level (Basic, Detailed, Debug, Rowlevel, Error, Minimal, Nothing)
  -logfile        = The logging file to write to
  -listdir        = List the directories in the repository
  -listjobs       = List the jobs in the specified directory
  -listrep        = List the available repositories
  -norep          = Do not log into the repository
  -version        = show the version, revision and build date
  -param          = Set a named parameter <NAME>=<VALUE>. For example -param:FILE=customers.csv
  -listparam      = List information concerning the defined parameters in the specified job.
  -export         = Exports all linked resources of the specified job. The argument is the name of a ZIP file.
  -custom         = Set a custom plugin specific option as a String value in the job using <NAME>=<Value>, for example: -custom:COLOR=Red
  -maxloglines    = The maximum number of log lines that are kept internally by Kettle. Set to 0 to keep all rows (default)
  -maxlogtimeout  = The maximum age (in minutes) of a log line while being kept internally by Kettle. Set to 0 to keep all rows indefinitely (default)

4.2.kettle从资源库获取ETL脚本

#找到安装kettle用户的用户目录
cd ~
#将windows中用户目录下的.kettle(隐藏文件)文件夹拷贝到当前目录(Linux下的用户目录)
ls -a	#查看所有文件,包含隐藏文件
#进入.kettle文件夹,修改/查看资源库配置文件repositories.xml

配置文件内容

<?xml version="1.0" encoding="UTF-8"?>  
<repositories> 
  <connection>
      .....
  </connection>  
  <repository>  <id>KettleFileRepository</id>  
    <name>fileRepository</name>  
    <description>filereposity</description>  
    <read_only>N</read_only>  
    <hides_hidden_files>N</hides_hidden_files>  
    <connection>.....</connection>
  </repository>  
</repositories>

5.启动kettle转换脚本和作业脚本

启动命令语法:

#执行job
sh /opt/kettle/kitchen.sh -rep=资源库名称 -user=(登陆资源库的)用户名 -pass=密码  -dir=脚本所在目录 -job=脚本名 -level=Basic > /opt/kettle/log/etl.log

#执行转换
sh /opt/kettle/pan.sh -rep=资源库名称 -user=(登陆资源库的)用户名 -pass=密码  -dir=脚本所在目录 -trans=脚本名 -level=Basic > /opt/kettle/log/etl.log

参考脚本:

#!/bin/sh
REP='fileRepository'
USER="$1"
PASS="$2"
DIR="$3"
FILE="$4"
TYPE="$5"

if test -e /opt/kettle/log"$DIR"
then
	echo '日志目录已存在'
else
	mkdir -p /opt/kettle/log"$DIR"
	echo '日志目录已创建'
fi
if [ "$TYPE" = "JOB" ] || [ "$TYPE" = "job" ]; then
	nohup sh /opt/kettle/pdi-ce-7.1.0.0-12/data-integration/kitchen.sh -rep="$REP" -user="$USER" -pass="$PASS"  -dir="$DIR" -job="$FILE" -level=Basic > "/opt/kettle/log$DIR$FILE.log" 2>&1 & 
	echo '执行:kitchen.sh'
else
	nohup sh /opt/kettle/pdi-ce-7.1.0.0-12/data-integration/pan.sh -rep="$REP" -user="$USER" -pass="$PASS"  -dir="$DIR" -trans="$FILE" -level=Basic > "/opt/kettle/log$DIR$FILE.log" 2>&1 & 
	echo '执行:pan.sh'
fi

echo "账号:$USER 密码:$PASS"
echo "目录:$DIR 文件:$FILE 类型:$TYPE"
echo "日志路径:/opt/kettle/log$DIR$FILE.log"
exit

6.提升ETL脚本导入MySQL数据库效率

useServerPrepStmts:如果服务器支持,是否使用服务器端预处理语句 默认值为“true” 调整为“ false”
rewriteBatchedStatements是否批量执行(对于insert,驱动则会把多条sql语句重写成一条风格很酷的sql语句,然后再发出去。 官方文档说,这种insert写法可以提高性能【对delete和update,驱动所做的事就是把多条sql语句累积起来再一次性发出去】)“true”
useCompression压缩数据传输,优化客户端和MySQL服务器之间的通信性能 “true”

kettle配置javascript环境 kettle javascript_资源库_07

characterEncoding:此处也可以设置字符及编码,用于解决数据库字符集不同造成的中文乱码问题。如:utf8

Kettle日志级别

Kettle的日志级别LogLevel分为以下几个:

  • Nothing 没有日志 不显示任何输出
  • Error 错误日志 仅仅显示错误信息
  • Minimal 最小日志 使用最小的日志
  • Basic 基本日志 缺省的日志级别
  • Detailed详细日志 给出日志输出的细节
  • Debug 调试日志 调试目的,调试输出
  • Rowlevel行级日志 打印出每一行记录的信息

大批量数据转换时,将日志级别调整为:Error 错误日志 仅仅显示错误信息 ,也可以提升数据转换速度。

7.js中可以通过getVariable(var, var)获取的变量列举:

内置变量

变量

描述

Internal.Kettle.Version

这是kettle的版本号,比如4.0.0

Internal.Kettle.Build.Version

这是kettle源代码的SVN的修订号

Internal.Kettle.Build.Date

这是kettle的build日期

Internal.Job.Filename.Directory

如果使用文件方式运行作业(.kjb),这个变量就是作业文件所在的目录。里用这个变量用户可以指定其它文件

Internal.Job.Filename.Name

如果使用文件方式运行作业(.kjb),这个变量就是作业文件名

Internal.Job.Name

当前正在执行的作业的名字

Internal.Transformation.Repository.Directory

如果使用资源库方式执行转换,这个变量是转换所在资源库目录的路径

Internal.Step.Partition.ID

如果一个步骤是以分区方式运行的,每个分区都有一个步骤拷贝。这个变量就是步骤拷贝所属的分区ID

Internal.Step.Partition.Number

如果一个步骤是以分区方式运行的,每个分区都有一个步骤拷贝器。这个变量就是步骤拷贝所属的分区编号,分区编号从0到分区个数减1

Internal.Slave.Transformation.Number

如果转换在子服务器上以集群方式运行,这个变量就是子服务器的名字

Internal.Cluster.Size

如果转换在子服务器上以集群方式运行,这个变量就是集群中子服务器的个数

Internal.Step.Unique.Number

这个变量是指定步骤的步骤拷贝的唯一编号。这个变量同样适用于分区和集群环境。取值从0到步骤拷贝个数减1

Internal.Cluster.Master

若转换以集群方式运行,如果是运行在主服务器上,这个值是Y,如果是运行在子服务器上,这个值是N

Internal.Step.Unique.Count

唯一的步骤拷贝个数。也适用于集群或分区的情况

Internal.Step.Name

正在执行的步骤的名字

Internal.Step.CopyNr

本地转换的步骤拷贝号(不考虑集群的情况)

kettle变量

变量

描述

KETTLE_SHARED_OBJECTS

作业和转换的共享对象文件的位置。默认的共享对象文件shared.xml,位于Kettle Home 目录下。设置这个变量可以覆盖默认值

KETTLE_EMPTY_STRING_DIFFERS_FROM_NULL

如果这个变量设置为Y,空字符串和null是不同的,否则就是相同的(默认)

KETTLE_MAX_LOG_SIZE_IN_LINES

kettle初始的最大日志行数。设置为0将保留所有日志行(默认)

KETTLE_MAX_LOG_TIMEOUT_IN_MINUTES

kettle中日志行的最长保留时间(单位:分钟)。设置为0将保留所有行(默认)

KETTLE_STEP_PERFORMANCE_SNAPSHOT_LIMIT

内存中的最大步骤性能快照数。设置为0将保留所有快照(默认)

KETTLE_PLUGIN_CLASSES

逗号分隔的类名列表,用来查找插件iandeannotation。参考http://wiki.pentaho.com/display/EAI/How+to+debug+a+Kettle+4+plugin

KETTLE_LOG_SIZE_LIMIT

如果在转换和作业的日志表的配置izhong没有设置“日志行数限制”参数,这类转换和作业将统一使用这个参数作为最大日志行

  • TRANS:对于转换日志表。
  • TRANS_PERFORMANCE:对于性能日志表。
  • STEP:对于步骤日志表。
  • JOB:对于作业日志表
  • JOBENTRY:对于作业项日志表。
  • CHANNEL:对于通道日志表。

kettle日志表变量

变量

描述

KETTLE_…_LOG_DB

设置日志表使用的数据库连接的名字

KETTLE_…_LOG_SCHEMA

设置日志表使用的数据库模式名

KETTLE_…_LOG_TABLE

设置日志表使用的日志表名

8.kettle中的参数在SQL脚本中的用法

kettle配置javascript环境 kettle javascript_资源库_08

上图中的说明有问题,并不是CRUD的结果,而是语句执行的状态值(具体内容还需继续测试。。。)

9.kettle按条件执行sql脚本的问题

1.现象

在转换脚本中按条件执行sql脚本存在问题,不管是否满足条件sql脚本都会先于过滤组件执行一次。如下图:

kettle配置javascript环境 kettle javascript_服务器_09

2.解决

上述问题可以在job中解决。如下图:

kettle配置javascript环境 kettle javascript_资源库_10

10.kettle的java脚本组件的本地调试

1.java脚本组件中的常用方法

kettle配置javascript环境 kettle javascript_java_11

2.组件中的Main方法的本地调试模板

package com.test.java;

import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.exception.KettleStepException;
import org.pentaho.di.trans.step.StepDataInterface;
import org.pentaho.di.trans.step.StepMetaInterface;
import org.pentaho.di.trans.steps.userdefinedjavaclass.TransformClassBase;
import org.pentaho.di.trans.steps.userdefinedjavaclass.UserDefinedJavaClass;
import org.pentaho.di.trans.steps.userdefinedjavaclass.UserDefinedJavaClassData;
import org.pentaho.di.trans.steps.userdefinedjavaclass.UserDefinedJavaClassMeta;

/**
 * 〈简述〉<br>
 * 〈Kettle的Main方法本地调试〉
 *
 * @author Howard4
 * @create 2021/12/25
 * @since 1.0.0
 */
public class KettleMainMethod extends TransformClassBase {

    public KettleMainMethod(UserDefinedJavaClass parent, UserDefinedJavaClassMeta meta, UserDefinedJavaClassData data) throws KettleStepException {
        super(parent, meta, data);
    }

    public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException {
        if (first) {
            first = false;

    /* TODO: Your code here. (Using info fields)

            FieldHelper infoField = get(Fields.Info, "info_field_name");

            RowSet infoStream = findInfoRowSet("info_stream_tag");

            Object[] infoRow = null;

            int infoRowCount = 0;

            // Read all rows from info step before calling getRow() method, which returns first row from any
            // input rowset. As rowMeta for info and input steps varies getRow() can lead to errors.
            while ((infoRow = getRowFrom(infoStream)) != null) {

                // do something with info data
                infoRowCount++;
            }
*/
        }

        Object[] r = getRow();

        if (r == null) {
            setOutputDone();
            return false;
        }

        // It is always safest to call createOutputRow() to ensure that your output row's Object[] is large
        // enough to handle any new fields you are creating in this step.
        r = createOutputRow(r, data.outputRowMeta.size());

  /* TODO: Your code here. (See Sample)

        // Get the value from an input field
        String foobar = get(Fields.In, "a_fieldname").getString(r);

        foobar += "bar";

        // Set a value in a new output field
        get(Fields.Out, "output_fieldname").setValue(r, foobar);

  */
        // Send the row on to the next step.
        putRow(data.outputRowMeta, r);

        return true;
    }

}

3.类中的两个方法

//获得输入端传入的所有字段名、字段类型等信息
List valueMetaList = getInputRowMeta().getValueMetaList();
//获得所有字段的值
Object[] r = getRow();

注意:在java脚本组件中不能使用泛型,所以上述方法并没有使用泛型。