CREATE FUNCTION
Описание
Этот оператор используется для создания пользовательской функции.
Синтаксис
CREATE [ GLOBAL ]
[{AGGREGATE | TABLES | ALIAS }] FUNCTION <function_name>
(<arg_type> [, ...])
[ RETURNS <ret_type> ]
[ INTERMEDIATE <inter_type> ]
[ WITH PARAMETER(<param> [,...]) AS <origin_function> ]
[ PROPERTIES ("<key>" = "<value>" [, ...]) ]
Обязательные параметры
1. <function_name>
Если
function_nameвключает имя базы данных, напримерdb1.my_func, пользовательская функция будет создана в соответствующей базе данных. В противном случае функция будет создана в базе данных текущего сеанса. Имя и параметры новой функции не должны одновременно совпадать с именем и параметрами существующей функции в текущем пространстве имён; иначе создание завершится ошибкой.
2. <arg_type>
Типы входных параметров функции. Можно объявить один или несколько фиксированных аргументов. Начиная с версии 4.1.5, объявление функций с переменным числом аргументов с помощью
...больше не поддерживается. Для передачи переменного числа значений используйте параметр типаARRAY.
3. <ret_type>
Тип возвращаемого значения функции. Это обязательный параметр при создании новой функции. При создании псевдонима для существующей функции этот параметр не требуется.
Необязательные параметры
1. GLOBAL
Если указан, создаваемая функция доступна глобально.
2. AGGREGATE
Если указан, создаваемая функция является агрегатной функцией.
3. TABLES
Если указан, создаваемая функция является табличной функцией.
4. ALIAS
Если указан, создаваемая функция является функцией-псевдонимом.
Если ни один из перечисленных выше параметров, определяющих тип функции, не указан, создаваемая функция является скалярной.
5. <inter_type>
Указывает тип данных на промежуточном этапе вычисления агрегатной функции.
6. <param>
Указывает параметры функции-псевдонима. Необходимо указать хотя бы один параметр.
7. <origin_function>
Указывает исходную функцию, которой соответствует функция-псевдоним.
8. <properties>
file: Указывает JAR-пакет, содержащий пользовательскую функцию (UDF). В среде из нескольких машин его также можно загрузить по HTTP. Этот параметр обязателен.symbol: Указывает имя класса, в котором содержится UDF. Этот параметр обязателен.type: Указывает тип вызова UDF. Значение по умолчанию — Native. При использовании Java UDF укажите JAVA_UDF.always_nullable: Указывает, может ли результат UDF содержать значения NULL. Это необязательный параметр со значением по умолчанию true.volatility: Указывает степень стабильности результата функции. Этот параметр поддерживается с версии 4.1.2. Он необязателен. Значение по умолчанию —volatileдля скалярных UDF иimmutableдля UDAF/UDTF. Допустимые значения:
immutable: При одинаковых входных данных всегда возвращается одинаковый результат. Большинство детерминированных UDF следует помечать какimmutable, чтобы оптимизатор мог выполнять дополнительные оптимизации плана.stable: Результат стабилен в пределах одного оператора SQL, но может меняться между операторами, как уnow(). Для функций этого типа отключены кэш SQL и переписывание запросов с использованием материализованных представлений.volatile: Результат может меняться при каждом вызове, как уrandom(). Для функций этого типа отключены кэш SQL, переписывание запросов с использованием материализованных представлений и многие правила переписывания запросов оптимизатора.
Требования к правам доступа
Для выполнения этой команды пользователь должен обладать привилегией ADMIN_PRIV.
Примеры
-
Создайте пользовательскую функцию UDF. Подробнее см. JAVA-UDF.
CREATE FUNCTION java_udf_add_one(int) RETURNS int PROPERTIES (
"file"="file:///path/to/java-udf-demo-jar-with-dependencies.jar",
"symbol"="org.apache.doris.udf.AddOne",
"always_nullable"="true",
"type"="JAVA_UDF",
"volatility"="immutable"
); -
Создайте пользовательскую функцию UDAF.
CREATE AGGREGATE FUNCTION simple_sum(INT) RETURNS INT PROPERTIES (
"file"="file:///pathTo/java-udaf.jar",
"symbol"="org.apache.doris.udf.demo.SimpleDemo",
"always_nullable"="true",
"type"="JAVA_UDF"
); -
Создайте пользовательскую функцию UDTF.
CREATE TABLES FUNCTION java_udtf(string, string) RETURNS array<string> PROPERTIES (
"file"="file:///pathTo/java-udaf.jar",
"symbol"="org.apache.doris.udf.demo.UDTFStringTest",
"always_nullable"="true",
"type"="JAVA_UDF"
); -
Создайте пользовательскую функцию-псевдоним. Подробнее см. Функция-псевдоним.
CREATE ALIAS FUNCTION id_masking(INT) WITH PARAMETER(id) AS CONCAT(LEFT(id, 3), '****', RIGHT(id, 4)); -
Создайте глобальную пользовательскую функцию-псевдоним.
CREATE GLOBAL ALIAS FUNCTION id_masking(INT) WITH PARAMETER(id) AS CONCAT(LEFT(id, 3), '****', RIGHT(id, 4)); -
Создайте Python UDF с характеристикой volatile. Для функций, зависящих от случайных значений, таких как
uuid.uuid4(), следует сохранять значение по умолчаниюvolatility = volatile; их нельзя ошибочно помечать какimmutable.CREATE TABLE cte_uuid_seed (id INT) ENGINE=OLAP DUPLICATE KEY(id)
DISTRIBUTED BY HASH(id) BUCKETS 1 PROPERTIES ("replication_num" = "1");
INSERT INTO cte_uuid_seed VALUES (1),(2),(3);
DROP FUNCTION IF EXISTS py_uuid_token(INT);
CREATE FUNCTION py_uuid_token(INT)
RETURNS STRING
PROPERTIES (
"type" = "PYTHON_UDF",
"symbol" = "py_uuid_token_impl",
"always_nullable" = "false",
"runtime_version" = "3.12.11",
"volatility" = "volatile"
)
AS $$
import uuid
def py_uuid_token_impl(x):
return f"{x}-{uuid.uuid4()}"
$$;
SET enable_cte_materialize = true;
SET inline_cte_referenced_threshold = 10;
WITH cte AS (SELECT id, py_uuid_token(id) AS token FROM cte_uuid_seed)
SELECT id, COUNT(DISTINCT token) AS distinct_tokens
FROM (SELECT id, token FROM cte UNION ALL SELECT id, token FROM cte) u
GROUP BY id ORDER BY id;Правильный результат:
+------+-----------------+
| id | distinct_tokens |
+------+-----------------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
+------+-----------------+Для этой функции следующее определение является неправильным:
DROP FUNCTION IF EXISTS py_uuid_token(INT);
CREATE FUNCTION py_uuid_token(INT)
RETURNS STRING
PROPERTIES (
"type" = "PYTHON_UDF",
"symbol" = "py_uuid_token_impl",
"always_nullable" = "false",
"runtime_version" = "3.12.11",
"volatility" = "immutable"
)
AS $$
import uuid
def py_uuid_token_impl(x):
return f"{x}-{uuid.uuid4()}"
$$;Выполните тот же запрос ещё раз:
WITH cte AS (SELECT id, py_uuid_token(id) AS token FROM cte_uuid_seed)
SELECT id, COUNT(DISTINCT token) AS distinct_tokens
FROM (SELECT id, token FROM cte UNION ALL SELECT id, token FROM cte) u
GROUP BY id ORDER BY id;Неправильный результат:
+------+-----------------+
| id | distinct_tokens |
+------+-----------------+
| 1 | 2 |
| 2 | 2 |
| 3 | 2 |
+------+-----------------+Почему это неправильно: Поскольку
py_uuid_tokenимеет характеристику volatile, каждый вызовuuid.uuid4()генерирует новое значение. Если функцию ошибочно пометить какvolatility = immutable, оптимизатор может счесть переписывание повторных обращений безопасным и выбрать план, в котором UDF вычисляется отдельно с каждой стороныUNION ALL. В результате одно и то же значениеidможет давать два разных значенияtoken, а результатCOUNT(DISTINCT token)меняется с1на2.