map reduce案例超详细讲解

实验一:对输入文件统计单词频率

A good beginning is half the battle,
Where there is a will there is a way.
There is no royal road to learning.

map输出,分割单词增加尾部1,方便统计

import sys

for line in sys.stdin:
	ss = line.strip().split(' ')
	for word in ss:
		print('\t'.join([word.strip(),'1']))

reduce统计

import sys

cur_word = None
sum = 0

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

	if cur_word == None:
		cur_word = word

	if cur_word != word:
		print('\t'.join([cur_word,str(sum)]))
		cur_word = word
		sum = 0

	sum += int(cnt)
	
print('\t'.join([cur_word,str(sum)]))

调用管道符测试

cat data.txt | python map.py | sort -k 1 | python reduce.py

在这里插入图片描述
上面是一个简单的例子
加大一点点难度
使用MapReduce实现如下功能(要mapreduce思维实现,考虑多节点协同处理,非以往的Python单节点处理数据思维)

现有数据 emp.csv 、 dept.txt
emp.csv ----------------------------- ------------------------ dept.csv
部门编号 姓名 年龄 -------------------- 部门编号 部门名称
20 zhaoyi 30 ----------------------------------- 20 技术部
30 liuer 25 ----------------------------------- 10 人事部
10 zhangsan 31 ----------------------------------- 30 财务部
20 lisi 40
30 wangwu 30
20 sunliu 22

最终要输出的如下

部门名称 人员列表
人事部 zhangshan:31
技术部 zhaoyi-30 ,lisi-40, sunliu–22
财务部 liuer-25,wangwu—30

这个是找的答案的

# Map:
import sys 
import io 
input_str = io.TextIOWrapper(sys.stdin.detach(),encoding='utf-8 ')
for line in input_str: 
     datas = line.strip().split(',')
     if(len(datas)==3):
           dept = datas[0]
           name = datas[1]+'-'+datas[2]
           print(dept+'\t'+name)
     if(len(datas)==2):
            dept = datas[0]
            name = datas[1]
            print(dept+'\t'+'*'+name)






# Reduce:
import sys 
import io 
input_str = io.TextIOWrapper(sys.stdin.detach(),encoding='utf-8 ')
cur_dept = None 
emp_list='' 
dept_name=''
for line in input_str: 
        dept, name = line.strip().split('\t')
        if cur_dept == None:
            cur_dept = dept
        if cur_dept != dept:
            print('\t'.join([dept_name, emp_list]))
            cur_dept = dept 
            emp_list = ''
        if "*" in name:
            dept_name = name[1:]
        else:
            emp_list += name + ','
            print('\t'.join([dept_name, emp_list]))

这个过程嘛……上面那个哟有点长我丢

在这里插入图片描述
按照这个分步骤一下
map的输入

cat demo.csv | python map2.py 
k1v1
1部门编号 , 姓名 ,年龄
220 , zhaoyi, 30
330 , liuer , 25
410 , zhangsan, 31
520 , lisi , 40
630 , wangwu , 30
720 ,sunliu ,22
820 , 技术部,
930 , 财务部,
1010 , 人事部,

先用一个csv把他们装起来
首先第一步我们在虚拟机上创建了文件:demo.csv 这个文件是题目两个文件合起来的,也可以用管道符合起来这里为了方便就没有用

文件的内容

20,zhaoyi,30
30,liuer,25
10,zhangsan,31
20,lisi,40
30,wangwu,30
20,sunliu,22
20,技术部
10,人事部
30,财务部

我们观察发现,第一行,到第六行,它有部门编号,名字,年龄
第七行到第九行是编号和部门名字
所以他们的区别在于长度不一样
在这里插入图片描述

#我们首先把map接受的东西区分一下
#1、第一他是有要分开的,一个是人的名字,一个是部门的名字
#2.增加一些东西给他去分开

import sys
for line in sys.stdin:
    print(line)#我们可以看看数据是怎样的

