Codificación de Apache Doris C++ UDF nativo (2)
1. Información medioambiental
1.1 Información de hardware
- Procesador : 4C
- Modelo de CPU : x64 (AVX2)
- Memoria : 10GB
- Disco duro : SSD de 66 GB
1.2 Información del software
- Versión de Linux : CentOS-7
- Versión de Apahce Doris : versión 0.15
- Versión de CodeBlocks : 20.03mingw
Dos, función TIME_TO_SEC personalizada
Implemente una UDF que pase un parámetro de tiempo y convierta su parte de tiempo en segundos.
2.1 Desarrollo e implementación del código fuente 1
2.1.1 Probar la función principal
//time_to_sec 的语法格式
// TIME_TO_SEC(time)
//语法格式说明
//time:传入时间,如果传入了日期部分,也不会管,只将时间部分转换成秒
//重点:是指将传入的时间转换成距离当天00:00:00的秒数,00:00:00为基数,等于 0 秒
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int time_to_sec(string text)
{
// clear other str
regex r("^((?![0-9]{2}:[0-9]{2}:[0-9]{2}).)*");
string time = regex_replace(text, r, "");
cout << time << endl;
// handle abnormal
if(time.length() != 8)
return NULL;
// get hh mm ss
int HH = atoi(time.substr(0,2).c_str());
int MM = atoi(time.substr(3,2).c_str());
int SS = atoi(time.substr(6,2).c_str());
// return sum sec
return HH*3600 + MM*60 + SS;
}
int main()
{
cout<<time_to_sec("1987-01-01 00:39:38")<<endl;
return 0;
}
2.1.2 Archivo de encabezado UDF
C++
#pragma once
#include "udf.h"
#include <bits/stdc++.h>
namespace doris_udf {
IntVal TIME_TO_SEC(FunctionContext* context, const StringVal& time);
/// --- Prepare / Close Functions ---
/// ---------------------------------
/// The UDF can optionally include a prepare function. The prepare function is called
/// before any calls to the UDF to evaluate values.
void AddUdfPrepare(FunctionContext* context, FunctionContext::FunctionStateScope scope);
/// The UDF can also optionally include a close function. The close function is called
/// after all calls to the UDF have completed.
void AddUdfClose(FunctionContext* context, FunctionContext::FunctionStateScope scope);
}
2.1.3 Archivo fuente UDF
C++
#include "time_to_sec.h"
namespace doris_udf {
IntVal TIME_TO_SEC(FunctionContext* context, const StringVal& time) {
// handle null
if (time.is_null) {
return IntVal::null();
}
// clear other str
using namespace std;
const string timestr((char *)time.ptr);
const regex r("^((?![0-9]{2}:[0-9]{2}:[0-9]{2}).)*");
const string replace_str = "";
string hms_time = regex_replace(timestr, r, replace_str);
// handle str abnormal
if(hms_time.length() != 8) {
return IntVal::null();
}
// get hh mm ss
int HH = atoi(hms_time.substr(0,2).c_str());
int MM = atoi(hms_time.substr(3,2).c_str());
int SS = atoi(hms_time.substr(6,2).c_str());
// return sum sec
return HH*3600 + MM*60 + SS;
}
/// --- Prepare / Close Functions ---
/// ---------------------------------
void AddUdfPrepare(FunctionContext* context, FunctionContext::FunctionStateScope scope) {
}
void AddUdfClose(FunctionContext* context, FunctionContext::FunctionStateScope scope) {
}
}
2.1.4 Resumen de los métodos de implementación
No se recomienda su uso, doris no es compatible con las funciones relacionadas con expresiones regulares, lo que provocará directamente que todos los nodos de be bloqueen.
2.2 Desarrollo e implementación del código fuente II
2.2.1 Probar la función principal
C++
//time_to_sec 的语法格式
// TIME_TO_SEC(time)
//语法格式说明
//time:传入时间,如果传入了日期部分,也不会管,只将时间部分转换成秒
//重点:是指将传入的时间转换成距离当天00:00:00的秒数,00:00:00为基数,等于 0 秒
#include <iostream>
#include <string>
#include <regex>
using namespace std;
int time_to_sec(string text)
{
// clear other str
string segSign = ":";
string::size_type pos1 = text.find(segSign);
if(pos1 == string::npos)
cout << "没找到!" << endl;
else
cout << "找到了!下标:" << pos1<<endl;
string time = text.substr(pos1-2,8);
cout << time << endl;
// handle abnormal
if(time.length() != 8)
return NULL;
// get hh mm ss
int HH = atoi(time.substr(0,2).c_str());
int MM = atoi(time.substr(3,2).c_str());
int SS = atoi(time.substr(6,2).c_str());
// return sum sec
return HH*3600 + MM*60 + SS;
}
int main()
{
cout<<time_to_sec("1987-01-01 00:39:38")<<endl;
return 0;
}
2.2.2 Archivo de encabezado UDF
C++
#pragma once
#include "udf.h"
#include <bits/stdc++.h>
namespace doris_udf {
IntVal TIME_TO_SEC(FunctionContext* context, const StringVal& time);
/// --- Prepare / Close Functions ---
/// ---------------------------------
/// The UDF can optionally include a prepare function. The prepare function is called
/// before any calls to the UDF to evaluate values.
void AddUdfPrepare(FunctionContext* context, FunctionContext::FunctionStateScope scope);
/// The UDF can also optionally include a close function. The close function is called
/// after all calls to the UDF have completed.
void AddUdfClose(FunctionContext* context, FunctionContext::FunctionStateScope scope);
}
2.2.3 Archivo fuente UDF
C++
#include "time_to_sec.h"
namespace doris_udf {
IntVal TIME_TO_SEC(FunctionContext* context, const StringVal& time) {
// handle null
if (time.is_null) {
return IntVal::null();
}
// clear other str
using namespace std;
string timestr((char *)time.ptr);
string segSign = ":";
string::size_type pos = timestr.find(segSign);
string hms_time;
if(pos == string::npos)
return IntVal::null();
else
hms_time = timestr.substr(pos-2,8);
// handle str abnormal
if(hms_time.length() != 8) {
return IntVal::null();
}
// get hh mm ss
int HH = atoi(hms_time.substr(0,2).c_str());
int MM = atoi(hms_time.substr(3,2).c_str());
int SS = atoi(hms_time.substr(6,2).c_str());
// return sum sec
IntVal result;
result.val = HH*3600 + MM*60 + SS;
return {
result.val};
}
/// --- Prepare / Close Functions ---
/// ---------------------------------
void AddUdfPrepare(FunctionContext* context, FunctionContext::FunctionStateScope scope) {
}
void AddUdfClose(FunctionContext* context, FunctionContext::FunctionStateScope scope) {
}
}
2.2.4 Resumen del Método de Implementación 2
Básicamente, la implementación API usando cadenas es simple, eficiente y tiene buena compatibilidad, finalmente se selecciona la segunda implementación.
3. Resultados de la compilación
4. Uso de funciones
4.1 Crear función UDF
CREATE FUNCTION
TIME_TO_SEC(String)
RETURNS INT PROPERTIES (
"symbol" = "_ZN9doris_udf11TIME_TO_SECEPNS_15FunctionContextERKNS_9StringValE",
"object_file" = "http://10.192.119.68:8088/udf/udf_samples/build/src/udf_samples/libtime_to_sec.so" );
4.2 Uso de funciones UDF
El SQL solidificado de Tableau que no era compatible con TIME_TO_SEC ahora puede ejecutarse normalmente.
V. Resumen
- El uso de UDF de C++ personalizado es consistente con el de funciones ordinarias, la única diferencia es que el alcance de las funciones integradas es global, mientras que el alcance de la UDF está dentro de la base de datos.
- No se recomienda utilizar C++ UDF nativo en la nueva versión posterior a 1.2, porque la compatibilidad es deficiente y GLIBC no funcionará una vez actualizado; se recomienda utilizar JAVA UDF
La codificación de la UDF C++ personalizada de Apache Doris ha finalizado. Si encuentra algún problema durante el proceso de revisión, deje un mensaje para comunicarse.