Repository: tajo Updated Branches: refs/heads/master c577102ee -> 34508a76d
TAJO-1997: Registering UDF, it needs to check duplication. Closes #883 Signed-off-by: Jihoon Son <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/tajo/repo Commit: http://git-wip-us.apache.org/repos/asf/tajo/commit/34508a76 Tree: http://git-wip-us.apache.org/repos/asf/tajo/tree/34508a76 Diff: http://git-wip-us.apache.org/repos/asf/tajo/diff/34508a76 Branch: refs/heads/master Commit: 34508a76db5e846df8271d2c8ad3ab3275d2a33b Parents: c577102 Author: Jongyoung Park <[email protected]> Authored: Mon Dec 21 19:15:56 2015 +0900 Committer: Jihoon Son <[email protected]> Committed: Mon Dec 21 19:16:49 2015 +0900 ---------------------------------------------------------------------- CHANGES | 3 + .../org/apache/tajo/catalog/FunctionDesc.java | 11 +++ .../apache/tajo/function/FunctionSignature.java | 17 ++++ .../org/apache/tajo/catalog/CatalogServer.java | 11 +-- .../apache/tajo/engine/eval/ExprTestBase.java | 22 ++--- .../engine/function/TestFunctionLoader.java | 50 +++++++++++ .../tajo/engine/function/FunctionLoader.java | 89 ++++++++++++++------ .../java/org/apache/tajo/master/TajoMaster.java | 19 +---- .../java/org/apache/tajo/worker/TajoWorker.java | 2 +- 9 files changed, 161 insertions(+), 63 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tajo/blob/34508a76/CHANGES ---------------------------------------------------------------------- diff --git a/CHANGES b/CHANGES index 51c1e62..5a8fa37 100644 --- a/CHANGES +++ b/CHANGES @@ -187,6 +187,9 @@ Release 0.12.0 - unreleased SUB TASKS + TAJO-1997: Registering UDF, it needs to check duplication. + (Contributed by Jongyoung Park. Committed by jihoon) + TAJO-2024: Remove getContentSummary from HCatalogStore. (hyunsik) TAJO-2004: S3TableSpace needs to extend FileTableSpace. (jaehwa) http://git-wip-us.apache.org/repos/asf/tajo/blob/34508a76/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java index 5fa0c15..8c10418 100644 --- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/catalog/FunctionDesc.java @@ -157,6 +157,10 @@ public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable, public int hashCode() { return Objects.hashCode(signature); } + + public int hashCodeWithoutType() { + return signature.hashCodeWithoutType(); + } @Override public boolean equals(Object obj) { @@ -167,6 +171,13 @@ public class FunctionDesc implements ProtoObject<FunctionDescProto>, Cloneable, } return false; } + + public boolean equalsSignature(Object obj) { + if (obj instanceof FunctionDesc) { + return this.getSignature().equalsWithoutType(((FunctionDesc) obj).getSignature()); + } + return false; + } @Override public Object clone() throws CloneNotSupportedException{ http://git-wip-us.apache.org/repos/asf/tajo/blob/34508a76/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSignature.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSignature.java b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSignature.java index 89ee017..ea4090f 100644 --- a/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSignature.java +++ b/tajo-catalog/tajo-catalog-common/src/main/java/org/apache/tajo/function/FunctionSignature.java @@ -144,4 +144,21 @@ public class FunctionSignature implements Comparable<FunctionSignature>, ProtoOb return o.paramTypes.length - paramTypes.length; } + + public boolean equalsWithoutType(Object obj) { + if (obj instanceof FunctionSignature) { + FunctionSignature other = (FunctionSignature) obj; + + boolean eq = name.equals(other.name); + eq = eq && TUtil.checkEquals(paramTypes, other.paramTypes); + eq = eq && returnType.equals(other.returnType); + return eq; + } else { + return false; + } + } + + public int hashCodeWithoutType() { + return Objects.hashCode(name, returnType, Objects.hashCode(paramTypes)); + } } http://git-wip-us.apache.org/repos/asf/tajo/blob/34508a76/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java ---------------------------------------------------------------------- diff --git a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java index d649c5f..d99daee 100644 --- a/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java +++ b/tajo-catalog/tajo-catalog-server/src/main/java/org/apache/tajo/catalog/CatalogServer.java @@ -95,13 +95,10 @@ public class CatalogServer extends AbstractService { private String bindAddressStr; final CatalogProtocolHandler handler; - private Collection<FunctionDesc> builtingFuncs; + private Collection<FunctionDesc> builtinFuncs; public CatalogServer() throws IOException { - super(CatalogServer.class.getName()); - this.handler = new CatalogProtocolHandler(); - this.linkedMetadataManager = new LinkedMetadataManager(Collections.EMPTY_LIST); - this.builtingFuncs = new ArrayList<>(); + this(Collections.EMPTY_LIST, new ArrayList<>()); } public CatalogServer(Collection<MetadataProvider> metadataProviders, Collection<FunctionDesc> sqlFuncs) @@ -109,7 +106,7 @@ public class CatalogServer extends AbstractService { super(CatalogServer.class.getName()); this.handler = new CatalogProtocolHandler(); this.linkedMetadataManager = new LinkedMetadataManager(metadataProviders); - this.builtingFuncs = sqlFuncs; + this.builtinFuncs = sqlFuncs; } @Override @@ -131,7 +128,7 @@ public class CatalogServer extends AbstractService { this.store = (CatalogStore) cons.newInstance(this.conf); - initBuiltinFunctions(builtingFuncs); + initBuiltinFunctions(builtinFuncs); } catch (Throwable t) { LOG.error("CatalogServer initialization failed", t); throw new TajoInternalError(t); http://git-wip-us.apache.org/repos/asf/tajo/blob/34508a76/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java ---------------------------------------------------------------------- diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java index 600a45f..602d566 100644 --- a/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java +++ b/tajo-core-tests/src/test/java/org/apache/tajo/engine/eval/ExprTestBase.java @@ -61,6 +61,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TimeZone; @@ -70,7 +71,7 @@ import static org.apache.tajo.TajoConstants.DEFAULT_TABLESPACE_NAME; import static org.junit.Assert.*; public class ExprTestBase { - private static TajoTestingCluster util; + private static TajoTestingCluster cluster; private static TajoConf conf; private static CatalogService cat; private static SQLAnalyzer analyzer; @@ -88,28 +89,29 @@ public class ExprTestBase { @BeforeClass public static void setUp() throws Exception { - util = new TajoTestingCluster(); - conf = util.getConfiguration(); - util.startCatalogCluster(); - cat = util.getCatalogService(); + cluster = new TajoTestingCluster(); + conf = cluster.getConfiguration(); + cluster.startCatalogCluster(); + cat = cluster.getCatalogService(); cat.createTablespace(DEFAULT_TABLESPACE_NAME, "hdfs://localhost:1234/warehouse"); cat.createDatabase(DEFAULT_DATABASE_NAME, DEFAULT_TABLESPACE_NAME); - Map<FunctionSignature, FunctionDesc> map = FunctionLoader.load(); - map = FunctionLoader.loadUserDefinedFunctions(conf, map); - for (FunctionDesc funcDesc : map.values()) { + Map<FunctionSignature, FunctionDesc> map = FunctionLoader.loadBuiltinFunctions(); + List<FunctionDesc> list = new ArrayList<>(map.values()); + list.addAll(FunctionLoader.loadUserDefinedFunctions(conf)); + for (FunctionDesc funcDesc : list) { cat.createFunction(funcDesc); } analyzer = new SQLAnalyzer(); preLogicalPlanVerifier = new PreLogicalPlanVerifier(cat); planner = new LogicalPlanner(cat, TablespaceManager.getInstance()); - optimizer = new LogicalOptimizer(util.getConfiguration(), cat, TablespaceManager.getInstance()); + optimizer = new LogicalOptimizer(cluster.getConfiguration(), cat, TablespaceManager.getInstance()); annotatedPlanVerifier = new LogicalPlanVerifier(); } @AfterClass public static void tearDown() throws Exception { - util.shutdownCatalogCluster(); + cluster.shutdownCatalogCluster(); } private static void assertJsonSerDer(EvalNode expr) { http://git-wip-us.apache.org/repos/asf/tajo/blob/34508a76/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestFunctionLoader.java ---------------------------------------------------------------------- diff --git a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestFunctionLoader.java b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestFunctionLoader.java index cf34c33..26f3262 100644 --- a/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestFunctionLoader.java +++ b/tajo-core-tests/src/test/java/org/apache/tajo/engine/function/TestFunctionLoader.java @@ -19,16 +19,25 @@ package org.apache.tajo.engine.function; import com.google.common.collect.Lists; +import org.apache.tajo.catalog.CatalogUtil; import org.apache.tajo.catalog.FunctionDesc; +import org.apache.tajo.catalog.proto.CatalogProtos; +import org.apache.tajo.common.TajoDataTypes; +import org.apache.tajo.exception.AmbiguousFunctionException; +import org.apache.tajo.function.FunctionInvocation; +import org.apache.tajo.function.FunctionSignature; +import org.apache.tajo.function.FunctionSupplement; import org.apache.tajo.util.StringUtils; import org.junit.Test; import java.io.IOException; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import static org.apache.tajo.LocalTajoTestingUtility.getResultText; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class TestFunctionLoader { @@ -42,4 +51,45 @@ public class TestFunctionLoader { String result = getResultText(TestFunctionLoader.class, "testFindScalarFunctions.result"); assertEquals(result.trim(), functionList.trim()); } + + @Test + public void testAmbiguousException() { + FunctionSignature signature = new FunctionSignature(CatalogProtos.FunctionType.GENERAL, "test1", + CatalogUtil.newSimpleDataType(TajoDataTypes.Type.TEXT), + CatalogUtil.newSimpleDataType(TajoDataTypes.Type.FLOAT8)); + + FunctionInvocation invocation = new FunctionInvocation(); + FunctionSupplement supplement = new FunctionSupplement(); + + FunctionDesc desc = new FunctionDesc(signature, invocation, supplement); + + List<FunctionDesc> builtins = new ArrayList<>(); + builtins.add(desc); + + signature = new FunctionSignature(CatalogProtos.FunctionType.GENERAL, "test2", + CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INT8), + CatalogUtil.newSimpleDataType(TajoDataTypes.Type.INT8)); + + desc = new FunctionDesc(signature, invocation, supplement); + builtins.add(desc); + + List<FunctionDesc> udfs = new ArrayList<>(); + + signature = new FunctionSignature(CatalogProtos.FunctionType.UDF, "test1", + CatalogUtil.newSimpleDataType(TajoDataTypes.Type.TEXT), + CatalogUtil.newSimpleDataType(TajoDataTypes.Type.FLOAT8)); + + desc = new FunctionDesc(signature, invocation, supplement); + udfs.add(desc); + + boolean afexOccurs = false; + + try { + FunctionLoader.mergeFunctionLists(builtins, udfs); + } catch (AmbiguousFunctionException e) { + afexOccurs = true; + } + + assertTrue(afexOccurs); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tajo/blob/34508a76/tajo-core/src/main/java/org/apache/tajo/engine/function/FunctionLoader.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/engine/function/FunctionLoader.java b/tajo-core/src/main/java/org/apache/tajo/engine/function/FunctionLoader.java index 18baf0f..1fb5acf 100644 --- a/tajo-core/src/main/java/org/apache/tajo/engine/function/FunctionLoader.java +++ b/tajo-core/src/main/java/org/apache/tajo/engine/function/FunctionLoader.java @@ -28,7 +28,6 @@ import org.apache.commons.logging.LogFactory; import org.apache.hadoop.fs.FileStatus; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; -import org.apache.hadoop.fs.PathFilter; import org.apache.tajo.annotation.Nullable; import org.apache.tajo.catalog.CatalogUtil; import org.apache.tajo.catalog.FunctionDesc; @@ -37,6 +36,7 @@ import org.apache.tajo.conf.TajoConf; import org.apache.tajo.engine.function.annotation.Description; import org.apache.tajo.engine.function.annotation.ParamOptionTypes; import org.apache.tajo.engine.function.annotation.ParamTypes; +import org.apache.tajo.exception.AmbiguousFunctionException; import org.apache.tajo.function.*; import org.apache.tajo.plan.function.python.PythonScriptEngine; import org.apache.tajo.util.ClassUtil; @@ -46,6 +46,7 @@ import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.*; +import java.util.stream.Collectors; import static org.apache.tajo.catalog.proto.CatalogProtos.FunctionType.GENERAL; @@ -59,7 +60,7 @@ public class FunctionLoader { * * @return */ - public static Map<FunctionSignature, FunctionDesc> load() { + public static Map<FunctionSignature, FunctionDesc> loadBuiltinFunctions() { Map<FunctionSignature, FunctionDesc> map = Maps.newHashMap(); List<FunctionDesc> dd = Lists.newArrayList(); @@ -87,13 +88,12 @@ public class FunctionLoader { * Load functions defined by users. * * @param conf - * @param functionMap * @return * @throws IOException */ - public static Map<FunctionSignature, FunctionDesc> loadUserDefinedFunctions(TajoConf conf, - Map<FunctionSignature, FunctionDesc> functionMap) + public static List<FunctionDesc> loadUserDefinedFunctions(TajoConf conf) throws IOException { + List<FunctionDesc> functionList = new LinkedList<>(); String[] codePaths = conf.getStrings(TajoConf.ConfVars.PYTHON_CODE_DIR.varname); if (codePaths != null) { @@ -110,37 +110,27 @@ public class FunctionLoader { List<Path> filePaths = TUtil.newList(); if (localFS.isDirectory(codePath)) { - for (FileStatus file : localFS.listStatus(codePath, new PathFilter() { - @Override - public boolean accept(Path path) { - return path.getName().endsWith(PythonScriptEngine.FILE_EXTENSION); - } - })) { + for (FileStatus file : localFS.listStatus(codePath, + (Path path) -> path.getName().endsWith(PythonScriptEngine.FILE_EXTENSION))) { filePaths.add(file.getPath()); } } else { filePaths.add(codePath); } for (Path filePath : filePaths) { - for (FunctionDesc f : PythonScriptEngine.registerFunctions(filePath.toUri(), - FunctionLoader.PYTHON_FUNCTION_NAMESPACE)) { - functionMap.put(f.getSignature(), f); - } + PythonScriptEngine.registerFunctions(filePath.toUri(), FunctionLoader.PYTHON_FUNCTION_NAMESPACE).forEach(functionList::add); } } } - return functionMap; + + return functionList; } public static Set<FunctionDesc> findScalarFunctions() { Set<FunctionDesc> functions = Sets.newHashSet(); - Set<Method> scalarFunctions = findPublicStaticMethods("org.apache.tajo.engine.function", new Predicate() { - @Override - public boolean evaluate(Object object) { - return ((Method) object).getAnnotation(ScalarFunction.class) != null; - } - }); + Set<Method> scalarFunctions = findPublicStaticMethods("org.apache.tajo.engine.function", + (Object object) -> ((Method) object).getAnnotation(ScalarFunction.class) != null); for (Method method : scalarFunctions) { ScalarFunction annotation = method.getAnnotation(ScalarFunction.class); @@ -170,12 +160,8 @@ public class FunctionLoader { } private static Set<Class> findFunctionCollections(String packageName) { - return ClassUtil.findClasses(null, packageName, new Predicate() { - @Override - public boolean evaluate(Object object) { - return ((Class)object).getAnnotation(FunctionCollection.class) != null; - } - }); + return ClassUtil.findClasses(null, packageName, (Object object) -> + ((Class)object).getAnnotation(FunctionCollection.class) != null); } private static Collection<FunctionDesc> buildFunctionDescs(ScalarFunction annotation, Method method) { @@ -299,4 +285,51 @@ public class FunctionLoader { return sqlFuncs; } + + public static Collection<FunctionDesc> loadFunctions(TajoConf conf) throws IOException, AmbiguousFunctionException { + List<FunctionDesc> functionList = new ArrayList<>(loadBuiltinFunctions().values()); + List<FunctionDesc> udfs = loadUserDefinedFunctions(conf); + + /* NOTE: + * For built-in functions, it is not done to check duplicates. + * There are two reasons. + * Firstly, it could be an useless operation in most of cases because built-in functions are not changed frequently + * but checking will be done each startup. + * Secondly, this logic checks duplicate excluding type, but there are already duplicates in built-in functions + * such as sum with/without 'distinct' feature. So to check duplicates in built-in functions, some other logic is needed. + * It should be another issue. + */ + // merge lists and return it. + return mergeFunctionLists(functionList, udfs); + } + + @SafeVarargs + static Collection<FunctionDesc> mergeFunctionLists(List<FunctionDesc> ... functionLists) + throws AmbiguousFunctionException { + + Map<Integer, FunctionDesc> funcMap = new HashMap<>(); + List<FunctionDesc> baseFuncList = functionLists[0]; + + // Build a map with a first list + for (FunctionDesc desc: baseFuncList) { + funcMap.put(desc.hashCodeWithoutType(), desc); + } + + // Check duplicates for other function lists(should be UDFs practically) + for (int i=1; i<functionLists.length; i++) { + for (FunctionDesc desc: functionLists[i]) { + if (funcMap.containsKey(desc.hashCodeWithoutType())) { + FunctionDesc storedDesc = funcMap.get(desc.hashCodeWithoutType()); + if (storedDesc.equalsSignature(desc)) { + throw new AmbiguousFunctionException(String.format("%s", storedDesc.toString())); + } + } + + funcMap.put(desc.hashCodeWithoutType(), desc); + baseFuncList.add(desc); + } + } + + return baseFuncList; + } } http://git-wip-us.apache.org/repos/asf/tajo/blob/34508a76/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java b/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java index 97e9613..91fba51 100644 --- a/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java +++ b/tajo-core/src/main/java/org/apache/tajo/master/TajoMaster.java @@ -18,7 +18,6 @@ package org.apache.tajo.master; -import com.codahale.metrics.Gauge; import com.google.common.annotations.VisibleForTesting; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -36,7 +35,6 @@ import org.apache.hadoop.yarn.util.RackResolver; import org.apache.hadoop.yarn.util.SystemClock; import org.apache.tajo.catalog.CatalogServer; import org.apache.tajo.catalog.CatalogService; -import org.apache.tajo.catalog.FunctionDesc; import org.apache.tajo.catalog.LocalCatalogWrapper; import org.apache.tajo.catalog.proto.CatalogProtos; import org.apache.tajo.catalog.proto.CatalogProtos.AlterTablespaceProto; @@ -47,7 +45,6 @@ import org.apache.tajo.conf.TajoConf; import org.apache.tajo.conf.TajoConf.ConfVars; import org.apache.tajo.engine.function.FunctionLoader; import org.apache.tajo.exception.*; -import org.apache.tajo.function.FunctionSignature; import org.apache.tajo.io.AsyncTaskService; import org.apache.tajo.master.rm.TajoResourceManager; import org.apache.tajo.metrics.ClusterResourceMetricSet; @@ -77,8 +74,6 @@ import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.net.InetSocketAddress; -import java.util.Collection; -import java.util.Map; import static org.apache.tajo.TajoConstants.DEFAULT_DATABASE_NAME; import static org.apache.tajo.TajoConstants.DEFAULT_TABLESPACE_NAME; @@ -182,7 +177,7 @@ public class TajoMaster extends CompositeService { checkAndInitializeSystemDirectories(); diagnoseTajoMaster(); - catalogServer = new CatalogServer(TablespaceManager.getMetadataProviders(), loadFunctions()); + catalogServer = new CatalogServer(TablespaceManager.getMetadataProviders(), FunctionLoader.loadFunctions(systemConf)); addIfService(catalogServer); catalog = new LocalCatalogWrapper(catalogServer, systemConf); @@ -220,21 +215,11 @@ public class TajoMaster extends CompositeService { LOG.info("Tajo Master is initialized."); } - private Collection<FunctionDesc> loadFunctions() throws IOException { - Map<FunctionSignature, FunctionDesc> functionMap = FunctionLoader.load(); - return FunctionLoader.loadUserDefinedFunctions(systemConf, functionMap).values(); - } - private void initSystemMetrics() { systemMetrics = new TajoSystemMetrics(systemConf, Master.class, getMasterName()); systemMetrics.start(); - systemMetrics.register(Master.Cluster.UPTIME, new Gauge<Long>() { - @Override - public Long getValue() { - return context.getClusterUptime(); - } - }); + systemMetrics.register(Master.Cluster.UPTIME, () -> context.getClusterUptime()); systemMetrics.register(Master.Cluster.class, new ClusterResourceMetricSet(context)); } http://git-wip-us.apache.org/repos/asf/tajo/blob/34508a76/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java ---------------------------------------------------------------------- diff --git a/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java b/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java index 8315c1c..de337ae 100644 --- a/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java +++ b/tajo-core/src/main/java/org/apache/tajo/worker/TajoWorker.java @@ -199,7 +199,7 @@ public class TajoWorker extends CompositeService { historyReader = new HistoryReader(workerContext.getWorkerName(), this.systemConf); - FunctionLoader.loadUserDefinedFunctions(systemConf, new HashMap<>()); + FunctionLoader.loadUserDefinedFunctions(systemConf); PythonScriptEngine.initPythonScriptEngineFiles();