在这里插入图片描述

    #line我们需要进行分割
    line = line.strip().split(",")#按照','分割
    #第一步取出部门编号 和人名
    #区别
    print(len(line))
    #line的长度,带人名的是3 部门的是2

在这里插入图片描述
完整map代码

#我们首先把map接受的东西区分一下
#1、第一他是有要分开的,一个是人的名字,一个是部门的名字
#2.增加一些东西给他去分开

import sys
for line in sys.stdin:
    #line我们需要进行分割
    line = line.strip().split(",")#按照','分割
    #第一步取出部门编号 和人名
    #区别
    #line的长度,带人名的是3 部门的是2
    #分类
    if len(line)==3:#带人名的是3
        #按照题目要求
        #输出--ID--------------名字-------------年龄
        print(line[0] + "\t" + line[1] + "-" + line[2])
    else:#部门的是2
        #这里用*和他们分开
        #输出--ID--------------*--部门名字
        print(line[0]+"\t"+'*'+line[1])

map的输出

k2v2
20zhaoyi-30
30liuer-25
10zhangsan-31
20lisi-40
30wangwu-30
20sunliu-22
20*技术部
10*人事部
30*财务部

对输出排序后交给reduce2处理

cat demo.csv | python map2.py |sort -k 1 |python reduce2.py
k3v3
10zhangsan-31
10*人事部
20lisi-40
20sunliu-22
20zhaoyi-30
20*技术部
30liuer-25
30wangwu-30
30*财务部

首先我们创建容器来装我们要的数据

id_name = None#这个用来装 ID
bm_name=" "#这个用来装     部门的 名字
yg_name=" "#这个用来装     员工的 名字

接着我们对k3,v3读取

for line in sys.stdin:
    #老规矩我们查看一下这个line,发现管道符命令已经对他排好序了,而且部门是放在最后一位的
    #k3,            v3
    # id(部门id)  massage(部门名字人名年龄那些)
    # 10         zhangsan - 31
    # 10           * 人事部
    id,massage = line.strip().split('\t')  #k3,v3创建

#第一步
#记录ID 确定输出的时候(什么时候完成了一个部门的总结就输出)

记录一个id

    if id_name==None:#也就是这个id_name还没有任何数据的时候
        id_name = id#那就把这个ID记录到这个id_name里面

确定输出的时候

f id_name != id:#这个是判断新的ID他是一个个读取的
        #例如读取到下面上一个的ID和下一个不一样的时候
        #10      *人事部
        #20      lisi-40
        #也就是编号10的部门以及读取完了这个时候对吧,所以他的10就可以输出了
        #输出       部门名字           员工信息
        print(str(bm_name)+"\t"+str(yg_name))

记录下一个id

        id_name = id  # 那就把这个不一样的ID记录到这个id_name里面
        #然后别忘记把员工的信息清空,因为你总不可能记录这个部门还保存着上一个部门的员工信息,这样到时候输出就不好输出了
        yg_name = " "

#第二步骤
#通过ID 添加信息
#部门 + 人的名字-年龄

#第二步
    if "*" in massage:
        bm_name = massage[1:]
    else:
        yg_name += massage+';'#这里我就解释一下为什么这两个加法不一样,首先我们输出的是 部门1 员工1;员工2; 是这样的部门是直接替换原来的但是员工是累加的

完整代码

import sys
id_name = None#这个用来装 ID
bm_name=" "#这个用来装     部门的 名字
yg_name=" "#这个用来装     员工的 名字
for line in sys.stdin:
    id,massage = line.strip().split('\t')
    if id_name==None:
        id_name = id
    if id_name != id:
        print(str(bm_name)+"\t"+str(yg_name))
        id_name = id 
        yg_name = " "
    if "*" in massage:
        bm_name = massage[1:]
    else:
        yg_name += massage+';'
print(str(bm_name) + "\t" + str(yg_name))

在这里插入图片描述

