CQL(Cassandra Query Language)函数

CQL支持两大类功能:

  • 标量函数,其简单地取多个值并且用它产生输出。
  • 聚合函数,用于聚合来自SELECT语句的多行结果。

在这两种情况下,CQL提供了许多本地的“硬编码”函数以及创建新的用户定义函数的能力。

出于安全问题的考虑,默认情况下用户自定义函数是被禁止的(即使启用了,用户自定义函数的执行也是沙盒化执行并且恶意方法不被允许执行,但是没有沙盒是完美的,所以用户自定义方法是选择加入的)。请参见enable_user_defined_functionsin cassandra.yaml以启用它们。

函数通过其名称标识:

function_name ::=  [ keyspace_name '.' ] name

表量函数(Scalar functions)

本地函数(Native functions)

Cast

cast函数可用于将一种本地数据类型转换为另一种数据类型。

下表描述了cast函数支持的转换。Cassandra将默认忽略任何将数据类型转换为其自己的数据类型的转换。

From To
ascii text, varchar
bigint tinyint, smallint, int,float,double, decimal,varint,text,varchar
boolean text, varchar
counter tinyint, smallint, int,bigint,float, double,decimal,varint,text,varchar
date timestamp
decimal tinyint, smallint, int,bigint,float, double,varint,text,varchar
double tinyint, smallint, int,bigint,float, decimal,varint,text,varchar
float tinyint, smallint, int,bigint,double, decimal,varint,text,varchar
inet text, varchar
int tinyint, smallint, bigint,float,double, decimal,varint,text,varchar
smallint tinyint, int, bigint,float,double, decimal,varint,text,varchar
time text, varchar
timestamp date, text, varchar
timeuuid timestamp, date, text,varchar
tinyint tinyint, smallint, int,bigint,float, double,decimal,varint,text,varchar
uuid text, varchar
varint tinyint, smallint, int,bigint,float, double,decimal,text,varchar

转换严格依赖于Java的语义。例如,double值1将被转换为文本值'1.0'。例如:

SELECT avg(cast(count as double)) FROM myTable

Token

token函数允许计算给定分区键的tokentoken函数的确切签名取决于有关的表和集群使用的分区器。

token的参数类型取决于分区键列的类型。返回类型取决于正在使用的分区器:

  • 对于Murmur3Partitioner,返回类型是bigint
  • 对于RandomPartitioner,返回类型为varint
  • 对于ByteOrderedPartitioner,返回类型为blob

例如,在使用默认Murmur3Partitioner的集群中,如果表定义如下:

CREATE TABLE users (
    userid text PRIMARY KEY,
    username text,
)

那么token函数将采用类型为text的单个参数(在这种情况下,分区键是userid(没有聚集列,因此分区键与主键相同)),返回类型将是bigint

Uuid

uuid函数不使用参数,并生成适用于INSERTUPDATE语句的随机类型4 uuid。

Timeuuid 函数

now

now函数不使用参数,并且在协调器节点上生成新的唯一timeuuid(在使用它的语句被执行的时候)。注意,这个方法对插入是有用的,但在WHERE子句中很大程度上是无意义的。例如,以下形式的查询:

SELECT * FROM myTable WHERE t = now()

将不会返回任何设计结果,因为now()返回的值保证是唯一的。

minTimeuuid andmaxTimeuuid

minTimeuuid(resp.maxTimeuuid)函数采用时间戳值t(其可以是时间戳或日期字符串<timestamps>),并返回与具有时间戳t的最小(最大)可能时间戳相对应的伪时间戳。例如:

SELECT * FROM myTable
 WHERE t > maxTimeuuid('2013-01-01 00:05+0000')
   AND t < minTimeuuid('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'生成的时间流,并且基本上等于t> maxTimeuuid'2013-01-01 00:05 + 0000')

    注意:我们调用由minTimeuuid和maxTimeuuid伪造UUID生成的值,因为它们不遵守由RFC 4122指定的基于时间的UUID生成过程。特别地,这两种方法返回的值不是唯一的。这意味着您应该只使用这些方法进行查询(如上例所示)。插入这些方法的结果几乎肯定是一个坏主意。

时间转换函数(Time conversion functions)

提供了许多函数来将时间符,时间戳或日期“转换”成另一种本地类型。

函数名词 输入类型 Description
toDate timeuuid 将timeuuid参数转换为日期类型
toDate timestamp 将时间戳参数转换为日期类型
toTimestamp timeuuid 将timeuuid参数转换为时间戳类型
toTimestamp date 将date参数转换为时间戳类型
toUnixTimestamp timeuuid 将timeuuid参数转换为bigInt原始值
toUnixTimestamp timestamp 将时间戳参数转换为bigInt原始值
toUnixTimestamp date 将date参数转换为bigInt原始值
dateOf timeuuid 类似于toTimestamp(timeuuid)
unixTimestampOf timeuuid 类似于toUnixTimestamp(timeuuid)

Blob转换函数

提供了许多函数来将本地类型“转换”为进制数据(blob)。对于CQL支持的每个类型(一个值得注意的例外是blob),函数typeAsBlob接受一个类型的参数,并将其返回为一个blob相反,函数blobAsType采用64位blob参数,并将其转换为bigint值。因此,例如,bigintAsBlob(3)0x0000000000000003blobAsBigint0x0000000000000003)是3

用户自定义函数

