vertica用户自定义扩展开发

开发用户定义的扩展(UDx)

用户自定义的扩展(UDx)是包含在外部共享库中的函数,这些库是使用Vertica SDK 以C ++,Python,Java或R开发的。外部库是使用CREATE LIBRARY语句在Vertica目录中定义的。它们最适合那些难以在SQL中执行的分析操作,或者需要经常执行但速度存在性能瓶颈的的分析操作。

UDx的主要优势是:

  • 它们可以在可以使用内部功能的任何地方使用。
  • 它们充分利用了Vertica的分布式计算功能。扩展通常在集群中的每个节点上并行执行。
  • Vertica处理UDx库向各个节点的分发。您只需要将库复制到启动器节点即可。
  • Vertica可以为您解决开发分布式分析代码的所有复杂问题。您的主要编程任务是读取数据,进行处理,然后使用Vertica SDK API 将其输出。

关于开发UDx,需要牢记以下几点:

  • 可以使用C ++,Python,Java和R等编程语言来开发UDx。(并非所有UDx类型都支持所有语言。)
  • 用Java,Python和R编写的UDx始终在隔离模式下运行
  • 用C ++开发的UDx可以选择以非隔离模式运行,这意味着它们可以直接在Vertica数据库进程中加载和运行。此选项提供最低的开销和最高的速度。但是,UDx代码中的任何错误都可能导致数据库不稳定。在将它们部署到实时环境中之前,您必须彻底测试打算以非隔离模式运行的所有UDx。考虑一下,无限制地运行C ++ UDx所带来的性能提升是否值得因为有缺陷的UDx可能引起的潜在数据库不稳定。
  • 因为UDx在Vertica群集上运行,所以它可以从数据库进程中节省处理器时间和内存。消耗大量计算资源的UDx会对数据库性能产生负面影响。
结构体

每种UDx类型都包含两个类。
主类完成主要工作(转换,聚合等)。该类通常至少具有三种方法:一种用于设置,一种用于清除(释放保留的资源),一种用于实际工作。有时会定义其他方法。
主处理方法接收ServerInterface类的实例作为参数。底层的Vertica SDK代码使用此对象来回调用Vertica进程,例如分配内存。您可以使用此类在UDx执行期间写入服务器日志。

第二个类是单例工厂。它定义了一个生成主类实例的方法,并且可能定义了其他方法来管理参数。

实施UDx时,必须将这两个类都子类化。

搭建开发环境

可选择在vertica非生产环境上进行开发测试UDx。

C++开发环境要求

至少,您需要在开发计算机上安装以下内容:

  • g ++及其相关的工具链,例如ld。
  • Vertica SDK文件。
Java开发环境要求
  • 与数据库主机上已安装的Java版本匹配的Java开发工具包(JDK)版本。
  • Vertica SDK文件。
Python开发环境要求

Vertica不需要任何其他文件或软件包。您可以使用文本编辑器在任何系统上开发Python UDx。

R开发环境要求

Vertica不需要任何其他文件或软件包。您可以使用文本编辑器在任何系统上开发R UDx。

UDx示例

在/opt/vertica/sdk/example目录下,有各种语言的UDx示例,可进行参考编写。

使用C++ SDK进行开发

可以以C++ 11编写各种类型的隔离或非隔离的UDx,其开发流程如下:
在这里插入图片描述

设置C++ SDK

SDK文件位于Vertica服务器根目录(通常为/opt/vertica/sdk)下的include子目录中,其中包含编译UDx库所需的头和源文件。

编译UDx时,include目录中有两个文件:

  • Vertica.h是SDK的主要头文件。您的UDx代码需要包含此文件才能找到SDK的定义。
  • Vertica.cpp 包含需要编译到UDx库中的支持代码。

大部分Vertica SDK API在VerticaUDx.h头文件中定义(该文件包含在头Vertica.h文件中)。

编译C++库

GNU g ++是唯一支持编译UDx库的编译器。应始终在与Vertica群集上使用的版本相同的的Linux上编译UDx代码。

编译库时,必须始终:

  • 将-shared和-fPIC标志传递给链接器。最简单的方法是在编译和链接库时将这些标志传递给g ++。
  • 当不使用宏参数时,使用-Wno-unused-value标志禁止显示警告。如果不使用此标志,则可能会收到 "逗号的左操作数无效"的警告。
  • 编译sdk/include/Vertica.cpp并将其链接到您的库中。该文件包含支持例程,可帮助您的UDx与Vertica通信。最简单的方法是将其包含在g++命令中以编译您的库。Vertica将此文件作为C++源而不是库提供,以限制库兼容性问题。
  • 使用g++ 的-I标志,将Vertica SDK include目录添加到搜索路径中。

示例:将MyUDx.cpp编译生成MyUDx.so文件

g++ -I /opt/vertica/sdk/include -Wall -shared -Wno-unused-value -fPIC -o MyUDx.so MyUDx.cpp /opt/vertica/sdk/include/Vertica.cpp
C++ SDK的数据类型

可参考:https://www.vertica.com/docs/9.1.x/HTML/CppSDK/annotated.htm


以UDSF(自定义标量函数) 为例,介绍使用C++开发UDx的开发的流程。

总述
UDSF类概述

您可以通过继承Vertica的SDK定义的ScalarFunction和ScalarFunctionFactory两个类创建UDSF 。

ScalarFunction

该ScalarFunction类是UDSF的核心。您的子类必须定义processBlock()执行标量运算的方法。它可以定义设置和删除功能的函数。

该processBlock()方法执行您希望UDSF执行的所有处理。当用户在SQL语句中调用函数时,Vertica会将函数参数中的数据捆绑在一起,并将其传递给processBlock()。