这里最后这个输出为什么在外面呢,首先第一点是,当记录最后一个部门的时候
开始记录这个部门
20 --------------------------*技术部--------------------------
也就是读到部门编号不一样的时候,20-30的时候,他会做判断 if id_name != id:,然后输出这个部门的所有东西
30 -------------------------- liuer-25-----------从这里开始新的记录
30 -------------------------- wangwu-3030 *财务部--------------记录完成
但是下面已没有不同的id支持他输出了
于是利用for循环的一个特性输出,(遍历完成后输出最后一个)
这个的理解需要我们来进行一个小实验

list=[1,2,3]
for i in list:
      print('猜猜我在外面会输出一个怎么样的i')
 print(i)
输出 3也就是最后一组

总结reduce

在这里插入图片描述

现有如下文本文件 emp.txt

depnameempnosalary
develop115200
develop74200
develop94500
develop86000
develop105200
personnel53500
personnel23900
sales34800
sales15000
sales44800

请统计出每个员工和所在部门平均工资的差值。

步骤
1、截取 部门名字 员工编号 -员工工资
2、总结好部门名字 员工1编号-员工1工资,员工2编号-员工2工资
3、截取 员工编号 员工工资-部门平均工资
4、统计 员工编号 员工工资相减部门平均工资

1、map

import sys
for line in sys.stdin:
    line = line.strip().split(",")
    print(line[0] + "\t" + line[1] + "-" + line[2])
# type demo.csv | python map.py
# develop 7-4200
# develop 8-6000
# sales   1-5000
# sales   4-4800
# develop 10-5200
# personnel       5-3500
# personnel       2-3900
# sales   3-4800
# develop 9-4500
# develop 11-5200


2、reduce

import sys
for line in sys.stdin:
    #分割
    line = line.strip().split("\t")
    #员工收入
    emp_sal = float(line[1].split("-")[0])  
    #部门收入
    dept_sal = float(line[1].split("-")[1])
    #差值
    sub = emp_sal - dept_sal
    print("%s%s%.2f"%(line[0],"\t",sub))
# type demo.csv | python map.py | python Reduce.py |python map2.py|python reduce2.py
# 7       -900.00
# 8       900.00
# 1       100.00
# 4       -100.00
# 10      1000.00
# 5       -700.00
# 2       -300.00
# 3       -33.33
# 9       -333.33

3、map2

import sys

for line in sys.stdin:
    line = line.strip().split("\t")
    sum = line[0]
    emps = line[1]
    emp = emps.split(",")
    #遍历每一名员工
    for i in range(len(emp)):
        #员工编号
        emp_id = emp[i].split("-")[0]
        #给每个员工后面加上部门总收入,员工编号——员工收入——部门总收入
        emp[i] = emp[i] + "-" + line[0]
        #key:员工编号       value:员工收入——部门总收入
        print("%s%s%s"%(emp_id,"\t",emp[i].split(emp_id+"-")[1]))
# type demo.csv | python map.py | python Reduce.py |python map2.py
# 7       4200-5100.00
# 8       6000-5100.00
# 1       5000-4900.00
# 4       4800-4900.00
# 10      5200-4200.00
# 5       3500-4200.00
# 2       3900-4200.00
# 3       4800-4833.33
# 9       4500-4833.33
# 11      5200-4833.33

4、reduce2.py

import sys
for line in sys.stdin:
    #分割
    line = line.strip().split("\t")
    #员工收入
    emp_sal = float(line[1].split("-")[0])  
    #部门收入
    dept_sal = float(line[1].split("-")[1])
    #差值
    sub = emp_sal - dept_sal
    print("%s%s%.2f"%(line[0],"\t",sub))
# type demo.csv | python map.py | python Reduce.py |python map2.py|python reduce2.py
# 7       -900.00
# 8       900.00
# 1       100.00
# 4       -100.00
# 10      1000.00
# 5       -700.00
# 2       -300.00
# 3       -33.33
# 9       -333.33

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南师大蒜阿熏呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值