Codificación de Apache Doris C++ UDF nativo (2)

1. Información medioambiental

1.1 Información de hardware

  1. Procesador : 4C
  2. Modelo de CPU : x64 (AVX2)
  3. Memoria : 10GB
  4. Disco duro : SSD de 66 GB

1.2 Información del software

  1. Versión de Linux : CentOS-7
  2. Versión de Apahce Doris : versión 0.15
  3. 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.

inserte la descripción de la imagen aquí

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.

inserte la descripción de la imagen aquí

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

inserte la descripción de la imagen aquí

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.

inserte la descripción de la imagen aquí

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.

Supongo que te gusta

Origin blog.csdn.net/ith321/article/details/132164442
Recomendado
Clasificación