当前位置: 首页 > news >正文

2 MapReduce

2 MapReduce

  • 1. MapReduce 介绍
    • 1.1 MapReduce 设计构思
  • 2. MapReduce 编程规范
  • 3. Mapper以及Reducer抽象类介绍
    • 1.Mapper抽象类的基本介绍
    • 2.Reducer抽象类基本介绍
  • 4. WordCount示例编写
  • 5. MapReduce程序运行模式
  • 6. MapReduce的运行机制详解
    • 6.1 MapTask 工作机制
    • 6.2 ReduceTask 工作机制
    • 6.3 Shuffle 过程
  • 7. Reduce 端实现 JOIN
    • 7.1 需求
    • 7.2 实现步骤
  • 8. Map端实现 JOIN
    • 8.1 概述
    • 8.2 实现步骤
  • 9. 社交粉丝数据分析
    • 9.1 需求分析
    • 9.2 实现步骤
  • 10. 倒排索引建立
    • 10.1 需求分析
    • 10.2 代码实现

1. MapReduce 介绍

MapReduce思想在生活中处处可见。或多或少都曾接触过这种思想。MapReduce的思想核心是“分而治之”,适用于大量复杂的任务处理场景(大规模数据处理场景)。即使是发布过论文实现分布式计算的谷歌也只是实现了这种思想,而不是自己原创。
Map负责“分”,即把复杂的任务分解为若干个“简单的任务”来并行处理。可以进行拆分的前提是这些小任务可以并行计算,彼此间几乎没有依赖关系。
Reduce负责“合”,即对map阶段的结果进行全局汇总。
MapReduce运行在yarn集群
—1.ResourceManager
—2.NodeManager
这两个阶段合起来正是MapReduce思想的体现。
在这里插入图片描述
还有一个比较形象的语言解释MapReduce:
我们要数图书馆中的所有书。你数1号书架,我数2号书架。这就是“Map”。我们人越多,数书就更快。
现在我们到一起,把所有人的统计数加在一起。这就是“Reduce”。

1.1 MapReduce 设计构思

MapReduce是一个分布式运算程序的编程框架,核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序,并发运行在Hadoop集群上。
既然是做计算的框架,那么表现形式就是有个输入(input),MapReduce操作这个输入(input),通过本身定义好的计算模型,得到一个输出(output)。
对许多开发者来说,自己完完全全实现一个并行计算程序难度太大,而MapReduce就是一种简化并行计算的编程模型,降低了开发并行应用的入门门槛。

Hadoop MapReduce构思体现在如下的三个方面:

1.如何对付大数据处理:分而治之
对相互间不具有计算依赖关系的大数据,实现并行最自然的办法就是采取分而治之的策略。并行计算的第一个重要问题是如何划分计算任务或者计算数据以便对划分的子任务或数据块同时进行计算。不可分拆的计算任务或相互间有依赖关系的数据无法进行并行计算!

2.构建抽象模型:Map和Reduce
MapReduce借鉴了函数式语言中的思想,用Map和Reduce两个函数提供了高层的并行编程抽象模型。
Map: 对一组数据元素进行某种重复式的处理;
Reduce: 对Map的中间结果进行某种进一步的结果整理。
MapReduce中定义了如下的Map和Reduce两个抽象的编程接口,由用户去编程实现:
map: (k1; v1) → [(k2; v2)]
reduce: (k2; [v2]) → [(k3; v3)]
Map和Reduce为程序员提供了一个清晰的操作接口抽象描述。通过以上两个编程接口,大家可以看出MapReduce处理的数据类型是<key,value>键值对。

3.MapReduce框架结构
一个完整的mapreduce程序在分布式运行时有三类实例进程:
MR AppMaster:负责整个程序的过程调度及状态协调;
MapTask:负责map阶段的整个数据处理流程;
ReduceTask:负责reduce阶段的整个数据处理流程。
在这里插入图片描述

2. MapReduce 编程规范

MapReduce 的开发一共有八个步骤, 其中 Map 阶段分为 2 个步骤,Shuffle 阶段 4 个步骤,Reduce 阶段分为 2 个步骤

1.Map 阶段 2 个步骤:
1.1 设置 InputFormat 类, 将数据切分为 Key-Value**(K1和V1)** 对, 输入到第二步
1.2 自定义 Map 逻辑, 将第一步的结果转换成另外的 Key-Value(K2和V2) 对, 输出结果

2.Shuffle 阶段 4 个步骤:
2.1 对输出的 Key-Value 对进行分区
2.2 对不同分区的数据按照相同的 Key 排序
2.3 (可选) 对分组过的数据初步规约, 降低数据的网络拷贝
2.4 对数据进行分组, 相同 Key 的 Value 放入一个集合中

3.Reduce 阶段 2 个步骤:
3.1 对多个 Map 任务的结果进行排序以及合并, 编写 Reduce 函数实现自己的逻辑, 对输入的 Key-Value 进行处理, 转为新的 Key-Value(K3和V3)输出
3.2 设置 OutputFormat 处理并保存 Reduce 输出的 Key-Value 数据
在这里插入图片描述

3. Mapper以及Reducer抽象类介绍

为了开发我们的MapReduce程序,一共可以分为以上八个步骤,其中每个步骤都是一个class类,我们通过job对象将我们的程序组装成一个任务提交即可。为了简化我们的MapReduce程序的开发,每一个步骤的class类,都有一个既定的父类,让我们直接继承即可,因此可以大大简化我们的MapReduce程序的开发难度,也可以让我们快速的实现功能开发。
MapReduce编程当中,其中最重要的两个步骤就是我们的Mapper类和Reducer类

1.Mapper抽象类的基本介绍

在hadoop2.x当中Mapper类是一个抽象类,我们只需要覆写一个java类,继承自Mapper类即可,然后重写里面的一些方法,就可以实现我们特定的功能,接下来我们来介绍一下Mapper类当中比较重要的四个方法
1.setup方法: 我们Mapper类当中的初始化方法,我们一些对象的初始化工作都可以放到这个方法里面来实现
2.map方法: 读取的每一行数据,都会来调用一次map方法,这个方法也是我们最重要的方法,可以通过这个方法来实现我们每一条数据的处理
3.cleanup方法: 在我们整个maptask执行完成之后,会马上调用cleanup方法,这个方法主要是用于做我们的一些清理工作,例如连接的断开,资源的关闭等等
4.run方法: 如果我们需要更精细的控制我们的整个MapTask的执行,那么我们可以覆写这个方法,实现对我们所有的MapTask更精确的操作控制

2.Reducer抽象类基本介绍

同样的道理,在我们的hadoop2.x当中,reducer类也是一个抽象类,抽象类允许我们可以继承这个抽象类之后,重新覆写抽象类当中的方法,实现我们的逻辑的自定义控制。接下来我们也来介绍一下Reducer抽象类当中的四个抽象方法
1.setup方法: 在我们的ReduceTask初始化之后马上调用,我们的一些对象的初始化工作,都可以在这个类当中实现
2.reduce方法: 所有从MapTask发送过来的数据,都会调用reduce方法,这个方法也是我们reduce当中最重要的方法,可以通过这个方法实现我们的数据的处理
3.cleanup方法: 在我们整个ReduceTask执行完成之后,会马上调用cleanup方法,这个方法主要就是在我们reduce阶段处理做我们一些清理工作,例如连接的断开,资源的关闭等等
4.run方法: 如果我们需要更精细的控制我们的整个ReduceTask的执行,那么我们可以覆写这个方法,实现对我们所有的ReduceTask更精确的操作控制

