本文為您介紹如何分別通過Java UDF和Python UDF實現擷取不包含分隔字元的索引值對字串中指定Key對應的Value值。
命令說明
本樣本將註冊一個名稱為UDF_EXTRACT_KEY_VALUE的自訂函數,下面對命令格式和入參進行說明。
命令格式:
string UDF_EXTRACT_KEY_VALUE(string <s>, string <split1>, string <split2>, string <keyname>)
命令功能:
在字串s中使用split1分割出索引值對後,再根據split2分割索引值對獲得鍵和值,最後返回鍵keyname對應的值。
說明該UDF不適用於字串本身包含分隔字元的情況,如果需要處理該情況請使用擷取字串(含分隔字元)Value樣本。
參數說明:
s:源字串,STRING類型,必填。
split1:通過split1分割出索引值對,STRING類型,必填。
split2:對分割出來的索引值對使用split2進行分割,STRING類型,必填。
keyname:待擷取值所對應的鍵名稱,STRING類型,必填。
開發和使用步驟
1. 代碼開發
Java UDF 程式碼範例
package com.aliyun.rewrite; //package名稱,可以根據您的情況定義。
import com.aliyun.odps.udf.UDF;
import java.util.HashMap;
import java.util.Map;
public class ExtractKeyValue extends UDF{
private static final int KEY_VALUE_LENGTH = 2;
/**
* 使用split1分割出索引值對後,再根據split2分割索引值對
* @param str 源字串
* @param split1 分割出索引值對的標識
* @param split2 分割出key value的標識
* @param keyname 目標key名稱
* @return 目標value
*/
public String evaluate(String str, String split1, String split2, String keyname) {
try {
// 通過split1分割出索引值對
if (str == null || "".equals(str)) {
return null;
}
Map<String, String> keyValueCache = new HashMap<>(8);
String[] extractedKeyValues = str.split(split1);
// 對分割出來的索引值對使用split2進行進一步分割
for (String keyValue : extractedKeyValues) {
storeKeyValue(keyValueCache, keyValue, split2);
}
// 擷取目標key的value
return keyValueCache.get(keyname);
} catch (Exception e) {
return null;
}
}
/**
* 使用split對索引值對進行分割,將分割後的結果緩衝到keyValueCache中
*
* @param keyValueCache 分割後的索引值對緩衝
* @param keyValue 待分割的索引值對
* @param split 分割符
*/
private void storeKeyValue(Map<String, String> keyValueCache, String keyValue, String split) {
if (keyValue == null || "".equals(keyValue)) {
return;
}
String[] keyValueArr = keyValue.split(split);
if (keyValueArr.length == KEY_VALUE_LENGTH) {
keyValueCache.put(keyValueArr[0], keyValueArr[1]);
}
}
}
使用Java語言編寫UDF代碼必須繼承UDF類,本例中evaluate方法定義了四個string類型的入參和string類型的傳回值,輸入參數和傳回值的資料類型將作為SQL語句中UDF的函數簽名Signature,其他代碼規範和要求請參考:UDF開發規範與通用流程(Java)。
Python3 UDF 程式碼範例
from odps.udf import annotate
@annotate("string,string,string,string->string")
class ExtractKeyValue(object):
def evaluate(self, s, split1, split2, keyname):
if not s:
return None
# 使用 split1 分割出索引值對,再使用split2分割
key_value_cache = dict(kv.split(split2) for kv in s.split(split1) if kv)
# 擷取目標 key 的 value
return key_value_cache.get(keyname)
MaxCompute預設使用Python 2,可以在Session層級使用命令set odps.sql.python.version=cp37
開啟Python 3。更多python3 UDF規範請參考:UDF開發規範與通用流程(Python3)。
Python2 UDF 程式碼範例
#coding:utf-8
from odps.udf import annotate
@annotate("string,string,string,string->string")
class ExtractKeyValue(object):
def evaluate(self, s, split1, split2, keyname):
if not s:
return None
# 使用 split1 分割出索引值對,再使用split2分割
key_value_cache = dict(kv.split(split2) for kv in s.split(split1) if kv)
# 擷取目標 key 的 value
return key_value_cache.get(keyname)
當Python 2代碼中出現中文字元時,運行程式會報錯,必須在代碼頭部增加編碼聲明。固定聲明格式為#coding:utf-8
或# -*- coding: utf-8 -*-
,二者等效。更多python2 UDF規範請參考:UDF開發規範與通用流程(Python2)。
2. 上傳資源和註冊函數
完成UDF代碼開發和調試之後,將資源上傳至MaxCompute並註冊函數,本樣本註冊函數名:UDF_EXTRACT_KEY_VALUE。Java UDF上傳資源與註冊函數詳情步驟請參見:打包、上傳及註冊,Python UDF請參見:上傳及註冊。
3. 使用樣本
成功註冊UDF後,執行以下命令,從索引值對字串中擷取鍵為name的值。
set odps.sql.python.version=cp37; -- python3 UDF需要使用該命令開啟python3
SELECT UDF_EXTRACT_KEY_VALUE('name:zhangsan;age:21;',';',':','name');
執行結果如下:
+----------+
| _c0 |
+----------+
| zhangsan |
+----------+