用户自定义函数允许在Cassandra中执行用户提供的代码。 默认情况下,Cassandra支持在Java和JavaScript中定义函数。 通过向类路径添加JAR,可以添加对其他符合JSR 223的脚本语言(例如Python,Ruby和Scala)的支持。

UDF是Cassandra模式的一部分。 因此,它们会自动传播到集群中的所有节点。

UDF可以重载 - 即具有不同参数类型但具有相同函数名称的多个UDF。 例:

CREATE FUNCTION sample ( arg int ) ...;
CREATE FUNCTION sample ( arg text ) ...;

用户自定义函数易受所选择的编程语言的普遍问题的影响。 因此,实现应该对空指针异常,非法参数或任何其他潜在的异常源是安全的。 在函数执行期间的异常将导致整个语句失败。

使用复杂类型(如集合,元组类型和用户定义的类型)作为参数和返回类型是有效的。元组类型和用户定义的类型由DataStax Java驱动程序的转换函数处理。有关处理元组类型和用户定义类型的详细信息,请参阅Java驱动程序的文档。

函数的参数可以是字面量或term。也可以使用准备语句的占位符。

您可以使用双引号字符串语法来包含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"); $$;

用户自定义函数可以在SELECTINSERTUPDATE语句中使用。

隐式可用的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接口的定义可以在org.apache.cassandra.cql3.functions.UDFContextApache Cassandra源代码中找到。

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_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
    $$;

CREATE FUNCTION与可选的OR REPLACE关键字创建一个函数或替换具有相同签名的现有函数。如果具有相同签名的函数已经存在,则无OR REPLACECREATE FUNCTION将失败。

如果使用可选的IF NOT EXISTS关键字,则只有具有相同签名的另一个函数不存在时,才会创建函数。

OR REPLACEIF NOT EXISTS不能一起使用。

必须为每个函数定义使用空值调用的行为。有两个选项:

  1. RETURNS NULL ON NULL INPUT声明如果任何输入参数为null,函数将返回null。
  2. CALLED ON NULL INPUT声明函数将总是被执行。
函数签名

签名用于区分各个功能。签名包括:

  1. 完全限定的函数名 - 即keyspace加函数名
  2. 所有参数类型的连接列表

键空间名称,函数名称和参数类型受默认命名约定和大小写敏感度规则的约束。

函数属于一个键空间。如果在中未指定键空间,则使用当前键空间(即使用USE语句指定的键空间)。无法在系统键空间中创建用户定义的函数。

删除函数

删除函数使用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)。

使用DROP FUNCTION和可选的IF EXISTS关键字删除一个已存在的函数,如果该函数不存在也不会抛出异常。

聚合函数

聚合函数处理一组行。 它们接收每行的值,并为整个集合返回一个值。

如果正常列标量函数UDT字段,writetimettl与聚合函数一起选择,则为它们返回的值将是与查询匹配的第一行的值。

本地聚合函数

Count

count函数可用于计算查询返回的行。例:

SELECT COUNT (*) FROM plays;
SELECT COUNT (1) FROM plays;

它也可以用于计数给定列的非空值:

SELECT COUNT (scores) FROM plays;

Max and Min

maxmin函数可用于计算查询对给定列返回的最大值和最小值。例如:

SELECT MIN (players), MAX (players) FROM plays WHERE game = 'quake';

Sum

sum函数可用于对给定列的查询返回的所有值进行求和。例如:

SELECT SUM (players) FROM plays;

Avg

avg函数可用于计算查询为给定列返回的所有值的平均值。例如:

SELECT AVG (players) FROM plays;

用户自定义聚合函数

用户自定义的聚合允许创建自定义聚合函数。 聚合函数的常见示例为countminmax

每个聚合需要类型为STYPE的初始状态(INITCOND,默认为null)。状态函数的第一个参数必须具有类型STYPE状态函数的其余参数必须与用户定义的聚合参数的类型匹配。状态函数对每一行调用一次,状态函数返回的值变为新的状态。在处理所有行之后,以最后状态值作为其参数来执行可选的FINALFUNC

STYPE是强制的,以便能够区分可能的状态和/或finalfunction的重载版本(因为过载可以在聚合创建之后出现)。

用户定义的聚合可以在SELECT语句中使用。

用户定义聚合的完整工作示例(假定已使用USE语句选择了键空间):

CREATE OR REPLACE FUNCTION 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 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 average(int)
    SFUNC averageState
    STYPE tuple
    FINALFUNC averageFinal
    INITCOND (0, 0);

CREATE TABLE atable (
    pk int PRIMARY KEY,
    val int
);

INSERT INTO atable (pk, val) VALUES (1,1);
INSERT INTO atable (pk, val) VALUES (2,2);
INSERT INTO atable (pk, val) VALUES (3,3);
INSERT INTO atable (pk, val) VALUES (4,4);

SELECT average(val) FROM atable;

创建聚合函数

创建(或替换)用户定义的聚合函数使用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 ]

参见上面的一个完整的例子。

使用可选的OR REPLACE关键字创建AGGREGATE可创建聚合或替换具有相同签名的现有聚合。如果具有相同签名的聚合已存在,则无OR REPLACECREATE AGGREGATE将失败。

使用可选的IF NOT EXISTS关键字创建AGGREGATE可以创建聚合(如果它不存在)。

OR REPLACEIF 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_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关键字删除聚合(如果存在),如果具有签名的函数不存在,则不执行任何操作。

你可能感兴趣的:(--Cassandra)