UDF示例:获取字符串(不含分隔符)Value

本文为您介绍如何分别通过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 |
+----------+