Hive UDTFの検証メモ(HiveMetaStore情報抽出)

##はじめに
* Qiita初投稿。不安はあるが何事もやってみる。
* 記述したコード類は例外処理などはあまり記載していない。
* ここに記載されている内容を試して被った損害については責任を負いかねますので、あらかじめご了承ください。

##概要
* HiveのDB/テーブル/列情報を、Hiveから直接HiveMetaStoreに接続して参照したい。
* Sqoopで定期的にMetaStoreからHiveにデータを取り込んだり、MetaStoreのテーブルを参照する外部表(※)を作成する方法など考えられるが、今回はあまり日本語情報を見かけないUDTFを使って実現したい。

※・・HiveMetaStoreに接続する外部表の例

```SQL:HiveのDB一覧参照(DBSテーブル).hql
CREATE EXTERNAL TABLE EXT_DBS(
  DB_ID bigint                   ,
  DESC varchar(4000)             ,
  DB_LOCATION_URI varchar(4000)  ,
  NAME varchar(128)              ,
  OWNER_NAME varchar(128)        ,
  OWNER_TYPE varchar(10)         ,
  CTLG_NAME varchar(256)
)
STORED BY 'org.apache.hive.storage.jdbc.JdbcStorageHandler'
TBLPROPERTIES (
  'hive.sql.database.type'='POSTGRES',
  "hive.sql.jdbc.driver"="org.postgresql.Driver",
  "hive.sql.jdbc.url"="jdbc:postgresql://vmhdpslv01.kotorish.com:5432/hive",
  "hive.sql.dbcp.username"="xxxx",
  "hive.sql.dbcp.password"="xxxxxx",
  'hive.sql.query'='select "DB_ID" as db_id,"DESC" as desc,"DB_LOCATION_URI" as db_location_uri,"NAME" as name,"OWNER_NAME" as owner_name,"OWNER_TYPE" as owner_type,"CTLG_NAME" as ctlg_name from "DBS"',
  "hive.sql.dbcp.maxActive"= "1"
);
```
→上記のようにDBに接続できるほか、HDFS上のファイルも指定可能。
参考：[LanguageManual DDL](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-ManagedandExternalTables "LanguageManual DDL")
→JDBCで他のDBに接続する際にJDBCストレージハンドラーを利用するため、Hive2.3.0以降で利用可能。([参考](https://www.progress.com/tutorials/jdbc/querying-external-tables-in-hive-using-native-jdbc-storage-handler "Querying external tables in Hive using native JDBC Storage Handler"))

##検証環境
* 検証環境構成図
![構成図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568280/9828b545-697f-b921-a514-3608eaefa1fd.jpeg)


* HDPサービス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568280/9f511d0a-44c3-f0ef-9131-9bc02b53f02c.png)

※リソース的にはかなり余裕がない状況で2台構成のHDPとなった(TIMELINE SERVICEがやたら落ちる・・)

##UDFの概要
* Hiveの組み込み関数では表現できないクエリに対応するために、Hiveでは以下の3種類のユーザー独自関数を使うことができる。
  * UDF：通常のユーザー関数。単一の入力値を受け取り、単一の出力値を生成するユーザー定義関数。
  * UDAF：ユーザー定義の集計関数。値のグループを受け入れ、単一の値を返すユーザー定義の集計関数。
  * UDTF：ユーザー定義の表関数。単一行で動作し、出力としてテーブルの複数の行を生成するユーザー定義テーブル生成関数。
* Java または Pythonで記述可能。
* 今回はJavaでUDTF作成して、動作を試す。

## UDTF作成の流れ
* Javaでコード記述、コンパイルしてJarファイルを作成する。
* JarファイルをHDFS上にアップロードする。
* HiveのCREATE FUNCTION句でJarファイルとClass名を指定してUDTFを作成する。(CREATE TEMPORARY FUNCTIONを実行した場合はセッション内のみ有効な一時的な関数を作成可能)

* 開発用のIDEは、自分は[Eclipse](https://mergedoc.osdn.jp/ "Pleiades All in One Eclipse ダウンロード")を利用した。

## 今回の検証内容
1.基本的なUDTFの動きを確認する。
2.応用編として、指定されたHiveMetaStoreのテーブルのレコードを取得するUDTFを作成する。

## 検証1.基本的なUDTFの動きを確認する。
* UDTFの作成方法は以下の通り。
  * 抽象クラス「GenericUDTF」を継承する。 
  * メソッド「initialize」「process」「close」を実装する。
  * initialize・・初期処理。出力列名、データ型などを設定する。
  * process・・・forwardメソッドに出力データを1行ずつ渡す。
  * close・・・・終了処理。DBの切断など必要に応じて行う。
* 検証1では、以下のように渡された値を2行にして返す関数を作成した。

```SQL:Sample1.hql
-- mydb.aには2レコード存在する。
select * from mydb.a;
+-------+--------+
| a.id  | a.val  |
+-------+--------+
| NULL  | abc    |
| NULL  | def    |
+-------+--------+

-- 関数getnameにx.valを渡す。
select getname(x.val) from mydb.a as x;
+---------------------------+
|         your_name         |
+---------------------------+
| Your Name is [abc] cnt=1  |
| Your Name is [abc] cnt=2  |
| Your Name is [def] cnt=1  |
| Your Name is [def] cnt=2  |
+---------------------------+

-- 関数getnameでは。1レコードの処理に対して2回forwardメソッドをcallしているため、
-- 上記のように合計4レコード抽出される。
```
* この検証で作成したUDTFサンプルコード

```Java:GetHiveMetaInfo4.java
package com.potato.refrain.test.hive;

import java.util.ArrayList;
import java.util.Iterator;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

public class GetHiveMetaInfo4 extends GenericUDTF {
	// Member
	private PrimitiveObjectInspector stringOI = null;
	private ArrayList<String> fieldNames ;
	private ArrayList<ObjectInspector> fieldOIs ;

	// ------------------------
	// 終了処理 
	// 処理する行がもうないことをUDTFに通知するために呼び出される。
	// クリーンアップや追加のforwardがあればここに記載する。
	// ------------------------
	@Override
	public void close() throws HiveException {
		// 終了時にConnectionをクローズする
	}
	// ------------------------
	// HiveでUDTF関数を実行すると初めに呼び出されるメソッド 
	// 列名やデータ型を設定する
	// ------------------------
	@Override
	public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
		// 引数を受け取る
		stringOI = (PrimitiveObjectInspector) argOIs[0];

		// Hiveで表示する列の設定をするための入れ物を用意
		this.fieldNames = new ArrayList<String>();
		this.fieldOIs   = new ArrayList<ObjectInspector>();

		this.fieldNames.add("Your_Name");
		this.fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector);//今回はString型として定義する

		return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames,fieldOIs);
	}
	// ------------------------
	// processメソッドでHive側にデータを返す
	// ------------------------
	@Override
	public void process(Object[] arg0) throws HiveException {
		Object obj[] = new Object[2];
		String name = stringOI.getPrimitiveJavaObject(arg0[0]).toString();

		ArrayList<Object []> rslt = new ArrayList<>(); 
		rslt.add(new Object[] {"Your Name is [" + name + "] cnt=1"});// 1行目
		rslt.add(new Object[] {"Your Name is [" + name + "] cnt=2"});// 2行目

		Iterator<Object[]> it = rslt.iterator();
		while(it.hasNext()) {
			Object rec = it.next();
			forward(rec);
		}

	}
}

```

* HDFS上の/tmp配下に、作成したjarファイルをアップロード

```shell:upload
[root@vmhdpmst01 ~]# hdfs dfs -put -f GetHiveMetaInfo.jar /tmp/
```

* Create Function

```SQL:CREATE_FUNC1.hql
create function getname as 'com.potato.refrain.test.hive.GetHiveMetaInfo4' using jar 'hdfs:///tmp/GetHiveMetaInfo.jar';
```

## 検証2.指定されたHiveMetaStoreのテーブルのレコードを取得するUDTFを作成する。

* サンプルコード

```Java:GetHiveMetaInfo3.javsa
package com.potato.refrain.test.hive;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableConstantStringObjectInspector;

public class GetHiveMetaInfo3 extends GenericUDTF {

	// Const
	final String DRIVER   = "org.postgresql.Driver";
	final String JDBC_CON = "jdbc:postgresql://vmhdpslv01.kotorish.com:5432/hive";
	final String USER     = "xxxxx";
	final String PASS     = "xxxxxx";

	// Member
	private Connection conn;
	private String TargetTBL;
	private ResultSet rs ;
	private ResultSetMetaData rsmd;
	private ArrayList<String> fieldNames ;
	private ArrayList<ObjectInspector> fieldOIs ;
	private HashMap<String,ObjectInspector> obimap ;

	// ------------------------
	// 終了処理 
	// 処理する行がもうないことをUDTFに通知するために呼び出される。
	// クリーンアップや追加のforwardがあればここに記載する。
	// ------------------------
	@Override
	public void close() throws HiveException {
		// 終了時にConnectionをクローズする
		try {
			this.conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	// ------------------------
	// HiveでUDTF関数を実行すると初めに呼び出されるメソッド
	// 列名やデータ型を設定する
	// ------------------------
	@Override
	public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
		// Hiveで表示する列の設定をするための入れ物を用意
		this.fieldNames = new ArrayList<String>();
		this.fieldOIs   = new ArrayList<ObjectInspector>();

		// Hiveから引数で渡されたテーブル名(=argOIsの一番目の要素)を取得する。※以下を参考にした
		// https://stackoverflow.com/questions/57314998/how-to-access-hive-udtf-parameters
		this.TargetTBL  = "\"" + ((WritableConstantStringObjectInspector) argOIs[0]).getWritableConstantValue().toString().toUpperCase() + "\"";

		// MetaStoreからデータ取得。エラーの場合は処理終了。
		if (!SetRS()) {
			return null;
		}

		// 列名とデータ型のMapを作成
		setMap();

		// 列名と列のデータ型情報をセット。
		try {
			for (int i = 1; i <= this.rsmd.getColumnCount(); i++ ) {
				String myType = this.rsmd.getColumnTypeName(i);
				String myClass = this.rsmd.getColumnClassName(i);
				fieldNames.add(this.rsmd.getColumnName(i)); // RecordSetのMeta情報から取得した列名をセット
				fieldOIs.add(getOIType(myType,myClass));     // 対象列のデータ型をHiveのデータ型として指定
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames,fieldOIs);
	}
	// ------------------------
	// processメソッドでHive側にデータを返す
	// ------------------------
	@Override
	public void process(Object[] arg0) throws HiveException {
		try {
			while(this.rs.next()) {
				// 1レコードをObject型の配列に格納してforwardを呼び出す(->Hiveにデータを返す)
				Object obj[] = new Object[this.rsmd.getColumnCount()];
				for (int i = 1; i <= this.rsmd.getColumnCount(); i++) {
					obj[i-1] = rs.getObject(this.rsmd.getColumnName(i));
				}
				forward(obj);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	// ------------------------
	// Hive Metastoreの情報を取得する部分。
	// ------------------------
	private boolean SetRS()  {

		boolean chk   = true;

		// Load Driver
		try {
			Class.forName("org.postgresql.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return false;
		}

		// Get Recordset Data
		try {
			this.conn              = DriverManager.getConnection(JDBC_CON, USER, PASS);
			String strSQL          = "SELECT * FROM " + this.TargetTBL;
			PreparedStatement stmt = conn.prepareStatement(strSQL);
			this.rs                = stmt.executeQuery() ;    // レコード取得
			this.rsmd              = this.rs.getMetaData();  // テーブル情報(列名、データ型など)取得
		} catch (Exception e) {
			System.out.println(e.getMessage());
			chk = false;
		}
		return chk;
	}
	// ------------------------
	// データ型定義
	// ------------------------
	private ObjectInspector getOIType(String strType,String strClass) throws Exception {
		ObjectInspector tmpOIType;

		// 変換マップのキーを指定して変換先のInspectorデータ型を取得。
		tmpOIType = (strType == "bytea") ? this.obimap.get(strType) : this.obimap.get(strClass);

		// 変換マップが不足していて変換先が判断できない場合(null)はString型のInspectorをセットする。
		tmpOIType = (tmpOIType == null) ? PrimitiveObjectInspectorFactory.javaStringObjectInspector : tmpOIType;
		return tmpOIType;
	}

	// ------------------------
	// ObjectInspector型への変換マップを作成しておく
	// ------------------------
	private void setMap() {
		this.obimap = new HashMap<>();
		this.obimap.put("bytea"               ,PrimitiveObjectInspectorFactory.javaByteObjectInspector);
		this.obimap.put("java.lang.Long"      ,PrimitiveObjectInspectorFactory.javaLongObjectInspector);
		this.obimap.put("java.lang.Integer"   ,PrimitiveObjectInspectorFactory.javaIntObjectInspector);
		this.obimap.put("java.math.BigDecimal",PrimitiveObjectInspectorFactory.javaHiveDecimalObjectInspector);
		this.obimap.put("java.lang.Float"     ,PrimitiveObjectInspectorFactory.javaFloatObjectInspector);
		this.obimap.put("java.lang.Double"    ,PrimitiveObjectInspectorFactory.javaDoubleObjectInspector);
		this.obimap.put("java.lang.String"    ,PrimitiveObjectInspectorFactory.javaStringObjectInspector);
		this.obimap.put("java.sql.Timestamp"  ,PrimitiveObjectInspectorFactory.javaTimestampObjectInspector);
		this.obimap.put("java.sql.Date"       ,PrimitiveObjectInspectorFactory.javaDateObjectInspector);
		this.obimap.put("java.sql.Time"       ,PrimitiveObjectInspectorFactory.javaTimestampObjectInspector);
		this.obimap.put("java.lang.Boolean"   ,PrimitiveObjectInspectorFactory.javaBooleanObjectInspector);
	}
}
```

* CREATE FUNCTION

```SQL:CREATE_FUNC2.sql
create function get_meta_info_pg as 'com.potato.refrain.test.hive.GetHiveMetaInfo3' using jar 'hdfs:///tmp/GetHiveMetaInfo.jar';
```

* 確認

```SQL:確認
-- Hive Meta Storeの"DBS"テーブルには、HiveのDBリストが格納されている。
-- get_meta_info_pgで情報取得できるか確認
SELECT get_meta_info_pg ('dbs');

+--------+------------------------+----------------------------------------------------+---------------------+-------------+-------------+------------+
| db_id  |          desc          |                  db_location_uri                   |        name         | owner_name  | owner_type  | ctlg_name  |
+--------+------------------------+----------------------------------------------------+---------------------+-------------+-------------+------------+
| 1      | Default Hive database  | hdfs://vmhdpmst01.kotorish.com:8020/warehouse/tablespace/managed/hive | default             | public      | ROLE        | hive       |
| 6      | NULL                   | hdfs://vmhdpmst01.kotorish.com:8020/warehouse/tablespace/managed/hive/sys.db | sys                 | hive        | USER        | hive       |
| 7      | NULL                   | hdfs://vmhdpmst01.kotorish.com:8020/warehouse/tablespace/managed/hive/information_schema.db | information_schema  | hive        | USER        | hive       |
| 11     | NULL                   | hdfs://vmhdpmst01.kotorish.com:8020/warehouse/tablespace/managed/hive/abc.db | abc                 | anonymous   | USER        | hive       |
| 12     | NULL                   | hdfs://vmhdpmst01.kotorish.com:8020/hivedata/mydb.db | mydb                | anonymous   | USER        | hive       |
| 21     | NULL                   | hdfs://vmhdpmst01.kotorish.com:8020/warehouse/tablespace/managed/hive/bbb.db | bbb                 | ken2        | USER        | hive       |
+--------+------------------------+----------------------------------------------------+---------------------+-------------+-------------+------------+
6 rows selected (5.714 seconds)
```

* 問題なく抽出できる事が確認できたので、DBSテーブル抽出用のViewを作成する。

```SQL:dbs_view.sql
CREATE VIEW v_dbs_info AS 
SELECT x.* FROM (SELECT get_meta_info_pg('dbs')) AS x;

-- 定義確認
desc v_dbs_info;
+------------------+------------+----------+
|     col_name     | data_type  | comment  |
+------------------+------------+----------+
| db_id            | bigint     |          |
| desc             | string     |          |
| db_location_uri  | string     |          |
| name             | string     |          |
| owner_name       | string     |          |
| owner_type       | string     |          |
| ctlg_name        | string     |          |
+------------------+------------+----------+

-- 確認
SELECT * FROM v_dbs_info;
+-------------------+------------------------+----------------------------------------------------+---------------------+------------------------+------------------------+-----------------------+
| v_dbs_info.db_id  |    v_dbs_info.desc     |             v_dbs_info.db_location_uri             |   v_dbs_info.name   | v_dbs_info.owner_name  | v_dbs_info.owner_type  | v_dbs_info.ctlg_name  |
+-------------------+------------------------+----------------------------------------------------+---------------------+------------------------+------------------------+-----------------------+
| 1                 | Default Hive database  | hdfs://vmhdpmst01.kotorish.com:8020/warehouse/tablespace/managed/hive | default             | public                 | ROLE                   | hive                  |
(省略)
```

## 気になる事
* Hiveログを確認すると、initializeメソッドが3回呼び出されていた。
* 返却する列名やデータ型をinitializeで指定しているので、複数回実行されては困る。
* 今後、原因調査していきたい。

```bash
[root@vmhdpmst01 hive]# cat /var/log/hive/hive-server2.out
MetaInfo3:initialize:入りました
MetaInfo3:initialize:入りました
MetaInfo3:initialize:入りました
MetaInfo3:process:入りました
```

## 最後に
* やはり外部表が使えるのであればUDTFよりも楽だと思う。
* とはいえ、工夫次第ではUDTFを使ってHiveがもう少し便利になると感じた。
* 機会があればもう少し深く調査していく。

## おまけ
・HiveのMetaStore情報からDB名、列名、データ型の一覧を取得するSQL(PostgreSQL)

```SQL:tableinfo.sql
SELECT
    db."NAME"        ,
    tbl."TBL_NAME"   ,
    col."COLUMN_NAME",
    col."TYPE_NAME"  ,
    col."INTEGER_IDX"
FROM 
   "DBS" db
   INNER JOIN "TBLS" tbl
     ON (db."DB_ID" = tbl."DB_ID")
   INNER JOIN "SDS" sds
     ON (tbl."SD_ID" = sds."SD_ID")
   INNER JOIN "COLUMNS_V2" col
     ON (col."CD_ID" = sds."CD_ID")
ORDER BY
    db."NAME"        ,
    tbl."TBL_NAME"   ,
    col."INTEGER_IDX",
    col."COLUMN_NAME"
;
        NAME        |         TBL_NAME          |               COLUMN_NAME               |   TYPE_NAME   | INTEGER_IDX
--------------------+---------------------------+-----------------------------------------+---------------+-------------
 default            | aaaasdfadfaf              | id                                      | int           |           0
 default            | aaaasdfadfaf              | val                                     | varchar(200)  |           1
 default            | abc                       | db_id                                   | string        |           0
 default            | abc                       | desc                                    | string        |           1
 default            | abc                       | db_location_uri                         | string        |           2
 default            | abc                       | name                                    | string        |           3
 default            | abc                       | owner_name                              | string        |           4
 default            | abc                       | owner_type                              | string        |
・・・・
(省略)
```

* UDTFでも同様に取得可能(しつこい？)

```Java:
package com.potato.refrain.test.hive;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDTF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;

public class GetHiveMetaInfo extends GenericUDTF {

	// Const
	final String DRIVER   = "org.postgresql.Driver";
	final String JDBC_CON = "jdbc:postgresql://vmhdpslv01.kotorish.com:5432/hive";
	final String USER     = "xxxxx";
	final String PASS     = "xxxxx";

	// Member
	private Connection conn;
	private ResultSet rs ;
	private ResultSetMetaData rsmd;
	private ArrayList<String> fieldNames ;
	private ArrayList<ObjectInspector> fieldOIs ;
	private HashMap<String,ObjectInspector> obimap ;
	final String SQL_GETMETA = ""
			+"SELECT"
			+"    db.\"NAME\"        ,"
			+"    tbl.\"TBL_NAME\"   ,"
			+"    col.\"COLUMN_NAME\","
			+"    col.\"TYPE_NAME\"  ,"
			+"    col.\"INTEGER_IDX\" "
			+"FROM                    "
			+"   \"DBS\" db           "
			+"   INNER JOIN \"TBLS\" tbl"
			+"     ON (db.\"DB_ID\" = tbl.\"DB_ID\")"
			+"   INNER JOIN \"SDS\" sds"
			+"     ON (tbl.\"SD_ID\" = sds.\"SD_ID\")"
			+"   INNER JOIN \"COLUMNS_V2\" col"
			+"     ON (col.\"CD_ID\" = sds.\"CD_ID\")"
			+"ORDER BY"
			+"    db.\"NAME\"        ,"
			+"    tbl.\"TBL_NAME\"   ,"
			+"    col.\"INTEGER_IDX\","
			+"    col.\"COLUMN_NAME\""
			+";";

	// ------------------------
	// 終了処理
	// 処理する行がもうないことをUDTFに通知するために呼び出される。
	// クリーンアップや追加のforwardがあればここに記載する。
	// ------------------------
	@Override
	public void close() throws HiveException {
		// 終了時にConnectionをクローズする
		try {
			this.conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	// ------------------------
	// HiveでUDTF関数を実行すると初めに呼び出されるメソッド
	// 列名やデータ型を設定する
	// ------------------------
	@Override
	public StructObjectInspector initialize(ObjectInspector[] argOIs) throws UDFArgumentException {
		// Hiveで表示する列の設定をするための入れ物を用意
		this.fieldNames = new ArrayList<String>();
		this.fieldOIs   = new ArrayList<ObjectInspector>();

		// MetaStoreからデータ取得。エラーの場合は処理終了。
		if (!SetRS()) {
			return null;
		}
		// 列名とデータ型のMapを作成
		setMap();
		// 列名と列のデータ型情報をセット。
		try {
			for (int i = 1; i <= this.rsmd.getColumnCount(); i++ ) {
				String myType = this.rsmd.getColumnTypeName(i);
				String myClass = this.rsmd.getColumnClassName(i);
				fieldNames.add(this.rsmd.getColumnName(i)); // RecordSetのMeta情報から取得した列名をセット
				fieldOIs.add(getOIType(myType,myClass));     // 対象列のデータ型をHiveのデータ型として指定
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames,fieldOIs);
	}
	// ------------------------
	// processメソッドでHive側にデータを返す
	// ------------------------
	@Override
	public void process(Object[] arg0) throws HiveException {
		try {
			while(this.rs.next()) {
				// 1レコードをObject型の配列に格納してforwardを呼び出す(->Hiveにデータを返す)
				Object obj[] = new Object[this.rsmd.getColumnCount()];
				for (int i = 1; i <= this.rsmd.getColumnCount(); i++) {
					obj[i-1] = rs.getObject(this.rsmd.getColumnName(i));
				}
				forward(obj);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	// ------------------------
	// Hive Metastoreの情報を取得する部分。
	// ------------------------
	private boolean SetRS()  {

		boolean chk   = true;

		// Load Driver
		try {
			Class.forName("org.postgresql.Driver");
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
			return false;
		}

		// Get Recordset Data
		try {
			this.conn              = DriverManager.getConnection(JDBC_CON, USER, PASS);
			String strSQL          = SQL_GETMETA;
			PreparedStatement stmt = conn.prepareStatement(strSQL);
			this.rs                = stmt.executeQuery() ;    // レコード取得
			this.rsmd              = this.rs.getMetaData();  // テーブル情報(列名、データ型など)取得
		} catch (Exception e) {
			System.out.println(e.getMessage());
			chk = false;
		}
		return chk;
	}
	// ------------------------
	// データ型定義
	// ------------------------
	private ObjectInspector getOIType(String strType,String strClass) throws Exception {
		ObjectInspector tmpOIType;

		// 変換マップのキーを指定して変換先のInspectorデータ型を取得。
		tmpOIType = (strType == "bytea") ? this.obimap.get(strType) : this.obimap.get(strClass);

		// 変換マップが不足していて変換先が判断できない場合(null)はString型のInspectorをセットする。
		tmpOIType = (tmpOIType == null) ? PrimitiveObjectInspectorFactory.javaStringObjectInspector : tmpOIType;
		return tmpOIType;
	}

	// ------------------------
	// ObjectInspector型への変換マップを作成しておく
	// ------------------------
	private void setMap() {
		this.obimap = new HashMap<>();
		this.obimap.put("bytea"               ,PrimitiveObjectInspectorFactory.javaByteObjectInspector);
		this.obimap.put("java.lang.Long"      ,PrimitiveObjectInspectorFactory.javaLongObjectInspector);
		this.obimap.put("java.lang.Integer"   ,PrimitiveObjectInspectorFactory.javaIntObjectInspector);
		this.obimap.put("java.math.BigDecimal",PrimitiveObjectInspectorFactory.javaHiveDecimalObjectInspector);
		this.obimap.put("java.lang.Float"     ,PrimitiveObjectInspectorFactory.javaFloatObjectInspector);
		this.obimap.put("java.lang.Double"    ,PrimitiveObjectInspectorFactory.javaDoubleObjectInspector);
		this.obimap.put("java.lang.String"    ,PrimitiveObjectInspectorFactory.javaStringObjectInspector);
		this.obimap.put("java.sql.Timestamp"  ,PrimitiveObjectInspectorFactory.javaTimestampObjectInspector);
		this.obimap.put("java.sql.Date"       ,PrimitiveObjectInspectorFactory.javaDateObjectInspector);
		this.obimap.put("java.sql.Time"       ,PrimitiveObjectInspectorFactory.javaTimestampObjectInspector);
		this.obimap.put("java.lang.Boolean"   ,PrimitiveObjectInspectorFactory.javaBooleanObjectInspector);
	}
}
```
* 結果

```SQL:Function作成～実行
-- FUNCTION作成
create function get_meta_info_view as 'com.potato.refrain.test.hive.GetHiveMetaInfo' using jar 'hdfs:///tmp/GetHiveMetaInfo.jar';

-- 確認
select get_meta_info_view();

-- 結果
+---------------------+----------------------------+------------------------------------------+----------------+--------------+
|        name         |          tbl_name          |               column_name                |   type_name    | integer_idx  |
+---------------------+----------------------------+------------------------------------------+----------------+--------------+
| default             | aaaasdfadfaf               | id                                       | int            | 0            |
| default             | aaaasdfadfaf               | val                                      | varchar(200)   | 1            |
| default             | abc                        | db_id                                    | string         | 0            |
| default             | abc                        | desc                                     | string         | 1            |
| default             | abc                        | db_location_uri                          | string         | 2            |
| default             | abc                        | name                                     | string         | 3            |
| default             | abc                        | owner_name                               | string         | 4            |
| default             | abc                        | owner_type                               | string         | 5            |
| default             | abc                        | ctlg_name                                | string         | 6            |
| default             | tbl1                       | id                                       | int            | 0            |
・・・
(省略)
```

以上.