hive中用python脚本做小表的关联

hive的表关联效率较低,应用中大表对外键小表的outer关联效率无法忍受,如果用python做个脚本在hive中处理很好。

forhive.py关联的两个函数

memjoin读入数据文件到内存,与hive中的数据表进行join,需要7个参数,如果关联多个文件则7+6x个参数
   第一个参数 tabledefinefile 文件中需给出数据表的定义,数据表名称 : 字段名称1,>字段名称2,...,字段名称n,参考tabledef.txt,数据表名称可以是后面文件名,如果不完全
一样文件路径需要包含数据表名称字样,被处理的数据表名称用的是stdin(一般为pvlog数>据表)
   第二个参数 joinfields hive数据表要关联的字段列表,用逗号,连接
   第三个参数 filepath 关联数据表的文件,如果是本地需要add file,如果是hdfs不需add file可直接读取
   第四个参数 keyfields 关联数据表中关联字段列表,用逗号,连接
   第五个参数 valuefields 关联数据表要输出的字段列表,用逗号,连接
   第六个参数 innerorouter 取值为inner时为inner join,取值为outer时为outer join>,outer join时hive数据表中每个记录都有输出
   第七个参数 defaultvalue 当outer join时如果关联数据表中没有取值用的缺省值
   之后的参加tabledefinefile只在一个文件中定义,该参数不需重复,再增加6个参数可>用于关联多个文件
memjoinindex读入数据文件到内存,与hive中的数据表进行join,需要6个参数,如果关联>多个文件则6x个参数
   与memjoin实现同样功能,参数用的是索引号,从0开始计

   没有tabledefinefile参数,6个参数与memjoin后面6个参数相同,字段名称全部改为字>段索引号

使用例子:

select *

 from
 (
  MAP id,fielda1,fielda2

  USING './forhive.py memjoin tabledef.txt id hdfs:/tableb/* id fieldb1,fieldb2 outer ,0,0 '
  AS id,fielda1,fielda2,

      fieldb1,fieldb2
  from (
   select *
   from tablea 
  ) a
 ) a;

python源码:

#!/usr/bin/python
#coding:utf8

import sys
import subprocess

#用于hive中处理数据的python函数集
#本python包主要完成基于内存的join

#分隔符
parametersep=","
valuesep="\t"
keyvaluesep=" : "

#初始化
def initMapValues(joinindex, filepath, keyindex, valueindex, innerorouter, defaultvalue, others):
    joinnumber = 0
    joinindexs = []
    joindicts = []
    innerorouters = []
    defaults = []
    while(True):
        joinindexs.append( [int(index) for index in joinindex.split(parametersep)] )
        joindicts.append( readFileToDict(filepath,keyindex,valueindex) )
        if(innerorouter != "inner" and innerorouter != "outer"):
            raise Exception, "error: innerorouter parameter error, must be inner or outer"
        innerorouters.append( innerorouter == "outer" )
        defaults.append( defaultvalue.split(parametersep) )
        joinnumber += 1
        if(len(others) <= 0):
            break
        if(len(others) < 6 ):
            raise Exception, "error: the number of parameters must be 6 multiple"
        joinindex, filepath, keyindex, valueindex, innerorouter, defaultvalue = others[:6]
        others = others[6:]
    return (joinnumber,joinindexs,joindicts,innerorouters,defaults)

#读文件到内存,之后处理标准输入的每行记录,内存表是要关联表的外键表,可以是多个字段的外键
#joinindex为标准输入的字段索引号,多个字段索引号的用逗号,分隔
#filepath是要读入内存的文件路径
#keyindex是文件中用于join的key字段索引号,多个字段索引号的用逗号,分隔,应与joinindex索引个数相同
#valueindex是文件中join后提取的字段索引号,多个字段索引号的用逗号,分隔
#innerorouter "inner"为inner join,"outer"为outer join
#defaultvalue是如果是outer join,对于没有外键提供的缺省值
#others为支持多个表同时join,其他表的joinindex,filepath,keyindex,valueindex,innerorouter,defaultvalue,...
def mapValueByIndex(args):
    joinnumber,joinindexs,joindicts,isouters,defaults = initMapValues(args[0], args[1], args[2], args[3], args[4], args[5], args[6:])
    for line in sys.stdin:
        line = line.strip()
        fields = line.split(valuesep)
        output = fields
        isprint = True
        for index in range(joinnumber) :
            value = [ fields[i] for i in joinindexs[index] ]
            getvalue = joindicts[index].get(valuesep.join(value))
            if( not getvalue ):
                if( not isouters[index] ):
                    isprint = False
                    break;
                else:
                    getvalue = defaults[index]
            output += getvalue
        if(isprint):
            print(valuesep.join(output))
    
    
