diff options
| author | chaochaoc <[email protected]> | 2024-07-23 11:27:16 +0800 |
|---|---|---|
| committer | chaochaoc <[email protected]> | 2024-07-23 11:27:16 +0800 |
| commit | faa70c31582fad4c7925d3cf16bb36b56241dc72 (patch) | |
| tree | 14b7aaf63d477137a5de4bdb49514e561c7d9ac0 | |
| parent | c2d05f2f9ed79533e26afadfb6152cd3a79192b4 (diff) | |
[GAL-625] feat: impl eval func use aviator-script
5 files changed, 187 insertions, 4 deletions
diff --git a/groot-core/pom.xml b/groot-core/pom.xml index 628670f..3243075 100644 --- a/groot-core/pom.xml +++ b/groot-core/pom.xml @@ -79,6 +79,10 @@ <artifactId>quartz</artifactId> </dependency> + <dependency> + <groupId>com.googlecode.aviator</groupId> + <artifactId>aviator</artifactId> + </dependency> <dependency> <groupId>org.apache.flink</groupId> @@ -123,8 +127,8 @@ <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> - <source>9</source> - <target>9</target> + <source>10</source> + <target>10</target> </configuration> </plugin> diff --git a/groot-core/src/main/java/com/geedgenetworks/core/expressions/EvalExecutor.java b/groot-core/src/main/java/com/geedgenetworks/core/expressions/EvalExecutor.java new file mode 100644 index 0000000..d3936f5 --- /dev/null +++ b/groot-core/src/main/java/com/geedgenetworks/core/expressions/EvalExecutor.java @@ -0,0 +1,35 @@ +package com.geedgenetworks.core.expressions; + +import com.googlecode.aviator.AviatorEvaluator; +import com.googlecode.aviator.Expression; +import com.googlecode.aviator.exception.ExpressionRuntimeException; +import com.googlecode.aviator.exception.ExpressionSyntaxErrorException; + +import java.util.Map; + +/** + * Eval Function Executor. + * + * @author chaoc + * @since 1.5 + */ +public final class EvalExecutor implements Calc { + + private final Expression script; + + public EvalExecutor(String script) { + try { + AviatorEvaluator.validate(script); + this.script = + AviatorEvaluator.getInstance().compile(script); + } catch (ExpressionSyntaxErrorException + | ExpressionRuntimeException e) { + throw new SyntaxErrorException("Eval script syntax error. ", e); + } + } + + @Override + public Object eval(final Map<String, Object> data) { + return script.execute(data); + } +} diff --git a/groot-core/src/main/java/com/geedgenetworks/core/expressions/SyntaxErrorException.java b/groot-core/src/main/java/com/geedgenetworks/core/expressions/SyntaxErrorException.java index 5c2fe2c..f058615 100644 --- a/groot-core/src/main/java/com/geedgenetworks/core/expressions/SyntaxErrorException.java +++ b/groot-core/src/main/java/com/geedgenetworks/core/expressions/SyntaxErrorException.java @@ -13,4 +13,8 @@ public class SyntaxErrorException extends RuntimeException { public SyntaxErrorException(String message) { super(message); } + + public SyntaxErrorException(String message, Throwable cause) { + super(message, cause); + } } diff --git a/groot-core/src/main/java/com/geedgenetworks/core/udf/Eval.java b/groot-core/src/main/java/com/geedgenetworks/core/udf/Eval.java index 7f62858..e42e0be 100644 --- a/groot-core/src/main/java/com/geedgenetworks/core/udf/Eval.java +++ b/groot-core/src/main/java/com/geedgenetworks/core/udf/Eval.java @@ -5,7 +5,7 @@ import com.geedgenetworks.common.exception.GrootStreamRuntimeException; import com.geedgenetworks.common.udf.UDF; import com.geedgenetworks.common.udf.UDFContext; import com.geedgenetworks.core.expressions.Calc; -import com.geedgenetworks.core.expressions.codegen.CalcCodeConvertor; +import com.geedgenetworks.core.expressions.EvalExecutor; import com.geedgenetworks.common.Event; import org.apache.flink.api.common.functions.RuntimeContext; @@ -30,7 +30,7 @@ public class Eval implements UDF { String expr = (String) udfContext.getParameters().get("value_expression"); List<String> outputField = udfContext.getOutput_fields(); output = outputField.get(0); - calc = CalcCodeConvertor.convert(expr); + calc = new EvalExecutor(expr); } @Override diff --git a/groot-core/src/test/java/com/geedgenetworks/core/expressions/EvalExecutorTest.java b/groot-core/src/test/java/com/geedgenetworks/core/expressions/EvalExecutorTest.java new file mode 100644 index 0000000..e1e9924 --- /dev/null +++ b/groot-core/src/test/java/com/geedgenetworks/core/expressions/EvalExecutorTest.java @@ -0,0 +1,140 @@ +package com.geedgenetworks.core.expressions; + +import com.googlecode.aviator.exception.ExpressionRuntimeException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class EvalExecutorTest { + + private static Map<String, Object> origin; + + @BeforeAll + public static void setUp() { + origin = new HashMap<>(); + origin.put("common_schema_type", "RTP"); + origin.put("common_sessions", 1); + origin.put("common_stream_dir", 3); + origin.put("common_vsys_id", 24); + + origin.put("common_server_ip", "172.17.200.50"); + origin.put("common_server_port", 36682); + origin.put("common_s2c_byte_num", 7570); + origin.put("common_s2c_pkt_num", 5); + + origin.put("common_client_ip", "172.17.201.16"); + origin.put("common_client_port", 42924); + origin.put("common_c2s_byte_num", 1834); + origin.put("common_c2s_pkt_num", 6); + + origin.put("common_out_dest_mac", "02:fc:08:dc:92:d7"); + origin.put("common_out_src_mac", "02:fc:08:dc:91:c3"); + } + + @Test + public void testValueExpression() throws Exception { + // constant + assertEquals(new EvalExecutor("'name'").eval(origin), "name"); + assertEquals(new EvalExecutor("5").eval(origin), 5L); + assertEquals(new EvalExecutor("true").eval(origin), true); + assertEquals(new EvalExecutor("false").eval(origin), false); + + // variable + assertEquals(new EvalExecutor("common_client_ip").eval(origin), + origin.get("common_client_ip")); + assertEquals(new EvalExecutor("common_client_port").eval(origin), + origin.get("common_client_port")); + } + + @Test + public void testConditionExpression() throws Exception { + int commonClientPort = (int) origin.get("common_client_port"); + int commonServerPort = (int) origin.get("common_server_port"); + int commonC2sPktNum = (int) origin.get("common_c2s_pkt_num"); + int commonS2cPktNum = (int) origin.get("common_s2c_pkt_num"); + int commonC2sByteNum = (int) origin.get("common_c2s_byte_num"); + int commonS2cByteNum = (int) origin.get("common_s2c_byte_num"); + assertEquals( + new EvalExecutor("common_client_port > common_server_port " + + "? common_c2s_pkt_num : common_s2c_pkt_num").eval(origin), + commonClientPort > commonServerPort ? commonC2sPktNum : commonS2cPktNum); + assertEquals( + new EvalExecutor("common_client_port > common_server_port " + + "? 'C2S:' + common_c2s_pkt_num : 'S2C:' + common_s2c_pkt_num").eval(origin), + commonClientPort > commonServerPort ? "C2S:" + commonC2sPktNum : "S2C:" + commonS2cPktNum); + assertEquals( + new EvalExecutor("common_c2s_pkt_num > common_s2c_pkt_num " + + "&& common_c2s_byte_num > common_s2c_byte_num ? common_client_port : common_server_port").eval(origin), + commonC2sPktNum > commonS2cPktNum + && commonC2sByteNum > commonS2cByteNum ? commonClientPort : commonServerPort + ); + + } + + @Test + public void testArithmeticExpression() throws Exception { + final Map<String, Object> map = Collections.emptyMap(); + assertEquals( + 1L, new EvalExecutor("5 & 3").eval(map)); + assertEquals( + 7L, new EvalExecutor("5 | 3").eval(map)); + assertEquals( + 20L, new EvalExecutor("5 << 2").eval(map)); + assertEquals( + 1L, new EvalExecutor("5 >> 2").eval(map)); + assertEquals( + 8L, new EvalExecutor("5 + 3").eval(map)); + assertEquals( + 2L, new EvalExecutor("5 - 3").eval(map)); + assertEquals( + 15L, new EvalExecutor("5 * 3").eval(map)); + assertEquals( + 2L, new EvalExecutor("5 / 2").eval(map)); + assertEquals( + 2L, new EvalExecutor("5 % 3").eval(map)); + + + final Map<String, Object> map1 = new HashMap<>(); + map1.put("flags", 8); + + assertEquals("B", + new EvalExecutor(" ( flags & 8 ) == 9 ? 'A' : 'B'").eval(map1)); + assertEquals("A", + new EvalExecutor(" ( 5 | flags ) == 13 ? 'A' : 'B'").eval(map1)); + } + + @Test + public void testFieldArithmeticExpression() throws Exception { + assertEquals(1L, + new EvalExecutor("common_c2s_pkt_num - common_s2c_pkt_num").eval(origin)); + + assertEquals(17L, new EvalExecutor("common_c2s_pkt_num + 10 + 1").eval(origin)); + + } + + @Test + public void testNullField() { + var evalExecutor = new EvalExecutor("( a > nil ? a : 0 ) + ( b > nil ? b : 10 )"); + assertEquals(10L, evalExecutor.eval(origin)); + } + + @Test + public void testError() { + assertThrows(SyntaxErrorException.class, + () -> new EvalExecutor("1L")); + assertThrows(SyntaxErrorException.class, + () -> new EvalExecutor("2 = 3")); + + final Map<String, Object> map = new HashMap<>(origin); + map.put("has_address", true); + var convert = new EvalExecutor("common_c2s_pkt_num + has_address"); + assertThrows(ExpressionRuntimeException.class, () -> convert.eval(map)); + } + +}
\ No newline at end of file |
