前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >0518-如何在Impala中使用UDF获取SessionId

0518-如何在Impala中使用UDF获取SessionId

作者头像
Fayson
发布2019-11-27 18:53:54
1K0
发布2019-11-27 18:53:54
举报
文章被收录于专栏:Hadoop实操Hadoop实操

1

文档编写目的

Hive在UDF中获取sessionId可以直接使用提供的java API,但是该UDF如果移植到Impala中是无法获取到Impala连接的SessionId的,要想获取Impala的SessionId,需要用C++来编写。

2

实现思路

1. 根据Impala的源码可知可通过UDF参数中的context上下文对象来取得该SessionId,具体调用关系如下:

代码语言:javascript
复制
context->impl()->state()->session_id();

源码参考:

代码语言:javascript
复制
https://github.com/cloudera/Impala/blob/cdh5-2.9.0_5.12.2/be/src/udf/udf.h#L234
https://github.com/cloudera/Impala/blob/cdh5-2.9.0_5.12.2/be/src/runtime/runtime-state.h#L112

但是从源码中方法的注释上我们可以看到,context的impl()方法是不允许在UDA/UDF中使用的:

因此从官方提供的UDF依赖包impala-udf-devel安装后的库中也可以看到,并没有runtime-state.h等编译需要的依赖文件:

上图的五个声明文件是官方提供的UDF依赖。

按照正常的Impala用C++来实现UDF的流程,context->impl()->state()->session_id()将不能编译成功。

2. 因此在编译该UDF文件时,只能通过引入impala的源码和编译源码时需要的依赖来实现。

3

编译流程

1. 安装maven

下载maven:

代码语言:javascript
复制
wget http://mirror.cogentco.com/pub/apache/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.tar.gz

解压:

代码语言:javascript
复制
tar  -zxvf  apache-maven-3.6.0-bin.tar.gz
mv apache-maven-3.6.0 /usr/local/

修改/etc/profile添加到环境变量

代码语言:javascript
复制
export MAVEN_HOME=/usr/local/apache-maven-3.6.0

另外,如果有配anaconda的环境变量,暂时注释

验证maven:

2. 升级cmake

下载cmake-3.3.2-1.gf.el7.x86_64.rpm,并制作本地yum源,可到https://pkgs.org下载:

代码语言:javascript
复制
yum -y install cmake-3.3.2-1.gf.el7.x86_64

3. 安装高版本的g++编译器,impala源码中引入了c++11新特性,g++太低将无法编译,此处安装的是7.3.1版本。

代码语言:javascript
复制
sudo yum -y install centos-release-scl
sudo yum -y install devtoolset-7
scl enable devtoolset-7 bash

验证g++:

4. 下载Impala源码

代码语言:javascript
复制
wget https://codeload.github.com/cloudera/Impala/zip/cdh5-trunk

解压到当前目录

代码语言:javascript
复制
unzip Impala-cdh5-trunk.zip

将该目录添加到环境变量IMPALA_HOME

代码语言:javascript
复制
export IMPALA_HOME=/data/Impala-cdh5-trunk
代码语言:javascript
复制
source /etc/profile

5. 安装依赖

代码语言:javascript
复制
yum install -y redhat-lsb.x86_64
yum -y group install "Development Tools"
yum -y install git ant libevent-devel automake libtool flex bison gcc-c++ 
yum -y install openssl-devel make
yum -y install doxygen.x86_64 glib-devel python-devel bzip2-devel svn libevent-devel krb5-workstation
yum -y install openldap-devel db4-devel python-setuptools python-pip cyrus-sasl* postgresql postgresql-server ant-nodeps lzo-devel lzop
yum -y install boost boost-devel

6. 编译源码

进入impala源码目录

代码语言:javascript
复制
./buildall.sh -notests(该命令将编译整个工程,耗时较长)
或者执行:
./buildall.sh -cmake_only

上述命令执行完毕之后检查以下几点:

be/generated-sources下是否有gen-cpp目录及内部是否有文件:

toolchain下是否已下载thrift,glog,gflags,rapidjson依赖

7. 创建UDF文件

创建文件夹:

代码语言:javascript
复制
mkdir -p /root/impala-udf
mkdir -p /root/impala-udf/include

将源码包内相关包复制到include下

