String 配置单元:如何按键对键/值字符串中的值求和

String 配置单元:如何按键对键/值字符串中的值求和,string,hive,key-value,String,Hive,Key Value,我有两个string列,其中包含key/value变量对。大概是这样的: column1 column2 a:1,b:2,c:3 a:5,c:3 a:12,b:4 a:9,b:3,d:5 如何将这些值(在现实生活中,我不知道我有多少个键,有些键只能在一列中找到)按特定键求和以得到以下结果: column12 a:6,b:2,c:6,d:0 a:21,b:7,c:0,d:5 或者这个: a b c d 6

我有两个
string
列,其中包含
key/value
变量对。大概是这样的:

    column1         column2
a:1,b:2,c:3         a:5,c:3
   a:12,b:4     a:9,b:3,d:5
如何将这些值(在现实生活中,我不知道我有多少个键,有些键只能在一列中找到)按特定键求和以得到以下结果:

         column12
  a:6,b:2,c:6,d:0
 a:21,b:7,c:0,d:5
或者这个:

 a  b  c  d
 6  2  6  0
21  7  0  5

谢谢你的帮助

方法之一是使用Hcatalog编写自定义mapreduce代码

下面的MR获取表1的输入列,并将结果列写入表2中(由于逻辑是在映射器中处理的,所以不需要使用reducer)