#从文件中读取数据表,生成用于表关联的字典
#输入:
#   filename 保存数据的文件名
#   keyindex key字段索引号,多个字段索引号用逗号分隔
#   valueindex value字段索引号,多个字段索引号用逗号分隔
#返回:
#   用于表关联的字典
def readFileToDict( filename, keyindex, valueindex ):
    result = {}
    keyindex = [ int(index) for index in keyindex.split(parametersep) ]
    valueindex = [ int(index) for index in valueindex.split(parametersep) ]
    if(filename[:5] == "hdfs:"):
        file = subprocess.Popen(["hadoop", "fs", "-cat", filename], stdout=subprocess.PIPE)
    else:
        file = subprocess.Popen(["cat", filename], stdout=subprocess.PIPE)
    #file = open(filename,"r")
    for line in file.stdout:
        #line = file.readline()
        line = line.strip()
        fields = line.split(valuesep)
        keys = [ fields[i] for i in keyindex ]
        values = [ fields[i] for i in valueindex ]
        result[valuesep.join(keys)] = values
    return result

#根据字段名称生成字段名称到索引号的字典
#输入:各字段用逗号分隔,
#返回字段名称到索引号的字典
def nameindex(namestr):
    names = [ name.strip() for name in namestr.split(",") ]
    namenum = len(names)
    return dict(zip(names,range(namenum)))

#从文件中读取表定义的字段名称
def getTableField(filename):
    tablefields = []
    if(filename[:5] == "hdfs:"):
        file = subprocess.Popen(["hadoop", "fs", "-cat", filename], stdout=subprocess.PIPE)
    else:
        file = subprocess.Popen(["cat", filename], stdout=subprocess.PIPE)
    #file = open(filename,"r")
    for line in file.stdout:
        #line = file.readline()
        line = line.strip()
        splitted = line.split(keyvaluesep)
        if(len(splitted) != 2):
            continue
        tablename, fieldnames = splitted
        fieldindex = nameindex(fieldnames)
        tablefields.append( {"name":tablename.strip(),"index":fieldindex,"fields":fieldnames} )
    return tablefields

#根据表定义,把字段名称转化为字段索引
def getFieldIndex(tablefields, filename, fieldnames ):
    tabledef = []
    for tabledef in tablefields:
        if(filename.find(tabledef["name"]) >= 0):
            break
    fieldnames = fieldnames.split(parametersep)
    fieldindex = [ tabledef["index"][name] for name in fieldnames ]
    if( tabledef ):
        return parametersep.join( [ str(index) for index in fieldindex ] )
    else:
        raise Exception, "not fould table define for " + filename

#读文件到内存,之后处理标准输入的每行记录,内存表是要关联表的外键表,可以是多个字段的外键
def mapValue(args):
    tablefields = getTableField(args[0])
    indexargs = args[1:]
    i = 0
    while( i < len(args[1:]) ):
        indexargs[i] = getFieldIndex(tablefields, "stdin", args[i+1])
        indexargs[i+2] = getFieldIndex(tablefields, args[i+2], args[i+3])
        indexargs[i+3] = getFieldIndex(tablefields, args[i+2], args[i+4])
        i += 6
    mapValueByIndex(indexargs)

#函数字典
functions = {
    "memjoin" : mapValue,
    "memjoinindex" : mapValueByIndex
}

#主函数入口
def main(args):
    func = functions.get(args[1])
    if(func):
        func(args[2:])
    else:
        raise Exception, "has no function " + args[1]

#打印用法
def printUsage():
    print("usage:")
    print("  ./forhive.py CMD parameters")
    print("  CMD :")
    print("  \t memjoin tabledefinefile joinfields filepath keyfields valuefields innerorouter defaultvalue ...")
    print("  \t memjoinindex joinindex filepath keyindex valueindex innerorouter defaultvalue ...")

if __name__ == '__main__':
    if(len(sys.argv) > 1):
        main(sys.argv)
    else:
        printUsage()

tabledef.txt

stdin : id,fielda1,fielda2

tableb : fieldb1,fieldb2

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值