大数据分析实践课堂笔记

环境准备

开发环境准备

  • 创建Maven项目,jdk1.8
  • 导入pom.xml依赖
    • hadoop-common
    • hadoop-client
    • hadoop-hdfs
    • hadoop-mapreduce-client-core
    • https://mvnrepository.com/找到所需要的包写入pom.xml文件

伪分布式搭建

普通用户创建

  • 普通用户赋予sudo权限

关闭、禁用防火墙sudo

  • ```
    sudo systemctl stop firewalld
    sudo systemctl disable firewalld

    1
    2
    3
    4
    5
    6
    7
    8
    9



    - ![image-20210914092622730](http://markdowntc.wanqqq29.cn//image-20210914092622730.png)

    ### 修改hostsname ->/etc/hostname

    - ```
    sudo vi /etc/hostname
  • image-20210914092729741

修改hosts文件,添加node1 ->/etc/hosts

  • ```
    sudo vi /etc/hosts

    1
    2
    3
    4
    5
    6
    7
    8

    - ![image-20210914092858718](http://markdowntc.wanqqq29.cn//image-20210914092858718.png)

    ### 固定ip

    - ```
    sudo vi /etc/sysconfig/network-scripts/ifcfg-ens33
    sudo systemctl reboot network
  • image-20210914093212466

安装jdk

  • 配置用户环境变量

    • 为解决多用户下系统变量冲突问题,现要求配置用户的环境变量

      • ```
        用户目录下:
        vi .bashrc
        1
        2
        3
        4
        5
        6
        7
        8
        9



        - ![image-20210914093909268](http://markdowntc.wanqqq29.cn//image-20210914093909268.png)

        - 生效环境变量

        - ```
        source .bashrc
    • image-20210914094002309

