@Override public void operate( FlowProcess flowProcess, FunctionCall<ExpressionOperation.Context> functionCall ) { functionCall.getContext().result.set( 0, evaluate( functionCall.getContext(), functionCall.getArguments() ) ); functionCall.getOutputCollector().add( functionCall.getContext().result ); } }
private Object evaluate( ExpressionFunction function, TupleEntry tupleEntry ) { TupleListCollector tuples = invokeFunction( function, tupleEntry, function.getFieldDeclaration() ); return tuples.entryIterator().next().getObject( 0 ); }
/** * Constructor ExpressionFunction creates a new ExpressionFunction instance. * <p> * This constructor assumes all parameter are of the same type. * * @param fieldDeclaration of type Fields * @param expression of type String * @param parameterType of type Class */ @ConstructorProperties({"fieldDeclaration", "expression", "parameterType"}) public ExpressionFunction( Fields fieldDeclaration, String expression, Class parameterType ) { super( fieldDeclaration, expression, parameterType ); verify( fieldDeclaration ); }
@Test public void testNoParamExpression() { Fields fields = new Fields( "a", "b" ).applyTypes( String.class, double.class ); String expression = "(int) (Math.random() * Integer.MAX_VALUE)"; Number integer = (Number) evaluate( new ExpressionFunction( new Fields( "result" ), expression ), getEntry( fields, "1", 2.0 ) ); assertNotNull( integer ); // Fields.NONE as argument selector integer = (Number) evaluate( new ExpressionFunction( new Fields( "result" ), expression ), TupleEntry.NULL ); assertNotNull( integer ); try { evaluate( new ExpressionFunction( new Fields( "result" ), "(int) (Math.random() * Integer.MAX_VALUE) + parameter" ), getEntry( fields, "1", 2.0 ) ); fail( "should throw exception" ); } catch( Exception exception ) { // ignore } }
@Test public void testNoParamExpression() { Fields fields = new Fields( "a", "b" ).applyTypes( String.class, double.class ); String expression = "(int) (Math.random() * Integer.MAX_VALUE)"; Number integer = (Number) evaluate( new ExpressionFunction( new Fields( "result" ), expression ), getEntry( fields, "1", 2.0 ) ); assertNotNull( integer ); // Fields.NONE as argument selector integer = (Number) evaluate( new ExpressionFunction( new Fields( "result" ), expression ), TupleEntry.NULL ); assertNotNull( integer ); try { evaluate( new ExpressionFunction( new Fields( "result" ), "(int) (Math.random() * Integer.MAX_VALUE) + parameter" ), getEntry( fields, "1", 2.0 ) ); fail( "should throw exception" ); } catch( Exception exception ) { // ignore } }
assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", int.class ), getEntry( 1, 2 ) ) ); assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", int.class ), getEntry( 1.0, 2.0 ) ) ); assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", int.class ), getEntry( "1", 2.0 ) ) ); assertEquals( 3l, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( 1, 2 ) ) ); assertEquals( 3l, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( 1.0, 2.0 ) ) ); assertEquals( 3l, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( "1", 2.0 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( 1, 2 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( 1.0, 2.0 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( "1", 2.0 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b" ), getEntry( arguments, 1, 2 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b" ), getEntry( arguments, 1.0, 2.0 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b" ), getEntry( arguments, "1", 2.0 ) ) ); assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "$0 + $1", int.class ), getEntry( 1, 2 ) ) ); assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "$0 + $1", int.class ), getEntry( 1.0, 2.0 ) ) ); assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "$0 + $1", int.class ), getEntry( "1", 2.0 ) ) ); assertEquals( true, evaluate( new ExpressionFunction( new Fields( "result" ), "(a != null) && (b > 0)", names, types ), getEntry( "1", 2.0 ) ) ); assertEquals( true, evaluate( new ExpressionFunction( new Fields( "result" ), "($0 != null) && ($1 > 0)", names, types ), getEntry( "1", 2.0 ) ) ); assertEquals( true, evaluate( new ExpressionFunction( new Fields( "result" ), "b.equals(\"1\") && (a == 2.0) && c.equals(\"2\")", names, types ), getEntry( 2.0, "1", "2" ) ) ); assertEquals( true, evaluate( new ExpressionFunction( new Fields( "result" ), "b.equals(\"1\") && (a == 2.0) && $2.equals(\"2\")", names, types ), getEntry( 2.0, "1", "2" ) ) );
/** * Constructor ExpressionFunction creates a new ExpressionFunction instance. * <p> * This constructor assumes all parameter are of the same type. * * @param fieldDeclaration of type Fields * @param expression of type String * @param parameterType of type Class */ @ConstructorProperties({"fieldDeclaration", "expression", "parameterType"}) public ExpressionFunction( Fields fieldDeclaration, String expression, Class parameterType ) { super( fieldDeclaration, expression, parameterType ); verify( fieldDeclaration ); }
@Override public void operate( FlowProcess flowProcess, FunctionCall<ExpressionOperation.Context> functionCall ) { functionCall.getContext().result.set( 0, evaluate( functionCall.getContext(), functionCall.getArguments() ) ); functionCall.getOutputCollector().add( functionCall.getContext().result ); } }
private Object evaluate( ExpressionFunction function, TupleEntry tupleEntry ) { TupleListCollector tuples = invokeFunction( function, tupleEntry, function.getFieldDeclaration() ); return tuples.entryIterator().next().getObject( 0 ); }
assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", int.class ), getEntry( 1, 2 ) ) ); assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", int.class ), getEntry( 1.0, 2.0 ) ) ); assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", int.class ), getEntry( "1", 2.0 ) ) ); assertEquals( 3l, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( 1, 2 ) ) ); assertEquals( 3l, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( 1.0, 2.0 ) ) ); assertEquals( 3l, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( "1", 2.0 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( 1, 2 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( 1.0, 2.0 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b", names, types ), getEntry( "1", 2.0 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b" ), getEntry( arguments, 1, 2 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b" ), getEntry( arguments, 1.0, 2.0 ) ) ); assertEquals( 3d, evaluate( new ExpressionFunction( new Fields( "result" ), "a + b" ), getEntry( arguments, "1", 2.0 ) ) ); assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "$0 + $1", int.class ), getEntry( 1, 2 ) ) ); assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "$0 + $1", int.class ), getEntry( 1.0, 2.0 ) ) ); assertEquals( 3, evaluate( new ExpressionFunction( new Fields( "result" ), "$0 + $1", int.class ), getEntry( "1", 2.0 ) ) ); assertEquals( true, evaluate( new ExpressionFunction( new Fields( "result" ), "(a != null) && (b > 0)", names, types ), getEntry( "1", 2.0 ) ) ); assertEquals( true, evaluate( new ExpressionFunction( new Fields( "result" ), "($0 != null) && ($1 > 0)", names, types ), getEntry( "1", 2.0 ) ) ); assertEquals( true, evaluate( new ExpressionFunction( new Fields( "result" ), "b.equals(\"1\") && (a == 2.0) && c.equals(\"2\")", names, types ), getEntry( 2.0, "1", "2" ) ) ); assertEquals( true, evaluate( new ExpressionFunction( new Fields( "result" ), "b.equals(\"1\") && (a == 2.0) && $2.equals(\"2\")", names, types ), getEntry( 2.0, "1", "2" ) ) );
/** * Constructor ExpressionFunction creates a new ExpressionFunction instance. * <p> * This constructor expects all parameter type names to be declared with their types. Positional parameters must * be named the same as in the given expression with the "$" sign prepended. * * @param fieldDeclaration of type Fields * @param expression of type String * @param parameterNames of type String[] * @param parameterTypes of type Class[] */ @ConstructorProperties({"fieldDeclaration", "expression", "parameterNames", "parameterTypes"}) public ExpressionFunction( Fields fieldDeclaration, String expression, String[] parameterNames, Class[] parameterTypes ) { super( fieldDeclaration, expression, parameterNames, parameterTypes ); verify( fieldDeclaration ); }
/** * This test checks for a deadlock when the same input is forked, adapted on one edge, then hashjoined back together. * * @throws Exception */ @Test public void testForkThenJoin() throws Exception { getPlatform().copyFromLocal( inputFileLower ); Tap sourceLower = getPlatform().getTextFile( new Fields( "offset", "line" ), inputFileLower ); Map sources = new HashMap(); sources.put( "lower", sourceLower ); Tap sink = getPlatform().getTextFile( new Fields( "line" ), getOutputPath( "join" ), SinkMode.REPLACE ); Function splitter = new RegexSplitter( new Fields( "num", "text" ), " " ); Pipe pipeLower = new Each( new Pipe( "lower" ), new Fields( "line" ), splitter ); Pipe pipeUpper = new Each( new Pipe( "upper", pipeLower ), new Fields( "text" ), new ExpressionFunction( Fields.ARGS, "text.toUpperCase(java.util.Locale.ROOT)", String.class ), Fields.REPLACE ); Pipe splice = new HashJoin( pipeLower, new Fields( "num" ), pipeUpper, new Fields( "num" ), Fields.size( 4 ) ); Map<Object, Object> properties = getProperties(); Flow flow = getPlatform().getFlowConnector( properties ).connect( sources, sink, splice ); flow.complete(); validateLength( flow, 5 ); List<Tuple> values = getSinkAsList( flow ); assertTrue( values.contains( new Tuple( "1\ta\t1\tA" ) ) ); assertTrue( values.contains( new Tuple( "2\tb\t2\tB" ) ) ); }
/** * Constructor ExpressionFunction creates a new ExpressionFunction instance. * <p> * This constructor expects all parameter type names to be declared with their types. Positional parameters must * be named the same as in the given expression with the "$" sign prepended. * * @param fieldDeclaration of type Fields * @param expression of type String * @param parameterNames of type String[] * @param parameterTypes of type Class[] */ @ConstructorProperties({"fieldDeclaration", "expression", "parameterNames", "parameterTypes"}) public ExpressionFunction( Fields fieldDeclaration, String expression, String[] parameterNames, Class[] parameterTypes ) { super( fieldDeclaration, expression, parameterNames, parameterTypes ); verify( fieldDeclaration ); }
/** * This test checks for a deadlock when the same input is forked, adapted on one edge, then hashjoined back together. * * @throws Exception */ @Test public void testForkThenJoin() throws Exception { getPlatform().copyFromLocal( inputFileLower ); Tap sourceLower = getPlatform().getTextFile( new Fields( "offset", "line" ), inputFileLower ); Map sources = new HashMap(); sources.put( "lower", sourceLower ); Tap sink = getPlatform().getTextFile( new Fields( "line" ), getOutputPath( "join" ), SinkMode.REPLACE ); Function splitter = new RegexSplitter( new Fields( "num", "text" ), " " ); Pipe pipeLower = new Each( new Pipe( "lower" ), new Fields( "line" ), splitter ); Pipe pipeUpper = new Each( new Pipe( "upper", pipeLower ), new Fields( "text" ), new ExpressionFunction( Fields.ARGS, "text.toUpperCase(java.util.Locale.ROOT)", String.class ), Fields.REPLACE ); Pipe splice = new HashJoin( pipeLower, new Fields( "num" ), pipeUpper, new Fields( "num" ), Fields.size( 4 ) ); Map<Object, Object> properties = getProperties(); Flow flow = getPlatform().getFlowConnector( properties ).connect( sources, sink, splice ); flow.complete(); validateLength( flow, 5 ); List<Tuple> values = getSinkAsList( flow ); assertTrue( values.contains( new Tuple( "1\ta\t1\tA" ) ) ); assertTrue( values.contains( new Tuple( "2\tb\t2\tB" ) ) ); }
/** * Constructor ExpressionFunction creates a new ExpressionFunction instance. * <p> * This constructor, when used with incoming arguments that have type information, the argument field * names can be used directly in the the expression, for example {@code a + b }. The type of {@code a} and {@code b} * will be inherited from the incoming argument fields. * <p> * Or, if the incoming argument selector is {@link Fields#NONE}, an expression using only static method calls * or constants can be used. * <p> * This is useful when inserting random numbers for example, {@code (int) (Math.random() * Integer.MAX_VALUE) }. * * @param fieldDeclaration of type Fields * @param expression of type String */ @ConstructorProperties({"fieldDeclaration", "expression"}) public ExpressionFunction( Fields fieldDeclaration, String expression ) { super( fieldDeclaration, expression ); verify( fieldDeclaration ); }
new ExpressionFunction( Fields.ARGS, "text.toUpperCase(java.util.Locale.ROOT)", String.class ), Fields.REPLACE ); Pipe rightPipeLower = new Each( new Pipe( "rightLower", rightPipeUpper ), new Fields( "text" ), new ExpressionFunction( Fields.ARGS, "text.toLowerCase(java.util.Locale.ROOT)", String.class ), Fields.REPLACE );
/** * Constructor ExpressionFunction creates a new ExpressionFunction instance. * <p> * This constructor, when used with incoming arguments that have type information, the argument field * names can be used directly in the the expression, for example {@code a + b }. The type of {@code a} and {@code b} * will be inherited from the incoming argument fields. * <p> * Or, if the incoming argument selector is {@link Fields#NONE}, an expression using only static method calls * or constants can be used. * <p> * This is useful when inserting random numbers for example, {@code (int) (Math.random() * Integer.MAX_VALUE) }. * * @param fieldDeclaration of type Fields * @param expression of type String */ @ConstructorProperties({"fieldDeclaration", "expression"}) public ExpressionFunction( Fields fieldDeclaration, String expression ) { super( fieldDeclaration, expression ); verify( fieldDeclaration ); }
new ExpressionFunction( Fields.ARGS, "text.toUpperCase(java.util.Locale.ROOT)", String.class ), Fields.REPLACE ); Pipe rightPipeLower = new Each( new Pipe( "rightLower", rightPipeUpper ), new Fields( "text" ), new ExpressionFunction( Fields.ARGS, "text.toLowerCase(java.util.Locale.ROOT)", String.class ), Fields.REPLACE );
pipeLower = new Each( pipeLower, new Fields( "num" ), new ExpressionFunction( Fields.ARGS, "Integer.parseInt( num )", String.class ), Fields.REPLACE );
pipeLower = new Each( pipeLower, new Fields( "num" ), new ExpressionFunction( Fields.ARGS, "Integer.parseInt( num )", String.class ), Fields.REPLACE );