代码语言:javascript
复制
cp -r toolchain/gflags-2.2.0-p1/include/gflags/ /root/impala-udf/include
cp -r toolchain/glog-0.3.4-p3/include/glog/ /root/impala-udf/include
cp -r toolchain/rapidjson-0.11/include/rapidjson/ /root/impala-udf/include
cp -r toolchain/thrift-0.9.0-p11/include/thrift/ /root/impala-udf/include
cp -r be/generated-sources/gen-cpp /root/impala-udf/include
cp -r be/src/* /root/impala-udf/include

编写获取SessionId的C++代码:

编写getSessionId.h

代码语言:javascript
复制
#ifndef SAMPLES_UDF_H
#define SAMPLES_UDF_H
#include <udf/udf.h>
#include <udf/udf-internal.h>
using namespace impala_udf;

StringVal GetSessionId(FunctionContext* context);
#endif

编写getSessionId.cc

从下方的Impala的JAVA源码中可以看到,SessionId存放在TUniqueId对象的两个字段中,取出时需将其转换成16进制字符串:

此处从context中取得TuniqueId对象之后,将其转化成16进制。

代码语言:javascript
复制
#define __STDC_FORMAT_MACROS

#include <stdlib.h>
#include "getSessionId.h"
#include <udf/udf.h>
#include <udf/udf-internal.h>
#include <runtime/runtime-state.h>
#include <string.h>
#include <vector>

#include <stdio.h>
#include <inttypes.h>
#include<iostream>  


using namespace std; 
namespace impala{
 class TUniqueId;
}
using namespace impala_udf;

string DecIntToHexStr(unsigned long long num)
{
    string str;
    long long Temp = num / 16;
    int left = num % 16;
    if (Temp > 0)
        str += DecIntToHexStr(Temp);
    if (left < 10)
        str += (left + '0');
    else
        str += ('A' + left - 10);
    return str;
}

StringVal getSessionId(FunctionContext* context) {
 impala::TUniqueId id = context->impl()->state()->session_id();
 string idhi = DecIntToHexStr(id.hi);
 string idlo = DecIntToHexStr(id.lo);
 string sessionid = idhi +":"+ idlo;
 return *(new StringVal(sessionid.data()));
}

编写CMakeList.txt文件:

代码语言:javascript
复制
cmake_minimum_required(VERSION 3.2.3)
# where to put generated libraries
set(LIBRARY_OUTPUT_PATH "build")
# where to put generated binaries
set(EXECUTABLE_OUTPUT_PATH "build")

find_program(CLANG_EXECUTABLE clang++)

SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -ggdb")

include_directories("include")

# Function to generate rule to cross compile a source file to an IR module.
# This should be called with the .cc src file and it will generate a
# src-file-ir target that can be built.
# e.g. COMPILE_TO_IR(test.cc) generates the "test-ir" make target.
set(IR_COMPILE_FLAGS "-emit-llvm" "-O3" "-c" "-Iinclude")
function(COMPILE_TO_IR SRC_FILE)
  get_filename_component(BASE_NAME ${SRC_FILE} NAME_WE)
  set(OUTPUT_FILE "build/${BASE_NAME}.ll")
  add_custom_command(
    OUTPUT ${OUTPUT_FILE}
    COMMAND ${CLANG_EXECUTABLE} ${IR_COMPILE_FLAGS} ${SRC_FILE} -o ${OUTPUT_FILE}
    DEPENDS ${SRC_FILE})
  add_custom_target(${BASE_NAME}-ir ALL DEPENDS ${OUTPUT_FILE})
endfunction(COMPILE_TO_IR)

# Build the UDA/UDFs into a shared library.
add_library(getSessionId SHARED getSessionId.cc)

# Custom targest to cross compile UDA/UDF to ir
if (CLANG_EXECUTABLE)
COMPILE_TO_IR(getSessionId.cc )
endif(CLANG_EXECUTABLE)

# This is an example of how to use the test harness to help develop UDF and UDAs.
target_link_libraries(getSessionId ImpalaUdf)

8. 编译UDF

代码语言:javascript
复制
cmake .
代码语言:javascript
复制
make

在该目录的build下可看见编译好的文件

4

验证UDF

1. 将libgetSessionId.so上传hdfs的/tmp下:

代码语言:javascript
复制
hdfs dfs -put libgetSessionId.so /tmp

2. 创建UDF并验证

代码语言:javascript
复制
CREATE FUNCTION getSessionId() RETURNS string location '/tmp/libgetSessionId.so' symbol='getSessionId';

查询

代码语言:javascript
复制
select *,getSessionId() from test_table;

从上图中可以看出,在一次查询中获取的sessionId相同。

断开连接后再次连接查询:

可以看到,与上一次连接相比,SessionId已发生改变。

3. 但是impala不同于hive,在cmz中impala的log不能看到impala的Sessionid,因此,不容易验证获取的正确性,但impala的log中有查询的query_id。

此处我们将context->impl()->state()->session_id();改为context->impl()->state()->query_id();重新编译后上传创建getQueryId()。

代码语言:javascript
复制
CREATE FUNCTION getQueryId() RETURNS string location '/tmp/libgetQueryId.so' symbol='getQueryId';

查询:

代码语言:javascript
复制
select *,getQueryId() from test_table;

可看到在两次的查询中query_id不同,符合预期,并且与log日志中的query_id相同:

5

总结

IMPALA的UDF,不论是java还是c++,都不能操作session。当官方提供的UDF API不能够满足需求时,引入IMPALA的源码来编译时可行的。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-01-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Hadoop实操 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档