4. WordCount示例编写

需求:在一堆给定的文本文件中统计输出每一个单词出现的总次数
node01服务器执行以下命令,准备数,数据格式准备如下:

cd /export/servers
vim wordcount.txt
#添加以下内容:
hello hello
world world
hadoop hadoop
hello world
hello flume
hadoop hive
hive kafka
flume storm
hive oozie

​ 将数据文件上传到hdfs上面去

hdfs dfs -mkdir /wordcount/
hdfs dfs -put wordcount.txt /wordcount/

定义一个mapper类

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;import java.io.IOException;// mapper程序:  需要继承 mapper类, 需要传入 四个类型:
/*  在hadoop中, 对java的类型都进行包装, 以提高传输的效率  writablekeyin :  k1   Long     ---- LongWritablevalin :  v1   String   ------ Textkeyout : k2   String   ------- Textvalout : v2   Long     -------LongWritable*/public class MapTask extends Mapper<LongWritable,Text,Text,LongWritable> {/**** @param key  : k1* @param value   v1* @param context  上下文对象   承上启下功能* @throws IOException* @throws InterruptedException*/@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {//1. 获取 v1 中数据String val = value.toString();//2. 切割数据String[] words = val.split(" ");Text text = new Text();LongWritable longWritable = new LongWritable(1);//3. 遍历循环, 发给 reducefor (String word : words) {text.set(word);context.write(text,longWritable);}}
}

定义一个reducer类

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;import java.io.IOException;/*** KEYIN  :  k2    -----Text* VALUEIN :  v2   ------LongWritable* KEYOUT  : k3    ------  Text* VALUEOUT : v3   ------ LongWritable*/
public class ReducerTask extends Reducer<Text, LongWritable, Text, LongWritable> {@Overrideprotected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {//1. 遍历 values 获取每一个值long  v3 = 0;for (LongWritable longWritable : values) {v3 += longWritable.get();  //1}//2. 输出context.write(key,new LongWritable(v3));}
}

定义一个主类,用来描述job并提交job

import com.sun.org.apache.bcel.internal.generic.NEW;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.nativeio.NativeIO;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;// 任务的执行入口: 将八步组合在一起
public class JobMain extends Configured implements Tool {// 在run方法中编写组装八步@Overridepublic int run(String[] args) throws Exception {Job job = Job.getInstance(super.getConf(), "JobMain");//如果提交到集群操作. 需要添加一步 : 指定入口类job.setJarByClass(JobMain.class);//1. 封装第一步:  读取数据job.setInputFormatClass(TextInputFormat.class);TextInputFormat.addInputPath(job,new Path("hdfs://node01:8020/wordcount.txt"));//2. 封装第二步:  自定义 map程序job.setMapperClass(MapTask.class);job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(LongWritable.class);//3. 第三步 第四步 第五步 第六步 省略//4. 第七步:  自定义reduce程序job.setReducerClass(ReducerTask.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(LongWritable.class);//5) 第八步  : 输出路径是一个目录, 而且这个目录必须不存在的job.setOutputFormatClass(TextOutputFormat.class);TextOutputFormat.setOutputPath(job,new Path("hdfs://node01:8020/output"));//6) 提交任务:boolean flag = job.waitForCompletion(true); // 成功  true  不成功 falsereturn flag ? 0 : 1;}public static void main(String[] args) throws Exception {Configuration configuration = new Configuration();JobMain jobMain = new JobMain();int i = ToolRunner.run(configuration, jobMain, args); //返回值 退出码System.exit(i); // 退出程序  0 表示正常  其他值表示有异常 1}
}

提醒:代码开发完成之后,就可以打成jar包放到服务器上面去运行了,实际工作当中,都是将代码打成jar包,开发main方法作为程序的入口,然后放到集群上面去运行

5. MapReduce程序运行模式

本地运行模式
1.mapreduce程序是被提交给LocalJobRunner在本地以单进程的形式运行
2.而处理的数据及输出结果可以在本地文件系统,也可以在hdfs上
3.怎样实现本地运行?写一个程序,不要带集群的配置文件本质是程序的conf中是否有mapreduce.framework.name=local以及yarn.resourcemanager.hostname=local参数
4.本地模式非常便于进行业务逻辑的debug,只要在idea中打断点即可
【本地模式运行代码设置】

configuration.set("mapreduce.framework.name","local");
configuration.set("yarn.resourcemanager.hostname","local");
-----------以上两个是不需要修改的,如果要在本地目录测试, 可有修改hdfs的路径-----------------
TextInputFormat.addInputPath(job,new Path("file:///D:\\wordcount\\input"));
TextOutputFormat.setOutputPath(job,new Path("file:///D:\\wordcount\\output"));

集群运行模式
1.将mapreduce程序提交给yarn集群,分发到很多的节点上并发执行
2.处理的数据和输出结果应该位于hdfs文件系统
3.提交集群的实现步骤:
将程序打成JAR包,然后在集群的任意一个节点上用hadoop命令启动 yarn jar hadoop_hdfs_operate-1.0-SNAPSHOT.jar cn.itcast.hdfs.demo1.JobMain

6. MapReduce的运行机制详解

6.1 MapTask 工作机制

在这里插入图片描述
整个Map阶段流程大体如上图所示。
简单概述:inputFile通过split被逻辑切分为多个split文件,通过Record按行读取内容给map(用户自己实现的)进行处理,数据被map处理结束之后交给OutputCollector收集器,对其结果key进行分区(默认使用hash分区),然后写入buffer,每个map task都有一个内存缓冲区,存储着map的输出结果,当缓冲区快满的时候需要将缓冲区的数据以一个临时文件的方式存放到磁盘,当整个map task结束后再对磁盘中这个map task产生的所有临时文件做合并,生成最终的正式输出文件,然后等待reduce task来拉数据。

详细步骤
1.读取数据组件 InputFormat (默认 TextInputFormat) 会通过 getSplits 方法对输入目录中文件进行逻辑切片规划得到 block, 有多少个 block就对应启动多少个 MapTask
2.将输入文件切分为 block 之后, 由 RecordReader 对象 (默认是LineRecordReader) 进行读取, 以 \n 作为分隔符, 读取一行数据, 返回 <key,value>. Key 表示每行首字符偏移值, Value 表示这一行文本内容
3.读取 block 返回 <key,value>, 进入用户自己继承的 Mapper 类中,执行用户重写的 map 函数, RecordReader 读取一行这里调用一次
4.Mapper 逻辑结束之后, 将 Mapper 的每条结果通过 context.write 进行collect数据收集. 在 collect 中, 会先对其进行分区处理,默认使用 HashPartitioner

MapReduce 提供 Partitioner 接口, 它的作用就是根据 Key 或 Value 及 Reducer 的数量来决定当前的这对输出数据最终应该交由哪个 Reduce task 处理, 默认对 Key Hash 后再以 Reducer 数量取模. 默认的取模方式只是为了平均 Reducer 的处理能力, 如果用户自己对 Partitioner 有需求, 可以订制并设置到 Job 上

5.接下来, 会将数据写入内存, 内存中这片区域叫做环形缓冲区, 缓冲区的作用是批量收集 Mapper 结果, 减少磁盘 IO 的影响. 我们的 Key/Value 对以及 Partition 的结果都会被写入缓冲区. 当然, 写入之前,Key 与 Value 值都会被序列化成字节数组

环形缓冲区其实是一个数组, 数组中存放着 Key, Value 的序列化数据和 Key, Value 的元数据信息, 包括 Partition, Key 的起始位置, Value 的起始位置以及 Value 的长度. 环形结构是一个抽象概念。 
缓冲区是有大小限制, 默认是 100MB. 当 Mapper 的输出结果很多时, 就可能会撑爆内存, 所以需要在一定条件下将缓冲区中的数据临时写入磁盘, 然后重新利用这块缓冲区. 这个从内存往磁盘写数据的过程被称为 Spill, 中文可译为溢写. 这个溢写是由单独线程来完成, 不影响往缓冲区写 Mapper 结果的线程. 溢写线程启动时不应该阻止 Mapper 的结果输出, 所以整个缓冲区有个溢写的比例 spill.percent. 这个比例默认是 0.8, 也就是当缓冲区的数据已经达到阈值 buffer size * spill percent = 100MB * 0.8 = 80MB, 溢写线程启动, 锁定这 80MB 的内存, 执行溢写过程. Mapper 的输出结果还可以往剩下的 20MB 内存中写, 互不影响

6.当溢写线程启动后, 需要对这 80MB 空间内的 Key 做排序 (Sort). 排序是 MapReduce 模型默认的行为, 这里的排序也是对序列化的字节做的排序

如果 Job 设置过 Combiner, 那么现在就是使用 Combiner 的时候了. 将有相同 Key 的 Key/Value 对的 Value 合并在起来, 减少溢写到磁盘的数据量. Combiner 会优化 MapReduce 的中间结果, 所以它在整个模型中会多次使用 \ 那哪些场景才能使用 Combiner 呢? 从这里分析, Combiner 的输出是 Reducer 的输入, Combiner 绝不能改变最终的计算结果. Combiner 只应该用于那种 Reduce 的输入 Key/Value 与输出 Key/Value 类型完全一致, 且不影响最终结果的场景. 比如累加, 最大值等. Combiner 的使用一定得慎重, 如果用好, 它对 Job 执行效率有帮助, 反之会影响 Reducer 的最终结果

7.合并溢写文件, 每次溢写会在磁盘上生成一个临时文件 (写之前判断是否有 Combiner), 如果 Mapper 的输出结果真的很大, 有多次这样的溢写发生, 磁盘上相应的就会有多个临时文件存在. 当整个数据处理结束之后开始对磁盘中的临时文件进行 Merge 合并, 因为最终的文件只有一个, 写入磁盘, 并且为这个文件提供了一个索引文件, 以记录每个reduce对应数据的偏移量
【mapTask的一些基础设置配置】

配置	默认值	解释
mapreduce.task.io.sort.mb	100	设置环型缓冲区的内存值大小
mapreduce.map.sort.spill.percent	0.8	设置溢写的比例
mapreduce.cluster.local.dir	${hadoop.tmp.dir}/mapred/local	溢写数据目录
mapreduce.task.io.sort.factor	10	设置一次合并多少个溢写文件

6.2 ReduceTask 工作机制

在这里插入图片描述
Reduce 大致分为 copy、sort、reduce 三个阶段,重点在前两个阶段。copy 阶段包含一个 eventFetcher 来获取已完成的 map 列表,由 Fetcher 线程去 copy 数据,在此过程中会启动两个 merge 线程,分别为 inMemoryMerger 和 onDiskMerger,分别将内存中的数据 merge 到磁盘和将磁盘中的数据进行 merge。待数据 copy 完成之后,copy 阶段就完成了,开始进行 sort 阶段,sort 阶段主要是执行 finalMerge 操作,纯粹的 sort 阶段,完成之后就是 reduce 阶段,调用用户定义的 reduce 函数进行处理

详细步骤:
1.Copy阶段,简单地拉取数据。Reduce进程启动一些数据copy线程(Fetcher),通过HTTP方式请求maptask获取属于自己的文件。
2.Merge阶段。这里的merge如map端的merge动作,只是数组中存放的是不同map端copy来的数值。Copy过来的数据会先放入内存缓冲区中,这里的缓冲区大小要比map端的更为灵活。merge有三种形式:内存到内存;内存到磁盘;磁盘到磁盘。默认情况下第一种形式不启用。当内存中的数据量到达一定阈值,就启动内存到磁盘的merge。与map 端类似,这也是溢写的过程,这个过程中如果你设置有Combiner,也是会启用的,然后在磁盘中生成了众多的溢写文件。第二种merge方式一直在运行,直到没有map端的数据时才结束,然后启动第三种磁盘到磁盘的merge方式生成最终的文件。
3.合并排序。把分散的数据合并成一个大的数据后,还会再对合并后的数据排序。
4.对排序后的键值对调用reduce方法,键相等的键值对调用一次reduce方法,每次调用会产生零个或者多个键值对,最后把这些输出的键值对写入到HDFS文件中。

6.3 Shuffle 过程

map 阶段处理的数据如何传递给 reduce 阶段,是 MapReduce 框架中最关键的一个流程,这个流程就叫 shuffle
shuffle: 洗牌、发牌 ——(核心机制:数据分区,排序,分组,规约,合并等过程)
在这里插入图片描述

shuffle 是 Mapreduce 的核心,它分布在 Mapreduce 的 map 阶段和 reduce 阶段。一般把从 Map 产生输出开始到 Reduce 取得数据作为输入之前的过程称作 shuffle。

1.Collect阶段:将 MapTask 的结果输出到默认大小为 100M 的环形缓冲区,保存的是 key/value,Partition 分区信息等。
2.Spill阶段:当内存中的数据量达到一定的阀值的时候,就会将数据写入本地磁盘,在将数据写入磁盘之前需要对数据进行一次排序的操作,如果配置了 combiner,还会将有相同分区号和 key 的数据进行排序。
3.Merge阶段:把所有溢出的临时文件进行一次合并操作,以确保一个 MapTask 最终只产生一个中间数据文件。
4.Copy阶段:ReduceTask 启动 Fetcher 线程到已经完成 MapTask 的节点上复制一份属于自己的数据,这些数据默认会保存在内存的缓冲区中,当内存的缓冲区达到一定的阀值的时候,就会将数据写到磁盘之上。
5.Merge阶段:在 ReduceTask 远程复制数据的同时,会在后台开启两个线程对内存到本地的数据文件进行合并操作。
6.Sort阶段:在对数据进行合并的同时,会进行排序操作,由于 MapTask 阶段已经对数据进行了局部的排序,ReduceTask 只需保证 Copy 的数据的最终整体有效性即可。

Shuffle 中的缓冲区大小会影响到 mapreduce 程序的执行效率,原则上说,缓冲区越大,磁盘io的次数越少,执行速度就越快
缓冲区的大小可以通过参数调整, 参数:mapreduce.task.io.sort.mb 默认100M

7. Reduce 端实现 JOIN

7.1 需求

假如数据量巨大,两表的数据是以文件的形式存储在 HDFS 中, 需要用 MapReduce 程序来实现以下 SQL 查询运算

select  a.id,a.date,b.name,b.category_id,b.price from t_order a left join t_product b on a.pid = b.id

商品表
在这里插入图片描述

订单数据表
在这里插入图片描述

7.2 实现步骤

通过将关联的条件作为map输出的key,将两表满足join条件的数据并携带数据所来源的文件信息,发往同一个reduce task,在reduce中进行数据的串联
1.定义orderBean

import org.apache.hadoop.io.Writable;import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;public class OrderJoinBean implements Writable {private String id="";  // 订单idprivate String date="";  //订单时间private String pid="";  // 商品的idprivate String amount="";  // 订单的数量private String name="";   //商品的名称private String categoryId=""; // 商品的分类idprivate String price="";  //商品的价格public String getId() {return id;}public void setId(String id) {this.id = id;}public String getDate() {return date;}public void setDate(String date) {this.date = date;}public String getPid() {return pid;}public void setPid(String pid) {this.pid = pid;}public String getAmount() {return amount;}public void setAmount(String amount) {this.amount = amount;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getCategoryId() {return categoryId;}public void setCategoryId(String categoryId) {this.categoryId = categoryId;}public String getPrice() {return price;}public void setPrice(String price) {this.price = price;}@Overridepublic String toString() {return id + "\t" + date + "\t" + pid + "\t" + amount + "\t" + name + "\t" + categoryId + "\t" + price;}@Overridepublic void write(DataOutput out) throws IOException {out.writeUTF(id);out.writeUTF(date);out.writeUTF(pid);out.writeUTF(amount);out.writeUTF(name);out.writeUTF(categoryId);out.writeUTF(price);}@Overridepublic void readFields(DataInput in) throws IOException {id = in.readUTF();date = in.readUTF();pid = in.readUTF();amount = in.readUTF();name = in.readUTF();categoryId = in.readUTF();price = in.readUTF();}
}

2.定义 Mapper

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;import java.io.IOException;public class MapperJoinTask extends Mapper<LongWritable,Text,Text,OrderJoinBean> {@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {// 通过文件片的方式获取文件的名称FileSplit fileSplit = (FileSplit) context.getInputSplit();String fileName = fileSplit.getPath().getName();//1. 获取每一行的数据String line = value.toString();//2. 切割处理String[] split = line.split(",");OrderJoinBean orderJoinBean = new OrderJoinBean();if(fileName.equals("orders.txt")){// 订单的数据orderJoinBean.setId(split[0]);orderJoinBean.setDate(split[1]);orderJoinBean.setPid(split[2]);orderJoinBean.setAmount(split[3]);}else{// 商品的数据orderJoinBean.setPid(split[0]);orderJoinBean.setName(split[1]);orderJoinBean.setCategoryId(split[2]);orderJoinBean.setPrice(split[3]);}//3. 发送给reduceTaskcontext.write(new Text(orderJoinBean.getPid()),orderJoinBean);}
}

3.定义 Reducer

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;import java.io.IOException;public class ReducerJoinTask extends Reducer<Text,OrderJoinBean,Text,OrderJoinBean> {@Overrideprotected void reduce(Text key, Iterable<OrderJoinBean> values, Context context) throws IOException, InterruptedException {//1. 遍历 :  相同的key会发给同一个reduce, 相同key的value的值形成一个集合OrderJoinBean orderJoinBean  = new OrderJoinBean();for (OrderJoinBean value : values) {String id = value.getId();if(id.equals("")){// 商品的数据orderJoinBean.setPid(value.getPid());orderJoinBean.setName(value.getName());orderJoinBean.setCategoryId(value.getCategoryId());orderJoinBean.setPrice(value.getPrice());}else {// 订单数据orderJoinBean.setId(value.getId());orderJoinBean.setDate(value.getDate());orderJoinBean.setPid(value.getPid());orderJoinBean.setAmount(value.getAmount());}}//2. 输出即可context.write(key,orderJoinBean);}
}

4.定义主类

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;public class JobReduceJoinMain extends Configured implements Tool {@Overridepublic int run(String[] args) throws Exception {//1. 获取job对象Job job = Job.getInstance(super.getConf(), "jobReduceJoinMain");//2. 拼装八大步骤job.setInputFormatClass(TextInputFormat.class);TextInputFormat.addInputPath(job,new Path("file:///D:\\reduce端join\\input"));job.setMapperClass(MapperJoinTask.class);job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(OrderJoinBean.class);job.setReducerClass(ReducerJoinTask.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(OrderJoinBean.class);job.setOutputFormatClass(TextOutputFormat.class);TextOutputFormat.setOutputPath(job,new Path("D:\\reduce端join\\out_put"));boolean b = job.waitForCompletion(true);return b?0:1;}public static void main(String[] args) throws Exception {Configuration conf = new Configuration();JobReduceJoinMain jobReduceJoinMain = new JobReduceJoinMain();int i = ToolRunner.run(conf, jobReduceJoinMain, args);System.exit(i);}
}

缺点:这种方式中,join的操作是在reduce阶段完成,reduce端的处理压力太大,map节点的运算负载则很低,资源利用率不高,且在reduce阶段极易产生数据倾斜

8. Map端实现 JOIN

8.1 概述

适用于关联表中有小表的情形.
使用分布式缓存,可以将小表分发到所有的map节点,这样,map节点就可以在本地对自己所读到的大表数据进行join并输出最终结果,可以大大提高join操作的并发度,加快处理速度

8.2 实现步骤

先在mapper类中预先定义好小表,进行join
引入实际场景中的解决方案:一次加载数据库
1.定义Mapper

import org.apache.hadoop.filecache.DistributedCache;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;public class MapperTask extends Mapper<LongWritable, Text, Text, Text> {private Map<String,String> map = new HashMap<>();// 初始化的方法, 只会被初始化一次@Overrideprotected void setup(Context context) throws IOException, InterruptedException {URI[] cacheFiles = DistributedCache.getCacheFiles(context.getConfiguration());URI fileURI = cacheFiles[0];FileSystem fs = FileSystem.get(fileURI, context.getConfiguration());FSDataInputStream inputStream = fs.open(new Path(fileURI));BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));String readLine  ="";while ((readLine = bufferedReader.readLine() ) != null  ) {// readlLine:  product一行数据String[] split = readLine.split(",");String pid = split[0];map.put(pid,split[1]+"\t"+split[2]+"\t"+split[3]);}}@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {//1. 读取一行数据: orders数据String line = value.toString();//2. 切割String[] split = line.split(",");String pid = split[2];//3. 到map中获取商品信息:String product = map.get(pid);//4. 发送给reduce: 输出context.write(new Text(pid),new Text(split[0]+"\t"+split[1]+"\t"+product +"\t"+split[3]));}
}

2.定义主类

import com.itheima.join.reduce.JobReduceJoinMain;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.filecache.DistributedCache;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;import java.net.URI;public class JobMapperJoinMain extends Configured implements Tool{@Overridepublic int run(String[] args) throws Exception {//设置缓存的位置, 必须在run的方法的最前, 如果放置在job任务创建后, 将无效// 缓存文件的路径, 必须存储在hdfs上, 否则也是无效的DistributedCache.addCacheFile(new URI("hdfs://node01:8020/cache/pdts.txt"),super.getConf());//1. 获取job 任务Job job = Job.getInstance(super.getConf(), "jobMapperJoinMain");job.setInputFormatClass(TextInputFormat.class);TextInputFormat.addInputPath(job,new Path("E:\\传智工作\\上课\\北京大数据30期\\大数据第六天\\资料\\map端join\\map_join_iput"));job.setMapperClass(MapperTask.class);job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(Text.class);job.setOutputFormatClass(TextOutputFormat.class);TextOutputFormat.setOutputPath(job,new Path("E:\\传智工作\\上课\\北京大数据30期\\大数据第六天\\资料\\map端join\\out_put_map"));boolean b = job.waitForCompletion(true);return b?0:1;}public static void main(String[] args) throws Exception {Configuration conf = new Configuration();JobMapperJoinMain jobMapperJoinMain = new JobMapperJoinMain();int i = ToolRunner.run(conf, jobMapperJoinMain, args);System.exit(i);}
}

9. 社交粉丝数据分析

9.1 需求分析

以下是qq的好友列表数据,冒号前是一个用户,冒号后是该用户的所有好友(数据中的好友关系是单向的)

A:B,C,D,F,E,O
B:A,C,E,K
C:A,B,D,E,I 
D:A,E,F,L
E:B,C,D,M,L
F:A,B,C,D,E,O,M
G:A,C,D,E,F
H:A,C,D,E,O
I:A,O
J:B,O
K:A,C,D
L:D,E,F
M:E,F,G
O:A,H,I,J

求出哪些人两两之间有共同好友,及他俩的共同好友都有谁?
【解题思路】
第一步

map
读一行   A:B,C,D,F,E,O
输出    <B,A><C,A><D,A><F,A><E,A><O,A>
在读一行   B:A,C,E,K
输出   <A,B><C,B><E,B><K,B>
REDUCE
拿到的数据比如<C,A><C,B><C,E><C,F><C,G>......
输出:  
<A-B,C>
<A-E,C>
<A-F,C>
<A-G,C>
<B-E,C>
<B-F,C>.....

第二步

map
读入一行<A-B,C>
直接输出<A-B,C>
reduce
读入数据  <A-B,C><A-B,F><A-B,G>.......
输出: A-B  C,F,G,.....

9.2 实现步骤

第一个MapReduce代码实现
【Mapper类】

public class Step1Mapper extends Mapper<LongWritable,Text,Text,Text> {@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {//1:以冒号拆分行文本数据: 冒号左边就是V2String[] split = value.toString().split(":");String userStr = split[0];//2:将冒号右边的字符串以逗号拆分,每个成员就是K2String[] split1 = split[1].split(",");for (String s : split1) {//3:将K2和v2写入上下文中context.write(new Text(s), new Text(userStr));}}
}

【Reducer类】

public class Step1Reducer extends Reducer<Text,Text,Text,Text> {@Overrideprotected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {//1:遍历集合,并将每一个元素拼接,得到K3StringBuffer buffer = new StringBuffer();for (Text value : values) {buffer.append(value.toString()).append("-");}//2:K2就是V3//3:将K3和V3写入上下文中context.write(new Text(buffer.toString()), key);}
}

JobMain:

public class JobMain extends Configured implements Tool {@Overridepublic int run(String[] args) throws Exception {//1:获取Job对象Job job = Job.getInstance(super.getConf(), "common_friends_step1_job");//2:设置job任务//第一步:设置输入类和输入路径job.setInputFormatClass(TextInputFormat.class);TextInputFormat.addInputPath(job, new Path("file:///D:\\input\\common_friends_step1_input"));//第二步:设置Mapper类和数据类型job.setMapperClass(Step1Mapper.class);job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(Text.class);//第三,四,五,六//第七步:设置Reducer类和数据类型job.setReducerClass(Step1Reducer.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(Text.class);//第八步:设置输出类和输出的路径job.setOutputFormatClass(TextOutputFormat.class);TextOutputFormat.setOutputPath(job, new Path("file:///D:\\out\\common_friends_step1_out"));//3:等待job任务结束boolean bl = job.waitForCompletion(true);return bl ? 0: 1;}public static void main(String[] args) throws Exception {Configuration configuration = new Configuration();//启动job任务int run = ToolRunner.run(configuration, new JobMain(), args);System.exit(run);}
}

第二个MapReduce代码实现
【Mapper类】

public class Step2Mapper extends Mapper<LongWritable,Text,Text,Text> {/*K1           V10            A-F-C-J-E- B----------------------------------K2             V2A-C            BA-E            BA-F            BC-E            B*/@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {//1:拆分行文本数据,结果的第二部分可以得到V2String[] split = value.toString().split("\t");String   friendStr =split[1];//2:继续以'-'为分隔符拆分行文本数据第一部分,得到数组String[] userArray = split[0].split("-");//3:对数组做一个排序Arrays.sort(userArray);//4:对数组中的元素进行两两组合,得到K2/*A-E-C ----->  A  C  EA  C  EA  C  E*/for (int i = 0; i <userArray.length -1 ; i++) {for (int j = i+1; j  < userArray.length ; j++) {//5:将K2和V2写入上下文中context.write(new Text(userArray[i] +"-"+userArray[j]), new Text(friendStr));}}}
}

【Reducer类】

public class Step2Reducer extends Reducer<Text,Text,Text,Text> {@Overrideprotected void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {//1:原来的K2就是K3//2:将集合进行遍历,将集合中的元素拼接,得到V3StringBuffer buffer = new StringBuffer();for (Text value : values) {buffer.append(value.toString()).append("-");}//3:将K3和V3写入上下文中context.write(key, new Text(buffer.toString()));}
}

【JobMain】

public class JobMain extends Configured implements Tool {@Overridepublic int run(String[] args) throws Exception {//1:获取Job对象Job job = Job.getInstance(super.getConf(), "common_friends_step2_job");//2:设置job任务//第一步:设置输入类和输入路径job.setInputFormatClass(TextInputFormat.class);TextInputFormat.addInputPath(job, new Path("file:///D:\\out\\common_friends_step1_out"));//第二步:设置Mapper类和数据类型job.setMapperClass(Step2Mapper.class);job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(Text.class);//第三,四,五,六//第七步:设置Reducer类和数据类型job.setReducerClass(Step2Reducer.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(Text.class);//第八步:设置输出类和输出的路径job.setOutputFormatClass(TextOutputFormat.class);TextOutputFormat.setOutputPath(job, new Path("file:///D:\\out\\common_friends_step2_out"));//3:等待job任务结束boolean bl = job.waitForCompletion(true);return bl ? 0: 1;}public static void main(String[] args) throws Exception {Configuration configuration = new Configuration();//启动job任务int run = ToolRunner.run(configuration, new JobMain(), args);System.exit(run);}
}

10. 倒排索引建立

10.1 需求分析

需求:有大量的文本(文档、网页),需要建立搜索索引
思路分析:
首选将文档的内容全部读取出来,加上文档的名字作为key,文档的value为1,组织成这样的一种形式的数据
map端数据输出:

hello-a.txt  1hello-a.txt 1hello-a.txt 1

reduce端数据输出:
hello-a.txt 3

10.2 代码实现

public class IndexCreate extends Configured implements Tool {public static void main(String[] args) throws Exception {ToolRunner.run(new Configuration(),new IndexCreate(),args);}@Overridepublic int run(String[] args) throws Exception {Job job = Job.getInstance(super.getConf(), IndexCreate.class.getSimpleName());job.setInputFormatClass(TextInputFormat.class);TextInputFormat.addInputPath(job,new Path("file:///D:\\倒排索引\\input"));job.setMapperClass(IndexCreateMapper.class);job.setMapOutputKeyClass(Text.class);job.setMapOutputValueClass(IntWritable.class);job.setReducerClass(IndexCreateReducer.class);job.setOutputKeyClass(Text.class);job.setOutputValueClass(IntWritable.class);job.setOutputFormatClass(TextOutputFormat.class);TextOutputFormat.setOutputPath(job,new Path("file:///D:\\倒排索引\\outindex"));boolean bool = job.waitForCompletion(true);return bool?0:1;}public static class IndexCreateMapper extends Mapper<LongWritable,Text,Text,IntWritable>{Text text = new Text();IntWritable v = new IntWritable(1);@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {//获取文件切片FileSplit fileSplit  = (FileSplit) context.getInputSplit();//通过文件切片获取文件名String name = fileSplit.getPath().getName();String line = value.toString();String[] split = line.split(" ");//输出 单词--文件名作为key  value是1for (String word : split) {text.set(word+"--"+name);context.write(text,v);}}}public static class IndexCreateReducer extends Reducer<Text,IntWritable,Text,IntWritable>{IntWritable value = new IntWritable();@Overrideprotected void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {int count = 0;for (IntWritable value : values) {count += value.get();}value.set(count);context.write(key,value);}}
}

相关文章:

2 MapReduce

2 MapReduce 1. MapReduce 介绍1.1 MapReduce 设计构思 2. MapReduce 编程规范3. Mapper以及Reducer抽象类介绍1.Mapper抽象类的基本介绍2.Reducer抽象类基本介绍 4. WordCount示例编写5. MapReduce程序运行模式6. MapReduce的运行机制详解6.1 MapTask 工作机制6.2 ReduceTask …...

OpenCV:SIFT关键点检测与描述子计算

目录 1. 什么是 SIFT&#xff1f; 2. SIFT 的核心步骤 2.1 尺度空间构建 2.2 关键点检测与精细化 2.3 方向分配 2.4 计算特征描述子 3. OpenCV SIFT API 介绍 3.1 cv2.SIFT_create() 3.2 sift.detect() 3.3 sift.compute() 3.4 sift.detectAndCompute() 4. SIFT 关…...

初识Cargo:Rust的强大构建工具与包管理器

初识Cargo&#xff1a;Rust的强大构建工具与包管理器 如果你刚刚开始学习Rust&#xff0c;一定会遇到一个名字&#xff1a;Cargo。Cargo是Rust的官方构建工具和包管理器&#xff0c;它让Rust项目的创建、编译、测试和依赖管理变得非常简单。本文将带你快速了解Cargo的基本用法…...

LightM-UNet(2024 CVPR)

论文标题LightM-UNet: Mamba Assists in Lightweight UNet for Medical Image Segmentation论文作者Weibin Liao, Yinghao Zhu, Xinyuan Wang, Chengwei Pan, Yasha Wang and Liantao Ma发表日期2024年01月01日GB引用> Weibin Liao, Yinghao Zhu, Xinyuan Wang, et al. Ligh…...

2025年02月01日Github流行趋势

项目名称&#xff1a;oumi 项目地址url&#xff1a;https://github.com/oumi-ai/oumi 项目语言&#xff1a;Python 历史star数&#xff1a;544 今日star数&#xff1a;103 项目维护者&#xff1a;xrdaukar, oelachqar, taenin, wizeng23, kaisopos 项目简介&#xff1a;一切你需…...

自动化测试框架搭建-封装requests-优化

目的 1、实际的使用场景&#xff0c;无法避免的需要区分GET、POST、PUT、PATCH、DELETE等不同的方式请求&#xff0c;以及不同请求的传参方式 2、python中requests中&#xff0c;session.request方法&#xff0c;GET请求&#xff0c;只支持params传递参数 session.request(me…...

什么是线性化PDF?

线性化PDF是一种特殊的PDF文件组织方式。 总体而言&#xff0c;PDF是一种极为优雅且设计精良的格式。PDF由大量PDF对象构成&#xff0c;这些对象用于创建页面。相关信息存储在一棵二叉树中&#xff0c;该二叉树同时记录文件中每个对象的位置。因此&#xff0c;打开文件时只需加…...

XML DOM 浏览器差异

DOM 解析中的浏览器差异 所有现代的浏览器都支持 W3C DOM 规范。 然而&#xff0c;浏览器之间是有差异的。一个重要的差异是&#xff1a; 处理空白和换行的方式 DOM - 空白和换行 XML 经常在节点之间包含换行或空白字符。这是在使用简单的编辑器&#xff08;比如记事本&…...

电子电气架构 --- 汽车电子拓扑架构的演进过程

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 简单&#xff0c;单纯&#xff0c;喜欢独处&#xff0c;独来独往&#xff0c;不易合同频过着接地气的生活…...

01-六自由度串联机械臂(ABB)位置分析

ABB工业机器人&#xff08;IRB2600&#xff09;如下图所示&#xff08;d1444.8mm&#xff0c;a1150mm&#xff0c;a2700mm&#xff0c;a3115mm&#xff0c;d4795mm&#xff0c;d685mm&#xff09;&#xff0c;利用改进DH法建模&#xff0c;坐标系如下所示&#xff1a; 利用改进…...

04树 + 堆 + 优先队列 + 图(D1_树(D6_B树(B)))

目录 一、学习前言 二、基本介绍 三、特性 1. 从概念上说起 2. 举个例子 四、代码实现 节点准备 大体框架 实现分裂 实现新增 实现删除 五、完整源码 一、学习前言 前面我们已经讲解过了二叉树、二叉搜索树&#xff08;BST&#xff09;、平衡二叉搜索树&#xff08…...

350.两个数组的交集 ②

目录 题目过程解法 题目 给你两个整数数组 nums1 和 nums2 &#xff0c;请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数&#xff0c;应与元素在两个数组中都出现的次数一致&#xff08;如果出现次数不一致&#xff0c;则考虑取较小值&#xff09;。可以不考虑…...

C#,入门教程(09)——运算符的基础知识

上一篇&#xff1a; C#&#xff0c;入门教程(08)——基本数据类型及使用的基础知识https://blog.csdn.net/beijinghorn/article/details/123906998 一、算术运算符号 算术运算符号包括&#xff1a;四则运算 加 , 减-, 乘*, 除/与取模%。 // 加法&#xff0c;运算 int va 1 …...

Python-基于PyQt5,wordcloud,pillow,numpy,os,sys等的智能词云生成器

前言&#xff1a;日常生活中&#xff0c;我们有时后就会遇见这样的情形&#xff1a;我们需要将给定的数据进行可视化处理&#xff0c;同时保证呈现比较良好的量化效果。这时候我们可能就会用到词云图。词云图&#xff08;Word cloud&#xff09;又称文字云&#xff0c;是一种文…...

海外问卷调查之渠道查,企业经营的指南针

海外问卷调查&#xff0c;是企业调研最常用到的方法&#xff0c;有目的、有计划、有系统地收集研究对象的现实状况或历史状况的一种有效手段&#xff0c;是指导企业经营的有效手段。 海外问卷调查充分运用历史法、观察法等方法&#xff0c;同时使用谈话、问卷、个案研究、测试…...

C++:虚函数与多态性习题

题目内容&#xff1a; 构建一个车&#xff08;vehicle&#xff09;基类&#xff0c;包含Run、Stop两个纯虚函数。由此基类&#xff0c;派生出&#xff08;Car&#xff09;轿车类&#xff0c;&#xff08;truck&#xff09;卡车类&#xff0c;在这两个类中别分定义Run和Stop两个…...

单片机基础模块学习——超声波传感器

一、超声波原理 左边发射超声波信号&#xff0c;右边接收超声波信号 左边的芯片用来处理超声波发射信号&#xff0c;中间的芯片用来处理接收的超声波信号 二、超声波原理图 T——transmit 发送R——Recieve 接收 U18芯片对输入的N_A1信号进行放大&#xff0c;然后输入给超声…...

通过protoc工具生成proto的pb.go文件以及使用protoc-go-inject-tag工具注入自定义标签

1.ProtoBuf认识,安装以及用法 参考:[golang 微服务] 3. ProtoBuf认识&#xff0c;安装以及golang 中ProtoBuf使用 2. 使用protoc-go-inject-tag工具注入自定义标签 这里有一个案例: syntaxproto3; package test;option go_package ".;test";message MyMessage {int6…...

42【语言的编码架构】

不同语言采用的编码架构不一样 火山采用&#xff1a;UTF-16 易语言采用&#xff1a;GBK php采用&#xff1a;UTF-8 这个编码架构指的就是文本所代表的字节集&#xff0c;比如易语言中“你好”表示的就是{196,227,186,195} 窗口程序集名保 留 保 留备 注窗口程序集_启动窗口 …...

TOF技术原理和静噪对策

本文章是笔者整理的备忘笔记。希望在帮助自己温习避免遗忘的同时&#xff0c;也能帮助其他需要参考的朋友。如有谬误&#xff0c;欢迎大家进行指正。 一、什么是TOF TOF 是Time of Flight的缩写&#xff0c;它是一种通过利用照射波和反射波之间的时间差来测量到物体的距离的测…...

ssh调试:fatal: Could not read from remote repository.

我遇到的原因和网上说的什么在生产密钥时没加邮箱&#xff0c;以及多个密钥的配置问题都不一样&#xff1b; 例如https://blog.csdn.net/baoyin0822/article/details/122584931 或https://blog.csdn.net/qq_55558061/article/details/124117445 我遇到的问题的原因跟他们都i不…...

win10部署本地deepseek-r1,chatbox,deepseek联网(谷歌网页插件)

win10部署本地deepseek-r1&#xff0c;chatbox&#xff0c;deepseek联网&#xff08;谷歌网页插件&#xff09; 前言一、本地部署DeepSeek-r1step1 安装ollamastep2 下载deepseek-r1step2.1 找到模型deepseek-r1step2.2 cmd里粘贴 后按回车&#xff0c;进行下载 step3 测试指令…...

SpringCloud系列教程:微服务的未来(十九)请求限流、线程隔离、Fallback、服务熔断

前言 前言 在现代微服务架构中&#xff0c;系统的高可用性和稳定性至关重要。为了解决系统在高并发请求或服务不可用时出现的性能瓶颈或故障&#xff0c;常常需要使用一些技术手段来保证服务的平稳运行。请求限流、线程隔离、Fallback 和服务熔断是微服务中常用的四种策略&…...

Hot100之子串

560和为K的子数组 题目 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列 思路解析 ps&#xff1a;我们的presum【0】就是0&#xff0c;如果没有这个0的话我们的第一个元素就无法减去上…...

SpringBoot笔记

1.创建 使用idea提供的脚手架创建springboot项目&#xff0c;选上需要的模块&#xff0c;会自动进行导包 打成jar包&#xff0c;之前直接用原生的maven打包的是一个瘦jar&#xff0c;不能直接跑&#xff0c;把服务器上部署的jar排除在外了&#xff0c;但是现在加上打包查件&am…...

一、TensorFlow的建模流程

1. 数据准备与预处理&#xff1a; 加载数据&#xff1a;使用内置数据集或自定义数据。 预处理&#xff1a;归一化、调整维度、数据增强。 划分数据集&#xff1a;训练集、验证集、测试集。 转换为Dataset对象&#xff1a;利用tf.data优化数据流水线。 import tensorflow a…...

4 Hadoop 面试真题

4 Hadoop 面试真题 1. Apache Hadoop 3.0.02. HDFS 3.x 数据存储新特性-纠删码Hadoop面试真题 1. Apache Hadoop 3.0.0 Apache Hadoop 3.0.0在以前的主要发行版本&#xff08;hadoop-2.x&#xff09;上进行了许多重大改进。 最低要求的Java版本从Java 7增加到Java 8 现在&…...

信息学奥赛一本通 ybt 1608:【 例 3】任务安排 3 | 洛谷 P5785 [SDOI2012] 任务安排

【题目链接】 ybt 1608&#xff1a;【 例 3】任务安排 3 洛谷 P5785 [SDOI2012] 任务安排 【题目考点】 1. 动态规划&#xff1a;斜率优化动规 2. 单调队列 3. 二分答案 【解题思路】 与本题题面相同但问题规模不同的题目&#xff1a; 信息学奥赛一本通 1607&#xff1a…...

实验六 项目二 简易信号发生器的设计与实现 (HEU)

声明&#xff1a;代码部分使用了AI工具 实验六 综合考核 Quartus 18.0 FPGA 5CSXFC6D6F31C6N 1. 实验项目 要求利用硬件描述语言Verilog&#xff08;或VHDL&#xff09;、图形描述方式、IP核&#xff0c;结合数字系统设计方法&#xff0c;在Quartus开发环境下&#xff…...

基于最近邻数据进行分类

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 完整代码&#xff1a; import torch import numpy as np from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score import matplotlib.pyplot as plt# 生成一个简单的数据…...

SpringSecurity:There is no PasswordEncoder mapped for the id “null“

文章目录 一、情景说明二、分析三、解决 一、情景说明 在整合SpringSecurity功能的时候 我先是去实现认证功能 也就是&#xff0c;去数据库比对用户名和密码 相关的类&#xff1a; UserDetailsServiceImpl implements UserDetailsService 用于SpringSecurity查询数据库 Logi…...

redex快速体验

第一步&#xff1a; 2.回调函数在每次state发生变化时候自动执行...

Flask框架基础入门教程_ezflaskapp

pip install flaskFlask 快速入门小应用 学东西&#xff0c;得先知道我们用这个东西&#xff0c;能做出来一个什么东西。 一个最小的基于flask 的应用可能看上去像下面这个样子&#xff1a; from flask import Flask app Flask(__name__)app.route(/) def hello_world():ret…...

Anaconda 全面解析:从入门到精通的操作教程

大家好&#xff0c;我是滔滔&#xff0c;欢迎来到我的空间。先简单介绍下anconda 一、环境管理 轻松创建独立的 Python 环境&#xff1a;可以为不同的项目创建不同的环境&#xff0c;每个环境可以有不同的 Python 版本和安装不同的包&#xff0c;避免了包冲突问题。例如&…...

3D图形学与可视化大屏:什么是材质属性,有什么作用?

一、颜色属性 漫反射颜色 漫反射颜色决定了物体表面对入射光进行漫反射后的颜色。当光线照射到物体表面时&#xff0c;一部分光被均匀地向各个方向散射&#xff0c;形成漫反射。漫反射颜色的选择会直接影响物体在光照下的外观。例如&#xff0c;一个红色的漫反射颜色会使物体在…...

HTML-新浪新闻-实现标题-排版

标题排版 图片标签&#xff1a;<img> src&#xff1a;指定图片的url&#xff08;绝对路径/相对路径&#xff09; width&#xff1a;图片的宽度&#xff08;像素/相对于父元素的百分比&#xff09; heigth&#xff1a;图片的高度&#xff08;像素/相对于父元素的百分比&a…...

.Net / C# 分析文件编码 并将 各种编码格式 转为 另一个编码格式 ( 比如: GB2312→UTF-8, UTF-8→GB2312)

相关库 .Net 8 编码识别: github.com/CharsetDetector/UTF-unknown <PackageReference Include"UTF.Unknown" Version"2.5.1" />代码 using UtfUnknown;var dir_path "D:\\Desktop\\新建文件夹2\\新建文件夹"; var dir_new_path &quo…...

本地部署 DeepSeek-R1 大模型

本地部署 DeepSeek-R1 大模型指南 1. 引言 1.1 DeepSeek-R1 模型简介 在人工智能的世界里&#xff0c;大型语言模型&#xff08;LLM&#xff09;正如一座巨大的宝库&#xff0c;里面储存着丰富的信息和无限的潜力。而DeepSeek-R1&#xff0c;就像那扇打开智慧之门的钥匙。它…...

canvas的基本用法

canvas canvas元素简介 1.是个container元素<canvas width100 height100></canvas>&#xff0c;有开闭标签 2.有且只有width和height两个attribute&#xff0c;不需要写单位 canvas的基本使用 const canvasEl document.getElementById(canvas01) const ctx …...

力扣【416. 分割等和子集】详细Java题解(背包问题)

首先我们可以求出数组和&#xff0c;当我们找到一个子集中元素的和为数组和的一半时&#xff0c;该就说明可以分割等和子集。 对于该问题我们可以转换成背包问题&#xff0c;求 数组里的元素 装入 数组和的一半大小的背包 能取得的最大值。 然后注意可以剪枝的地方。 代码&…...

UE学习日志#17 C++笔记#3 基础复习3

19.2 [[maybe_unused]] 禁止编译器在未使用某些内容时发出警告 19.3 [[noreturn]] 永远不会把控制权返回给调用点 19.4 [[deprecated]] 标记为已弃用&#xff0c;仍然可以使用但是不鼓励使用 可以加参数表示弃用的原因[[deprecated("")]] 19.5 [[likely]]和[[un…...

c++:vector

1.使用 1.1构造函数 常见的三种构造方式&#xff1a;空构造&#xff0c;拷贝构造&#xff0c;指定元素构造 1.2iterator begin和end也分为正向和反向。 注意&#xff1a;反向迭代器可以反向遍历是因为在定义rbegin和rend函数的时候把尾地址给到了rbegin&#xff0c;而不是说改…...

37. RGBLCD实验

一、RGBLCD显示原理简介 1、像素点 于一个“小灯“&#xff0c;不管是液晶屏&#xff0c;还是手机&#xff0c;平板&#xff0c;RGBLCD屏幕他都是有由一个个的彩色小灯构成的。彩色点阵屏每个像素点有三个小灯&#xff0c;红色、绿色和蓝色&#xff0c;也叫做RGB。RGB就是光的…...

反馈驱动、上下文学习、多语言检索增强等 | Big Model Weekly 第55期

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 01 A Bayesian Approach to Harnessing the Power of LLMs in Authorship Attribution 传统方法严重依赖手动特征&#xff0c;无法捕捉长距离相关性&#xff0c;限制了其有效性。最近的研究利用预训练语言模型的…...

【深度分析】微软全球裁员计划不影响印度地区,将继续增加当地就业机会

当微软的裁员刀锋掠过全球办公室时&#xff0c;班加罗尔的键盘声却愈发密集——这场资本迁徙背后&#xff0c;藏着数字殖民时代最锋利的生存法则。 表面是跨国公司的区域战略调整&#xff0c;实则是全球人才市场的地壳运动。微软一边在硅谷裁撤年薪20万美金的高级工程师&#x…...

H. Mad City

题目链接&#xff1a;Problem - H - Codeforces 题目大意&#xff1a;给定一个带环的图&#xff0c; 以及a, b两点 判断再图上不断的移动&#xff0c; b想不与a相遇&#xff0c; a想捉到b, 并且二者只能移动一步。 若b跑不掉 NO 否则YES. 具体题目看链接 输入&#xff1a; …...

【C++】类与对象(下)

&#x1f984; 个人主页: 小米里的大麦-CSDN博客 &#x1f38f; 所属专栏: 小米里的大麦——C专栏_CSDN博客 &#x1f381; 代码托管: 小米里的大麦的Gitee仓库 ⚙️ 操作环境: Visual Studio 2022 文章目录 1. 再谈构造函数1.1 构造函数体赋值1.2 初始化列表1.3 explicit 关键…...

AJAX案例——图片上传个人信息操作

黑马程序员视频地址&#xff1a; AJAX-Day02-11.图片上传https://www.bilibili.com/video/BV1MN411y7pw?vd_source0a2d366696f87e241adc64419bf12cab&spm_id_from333.788.videopod.episodes&p26 图片上传 <!-- 文件选择元素 --><input type"file"…...

Redis-布隆过滤器

文章目录 布隆过滤器的特点:实践布隆过滤器应用 布隆过滤器的特点: 就可以把布隆过滤器理解为一个set集合&#xff0c;我们可以通过add往里面添加元素&#xff0c;通过contains来判断是否包含某个元素。 布隆过滤器是一个很长的二进制向量和一系列随机映射函数。 可以用来检索…...

OpenCV 图像旋转

在学习 OpenCV 和 Matplotlib 处理图像时&#xff0c;遇到了一些关于 cv2.imread()、cv2.getRotationMatrix2D()、plt.imshow() 的问题&#xff1a; import cv2 import numpy as np import matplotlib.pyplot as pltimg cv2.imread(img2.png, 1) # 读取彩色图像&#xff08;…...