函数
CQL 支持两大类函数
在这两种情况下,CQL 都提供了一些本地的“硬编码”函数,以及创建新的用户定义函数的能力。
|
默认情况下,出于安全考虑,用户定义函数默认情况下是禁用的(即使启用,用户定义函数的执行也是沙盒化的,并且“恶意”函数不应该被允许做坏事,但没有沙盒是完美的,因此使用用户定义函数是选择加入的)。请参阅 |
函数由其名称标识
function_name ::= [ keyspace_name'.' ] name
标量函数
原生函数
强制转换
cast 函数可用于将一种原生数据类型转换为另一种数据类型。
下表描述了 cast 函数支持的转换。Cassandra 会静默忽略将数据类型转换为其自身数据类型的任何强制转换。
| 从 | 到 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
转换严格依赖于 Java 的语义。例如,双精度值 1 将转换为文本值 '1.0'。例如
SELECT avg(cast(count as double)) FROM myTable
令牌
token 函数计算给定分区键的令牌。令牌函数的确切签名取决于所关注的表和集群使用的分区器。
token 的参数类型取决于分区键列类型。返回类型取决于定义的分区器
| 分区器 | 返回类型 |
|---|---|
Murmur3Partitioner |
|
RandomPartitioner |
|
ByteOrderedPartitioner |
|
例如,考虑以下表
CREATE TABLE users (
userid text PRIMARY KEY,
username text,
);
该表使用默认的 Murmur3Partitioner。token 函数使用单个参数 text,因为分区键是 userid,类型为 text。返回类型将为 bigint。
Timeuuid 函数
now
now 函数不接受任何参数,并在协调器节点上生成一个新的唯一 timeuuid,时间为函数被调用时的时间。请注意,此方法对于插入很有用,但在 WHERE 子句中基本上没有意义。
例如,以下形式的查询
SELECT * FROM myTable WHERE t = now();
将不会返回结果,因为设计使然,因为 now() 返回的值保证是唯一的。
current_timeuuid 是 now 的别名。
min_timeuuid 和 max_timeuuid
min_timeuuid 函数接受一个 timestamp 值 t,可以是时间戳或日期字符串。它返回一个伪timeuuid,对应于时间戳 t 的最小可能 timeuuid。max_timeuuid 的工作原理类似,但返回最大可能 timeuuid。
例如
SELECT * FROM myTable
WHERE t > max_timeuuid('2013-01-01 00:05+0000')
AND t < min_timeuuid('2013-02-02 10:00+0000');
将选择 timeuuid 列 t 在 '2013-01-01 00:05+0000' 之后且在 '2013-02-02 10:00+0000' 之前的所有行。子句 t >= maxTimeuuid('2013-01-01 00:05+0000') 仍然不会选择在 '2013-01-01 00:05+0000' 处生成的 timeuuid,并且本质上等效于 t > maxTimeuuid('2013-01-01 00:05+0000')。
|
|
日期时间函数
检索当前日期/时间
以下函数可用于检索函数被调用时的日期/时间
| 函数名称 | 输出类型 |
|---|---|
|
|
|
|
|
|
|
|
例如,可以使用以下方法检索过去两天的数据
SELECT * FROM myTable WHERE date >= current_date() - 2d;
时间转换函数
提供了一些函数,用于将 timeuuid、timestamp 或 date 转换为其他 native 类型。
| 函数名称 | 输入类型 | 描述 |
|---|---|---|
|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
|
|
将 |
Blob 转换函数
提供了一些函数,用于将原生类型转换为二进制数据或 blob。对于 CQL 支持的每种 类型,函数 type_as_blob 接受类型为 type 的参数,并将其作为 blob 返回。相反,函数 blob_as_type 接受一个 64 位 blob 参数,并将其转换为 bigint 值。例如,bigint_as_blob(3) 返回 0x0000000000000003,而 blob_as_bigint(0x0000000000000003) 返回 3。
数学函数
Cql 提供以下数学函数:abs、exp、log、log10 和 round。这些函数的返回类型始终与输入类型相同。
| 函数名称 | 描述 |
|---|---|
|
返回输入的绝对值。 |
|
返回 e 的输入次方。 |
|
返回输入的自然对数。 |
|
返回输入以 10 为底的对数。 |
|
使用舍入模式 |
集合函数
提供了一些函数,用于对集合列进行操作。
| 函数名称 | 输入类型 | 描述 |
|---|---|---|
|
|
获取 |
|
|
获取 |
|
|
获取集合参数中的元素数量。 |
|
|
获取集合参数中的最小元素。 |
|
|
获取集合参数中的最大元素。 |
|
数值 |
计算集合参数中所有元素的总和。返回值与输入集合元素的类型相同,因此如果值的总和超过类型所能表示的最大值,则存在数据类型溢出的风险。 |
|
数值 |
计算集合参数中所有元素的平均值。空集合的平均值为零。返回值与输入集合元素的类型相同,可能包含舍入和截断。例如, |
数据屏蔽函数
一些函数允许隐藏包含敏感数据的列的真实内容。
| 函数 | 描述 |
|---|---|
|
将第一个参数替换为 示例
|
|
将它的参数替换为相同类型的任意固定默认值。对于文本值,这将是 可变长度多值类型(如列表、集合和映射)被屏蔽为空集合。 固定长度多值类型(如元组、用户定义类型 (UDT) 和向量)通过将每个值替换为值类型的默认屏蔽值来屏蔽。 示例
|
|
将第一个参数替换为第二个参数上的替换值。替换值需要与被替换值具有相同的类型。 示例
|
|
返回第一个 示例
|
|
返回第一个 示例
|
|
返回包含第一个参数哈希值的 示例
|
向量相似度函数
一些函数允许获取浮点数向量的相似度得分。
| 函数 | 描述 |
|---|---|
|
计算两个相同维度的浮点数向量的余弦相似度得分。 示例
|
|
计算两个相同维度的浮点数向量的欧几里得距离。 示例
|
|
计算两个相同维度的浮点数向量的点积。 示例
|
用户定义的标量函数
用户定义函数 (UDF) 在 Cassandra 中执行用户提供的代码。默认情况下,Cassandra 支持在 Java 中定义函数。
UDF 是 Cassandra 架构的一部分,并自动传播到集群中的所有节点。UDF 可以 重载,因此具有不同参数类型的多个 UDF 可以具有相同的函数名。
|
JavaScript 用户定义函数在 Cassandra 4.1 中已被弃用。为了准备 Cassandra 5.0,它们的移除工作已经开始。有关更多信息,请参阅 CASSANDRA-17281、CASSANDRA-18252。 |
例如
CREATE FUNCTION sample ( arg int ) ...;
CREATE FUNCTION sample ( arg text ) ...;
UDF 容易受到所选编程语言的所有常见问题的困扰。因此,实现应该对空指针异常、非法参数或任何其他潜在的异常来源是安全的。函数执行期间的异常将导致整个语句失败。UDF 使用的有效查询是 SELECT、INSERT 和 UPDATE 语句。
复杂 类型(如集合、元组类型和用户定义类型)是 UDF 中有效的参数和返回值类型。元组类型和用户定义类型使用 DataStax Java 驱动程序转换函数。有关处理元组类型和用户定义类型的详细信息,请参阅 Java 驱动程序文档。
函数的参数可以是字面量或项。准备好的语句占位符也可以使用。
请注意使用双美元符号语法来包含 UDF 源代码。
例如
CREATE FUNCTION some_function ( arg int )
RETURNS NULL ON NULL INPUT
RETURNS int
LANGUAGE java
AS $$ return arg; $$;
SELECT some_function(column) FROM atable ...;
UPDATE atable SET col = some_function(?) ...;
CREATE TYPE custom_type (txt text, i int);
CREATE FUNCTION fct_using_udt ( udtarg frozen )
RETURNS NULL ON NULL INPUT
RETURNS text
LANGUAGE java
AS $$ return udtarg.getString("txt"); $$;
隐式可用的 udfContext 字段(或脚本 UDF 的绑定)提供了创建新的 UDT 和元组值所需的必要功能
CREATE TYPE custom_type (txt text, i int);
CREATE FUNCTION fct\_using\_udt ( somearg int )
RETURNS NULL ON NULL INPUT
RETURNS custom_type
LANGUAGE java
AS $$
UDTValue udt = udfContext.newReturnUDTValue();
udt.setString("txt", "some string");
udt.setInt("i", 42);
return udt;
$$;
UDFContext 接口的定义可以在 Apache Cassandra 源代码中找到,用于 org.apache.cassandra.cql3.functions.UDFContext。
public interface UDFContext
{
UDTValue newArgUDTValue(String argName);
UDTValue newArgUDTValue(int argNum);
UDTValue newReturnUDTValue();
UDTValue newUDTValue(String udtName);
TupleValue newArgTupleValue(String argName);
TupleValue newArgTupleValue(int argNum);
TupleValue newReturnTupleValue();
TupleValue newTupleValue(String cqlDefinition);
}
Java UDF 已经包含一些用于定义常见接口和类的导入。这些导入是
import java.nio.ByteBuffer;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.cassandra.cql3.functions.UDFContext;
import com.datastax.driver.core.TypeCodec;
import com.datastax.driver.core.TupleValue;
import com.datastax.driver.core.UDTValue;
请注意,这些便捷导入不适用于脚本 UDF。
CREATE FUNCTION 语句
创建新的用户定义函数使用 CREATE FUNCTION 语句
create_function_statement::= CREATE [ OR REPLACE ] FUNCTION [ IF NOT EXISTS]
function_name '(' arguments_declaration ')'
[ CALLED | RETURNS NULL ] ON NULL INPUT
RETURNS cql_type
LANGUAGE identifier
AS string arguments_declaration: identifier cql_type ( ',' identifier cql_type )*
例如
CREATE OR REPLACE FUNCTION somefunction(somearg int, anotherarg text, complexarg frozen<someUDT>, listarg list)
RETURNS NULL ON NULL INPUT
RETURNS text
LANGUAGE java
AS $$
// some Java code
$$;
CREATE FUNCTION IF NOT EXISTS akeyspace.fname(someArg int)
CALLED ON NULL INPUT
RETURNS text
LANGUAGE java
AS $$
// some Java code
$$;
带有可选 OR REPLACE 关键字的 CREATE FUNCTION 创建一个函数或用具有相同签名的函数替换现有函数。没有 OR REPLACE 的 CREATE FUNCTION 如果已经存在具有相同签名的函数,则会失败。如果使用可选的 IF NOT EXISTS 关键字,则只有在不存在具有相同签名的其他函数时才会创建函数。OR REPLACE 和 IF NOT EXISTS 不能一起使用。
必须为每个函数定义 null 输入值的处理方式
-
RETURNS NULL ON NULL INPUT声明如果任何输入参数为null,则函数将始终返回null。 -
CALLED ON NULL INPUT声明函数将始终被执行。
DROP FUNCTION 语句
删除函数使用 DROP FUNCTION 语句
drop_function_statement::= DROP FUNCTION [ IF EXISTS ] function_name [ '(' arguments_signature ')' ]
arguments_signature::= cql_type ( ',' cql_type )*
例如
DROP FUNCTION myfunction;
DROP FUNCTION mykeyspace.afunction;
DROP FUNCTION afunction ( int );
DROP FUNCTION afunction ( text );
如果存在多个具有相同名称但不同签名的重载函数,则必须在删除命令中指定函数的参数类型,即 arguments_signature。带有可选 IF EXISTS 关键字的 DROP FUNCTION 如果函数存在则删除函数,但如果不存在则不会抛出错误。
聚合函数
聚合函数作用于一组行。每个行的值作为输入,以返回为聚合的行集返回的单个值。
如果 normal 列、scalar functions、UDT 字段、writetime 或 ttl 与聚合函数一起被选中,则为它们返回的值将是与查询匹配的第一行的值。
原生聚合
Count
count 函数可用于计算查询返回的行数。
例如
SELECT COUNT (*) FROM plays;
SELECT COUNT (1) FROM plays;
它还可以计算给定列的非空值数量
SELECT COUNT (scores) FROM plays;
Max 和 Min
max 和 min 函数计算查询为给定列返回的最大值和最小值。
例如
SELECT MIN (players), MAX (players) FROM plays WHERE game = 'quake';
用户定义的聚合函数 (UDA)
用户定义的聚合允许创建自定义聚合函数。用户定义的聚合可以在 SELECT 语句中使用。
每个聚合函数需要一个类型为 STYPE 的初始状态,由 INITCOND 值定义(默认值为 null)。状态函数的第一个参数必须为 STYPE 类型。状态函数的其余参数必须与用户定义的聚合函数参数的类型匹配。状态函数对每行调用一次,状态函数返回的值将成为新的状态。处理完所有行后,可选的 FINALFUNC 将使用最后一个状态值作为其参数执行。
STYPE 值是强制性的,以便区分状态和/或最终函数的可能重载版本,因为重载可能在创建聚合函数后出现。
用户定义聚合函数的完整工作示例(假设已使用 USE 语句选择了一个键空间)
CREATE OR REPLACE FUNCTION test.averageState(state tuple<int,bigint>, val int)
CALLED ON NULL INPUT
RETURNS tuple
LANGUAGE java
AS $$
if (val != null) {
state.setInt(0, state.getInt(0)+1);
state.setLong(1, state.getLong(1)+val.intValue());
}
return state;
$$;
CREATE OR REPLACE FUNCTION test.averageFinal (state tuple<int,bigint>)
CALLED ON NULL INPUT
RETURNS double
LANGUAGE java
AS $$
double r = 0;
if (state.getInt(0) == 0) return null;
r = state.getLong(1);
r /= state.getInt(0);
return Double.valueOf(r);
$$;
CREATE OR REPLACE AGGREGATE test.average(int)
SFUNC averageState
STYPE tuple
FINALFUNC averageFinal
INITCOND (0, 0);
CREATE TABLE test.atable (
pk int PRIMARY KEY,
val int
);
INSERT INTO test.atable (pk, val) VALUES (1,1);
INSERT INTO test.atable (pk, val) VALUES (2,2);
INSERT INTO test.atable (pk, val) VALUES (3,3);
INSERT INTO test.atable (pk, val) VALUES (4,4);
SELECT test.average(val) FROM atable;
CREATE AGGREGATE 语句
创建(或替换)用户定义的聚合函数使用 CREATE AGGREGATE 语句
create_aggregate_statement ::= CREATE [ OR REPLACE ] AGGREGATE [ IF NOT EXISTS ]
function_name '(' arguments_signature')'
SFUNC function_name
STYPE cql_type:
[ FINALFUNC function_name]
[ INITCOND term ]
有关完整示例,请参见上文。
CREATE AGGREGATE 命令使用可选的 OR REPLACE 关键字创建聚合函数,或者用具有相同签名的聚合函数替换现有聚合函数。如果已存在具有相同签名的聚合函数,则不带 OR REPLACE 的 CREATE AGGREGATE 命令将失败。CREATE AGGREGATE 命令使用可选的 IF NOT EXISTS 关键字创建聚合函数(如果不存在)。OR REPLACE 和 IF NOT EXISTS 短语不能一起使用。
STYPE 值定义状态值的类型,必须指定。可选的 INITCOND 定义聚合函数的初始状态值;默认值为 null。对于声明为 RETURNS NULL ON NULL INPUT 的状态函数,必须指定非空 INITCOND。
SFUNC 值引用一个现有的函数,用作修改状态的函数。状态函数的第一个参数必须为 STYPE 类型。状态函数的其余参数必须与用户定义的聚合函数参数的类型匹配。状态函数对每行调用一次,状态函数返回的值将成为新的状态。对于声明为 RETURNS NULL ON NULL INPUT 并使用 null 调用的状态函数,状态不会更新。处理完所有行后,可选的 FINALFUNC 将使用最后一个状态值作为其参数执行。它必须只接受一个类型为 STYPE 的参数,但 FINALFUNC 的返回类型可能不同。声明为 RETURNS NULL ON NULL INPUT 的最终函数意味着如果最后一个状态为 null,则聚合函数的返回值将为 null。
如果未定义 FINALFUNC,则聚合函数的总体返回类型为 STYPE。如果定义了 FINALFUNC,则为该函数的返回类型。
DROP AGGREGATE 语句
删除用户定义的聚合函数使用 DROP AGGREGATE 语句
drop_aggregate_statement::= DROP AGGREGATE [ IF EXISTS ] function_name[ '(' arguments_signature ')'
]
例如
DROP AGGREGATE myAggregate;
DROP AGGREGATE myKeyspace.anAggregate;
DROP AGGREGATE someAggregate ( int );
DROP AGGREGATE someAggregate ( text );
DROP AGGREGATE 语句删除使用 CREATE AGGREGATE 创建的聚合函数。如果存在多个具有相同名称但签名不同的重载聚合函数,则必须指定要删除的聚合函数的参数类型。
DROP AGGREGATE 命令使用可选的 IF EXISTS 关键字删除聚合函数(如果存在),如果不存在具有该签名的函数,则不执行任何操作。