配置免密登录

  • ```
    ssh-keygen -t rsa -P “”
    cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
    service sshd restart

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    - 私钥 除数-1,公钥 随机的一个数

    ### 安装hadoop伪分布式

    - 解压

    - 配置环境变量

    - ![image-20210914095737019](http://markdowntc.wanqqq29.cn//image-20210914095737019.png)

    - 更改hadoop配置 /etc/hadoop/env.sh、yarn-env.sh -> javahome

    - ```
    vi hadoop/etc/hadoop/hadoop.env.sh
    vi hadoop/etc/hadoop/yarn-env.sh

    修改以上文件的JAVA_HOME
    • hdfs-site.xml

      • ``` dfs.namenode.name.dir /home/map/hdfs/namenode dfs.datanode.data.dir /home/map/hdfs/datanode dfs.replication 3
        1
        2
        3

        - 新建目录

        mkdir -p /home/map/hdfs/namenode
        mkdir -p /home/map/hdfs/datanode
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13



        - core-site.xml

        - ```
        <?xml version="1.0"?>
        <configuration>
        <property>
        <name>fs.defaultFS</name>
        <value>hdfs://node1:9000/</value>
        </property>
        </configuration>
    • mapred-site.xml

      • ```
        mv mapred-site.xml.template mapred-site.xml
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10

        - ```
        <?xml version="1.0"?>
        <configuration>
        <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
        </property>
        </configuration>

    • yarn-site.xml

      • ``` yarn.nodemanager.aux-services mapreduce_shuffle yarn.nodemanager.aux-services.mapreduce_shuffle.class org.apache.hadoop.mapred.ShuffleHandler yarn.resourcemanager.hostname node1
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13

        -

        - 格式化

        - ```hadoop
        hadoop namenode –format

        - 启动

        - ```
        start-all.sh
        start-yarn.sh
    • 验证

      • image-20210914111934162

遇到问题

  • 免密登录不生效

    • 查看系统安全日志,定位问题

      • 执行 sudo cat /var/log/secure 查看系统的安全日志,然后在安全日志中看到SSH登录过程中提示了如下错误:

      • image-20210914102538005

      • 找到问题:Authentication refused: bad ownership or modes for directory /home/map

        后面的目录代表权限不匹配

      • 解决:

        (替换成你log中的目录)执行如下:

        1
        2
        3
        chmod g-w /home/map
        chmod 700 ./.ssh
        chmod 600 ~/.ssh/authorized_keys

        重启SSH服务 $ service sshd restart

mapreduce 开发

python-hadoop参考文档

map部分与sh

Partitioner

成果

数据清洗

把旧球队名替换为新球队名

分别给东西部球队添加标记;1970年之前的球队统一添加M标记

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#!/usr/bin/env python3
# coding=UTF-8
##map
import sys # 导入sys包

Line = ''
data = []
newTeam = ['金州勇士队', '金州勇士队', '洛杉矶湖人队', '费城76人队', '萨克拉门托国王队', '亚特兰大老鹰队', '华盛顿奇才队', '华盛顿奇才队', '俄克拉荷马城雷霆队', '底特律活塞队',
'布鲁克林篮网队', '达拉斯独行侠队']
oldTeam = ['费城勇士队', '旧金山勇士队', '明尼阿波利斯湖人队', '赛拉库斯民族队', '罗切斯特皇家队', '圣路易斯老鹰队', '华盛顿子弹队', '巴尔的摩子弹队', '西雅图超音速队',
'福特韦恩活塞队', '新泽西网队', '达拉斯小牛队']
eastTeam = ['亚特兰大老鹰队', '夏洛特黄蜂队', '迈阿密热火队', '奥兰多魔术队', '华盛顿奇才队', '波士顿凯尔特人队', '布鲁克林篮网队', '纽约尼克斯队', '费城76人队', '多伦多猛龙队',
'芝加哥公牛队', '克里夫兰骑士队', '底特律活塞队', '印第安纳步行者队', '密尔沃基雄鹿队']
westTeam = ['金州勇士队', '芝加哥牡鹿队', '洛杉矶湖人队', '华盛顿国会队', '塞拉库斯民族队', '萨克拉门托国王队', '菲尼克斯太阳队', '波特兰开拓者队',
'俄克拉荷马城雷霆队', '休斯顿火箭队', '犹他爵士队', '圣安东尼奥马刺队', '达拉斯独行侠队']
# 从标准输入中获取数据
for line in sys.stdin:
Team = []
# data为每行csv的列表格式 ['1947', '4.16-4.22', '金州勇士队', '4-1', '芝加哥牡鹿队', '']
data = line.strip().split(',')
if data[5] == '\n':
data[5] = ' '
# data[2]为冠军队名
# 对改名的冠军队名进行更新
if data[2] in oldTeam:
a = oldTeam.index(data[2])
data[2] = newTeam[a]
# if冠军队之前改过名,以新队名添加东西部标识
# if data[0] >= '1970':
# if data[2] in eastTeam:
# data.insert(0,'E')
# elif data[2] in westTeam:
# data.insert(0,'W')
if data[0] >= '1970':
if data[2] in eastTeam:
Team.append('E')
for ii in data:
Team.append(ii)
elif data[2] in westTeam:
Team.append('W')
for ii in data:
Team.append(ii)
else:
Team.append('M')
for ii in data:
Team.append(ii)
else:
Team.append('M')
for ii in data:
Team.append(ii)
# if冠军队伍没有改名,添加东西部标识
else:
if data[0] >= '1970':
if data[2] in eastTeam:
Team.append('E')
for ii in data:
Team.append(ii)
elif data[2] in westTeam:
Team.append('W')
for ii in data:
Team.append(ii)
else:
Team.append('M')
for ii in data:
Team.append(ii)
else:
Team.append('M')
for ii in data:
Team.append(ii)

if data[4] in oldTeam:
b = oldTeam.index(data[4])
data[4] = newTeam[b]
Team[5] = data[4]

# 将列表data转为字符串
Line = ",".join(Team)
# 输出
print(Line)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HADOOP_CMD="/home/map/apps/hadoop/bin/hadoop"
STREAM_JAR_PATH="/home/map/apps/hadoop/share/hadoop/tools/lib/hadoop-streaming-2.7.6.jar"

INPUT_FILE_PATH_1="/nba.csv"
OUTPUT_PATH="/data_output"
$HADOOP_CMD fs -rm -r -skipTrash $OUTPUT_PATH #每次执行时都删除输出路径,否则会出错

$HADOOP_CMD jar $STREAM_JAR_PATH \
-input $INPUT_FILE_PATH_1 \
-output $OUTPUT_PATH \
-mapper "python3 map.py" \
-jobconf mapred.map.tasks=1 \
-jobconf mapred.reduce.tasks=0\
-file map.py \

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
[map@node1 program]$ hadoop fs -cat /data_output/part-00000
M,1947,4.16-4.22,金州勇士队,4-1,芝加哥牡鹿队,
M,1948,4.10-4.21,华盛顿奇才队,4-2,金州勇士队,
M,1949,4.4-4.13,洛杉矶湖人队,4-2,华盛顿国会队,
M,1950,4.8-4.23,洛杉矶湖人队,4-2,塞拉库斯民族队,
M,1951,4.7-4.21,萨克拉门托国王队,4-3,纽约尼克斯队,
M,1952,4.12-4.25,洛杉矶湖人队,4-3,纽约尼克斯队,
M,1953,4.4-4.10,洛杉矶湖人队,4-1,纽约尼克斯队,
M,1954,3.31-4.12,洛杉矶湖人队,4-3,塞拉库斯民族队,
M,1955,3.31-4.10,塞拉库斯民族队,4-3,底特律活塞队,
M,1956,3.31-4.7,金州勇士队,4-1,底特律活塞队,
M,1957,3.30-4.13,波士顿凯尔特人队,4-3,亚特兰大老鹰队,
M,1958,3.29-4.12,亚特兰大老鹰队,4-2,波士顿凯尔特人队,
M,1959,4.4-4.9,波士顿凯尔特人队,4-0,洛杉矶湖人队,
M,1960,3.27-4.9,波士顿凯尔特人队,4-3,亚特兰大老鹰队,
M,1961,4.2-4.11,波士顿凯尔特人队,4-1,亚特兰大老鹰队,
M,1962,4.7-4.18,波士顿凯尔特人队,4-3,洛杉矶湖人队,
M,1963,4.14-4.24,波士顿凯尔特人队,4-2,洛杉矶湖人队,
M,1964,4.18-4.26,波士顿凯尔特人队,4-1,金州勇士队,
M,1965,4.18-4.25,波士顿凯尔特人队,4-1,洛杉矶湖人队,
M,1966,4.17-4.28,波士顿凯尔特人队,4-3,洛杉矶湖人队,
M,1967,4.14-4.24,费城76人队,4-2,金州勇士队,
M,1968,4.21-5.2,波士顿凯尔特人队,4-2,洛杉矶湖人队,
M,1969,4.23-5.5,波士顿凯尔特人队,4-3,洛杉矶湖人队,杰里·韦斯特
E,1970,4.24-5.8,纽约尼克斯队,4-3,洛杉矶湖人队,威利斯·里德
E,1971,4.21-4.30,密尔沃基雄鹿队,4-0,华盛顿奇才队,贾巴尔
W,1972,4.26-5.7,洛杉矶湖人队,4-1,纽约尼克斯队,张伯伦
E,1973,5.1-5.10,纽约尼克斯队,4-1,洛杉矶湖人队,威利斯·里德
E,1974,4.28-5.12,波士顿凯尔特人队,4-3,密尔沃基雄鹿队,约翰·哈夫利切克
W,1975,5.18-5.25,金州勇士队,4-0,华盛顿奇才队,里克·巴里
E,1976,5.23-6.6,波士顿凯尔特人队,4-2,菲尼克斯太阳队,乔·乔·怀特
W,1977,5.22-6.5,波特兰开拓者队,4-2,费城76人队,比尔·沃顿
E,1978,5.21-6.7,华盛顿奇才队,4-3,俄克拉荷马城雷霆队,韦斯·昂塞尔德
W,1979,5.20-6.1,俄克拉荷马城雷霆队,4-1,华盛顿奇才队,丹尼斯·约翰逊
W,1980,5.4-5.16,洛杉矶湖人队,4-2,费城76人队,埃尔文·约翰逊
E,1981,5.5-5.14,波士顿凯尔特人队,4-2,休斯顿火箭队,塞德里克·麦克斯维尔
W,1982,5.27-6.8,洛杉矶湖人队,4-2,费城76人队,埃尔文·约翰逊
E,1983,5.22-5.31,费城76人队,4-0,洛杉矶湖人队,摩西·马龙
E,1984,5.27-6.12,波士顿凯尔特人队,4-3,洛杉矶湖人队,拉里·伯德
W,1985,5.27-6.9,洛杉矶湖人队,4-2,波士顿凯尔特人队,贾巴尔
E,1986,5.26-6.8,波士顿凯尔特人队,4-2,休斯顿火箭队,拉里·伯德
W,1987,6.2-6.14,洛杉矶湖人队,4-2,波士顿凯尔特人队,埃尔文·约翰逊
W,1988,6.7-6.21,洛杉矶湖人队,4-3,底特律活塞队,詹姆斯·沃西
E,1989,6.6-6.13,底特律活塞队,4-0,洛杉矶湖人队,乔·杜马斯
E,1990,6.5-6.14,底特律活塞队,4-1,波特兰开拓者队,伊塞亚·托马斯
E,1991,6.2-6.12,芝加哥公牛队,4-1,洛杉矶湖人队,迈克尔·乔丹
E,1992,6.3-6.14,芝加哥公牛队,4-2,波特兰开拓者队,迈克尔·乔丹
E,1993,6.9-6.20,芝加哥公牛队,4-2,菲尼克斯太阳队,迈克尔·乔丹
W,1994,6.8-6.22,休斯顿火箭队,4-3,纽约尼克斯队,哈基姆·奥拉朱旺
W,1995,6.7-6.14,休斯顿火箭队,4-0,奥兰多魔术队,哈基姆·奥拉朱旺
E,1996,6.5-6.16,芝加哥公牛队,4-2,俄克拉荷马城雷霆队,迈克尔·乔丹
E,1997,6.1-6.13,芝加哥公牛队,4-2,犹他爵士队,迈克尔·乔丹
E,1998,6.3-6.14,芝加哥公牛队,4-2,犹他爵士队,迈克尔·乔丹
W,1999,6.16-6.25,圣安东尼奥马刺队,4-1,纽约尼克斯队,蒂姆·邓肯
W,2000,6.7-6.19,洛杉矶湖人队,4-2,印第安纳步行者队,沙奎尔·奥尼尔
W,2001,6.6-6.15,洛杉矶湖人队,4-1,费城76人队,沙奎尔·奥尼尔
W,2002,6.5-6.12,洛杉矶湖人队,4-0,布鲁克林篮网队,沙奎尔·奥尼尔
W,2003,6.5-6.16,圣安东尼奥马刺队,4-2,布鲁克林篮网队,蒂姆·邓肯
E,2004,6.7-6.16,底特律活塞队,4-1,洛杉矶湖人队,昌西·比卢普斯
W,2005,6.10-6.24,圣安东尼奥马刺队,4-3,底特律活塞队,蒂姆·邓肯
E,2006,6.9-6.21,迈阿密热火队,4-2,达拉斯独行侠队,德怀恩·韦德
W,2007,6.8-6.15,圣安东尼奥马刺队,4-0,克里夫兰骑士队,托尼·帕克
E,2008,6.6-6.18,波士顿凯尔特人队,4-2,洛杉矶湖人队,保罗·皮尔斯
W,2009,6.5-6.15,洛杉矶湖人队,4-1,奥兰多魔术队,科比·布莱恩特
W,2010,6.4-6.18,洛杉矶湖人队,4-3,波士顿凯尔特人队,科比·布莱恩特
W,2011,6.1-6.13,达拉斯独行侠队,4-2,迈阿密热火队,德克·诺维茨基
E,2012,6.13-6.22,迈阿密热火队,4-1,俄克拉荷马城雷霆队,勒布朗·詹姆斯
E,2013,6.7-6.21,迈阿密热火队,4-3,圣安东尼奥马刺队,勒布朗·詹姆斯
W,2014,6.6-6.16,圣安东尼奥马刺队,4-1,迈阿密热火队,科怀·伦纳德
W,2015,6.5-6.17,金州勇士队,4-2,克里夫兰骑士队,安德烈·伊戈达拉
E,2016,6.3-6.20,克里夫兰骑士队,4-3,金州勇士队,勒布朗·詹姆斯
W,2017,6.2-6.13,金州勇士队,4-1,克利夫兰骑士队,凯文·杜兰特
W,2018,6.1-6.9,金州勇士队,4-0,克利夫兰骑士队,凯文·杜兰特
E,2019,5.31-6.14,多伦多猛龙队,4-2,金州勇士队,科怀·伦纳德

image-20211001164652951

分类

通过Partitioner分类存放,这次Partitioner只实现了把M根EW分开,EW还是在一个文件夹内

1
2
3
4
5
6
7
8
#!/usr/bin/env python3
# coding=UTF-8
##map
import sys
for line in sys.stdin:
#将字符串转换为列表dataList 方便操作
dataList = line.split(',')
print(dataList)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/usr/bin/env python3
# coding=UTF-8
# reduce

import sys,re

Count = []
kV = {}
for line in sys.stdin:
line = re.sub("\[",'',line)
line = re.sub("\]",'',line)
line = re.sub("'",'',line)
line = re.sub("\t\n",'',line)
lineContent = line.split(', ')
if lineContent[2] not in Count:
Count.append(lineContent[2])
kV[lineContent[2]] = 1
elif lineContent[2] in Count:
xx = {lineContent[2]: kV[lineContent[2]] + 1}
kV.update(xx)
print(kV)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
HADOOP_CMD="/home/map/apps/hadoop/bin/hadoop"
STREAM_JAR_PATH="/home/map/apps/hadoop/share/hadoop/tools/lib/hadoop-streaming-2.7.6.jar"

INPUT_FILE_PATH_1="/data_output/part-00000"
OUTPUT_PATH="/pp_output"
$HADOOP_CMD fs -rm -r -skipTrash $OUTPUT_PATH #每次执行时都删除输出路径,否则会出错

$HADOOP_CMD jar $STREAM_JAR_PATH \
-D stream.map.output.field.separator=, \
-D stream.num.map.output.key.fields=1 \
-D map.output.key.field.separator=\t \
-D mapred.text.key.partitioner.options=-k1,1 \
-input $INPUT_FILE_PATH_1 \
-output $OUTPUT_PATH \
-mapper "python3 main.py" \
-reducer "python3 reduce.py" \
-jobconf mapred.map.tasks=3 \
-jobconf mapred.reduce.tasks=3 \
-file main.py \
-file reduce.py \
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner

image-20211001165523346

只分类1970年后的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/usr/bin/env python3
# coding=UTF-8
##map
import sys,re
for line in sys.stdin:
#将字符串转换为列表dataList 方便操作
line = re.sub("\[", '', line)
line = re.sub("\]", '', line)
line = re.sub("'", '', line)
line = re.sub("\t\n", '', line)
dataList = line.split(',')
if dataList[0] == 'W':
print(dataList)
elif dataList[0] =='E':
print(dataList)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env python3
# coding=UTF-8
# reduce

import sys,re

Count = []
kVw = {}
kVe = {}
for line in sys.stdin:
line = re.sub("\[",'',line)
line = re.sub("\]",'',line)
line = re.sub("'",'',line)
line = re.sub("\t\n",'',line)
lineContent = line.split(', ')
# print(lineContent)
# if lineContent[0] == 'W' or 'E':
# print(lineContent[0])
if lineContent[0][0:1] == 'W':
if lineContent[2] not in Count:
Count.append(lineContent[2])
kVw[lineContent[2]] = 1
elif lineContent[2] in Count:
xx = {lineContent[2]: kVw[lineContent[2]] + 1}
kVw.update(xx)

elif lineContent[0][0:1] == 'E':
if lineContent[2] not in Count:
Count.append(lineContent[2])
kVe[lineContent[2]] = 1
elif lineContent[2] in Count:
xx = {lineContent[2]: kVe[lineContent[2]] + 1}
kVe.update(xx)
print(kVw,'#W')
print(kVe,'#E')


# if lineContent[2] not in Count:
# Count.append(lineContent[2])
# kV[lineContent[2]] = 1
# elif lineContent[2] in Count:
# xx = {lineContent[2]: kV[lineContent[2]] + 1}
# kV.update(xx)
# print(kV)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
HADOOP_CMD="/home/map/apps/hadoop/bin/hadoop"
STREAM_JAR_PATH="/home/map/apps/hadoop/share/hadoop/tools/lib/hadoop-streaming-2.7.6.jar"

INPUT_FILE_PATH_1="/data_output/part-00000"
OUTPUT_PATH="/ppp_output"
$HADOOP_CMD fs -rm -r -skipTrash $OUTPUT_PATH #每次执行时都删除输出路径,否则会出错

$HADOOP_CMD jar $STREAM_JAR_PATH \
-D stream.map.output.field.separator=, \
-D stream.num.map.output.key.fields=1 \
-D map.output.key.field.separator=\t \
-D mapred.text.key.partitioner.options=-k1,1 \
-input $INPUT_FILE_PATH_1 \
-output $OUTPUT_PATH \
-outputformat org.apache.hadoop.mapreduce.lib.output.MultipleOutputs \
-mapper "python3 mainF.py" \
-reducer "python3 reduceF.py" \
-jobconf mapred.map.tasks=3 \
-jobconf mapred.reduce.tasks=3 \
-file mainF.py \
-file reduceF.py \
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner