Joiners are components of graph that join data from all connected input ports based on defined key and propagate the result to output port.
In either of these components, you must define some transformation using the transform() function. In addition to this required function, you can define other two functions: init() and finished(). If you want to declare and initialize some variables, if you want to anything what should be done at the beginning of data processing by the component, you should do it within the init() function. If you want to free memory, delete some temporary files, you should define it within the finished() function. Either of these functions is called only once. The init() function is called at the beginning, the finished() function is called at the end. Unlike them, the required transform() function is called many times. It is called after init() and before finished().
All joiners implement a RecordTransform interface or inherit from a DataRecordTransform class.
Common attributes
| Attribute | Description | Exp. |
|---|---|---|
id | component identification | string |
type | component type. This attribute is automatically generated from gui. | string |
Joins records on port 0 (Master records) with records on port 1 (Slave records). Joining is based on specified key fields and their similarity - with defined maximum disimilarity/distance - computed as edit distance - “Levenshtein distance”
Input ports: * 0 - driver records
Output ports:
Xml attributes:
| Attribute | Mandatory | Description | Default | ETL Version since |
|---|---|---|---|---|
id | yes | component identification | ||
type | yes | component type | APROX_MERGE_JOIN | |
joinKey | yes | field names with number of letters, weight and strength of comparison as four boolean values for each comparison level separated by :;| {colon, semicolon, pipe}. General form: fieldName maxNumberOfLetterstoChange fieldWeight identicalComparison tertiaryComparison secondaryComparison primaryComparison. Since ver. 2.5 it is advocated to use new firm syntax: $masterField=$slaveField(maxNumberOfLetterstoChange fieldWeight identicalComparison tertiaryComparison secondaryComparison primaryComparison). Conformity between two strings equals zero if transformation of one string to another necessitates more then maxNumberOfLetterstoChange letters to change. Weight of each field difference is counted due to following algorithm: weight given by user divided by sum of weights given by user. | ||
matchingKey | yes | field name for comparing driver and slave records. Since ver. 2.5 it is advocated to use new firm syntax: $masterField=$slaveField. | ||
transformClass | if no transform | name of the class to be used for transforming joined data which has conformity greater then conformity limit.If no class name is specified then it is expected that the transformation Java source code is embedded in XML | ||
transform | if no transformClass | contains definition of transformation for joined records which has conformity greater then conformity limit in internal clover format | ||
transformURL | no | contains path to the file with transformation code. | ||
charset | no | encoding of extern source | ISO-8859-1 | |
transformClassForSuspicious | if no transform ForSuspicious | name of the class to be used for transforming joined data which has conformity smaller then conformity limit.If no class name is specified then it is expected that the transformation Java source code is embedded in XML | ||
transformForSuspicious | if no transformClass ForSuspicious | contains definition of transformation for joined records which has conformi ty smaller then conformity limit in internal clover format | ||
transformURLForSuspicious | no | contains path to the file with transformation code. | ||
slaveOverrideKey | no since ver. 2.5 deprecated | can be used to specify different key field names for records on slave input; field names separated by :;| {colon, semicolon, pipe} | ||
slaveMatchingOverride | no since ver. 2.5 deprecated | can be used to specify different key field name for records on slave input | ||
conformity | no | joined records are divided to two sets depending on their computed conformity is greater or smaller then this parameter | 0.75 | |
errorActions | no | defines if graph is to stop, when transformation returns negative value. Available actions are: STOP or CONTINUE. For CONTINUE action, error message is logged to console or file (if errorLog attribute is specified) and for STOP there is thrown TransformExceptions and graph execution is stopped. Error action can be set for each negative value (value1=action1;value2=action2;…) or for all values the same action (STOP or CONTINUE). It is possible to define error actions for some negative values and for all other values (MIN_INT=myAction). | -1=CONTINUE;MIN_INT=STOP | 2.6 |
errorLog | no | path to the error log file. | 2.6 |
joinKey - comparison strength:
Example:
<Node id="APROX_MERGE_JOIN0" type="APROX_MERGE_JOIN"> <attr name="matchingKey">key</attr> <attr name="transform">${out.0.lname} = ${in.0.lname}; ${out.0.fname} = ${in.0.fname}; ${out.0.birthdate} = ${in.0.birthdate}; ${out.0.gender} = ${in.0.gender}; ${out.0.first_name} = ${in.1.first_name}; ${out.0.last_name} = ${in.1.last_name}; ${out.0.birth_date} = ${in.1.birth_date}; ${out.0.gender1} = ${in.1.gender}; </attr> <attr name="conformity">0.8</attr> <attr name="slaveOverrideKey">last_name;first_name</attr> <attr name="joinKey">lname 2 0.75 false true true true;fname 4 0.25 false false false true</attr> <attr name="transformForSuspicious">${out.1.lname} = ${in.0.lname}; ${out.1.fname} = ${in.0.fname}; ${out.1.first_name} = ${in.1.first_name}; ${out.1.last_name} = ${in.1.last_name}; </attr> </Node> <Node conformity="0.81" id="APROX_MERGE_JOIN1" joinKey="$fname=$first_name(3 0.8 true false false false);$lname=$last_name(4 0.2 true false false false);" matchingKey="$key=$key;#" transformClass="customizedTransformExample" type="APROX_MERGE_JOIN"> <attr name="transformForSuspicious"><![CDATA[${out.0.lname} = ${in.0.lname}; ${out.0.fname} = ${in.0.fname}; ${out.0.birthdate} = ${in.0.birthdate}; ${out.0.gender} = ${in.0.gender}; ${out.0.first_name} = ${in.1.first_name}; ${out.0.last_name} = ${in.1.last_name}; ${out.0.birth_date} = ${in.1.birth_date}; ${out.0.gender1} = ${in.1.gender};]]></attr> </Node>
Joins records from input port and database based on specified key. It expects that on port [0], there is a driver and from database is a slave. For each driver record, slave record is looked up in database. Pair of driver and slave records is sent to transformation class. The method transform is called for every pair of driver&slave. It skips driver records for which there is no corresponding slave (if there is connected output port 1, thees records are sent to it) - unless outer join (leftOuterJoin option) is specified, when only driver record is passed to transform method (no records is sent to output port 1).
Input ports: * one input port defined/connected.
Output ports:
Xml attributes:
| Attribute | Mandatory | Description | Default | ETL Version since |
|---|---|---|---|---|
id | yes | component identification | ||
type | yes | component type | DBJOIN | |
dbConnection | yes | id of the Database Connection object to be used to access the database | ||
sqlQuery | yes | query to be sent to database | ||
joinKey | yes | field names separated by [:;|] | ||
transformClass | no | name of the class to be used for transforming joined data. | ||
transform | no | contains definition of transformation in internal clover format or as java code | ||
transformURL | no | contains path to the file with transformation code. If not transformClass, nor transform, nor transformURL is not specified only records from database are sent to output port. | ||
charset | no | encoding of extern source | ISO-8859-1 | |
metadata | no | metadata for data from database. If is not specified it can be obtained from sql query attribute. | ||
leftOuterJoin | no | if left outer join has be performed | false | |
maxCached | no | number of sets of records with different key which will be stored in memory | 100 | |
errorActions | no | defines if graph is to stop, when transformation returns negative value. Available actions are: STOP or CONTINUE. For CONTINUE action, error message is logged to console or file (if errorLog attribute is specified) and for STOP there is thrown TransformExceptions and graph execution is stopped. Error action can be set for each negative value (value1=action1;value2=action2;…) or for all values the same action (STOP or CONTINUE). It is possible to define error actions for some negative values and for all other values (MIN_INT=myAction). | -1=CONTINUE;MIN_INT=STOP | 2.6 |
errorLog | no | path to the error log file. | 2.6 |
Example:
<Node id="dbjoin0" type="DBJOIN"> <attr name="metadata">Metadata3</attr> <attr name="transformClass">TransformTransformdbjoin0</attr> <attr name="sqlQuery">select * from employee where Employee_ID=?</attr> <attr name="joinKey">EmployeeID</attr> <attr name="dbConnection">DBConnection0</attr> </Node>
Joins two records from two different input flows based on specified key. The flow on port 0 is the driver, the flow on port 1 is the slave. First, all records from slave flow are read and stored in hash table. Then for every record from driver flow, corresponding record from slave flow is looked up (if it exists)
Description:
Joins records on input ports. It expects driver stream at port [0] and slave streams at other input ports. Slave streams are expected to be small enough to store all the slave records in hashtable.
Each driver record is joined with corresponding slave records according to join keys specification.
There are three join modes available: inner, left outer, full outer.
In case you use outer mode, till 2.4 version be sure your transformation code is able to handle null input records. From 2.5 version it doesn't happen any more, because for lacking record there is used special null record - all getValue methods returns null instead of throwing exception. If you want to realise some action for such record you can compare it with NullRecord.NULL_RECORD (see example below). Hash join does not require input data to be sorted. But it spends some time at the beginning initializing hashtable of slave records. It is generally good idea to specify how many records are expected to be stored in each hashtable (there is one hashtable per each slave input), especially when you expect the number to be really great. It is better to specify slightly greater number to ensure that rehashing won't occure. For small record sets - up to 512 records, there is no need to specify the size.
Input ports: * 0 - driver record input.
Output ports:
Xml attributes:
| Attribute | Mandatory | Description | Default | ETL Version since |
|---|---|---|---|---|
id | yes | component identification | ||
type | yes | component type | EXT_HASH_JOIN | |
joinKey | yes | join key specification in format mapping1#mapping2…, where mapping has format driver_field1=slave_field1| driver_field2=slave_field2|… Since 2.5 version it is advocated to precede clover fields name by '$'. In case slave_field is missing it is supposed to be the same as the driver_field. When driver_field is missing (ie there's nothin before '='), it will be taken from the first mapping. Order of mappings corresponds to order of slave input ports. In case a mapping is empty or missing for some slave, the component will use first mapping instead of it. | ||
transformClass | if no transform | name of the class to be used for transforming joined data. If no class name is specified then it is expected that the transformation Java source code is embedded in XML | ||
transform | if no transformClass | contains definition of transformation | ||
transformURL | no | contains path to the file with transformation code. | ||
charset | no | encoding of extern source | ISO-8859-1 | |
joinType | no | inner/leftOuter/fullOuter Specifies type of join operation. | inner | |
hashTableSize | no | how many records are expected (roughly) to be in hashtable. | 512 | |
slaveDuplicates | no | true/false - allow records on slave port with duplicate keys. False - multiple duplicate records are discarded - only the first one is used for join. | false | |
errorActions | no | defines if graph is to stop, when transformation returns negative value. Available actions are: STOP or CONTINUE. For CONTINUE action, error message is logged to console or file (if errorLog attribute is specified) and for STOP there is thrown TransformExceptions and graph execution is stopped. Error action can be set for each negative value (value1=action1;value2=action2;…) or for all values the same action (STOP or CONTINUE). It is possible to define error actions for some negative values and for all other values (MIN_INT=myAction). | -1=CONTINUE;MIN_INT=STOP | 2.6 |
errorLog | no | path to the error log file. | 2.6 |
Example:
<Node id="JOIN" type="EXT_HASH_JOIN" joinKey="CustomerID" transformClass="org.jetel.test.reformatOrders"/> <Node id="JOIN" type="EXT_HASH_JOIN" joinKey="EmployeeID" joinType="inner"> <attr name="transform">//#TL function transform(){ $OrderID := $OrderID; $CustomerID := $CustomerID; $EmployeeID := $EmployeeID; $EmployeeID2 := num2str($1.EmployeeID); $LastName := concat($1.LastName,":",$1.FirstName); } </attr> </Node> In-line transformation for 2.4 and lower ver.: <Node id="JOIN" type="EXT_HASH_JOIN" joinKey="EmployeeID=EmployeeID#CustomerID=CUSTOMERID" joinType="leftOuter"> <attr name="transform"> import org.jetel.component.DataRecordTransform; import org.jetel.data.*; public class reformatJoinTest extends DataRecordTransform{ public boolean transform(DataRecord[] source, DataRecord[] target){ if (source[0] != null) { target[0].getField(0).setValue(source[0].getField(0).getValue()); // OrderID target[0].getField(1).setValue(source[0].getField(1).getValue()); // CustomerID target[0].getField(2).setValue(source[0].getField(2).getValue()); // EmployeeID } else { target[0].getField(1).setValue("*MISSING*"); } if (source[1]!=null){ target[0].getField(4).setValue(source[1].getField(1) + ", " + source[1].getField(2)); // Name } else { target[0].getField(4).setValue("*MISSING*"); } if (source[2]!=null){ target[0].getField(3).setValue(source[2].getField(1).getValue()); // Company } else { target[0].getField(3).setValue("*MISSING*"); } target[0].getField(5).setValue("*MISSING*"); return true; } } </attr> </Node> In-line transformation since 2.5 ver.: <Node id="JOIN" type="EXT_HASH_JOIN" joinKey="$EmployeeID=$EmployeeID#$CustomerID=$CUSTOMERID" joinType="leftOuter"> <attr name="transform"> import org.jetel.component.DataRecordTransform; import org.jetel.data.*; public class reformatJoinTest extends DataRecordTransform{ public boolean transform(DataRecord[] source, DataRecord[] target){ target[0].getField(0).setValue(source[0].getField(0).getValue()); // OrderID target[0].getField(1).setValue(source[0].getField(1).getValue()); // CustomerID target[0].getField(2).setValue(source[0].getField(2).getValue()); // EmployeeID target[0].getField(3).setValue(source[2].getField(1).getValue()); // Company target[0].getField(4).setValue(source[1].getField(1) + ", " + source[1].getField(2)); // Name if (source[0] == NullRecord.NULL_RECORD){ target[0].getField(4).setValue("driver missing"); } if (source[1] instanceof NullRecord.NULL_RECORD){ target[0].getField(4).setValue("1st slave missing"); } if (source[2].equals(NullRecord.NULL_RECORD)){ target[0].getField(4).setValue("2nd slave missing"); } return true; } } </attr> </Node>
Joins records on input port and from lookup table. It expects that on port [0], there is a driver and from lookup table is a slave. For each driver record, slave record is looked up in lookup table. Pair of driver and slave records is sent to transformation class. The method transform is called for every pair of driver&slave. It skips driver records for which there is no corresponding slave (if there is connected output port 1, theese records are sent to it) - unless outer join (leftOuterJoin option) is specified, when only driver record is passed to transform method (no records is sent to output port 1).
Note: In transformation, records from lookup table are treated as records from 1st source, while records from input port are treated as 0th source (see example).
Input ports: * one input port defined/connected.
Output ports:
Xml attributes:
| Attribute | Mandatory | Description | Default | ETL Version since |
|---|---|---|---|---|
id | yes | component identification | ||
type | yes | component type | LOOKUP_JOIN | |
joinKey | yes | field names separated by [:;|]. | ||
lookupTable | yes | name of lookup table where are slave records. | ||
transform | if no transformClass | contains definition of transformation in internal clover format or as java code | ||
transformClass | if no transform | name of the class to be used for transforming joined data. If no class name is specified then it is expected that the transformation. Java source code is embedded in XML | ||
transformURL | no | contains path to the file with transformation code. | ||
charset | no | encoding of extern source | ISO-8859-1 | |
leftOuterJoin | no | true/false | false | |
freeLookupTable | no | idicates if close lookup table after finishing execute() method. All records, which are stored only in memory will be lost. | false | |
errorActions | no | defines if graph is to stop, when transformation returns negative value. Available actions are: STOP or CONTINUE. For CONTINUE action, error message is logged to console or file (if errorLog attribute is specified) and for STOP there is thrown TransformExceptions and graph execution is stopped. Error action can be set for each negative value (value1=action1;value2=action2;…) or for all values the same action (STOP or CONTINUE). It is possible to define error actions for some negative values and for all other values (MIN_INT=myAction). | -1=CONTINUE;MIN_INT=STOP | 2.6 |
errorLog | no | path to the error log file. | 2.6 |
Example:
<Node id="JOIN" type="LOOKUP_JOIN"> <attr name="lookupTable">LookupTable0</attr> <attr name="joinKey">EmployeeID</attr> <attr name="transform">//#TL function transform(){ $OrderID := $OrderID; $CustomerID := $CustomerID; $EmployeeID := $EmployeeID; $EmployeeID2 := num2str($1.EmployeeID); $LastName := concat($1.LastName,":",$1.FirstName); } </attr> </Node> In-line transformation for 2.4 ver. and lower: <Node id="JOIN" type="LOOKUP_JOIN"> <attr name="lookupTable">LookupTable0</attr> <attr name="joinKey">EmployeeID</attr> <attr name="transform"> import org.jetel.component.DataRecordTransform; import org.jetel.data.DataRecord; import org.jetel.data.RecordKey; import org.jetel.data.lookup.LookupTable; import org.jetel.exception.JetelException; import org.jetel.graph.TransformationGraph; public class reformatTest extends DataRecordTransform{ public boolean transform(DataRecord[] source, DataRecord[] target){ if (source[1]==null) return false; // skip this one target[0].getField(0).setValue(source[0].getField(0).getValue()); target[0].getField(1).setValue(source[0].getField(1).getValue()); target[0].getField(2).setValue(source[0].getField(2).getValue()); target[0].getField(3).setValue(source[1].getField(0).getValue()); target[0].getField(4).setValue(source[1].getField(1).getValue()); return true; } } </attr> </Node> In-line transformation since 2.5 ver.: <Node id="JOIN" type="LOOKUP_JOIN"> <attr name="lookupTable">LookupTable0</attr> <attr name="joinKey">EmployeeID</attr> <attr name="transform"> import org.jetel.component.DataRecordTransform; import org.jetel.data.DataRecord; import org.jetel.data.RecordKey; import org.jetel.data.lookup.LookupTable; import org.jetel.exception.JetelException; import org.jetel.graph.TransformationGraph; public class reformatTest extends DataRecordTransform{ public boolean transform(DataRecord[] source, DataRecord[] target){ if (source[1]==NullRecord.NULL_RECORD) { errorMessage = "Slave record not found"; } target[0].getField(0).setValue(source[0].getField(0).getValue()); target[0].getField(1).setValue(source[0].getField(1).getValue()); target[0].getField(2).setValue(source[0].getField(2).getValue()); target[0].getField(3).setValue(source[1].getField(0).getValue()); target[0].getField(4).setValue(source[1].getField(1).getValue()); return true; } } </attr> </Node>
Joins sorted records on input ports. It expects driver stream at port [0] and slave streams at other input ports. Each driver record is joined with corresponding slave records according to join keys specification. The method transform is every composed of driver and corresponding slaves. There are three join modes available: inner, left outer, full outer.
Inner mode processess only driver records for which all associated slaves are available.
Left outer mode furthermore processes driver records with missing slaves.
Full outer mode additionally calls transformation method for slaves without driver.
In case you use outer mode, till 2.4 version be sure your transformation code is able to handle null input records. From 2.5 version it doesn't happen any more, because for lacking record there is used special null record - all getValue methods returns null instead of throwing exception. If you want to realise some action for such record you can compare it with NullRecord.NULL_RECORD (see example below).
Input ports: * 0 - sorted driver record input
Output ports:
Xml attributes:
| Attribute | Mandatory | Description | Default | ETL Version since |
|---|---|---|---|---|
id | yes | component identification | ||
type | yes | component type | EXT_MERGE_JOIN | |
joinKey | yes | Join key formatted as masterKeyFields#slave1KeyFields#…#slaveNKeyFields where masterKeyFields or slave#KeyFields are sequences of master or slave field names separated by semicolon and preceded by a dollar sign: $fieldK;…;$fieldM. Since 2.5 version it is advocated to precede clover fields name by '$'. Order of slave key parts corresponds to the order of slave input ports. | ||
transformClass | if no transform | name of the class to be used for transforming joined data. If no class name is specified then it is expected that the transformation Java source code is embedded in XML | ||
transform | if no transformClass | contains definition of transformation | ||
transformURL | no | contains path to the file with transformation code. | ||
charset | no | encoding of extern source | ISO-8859-1 | |
joinType | no | inner/leftOuter/fullOuter Specifies type of join operation. | inner | |
slaveDuplicates | no | true/false - allow records on slave port with duplicate keys. False - multiple duplicate records are discarded - only the last one is used for join. | true | |
ascendingInputs | no | true/false - input is sorted in ascending/descending order, respectively. | true | |
errorActions | no | defines if graph is to stop, when transformation returns negative value. Available actions are: STOP or CONTINUE. For CONTINUE action, error message is logged to console or file (if errorLog attribute is specified) and for STOP there is thrown TransformExceptions and graph execution is stopped. Error action can be set for each negative value (value1=action1;value2=action2;…) or for all values the same action (STOP or CONTINUE). It is possible to define error actions for some negative values and for all other values (MIN_INT=myAction). | -1=CONTINUE;MIN_INT=STOP | 2.6 |
errorLog | no | path to the error log file. | 2.6 |
Example:
<Node id="JOIN" type="EXT_MERGE_JOIN" joinKey="CustomerID" transformClass="org.jetel.test.reformatOrders"/> <Node id="JOIN" type="EXT_MERGE_JOIN" joinKey="EmployeeID=SlaveID;EmployeeType=SlaveType#EmployeeID=SlaveID;EmployeeType=SlaveType2" joinType="inner"> <attr name="transform"> function transform() { ${out.0.car} = ${in.0.car}; ${out.0.seqKey} = ${in.0.seqKey}; ${out.0.mobilephone} = ${in.0.mobilephone}; ${out.0.financial_bonus} = ((${in.1.monthly_bonus})*12)+(${in.1.yearly_bonus}) } </attr> </Node> In-line transformation for 2.4 and lower ver.: <Node id="JOIN" type="EXT_MERGE_JOIN" joinKey="EmployeeID;EmployeeType" leftOuterJoin="true"> <attr name="transform"> import org.jetel.component.DataRecordTransform; import org.jetel.data.*; public class reformatJoinTest extends DataRecordTransform{ int recNo = 0; public boolean transform(DataRecord[] source, DataRecord[] target){ target[0].getField(0).setValue(source[0].getField(0).getValue()); target[0].getField(1).setValue(source[0].getField(1).getValue()); target[0].getField(2).setValue(source[0].getField(2).getValue()); if (source[1]!=null){ target[0].getField(3).setValue(source[1].getField(0).getValue()); target[0].getField(4).setValue(source[1].getField(1).getValue()); }else{ System.out.println("Slave record not found for " + recNo + "th record."); } recNo++; return true; } } </attr> </Node> In-line transformation since 2.5 ver.: <Node id="JOIN" type="EXT_MERGE_JOIN" joinKey="$EmployeeID;$EmployeeType" leftOuterJoin="true"> <attr name="transform"> import org.jetel.component.DataRecordTransform; import org.jetel.data.*; public class reformatJoinTest extends DataRecordTransform{ int recNo = 0; public boolean transform(DataRecord[] source, DataRecord[] target){ if (source[1] == NullRecord.NULL_RECORD) { System.out.println("Slave record not found for " + recNo + "th record."); } target[0].getField(0).setValue(source[0].getField(0).getValue()); target[0].getField(1).setValue(source[0].getField(1).getValue()); target[0].getField(2).setValue(source[0].getField(2).getValue()); target[0].getField(3).setValue(source[1].getField(0).getValue()); target[0].getField(4).setValue(source[1].getField(1).getValue()); recNo++; return true; } } </attr> </Node>
COMMERCIAL, since version 2.8
Joins data records that are not equal with respect to a given join key and operator.
The RelationalJoin component has two input ports. The first one is referred to as the master port, the second one is referred to as the slave port. Each data record from the master port is joined with corresponding data records from the slave port. Data records to be joined are specified by a join key and a relational operator. Any of the following relational operators may be used: !=, <, <=, >, >=. The < operator for example means that each data record from the master port is joined with all data records from the slave port that are lexicographically greater.
Data records coming through the master port are processed one by one. On the other hand, data records coming through the slave port need to be buffered. In the worst case, all the slave data records need to be buffered. Thus the number of data records on the slave port should be as small as possible.
All data records coming through connected input ports have to be sorted in the following way:
| Operator(s) | Required sort order of input data records |
|---|---|
!= | Data records DO NOT NEED to be sorted on either of the input ports. |
<, <= | Data records have to be sorted in the DESCENDING ORDER on both input ports. |
>, >= | Data records have to be sorted in the ASCENDING ORDER on both input ports. |
In case the ordering is incorrect, execution of the component fails.
Input ports:
* 0 – master record input
Output ports:
XML attributes:
| Attribute | Mandatory | Description | Default |
|---|---|---|---|
id | yes | Identification of the component. | N/A |
type | yes | The type of the component (has to be RELATIONAL_JOIN). | N/A |
transform | yes/no | Join transform as a Java or CTL source code. | null |
transformUrl | yes/no | URL of an external Java/CTL source code of the join transform. | null |
transformUrlCharset | no | Character set used in the source code of the join transform specified via an URL. | ISO-8859-1 |
transformClassName | yes/no | Class name of a Java class implementing the join transform. | null |
joinKey | yes | Join key formatted as masterKeyFields#slaveKeyFields where masterKeyFields or slaveKeyFields are sequences of master or slave field names separated by semicolon and preceded by a dollar sign: $fieldK;…;$fieldM. | N/A |
joinOperator | yes | Relational operator used for data record comparison. Any of the !=, <, <=, >, >= operators may be used. | N/A |
joinType | no | Type of join. One of INNER, LEFT_OUTER join types may be used. | INNER |