processBlock()方法的输入和输出由BlockReader和BlockWriter类的对象提供。它们定义了用于读取UDSF的输入数据和写入输出数据的方法。

开发UDSF的大部分工作是写作processBlock()。这就是函数中所有处理的地方。您的UDSF应该遵循以下基本模式:

  • BlockReader使用特定于数据类型的方法从对象中读取一组参数。
  • 以某种方式处理数据。
  • 使用BlockWriter类的特定于数据类型的方法之一输出结果值。
  • 通过调用BlockWriter.next()和BlockReader.next()前进到输出和输入的下一行。

这个过程一直持续到没有更多的数据行要读取(BlockReader.next()返回false)为止。

您必须确保processBlock()读取其输入中的所有行,并为每行输出一个值。否则可能会损坏Vertica读取以获取UDSF输出的数据结构。

ScalarFunctionFactory

该ScalarFunctionFactory类告诉Vertica有关UDSF的元数据:它的参数和数据类型数量,以及其返回值的数据类型。它还实例化的子类ScalarFunction。

必须在ScalarFunctionFactory子类中实现以下方法:

  • createScalarFunction()实例化一个ScalarFunction子类。
  • getPrototype()告诉Vertica UDSF的参数和返回类型。除了一个ServerInterface对象外,此方法还获得两个ColumnTypes对象。该函数所需要做的就是在这两个对象上调用类函数以构建参数列表和单个返回值类型。
  • 如果您的函数返回列大小(长度可以变化的返回数据类型,例如VARCHAR)或需要精度的值,则必须实现 getReturnType()。Vertica调用此方法以查找结果每一行中返回的数据的长度或精度。此方法的返回值取决于您的processBlock()方法返回的数据类型。getReturnType()方法的输入是一个SizedColumnTypes对象,其中包含输入参数类型及其长度。该对象将被传递到您的processBlock()函数的实例。您的实现getReturnType()必须从此输入中提取数据类型和长度,并确定输出行的长度或精度。然后,它将此信息保存在SizedColumnTypes该类的另一个实例中。
  • 如果您的函数接受其他参数,需要定义一个获取参数的函数getParameterType。它从一个对象获取其参数值,该对象可以从传递给您的处理方法的对象中获得。

定义工厂类后,您需要调用RegisterFactory宏。该宏实例化了工厂类的成员,因此Vertica可以与其进行交互并提取其中包含的有关UDSF的元数据。

C++ UDSF API

可参考:ScalarFunction and ScalarFunctionFactory C++ Interface

示例

以下示例显示了一个非常基本的子类,ScalarFunction名为Add2ints。顾名思义,它将两个整数相加,返回一个整数结果。它还演示了包括主Vertica SDK头文件(Vertica.h)以及如何使用Vertica名称空间。尽管不是必需的,但使用名称空间可以使您不必在每个Vertica SDK类引用之前添加前缀Vertica::。

ScalarFunction :

// Include the top-level Vertica SDK file
#include "Vertica.h"
// Using the Vertica namespace means we don't have to prefix all
// class references with Vertica::
using namespace Vertica;
/* 
 * ScalarFunction implementation for a UDSF that adds 
 * two numbers together. 
 */
class Add2Ints : public ScalarFunction
 {
    public:
   /*
    * This function does all of the actual processing for the UDF.
    * In this case, it simply reads two integer values and returns
    * their sum.
    *
    * The inputs are retrieved via arg_reader
    * The outputs are returned via arg_writer
    */
    virtual void processBlock(ServerInterface &srvInterface,
                            BlockReader &arg_reader,
                            BlockWriter &res_writer)
    {
    // While we have input to process
        do {
            // Read the two integer input parameters by calling the
            // BlockReader.getIntRef class function
            const vint a = arg_reader.getIntRef(0);
            const vint b = arg_reader.getIntRef(1);
            // Call BlockWriter.setInt to store the output value, which is the
            //  two input values added together
            res_writer.setInt(a+b);
            // Finish writing the row, and advance to the next output row
            res_writer.next();
            // Continue looping until there are no more input rows
        } while (arg_reader.next());
  }
};

ScalarFunctionFactory :

/*
 * This class provides metadata about the ScalarFunction class, and
 * also instantiates a member of that class when needed.
 */
class Add2IntsFactory : public ScalarFunctionFactory
{
	// return an instance of Add2Ints to perform the actual addition.
	virtual ScalarFunction *createScalarFunction(ServerInterface &interface)
	{
		// Calls the vt_createFuncObj to create the new Add2Ints class instance.
		return vt_createFuncObj(interface.allocator, Add2Ints);
	}
	// This function returns the description of the input and outputs of the
	// Add2Ints class's processBlock function.  It stores this information in
	// two ColumnTypes objects, one for the input parameters, and one for
	// the return value.
	virtual void getPrototype(ServerInterface &interface,
	ColumnTypes &argTypes,
	ColumnTypes &returnType)
	{
		// Takes two ints as inputs, so add ints to the argTypes object
		argTypes.addInt();
		argTypes.addInt();
		// returns a single int, so add a single int to the returnType object.
		// Note that ScalarFunctions *always* return a single value.
		returnType.addInt();
	}
};

RegisterFactory宏:

使用RegisterFactory宏注册一个ScalarFunctionFactory子类。该宏实例化工厂类,并使其中包含的元数据可供Vertica访问。要调用此宏,请将其传递给您的工厂类的名称。

RegisterFactory(Add2IntsFactory);

对于获取其他参数的示例,可参考:
C++ Example: Defining Parameters
对于获取返回列长度或精度的getReturnType()函数,UDSF处并没有示例,可参考UDTF处的示例:关注getReturnType的定义

之后就可以编译,创建库,创建函数来使用该UDx。

本文主要参考:Developing User-Defined Extensions (UDxs)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值