import java.io.IOException;
导入java.util.*;
导入org.apache.hadoop.fs.Path;
导入org.apache.hadoop.conf.*;
导入org.apache.hadoop.io.*;
导入org.apache.hadoop.mapreduce.*;
导入org.apache.hadoop.util.*;
导入org.apache.hcatalog.common.*;
导入org.apache.hcatalog.mapreduce.*;
导入org.apache.hcatalog.data.*;
导入org.apache.hcatalog.data.schema.*;
导入org.apache.commons.lang3.ArrayUtils;
公共类HCatSum扩展配置的实现工具{
公共静态类映射
延伸
制图员{
字符串列1;
字符串列2;
字符串val;
@凌驾
受保护的空图(
可写可比键,
HCatRecord值,
org.apache.hadoop.mapreduce.Mapper.Context)
抛出IOException、InterruptedException{
column1=(String)value.get(0);//a:1,b:2,c:3
column2=(String)value.get(1);//a:5,c:3
String colArray[]=(String[])ArrayUtils.addAll(
列1.拆分(“,”),列2.拆分(“,”);
HashMap hs=新的HashMap();
for(字符串标记:colArray){
字符串tokensplit[]=token.split(“:”);
字符串k=tokensplit[0];
intv=Integer.parseInt(tokensplit[1]);
如果(hs.containsKey(k)){
int prev=hs.get(k);
hs.put(k,prev+v);
}否则{
hs.put(k,v);
}
}
val=Arrays.toString(hs.entrySet().toArray());//[a=6,b=2,c=6]
HCatRecord记录=新的默认HCatRecord(1);
记录集(0,val);
write(null,record);
}
}
公共int运行(字符串[]args)引发异常{
配置conf=getConf();
args=新的GenericOptions解析器(conf,args).getRemainingArgs();
//获取输入和输出表名作为参数
字符串InputableName=args[0];
字符串outputTableName=args[1];
//假定为默认数据库
字符串dbName=null;
作业作业=新作业(配置,“HCatsum”);
HCatInputFormat.setInput(作业,
InputJobInfo.create(dbName,inputTableName,null));
job.setJarByClass(HCatSum.class);
job.setMapperClass(Map.class);
//作为输入的HCatalog记录
job.setInputFormatClass(HCatInputFormat.class);
//映射器以字符串作为键,以整数作为值
job.setMapOutputKeyClass(WritableComparable.class);
setMapOutputValueClass(DefaultHCatRecord.class);
//忽略reducer输出的键;将HCatalog记录作为
//价值观
job.setOutputKeyClass(WritableComparable.class);
job.setOutputValueClass(DefaultHCatRecord.class);
job.setOutputFormatClass(HCatOutputFormat.class);
HCatOutputFormat.setOutput(作业,
create(dbName,outputTableName,null));
HCatSchema s=HCatOutputFormat.getTableSchema(作业);
System.err.println(“信息:为写入而显式设置的输出架构:”
+(s),;
HCatOutputFormat.setSchema(作业,s);
返回(job.waitForCompletion(true)?0:1;
}
公共静态void main(字符串[]args)引发异常{
int exitCode=ToolRunner.run(新的HCatSum(),args);
系统退出(退出代码);
}
}
如何使用HCatalog运行MR(参考链接):


希望这有帮助。

这里有一个解决方案。这是一个有点黑客,但将工作,无论你有多少把钥匙

udf0.py

#/usr/bin/python

import sys
from collections import Counter

for line in sys.stdin:
    words = line.strip().split('\t')
    c = Counter()

    for word in words:
        d = {}
        s = word.split(',')
        for ss in s:
            k,v = ss.split(':')
            d[k] = int(v)

        c.update(d)

    print ','.join([str(k)+':'+str(v) for k,v in dict(c).iteritems()])
#!/usr/bin/python

import sys

for line in sys.stdin:
    w0, w1 = line.strip().split('\t')

    out = {}
    d = {}
    l = []

    s0 = w0.strip().split(',')
    s1 = w1.strip().split(',')

    for ss in s0:
        k,v = ss.split(':')
        d[k] = int(v)

    for ss in s1:
        l.append(ss)

    for keys in l:
        if d.get(keys, None) is not None:
            out[keys] = d[keys]
        else:
            out[keys] = 0

     print ','.join([str(k)+':'+str(v) for k,v in out.iteritems()])
udf1.py

#/usr/bin/python

import sys
from collections import Counter

for line in sys.stdin:
    words = line.strip().split('\t')
    c = Counter()

    for word in words:
        d = {}
        s = word.split(',')
        for ss in s:
            k,v = ss.split(':')
            d[k] = int(v)

        c.update(d)

    print ','.join([str(k)+':'+str(v) for k,v in dict(c).iteritems()])
#!/usr/bin/python

import sys

for line in sys.stdin:
    w0, w1 = line.strip().split('\t')

    out = {}
    d = {}
    l = []

    s0 = w0.strip().split(',')
    s1 = w1.strip().split(',')

    for ss in s0:
        k,v = ss.split(':')
        d[k] = int(v)

    for ss in s1:
        l.append(ss)

    for keys in l:
        if d.get(keys, None) is not None:
            out[keys] = d[keys]
        else:
            out[keys] = 0

     print ','.join([str(k)+':'+str(v) for k,v in out.iteritems()])
配置单元查询

add file /home/username/udf0.py;
add file /home/username/udf1.py;

SELECT TRANSFORM(dict, unique_keys)
       USING 'python udf1.py'
       AS (final_map STRING)
FROM (
  SELECT DISTINCT dict
    , CONCAT_WS(',', unique_keys) as unique_keys
  FROM (
    SELECT dict
      , COLLECT_SET(keys) OVER () AS unique_keys
    FROM (
      SELECT dict
        , keys
      FROM (
        SELECT dict
          , map_keys(str_to_map(dict)) AS key_arr
        FROM (
          SELECT TRANSFORM (col1, col2)
                 USING 'python udf0.py'
                 AS (dict STRING)
          FROM db.tbl ) x ) z
      LATERAL VIEW EXPLODE(key_arr) exptbl AS keys ) a ) b ) c
输出:

a:6,b:2,c:6,d:0
a:21,b:7,c:0,d:5
解释:

a:6,b:2,c:6,d:0
a:21,b:7,c:0,d:5

第一个UDF将获取您的字符串,将其转换为python字典并更新键(即,将具有匹配键的值添加到一起)。由于您不知道实际的键,您将知道需要从每个字典中提取键(
map\u keys()
,在配置单元查询中),分解表,然后将它们收集回一个唯一的集合。现在,您将拥有任何字典中所有可能的键。然后,您可以使用第二个UDF导入在第一个UDF中创建的字典,检查每个键是否存在,如果不存在,则将其值设置为零

假设每一行都有一个唯一的标识符“id”,下面的查询
应该有用

选择id,收集列表(CONCAT(键“:”,val))作为第12列
从…起
(  
选择id、key、SUM(val)作为val
从…起
(  
选择id,k1为键,k2为键,v1为val,v2为val
从…起
(  
选择id,str_-to-u-map(col1,',':')作为c1,str_-to-u-map(col2,',':')作为c2
从桌子上
)x
侧视图分解(c1)e1为k1,v1
侧视图分解(c2)e2为k2,v2
)y
)z