Hadoop基础学习---6、MapReduce框架原理

news2024/11/20 6:21:48

1、MapReduce框架原理

在这里插入图片描述

1.1 InputFormat数据输入

1.1.1 切片与MapTask并行度决定机制

1、问题引出
MapTask的并行度决定Map阶段的任务处理并发度,进而影响到整个job的处理速度。
2、MapTask并行度决定机制
数据块:Block是HDFS物理上吧数据分成一块一块。数据块是HDFS储存数据单位。

数据切片:数据切片只是在逻辑上对输出进行分片,并不会在磁盘上将其切分成片进行储存。数据切片是MapReduce程序计算输入数据的单位,一个切片会对应启动一个MapTask。

在这里插入图片描述

1.1.2 Job提交流程源码与切片源码详解

1、Job提交流程源码解析

waitForCompletion()
submit();
// 1 建立连接
connect();
// 1)创建提交 Job 的代理
new Cluster(getConfiguration());
// (1)判断是本地运行环境还是 yarn 集群运行环境
initialize(jobTrackAddr, conf); 
// 2 提交 job
submitter.submitJobInternal(Job.this, cluster)
// 1)创建给集群提交数据的 Stag 路径
Path jobStagingArea = JobSubmissionFiles.getStagingDir(cluster, conf);
// 2)获取 jobid ,并创建 Job 路径
JobID jobId = submitClient.getNewJobID();
// 3)拷贝 jar 包到集群
copyAndConfigureFiles(job, submitJobDir);
rUploader.uploadFiles(job, jobSubmitDir);
// 4)计算切片,生成切片规划文件
writeSplits(job, submitJobDir);
maps = writeNewSplits(job, jobSubmitDir);
input.getSplits(job);
// 5)向 Stag 路径写 XML 配置文件
writeConf(conf, submitJobFile);
conf.writeXml(out);
// 6)提交 Job,返回提交状态
status = submitClient.submitJob(jobId, submitJobDir.toString(),
job.getCredentials());

Job提交流程源码解析
在这里插入图片描述
2、FileInputFormat切片源码解析
在这里插入图片描述

1.1.3 FileInputFormat 切片机制

1、切片机制
(1)简单地按照文件的内容长度进行切片
(2)切片大小。默认等于Block大小
(3)切片时不考虑数据集整体,而是逐个针对每一个文件单独切片
2、案例分析
在这里插入图片描述
3、源码解析
(1)源码中计算切片大小的公式

Math.max(minSize, Math.min(maxSize, blockSize));
mapreduce.input.fileinputformat.split.minsize=1 默认值为1
mapreduce.input.fileinputformat.split.maxsize= Long.MAXValue 默认值Long.MAXValue
因此,默认情况下,切片大小=blocksize。

(2)切片大小设置
maxsize(切片最大值):参数如果调得比blockSize小,则会让切片变小,而且就等于配置的这个参数的值。
minsize(切片最小值):参数调的比blockSize大,则可以让切片变得比blockSize还大。
(3)获取切片信息API

// 获取切片的文件名称
String name = inputSplit.getPath().getName();
// 根据文件类型获取切片信息
FileSplit inputSplit = (FileSplit) context.getInputSplit();

1.1.4 TextInputFormat

1、FileInputFormat实现类
FileInputFormat 常见的接口实现类包括:TextInputFormat、KeyValueTextInputFormat、
NLineInputFormat、CombineTextInputFormat 和自定义 InputFormat 等。

2、TextInputFormat
TextInputFormat 是默认的 FileInputFormat 实现类。按行读取每条记录。键是存储该行在整个文件中的起始字节偏移量, LongWritable 类型。值是这行的内容,不包括任何行终止符(换行符和回车符),Text 类型。

1.1.5 CombineTextInputFormat 切片机制

框架默认的TextInputFormat切片机制时对任务按文件规划切片,不管文件多小,都会时一个单独的切片,都会交给一个MapTask,这样如果有大量小文件,就会产生大量的MapTask,处理效率极其低下。

1、应用场景:
CombineTextInputFormat 用于小文件过多的场景,它可以将多个小文件从逻辑上规划到
一个切片中,这样,多个小文件就可以交给一个 MapTask 处理。
2、虚拟储存切片最大值设置
CombineTextInputFormat.setMaxInputSplitSize(job,4194304);//4M
注意:虚拟存储切片最大值设置最好根据实际的小文件大小情况来设置具体的值。
3、切片机制
生成切片过程包括:虚拟储存过程和切片过程两部分。

在这里插入图片描述
(1)虚拟储存过程:
将输入目录下所以文件大小,依次和设置的setMaxInputSpiltSize值比较,如果不大于设置的最大值,逻辑上划分一个块。如果输入文件大于设置·的最大值且大于两倍,那么以最大值切割一块;当剩余数据大小超过设置的最大值且不大于最大值两倍,此时将文件均分成2个虚拟储存块(防止出现太小切片)。
例如setMaxInputSpiltSize值为4M,输入文件大小为8.02M,先逻辑上分成一个4M。剩余的大小为4.02M,如果按照4M逻辑划分,就会出现0.02M的小的虚拟储存文件,所以将剩余的4.02文件切分成(2.01M,2.01M)两个文件。
(2)切片过程:
(a)判断虚拟储存的文件大小是否大于setMaxInputSpiltSize值,大于等于则单独形成一个切片。
(b)如果不大于则跟下一个虚拟储存文件进行合并,共同形成一个切片。
(c)测试举例: 有 4 个小文件大小分别为 1.7M、5.1M、3.4M 以及 6.8M 这四个小
文件,则虚拟存储之后形成 6 个文件块,大小分别为:1.7M,(2.55M、2.55M),3.4M 以及(3.4M、3.4M)
最终会形成三个切片,大小分别为:(1.7+2.55)M,(2.55+3.4)M,(3.4+3.4)M

1.1.6 CombineTextInputFormat案例实操

1、需求
将输入的大量小文件合并成一个切片统一处理
(1)输入数据
在这里插入图片描述
(2)期望
期望一个切片处理四个文件
2、实现过程
(1)正常情况下,这是要生成4个切片的
(2)在 WordcountDriver 中增加如下代码,运行程序,并观察运行的切片个数为 1。

// 如果不设置 InputFormat,它默认用的是 TextInputFormat.class
job.setInputFormatClass(CombineTextInputFormat.class);
//虚拟存储切片最大值设置 20m   
CombineTextInputFormat.setMaxInputSplitSize(job, 20971520);

运行如果为 1 个切片:

number of splits:1

说明:为什么设置20M就是只有一个切片呢?
因为四个文件加起来都没有20M大(我们设置的MaxInputSpiltSize的大小)

1.2 MapReduce 工作流程

(1)
在这里插入图片描述
(2)在这里插入图片描述
上面的流程是整个MapReduce最全工作流程,但是Shuffle过程只是从第7步开始到第16步结束,具体Shuffle过程详解,如下:
(1)MapTask收集我们的map()方法输出的kv对,放到内存缓冲区中
(2)从内存缓冲区不断溢出到本地磁盘问就,可能会溢出多个文件
(3)多个溢出文件会被合并成大的溢出文件
(4)在溢出过程及合并过程中,都有调用Partitioner进行分区和针对key进行排序
(5)ReduceTask根据自己的分区号,去各个MapTask机器上取相对应的结果分区数据
(6)ReduceTask会抓取同一个分区的来着不同MapTask的结果文件,ReduceTask会将这些文件再进行合并(归并排序)
(7)合并成大文件后,Shuffle的过程也就结束了,后面进入ReduceTask的逻辑运算过程(从文件中取出一个一个的键值对Group,调用用户自定义的reduce()方法)

注意:
(1)Shuffle中的缓冲区大小会影响到MapReduce程序的执行效率,从原则上·说,缓冲器越大,磁盘IO的次数越少,执行的速度越快。
(2)缓冲区的大小可以通过参数调整,参数:mapreduce.task.io.sort.mb默认是100M

1.3 Shuffle机制

1.3.1 Shuffle机制

Map方法之后,Reduce方法之前的数据处理过程称之为Shuffle。

在这里插入图片描述

1.3.2 Partition

1、问题引出
要求将统计结果按照条件输出到不同文件中(分区)。比如:将统计结果按照收集归属地不同省份输出到不同文件中。
2、默认Partitioner分区
在这里插入图片描述
默认分区时根据key的hashCode对ReduceTasks个数取模得到的。用户没法控制哪个key储存到哪个分区

3、自定义Partitioner步骤
(1)自定义类继承Partitioner,重写getPartition()方法

public class CustomPartitioner extends Partitioner<Text, FlowBean> {
@Override
public int getPartition(Text key, FlowBean value, int numPartitions) {
// 控制分区代码逻辑
… …
return partition;
	}
}

(2)在驱动中,设置自定义Partitioner

job.setPartitionerClass(CustomPartitioner.class);

(3)自定义Partition后,要根据自定义Partitioner的逻辑设置相对应数量的ReduceTask

job.setNumReduceTasks(5); //我的逻辑分区数量是5

(4)分区总结
(a)如果ReduceTask的数量大于getPartition的结果数,则会多产生几个空的输出文件part-r-000xx;
(b)如果1 小于 ReduceTask的数量 小于 getPartition的结果数,则有一部分分区数据无处安放,会Exception;
(c)如 果ReduceTask的数量=1,则不管MapTask端输出多少个分区文件,最终结果都交给这一个
ReduceTask,最终也就只会产生一个结果文件 part-r-00000;
(d)分区号必须从零开始,逐一累加。

1.3.3 Partition 分区案例实操

1、需求
将统计结果按照手机归属地不同省份输出到不同文件中(分区)
(1)输入数据文件(百度网盘自取数据文件)
链接:https://pan.baidu.com/s/1i2FdQTWFijkrr29n9xAj8Q
提取码:zhm6
(2)手机号 136、137、138、139 开头都分别放到一个独立的 4 个文件中,其他开头的放到
一个文件中。
2、需求分析
在这里插入图片描述
3、在序列化实操的基础上,增加一个分区类

package org.example.fenqu;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;

/**
 * @ClassName MyPartition
 * @Description TODO
 * @Author Zouhuiming
 * @Date 2023/5/21 11:29
 * @Version 1.0
 */
public class MyPartition extends Partitioner<Text,FlowBean> {
    @Override
    public int getPartition(Text text, FlowBean flowBean, int i) {
        String phone=text.toString();
        String prePhone=phone.substring(0,3);

        //定义分区编号
        int partition;
        if ("136".equals(prePhone)){
            partition=0;
        }else if ("137".equals(prePhone)){
            partition=1;
        }else if ("138".equals(prePhone)){
            partition=2;
        }else if ("139".equals(prePhone)){
            partition=3;
        }
        else {
            partition=4;
        }

        return partition;
    }
}


(4)在驱动函数中增加自定义数据分区设置和ReduceTask设置

package org.example.fenqu;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;

/**
 * @ClassName MyPartition
 * @Description TODO
 * @Author Zouhuiming
 * @Date 2023/5/21 11:29
 * @Version 1.0
 */
public class MyPartition extends Partitioner<Text,FlowBean> {
    @Override
    public int getPartition(Text text, FlowBean flowBean, int i) {
        String phone=text.toString();
        String prePhone=phone.substring(0,3);

        //定义分区编号
        int partition;
        if ("136".equals(prePhone)){
            partition=0;
        }else if ("137".equals(prePhone)){
            partition=1;
        }else if ("138".equals(prePhone)){
            partition=2;
        }else if ("139".equals(prePhone)){
            partition=3;
        }
        else {
            partition=4;
        }

        return partition;
    }
}


1.3.4 WritableComparable排序

1·、排序概述
排序是MapReduce框架中最重要的操作之一。

MapTask和ReduceTask均会对数据按照ket进行排序。该操作属于Hadoop默认行为。任何应用程序中的数据均会被排序,而不管逻辑上是否需要。

默认排序是按照字典顺序排序,且实现该排序的方法是快速排序

对于MapTask,它将会处理的结果暂时存放到环形缓冲区中,当环形缓冲区使用率达到一定阙值后,再对缓冲区中的数据进行一次快速排序,并将这些有序数据溢写到磁盘上,而当数据处理完毕后,它会对磁盘上所以文件进行归并排序。

对于ReduceTask,它从每个MapTask上远程拷贝相应的数据文件,如果文件大小超过一定阙值,则溢写到磁盘上,否者储存在内存中。如果磁盘上文件数目达到一定阙值,则进行一次归并排序以生成一个更大的文件;如果内存中文件大小或者数目超过一定的阙值,则进行一次合并后将数据溢写到磁盘上。当所以数据拷贝完毕后,ReduceTask统一对内存和磁盘上的所有数据进行一次归并排序。

2、排序的分类
(1)部分排序
MapReduce根据输入记录的键值对数据集进行排序。保证输出的每个文件内部有序。
(2)全排序
最终输出结果只有一个文件,且文件内部有序。实现方式是只设置一个ReduceTask。但该方法在处理大型文件时效率极低,因为一台机器处理所有文件,完全丧失了MapReduce所提供的并行架构。
(3)辅助排序(GroupingComparator)
在Reduce端对key进行分组。应用于:在接受的key为bean对象的时候,想让一个或几个这段相同(全部字段比较不相同)的key进入到同一个Reduce方法,可以采用分组排序。
(4)二次排序
在自定义排序过程中,如果compareTo中的判断条件为两个即为二次排序。

3、自定义排序WritableComparable 原理分析
bean对象作为key传输,需要实现WritableComparable接口重写compareTo()方法,就可以实现排序

@Override
public int compareTo(FlowBean bean) {
int result;
// 按照总流量大小,倒序排列
if (this.sumFlow > bean.getSumFlow()) {
result = -1;
}else if (this.sumFlow < bean.getSumFlow()) {
result = 1;
}else {
result = 0;
}
return result;
}
1.3.5 WritableComparable排序案例实操(全排序)

1、需求
根据序列化案例(上一篇文章最后一个案例)产生的结果再次对总流量进行倒序排序。
2、需求分析
在这里插入图片描述
3、代码实现
1、FlowBean对象在需求1基础上增加了比较功能

package org.example.paixu;

import org.apache.hadoop.io.Writable;
import org.apache.hadoop.io.WritableComparable;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

/**
 * @ClassName FlowBean
 * @Description TODO
 * @Author Zouhuiming
 * @Date 2023/5/20 10:13
 * @Version 1.0
 */
public class FlowBean implements  WritableComparable<FlowBean> {
    private Long  upFlow;
    private Long downFlow;
    private long sumFlow;

    public FlowBean() {
    }

    public Long getUpFlow() {
        return upFlow;
    }

    public void setUpFlow(Long upFlow) {
        this.upFlow = upFlow;
    }

    public Long  getDownFlow() {
        return downFlow;
    }

    public void setDownFlow(Long  downFlow) {
        this.downFlow = downFlow;
    }

    public void setSumFlow() {
        this.sumFlow = this.upFlow+this.downFlow;
    }

    //实现序列化
    @Override
    public void write(DataOutput dataOutput) throws IOException {
        dataOutput.writeLong(upFlow);
        dataOutput.writeLong(downFlow);
        dataOutput.writeLong(sumFlow);
    }
    //实现反序列化
    @Override
    public void readFields(DataInput dataInput) throws IOException {
        this.upFlow=dataInput.readLong();
        this.downFlow=dataInput.readLong();
        this.sumFlow=dataInput.readLong();
    }

    @Override
    public String toString() {
        return upFlow+"\t"+downFlow+"\t"+sumFlow;
    }


    @Override
    public int compareTo(FlowBean o) {
        //倒序排列
        return this.sumFlow>o.sumFlow?-1:1;
    }
}


2、编写Mapper类

package org.example.paixu;

import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;

import java.io.IOException;

/**
 * @ClassName FlowMapper
 * @Description TODO
 * @Author Zouhuiming
 * @Date 2023/5/20 10:21
 * @Version 1.0
 */
public class FlowMapper extends Mapper<LongWritable,Text,FlowBean,Text> {
    private Text outV=new Text();
    private FlowBean outK=new FlowBean();

    @Override
    protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, FlowBean, Text>.Context context) throws IOException, InterruptedException {
        String s = value.toString();
        String[] split = s.split("\t");

        String phone=split[0];
        outV.set(phone);
        outK.setUpFlow(Long.parseLong(split[1]));
        outK.setDownFlow(Long.parseLong(split[2]));
        outK.setSumFlow();

        context.write(outK,outV);
    }
}


3、编写Reducer类

package org.example.paixu;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 * @ClassName FlowReducer
 * @Description TODO
 * @Author Zouhuiming
 * @Date 2023/5/20 10:29
 * @Version 1.0
 */
public class FlowReducer extends Reducer <FlowBean, Text,Text,FlowBean>{

    @Override
    protected void reduce(FlowBean key, Iterable<Text> values, Reducer<FlowBean, Text, Text, FlowBean>.Context context) throws IOException, InterruptedException {
        for (Text value : values) {
            context.write(value,key);
        }
    }
}


4、编写Driver类

package org.example.paixu;

import org.apache.hadoop.conf.Configuration;
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.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

/**
 * @ClassName FlowDriver
 * @Description TODO
 * @Author Zouhuiming
 * @Date 2023/5/20 10:38
 * @Version 1.0
 */
public class FlowDriver {
    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        //1、获取job对象
        Configuration configuration=new Configuration();
        Job job=Job.getInstance(configuration);

        //2、关联本Driver类
        job.setJarByClass(FlowDriver.class);


        //3、关联Mapper和Reducer
        job.setMapperClass(FlowMapper.class);
        job.setReducerClass(FlowReducer.class);

        //4、设置Map端输出KV类型
        job.setMapOutputKeyClass(FlowBean.class);
        job.setMapOutputValueClass(Text.class);

        //5、设置程序最终输出的KV类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(FlowBean.class)

        //6、设置程序的输入和输出路径
        FileInputFormat.addInputPath(job,new Path("E:\\test\\output1"));
        FileOutputFormat.setOutputPath(job,new Path("E:\\test\\output2"));

        //7、提交Job
        System.exit(job.waitForCompletion(true)?0:1);
    }
}


1.3.6 WritableComparable排序案例实操(区内排序)

前提:这个案例和上一个案例区别不大,就是增加了分区而已,所以只需要增加自定义分区类和修改一个Driver类就行,像Mapper类和Reducer类是不用修改的。
(1)增加自定义分区类

package org.example.paixu;

import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Partitioner;

/**
 * @ClassName MyPartition
 * @Description TODO
 * @Author Zouhuiming
 * @Date 2023/5/21 11:29
 * @Version 1.0
 */
public class MyPartition extends Partitioner< FlowBean,Text> {

    @Override
    public int getPartition(FlowBean flowBean, Text text, int i) {
        String phone=text.toString();
        String prePhone=phone.substring(0,3);

        //定义分区编号
        int partition;
        if ("136".equals(prePhone)){
            partition=0;
        }else if ("137".equals(prePhone)){
            partition=1;
        }else if ("138".equals(prePhone)){
            partition=2;
        }else if ("139".equals(prePhone)){
            partition=3;
        }
        else {
            partition=4;
        }
        return partition;
    }
}


(2)修改Driver

package org.example.paixu;

import org.apache.hadoop.conf.Configuration;
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.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import java.io.IOException;

/**
 * @ClassName FlowDriver
 * @Description TODO
 * @Author Zouhuiming
 * @Date 2023/5/20 10:38
 * @Version 1.0
 */
public class FlowDriver {
    public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
        //1、获取job对象
        Configuration configuration=new Configuration();
        Job job=Job.getInstance(configuration);

        //2、关联本Driver类
        job.setJarByClass(FlowDriver.class);


        //3、关联Mapper和Reducer
        job.setMapperClass(FlowMapper.class);
        job.setReducerClass(FlowReducer.class);

        //4、设置Map端输出KV类型
        job.setMapOutputKeyClass(FlowBean.class);
        job.setMapOutputValueClass(Text.class);

        //5、设置程序最终输出的KV类型
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(FlowBean.class);


        //8、指定自定义分区器
        job.setPartitionerClass(MyPartition.class);

        //9、同时指定相应数量的ReduceTask
        job.setNumReduceTasks(5);

        //6、设置程序的输入和输出路径
        FileInputFormat.addInputPath(job,new Path("E:\\test\\output1"));
        FileOutputFormat.setOutputPath(job,new Path("E:\\test\\output2"));

        //7、提交Job
        System.exit(job.waitForCompletion(true)?0:1);
    }
}


1.3.7 Combiner 合并
  • Combiner是MR程序中Mapper和Reducer之外的一种组件
  • Combiner组件的父类就是Reducer
  • Combiner和Reducer的区别就是运行位置
    • Combiner是在每一个MapTask所在的节点运行
    • Reducer是接受全局所以Mapper的输出结果
  • Combiner的意义就是对每一个MapTask的输出进行局部汇总,以减少网络传输量
  • Combiner能够应用的前提是不能影响最终的业务逻辑,而且,Combine的输出kv应该跟Reducer的输入kv类型要对应起来
    在这里插入图片描述

1、自定义Combiner实现步骤
(1)自定义一个Combiner继承Reducer,重写Reduce()方法

package org.example._07Combiner;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 * @ClassName CombinerClass
 * @Description TODO
 * @Author Zouhuiming
 * @Date 2023/5/22 9:11
 * @Version 1.0
 */
public class CombinerClass extends Reducer<Text, IntWritable,Text, IntWritable> {
    private IntWritable outV=new IntWritable();
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        int sum=0;
        for (IntWritable value : values) {
            sum+=value.get();
        }
        outV.set(sum);
        context.write(key,outV);
    }
}


(2)在Job驱动类中设置

job.setCombinerClass(WordCountCombiner.class);
1.3.8 合并案例实操

1、需求(我的还是单词统计的代码)
统计过程中对每一个 MapTask 的输出进行局部汇总,以减小网络传输量即采用Combiner 功能。
(1)数据输入
自己创造一个就行了吧(到这应该会自己创造自己需要用的数据)
(2)期望数据输出
自己算吧

2、案例实操
(1)增加一个类继承Reducer

package org.example._07Combiner;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

import java.io.IOException;

/**
 * @ClassName CombinerClass
 * @Description TODO
 * @Author Zouhuiming
 * @Date 2023/5/22 9:11
 * @Version 1.0
 */
public class CombinerClass extends Reducer<Text, IntWritable,Text, IntWritable> {
    private IntWritable outV=new IntWritable();
    @Override
    protected void reduce(Text key, Iterable<IntWritable> values, Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
        int sum=0;
        for (IntWritable value : values) {
            sum+=value.get();
        }
        outV.set(sum);
        context.write(key,outV);
    }
}


(2)在驱动类中指定Combiner

 job.setCombinerClass(CombinerClass.class);

说明:其实这里也可以直接填以下代码

job.setCombinerClass(WordCountReduce.class);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/562521.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3D CAD模型的体素化

你有没有搜索过如何将 Cad 模型转换为 python 就绪的 numpy 数组&#xff0c;但没有得到任何明确的答案&#xff1f; 我也是。 经过长时间的研究并尝试了很多软件和 python 库&#xff0c;我终于能够将 3D STEP 文件转换为 3 维 numpy 数组。 如果你想做同样的事情或只是想知道…

线性表的总结

逻辑结构 逻辑结构 具有相同特性的数据元素的有限序列 特性 有穷性&#xff1a;一个线性表的元素个数是有限的 一致性&#xff1a;一个线性表的所有元素的性质相同&#xff0c;也就是具有相同的数据类型 序列性&#xff1a;所有元素之间的相对…

OJ练习第114题——T 秒后青蛙的位置

T 秒后青蛙的位置 力扣链接&#xff1a;1377. T 秒后青蛙的位置 题目描述 给你一棵由 n 个顶点组成的无向树&#xff0c;顶点编号从 1 到 n。青蛙从 顶点 1 开始起跳。规则如下&#xff1a; 在一秒内&#xff0c;青蛙从它所在的当前顶点跳到另一个 未访问 过的顶点&#xf…

十、数据仓库详细介绍(数据质量)流程与工具

上篇我们主要介绍了以下三部分内容。 第一部分&#xff0c;介绍了五种常见的数据管理知识体系&#xff0c;数据质量在所有的知识体系中都有非常重要的地位&#xff0c;数据应用体现数据价值&#xff0c;数据质量为应用提供支撑。 第二部分&#xff0c;我们介绍了数据质量评判的…

程序优化 - ABAP并行处理

SAP的并行方式有很多种&#xff1a; SPTA框架&#xff0c;参考debug可以看出这个核心也是异步bgRFC 异步RFC&#xff0c;使用CALL FUNCTION “XXXXXX” STARTING NEW TASK XXXX CALLING XXXX ON END OF TASK BANK_PP_JOBCTRL框架 拆分成多个后台JOB执行 这里只说SPTA框架…

【高危】Linux Kernel OverlayFS 权限提升漏洞(POC公开)

漏洞描述 Linux Kernel OverlayFS 是 Linux 内核提供的一种文件系统&#xff0c;允许将多个文件系统合并为一个单一的虚拟文件系统。 在 Linux Kernel OverlayFS 受影响版本中&#xff0c;当用户将具备特权的文件从 nosuid 的挂载点复制到另一个挂载点时&#xff0c;未授权的…

【严重】ejs 存在服务端模板注入漏洞(存在POC)

漏洞描述 EJS 是开源的 JavaScript 模板引擎&#xff0c;允许在HTML代码中使用JavaScript代码块&#xff0c;closeDelimiter 参数是 EJS 模板中的结束标记&#xff0c;用于指定结束分隔符。 由于对 CVE-2022-29078 漏洞修复不完全&#xff0c;当应用程序使用 EJS 模板引擎&am…

如何恢复已删除或丢失的音乐文件

您是否遇到过您或其他人不小心删除了您的音乐文件的情况&#xff1f;作为我自己的音乐爱好者&#xff0c;我知道这种感觉有多么毁灭性。听音乐让我们平静和放松&#xff0c;它可以帮助一些人在工作时提高工作效率或缓解他们感受到的压力。 这就是为什么如果您不小心丢失了您心…

springcloud-alibaba (04)Gateway与Nacos结合使用

Gateway与Nacos结合使用 &#x1f389;欢迎来到这里&#xff0c;今天我将为大家介绍如何将Spring Cloud Gateway和Nacos结合使用&#xff0c;实现一个高效稳定的服务网关&#xff01;在微服务架构中&#xff0c;API网关是必不可少的一部分&#xff0c;它提供了路由请求、负载均…

java版企业工程项目管理系统源代码-功能清单 图文解析

Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目显示…

新手如何写新闻稿?一文带你了解记者稿的写作步骤与技巧

作为一名新手记者&#xff0c;写稿件是必须掌握的基本技能。记者稿的写作方式有很多种&#xff0c;但基本的步骤和技巧是相同的。在这篇文章中&#xff0c;我将向大家介绍记者稿的写作步骤和技巧&#xff0c;希望能对想要成为一名优秀记者的你有所帮助。 一、确定新闻价值 在写…

代码随想录训练营Day50| 123.买卖股票的最佳时机III 188.买卖股票的最佳时机IV

目录 学习目标 学习内容 123.买卖股票的最佳时机III 188.买卖股票的最佳时机IV 学习目标 123.买卖股票的最佳时机III 188.买卖股票的最佳时机IV 学习内容 123.买卖股票的最佳时机III 123. 买卖股票的最佳时机 III - 力扣&#xff08;LeetCode&#xff09;https://lee…

深度分析:智能照明百亿赛道,Yeelight易来如何做到智能照明和定制照明双C位

日前&#xff0c;艾瑞咨询发布了《2023年中国家用智能照明行业研究报告》&#xff0c;报告显示&#xff0c;中国家用智能照明市场迎来爆发式增长&#xff0c;市场占有率从2016年仅2.0%上升到2022年的20.4%&#xff0c;7年间占比增长20%。预计2023年家用智能照明市场规模将突破1…

千呼万唤始出来!从源码到架构的Spring全系列笔记,已全部分享

因粉丝强烈要求小编整理一套spring全系列资料集合&#xff0c;不然就要集体给小编寄刀片了&#xff0c;今天终于是千呼万唤始出来&#xff0c;给大家连夜整理这一套可以说是全网最全最细的Spring全系列资料&#xff0c;今天毫无保留的给大家分享出来一起学习&#xff01;一起牛…

【JavaSE】Java基础语法(七):二维数组

文章目录 &#x1fa82;1. 二维数组概述&#x1fa82;2. 二维数组动态初始化&#x1fa82;3. 二维数组访问元素的细节问题&#x1fa82;4. 二维数组静态初始化&#x1fa82;5. 二维数组遍历&#x1fa82;6. 二维数组求和 &#x1fa82;1. 二维数组概述 概述 : 二维数组也是一种…

数据库范式理论

目录 1、1NF 2、2NF 3、3NF 4、BCNF 5、4NF 1、1NF 在实际应用中&#xff0c;数据库表的每一列&#xff08;也称为属性&#xff09;都是不可分割的原子数据项&#xff0c;不能是集合&#xff0c;数组&#xff0c;记录等非原子数据项。即在实际应用中实体中的某个属性有多个…

直播电商迈入新周期,快手如何抢跑?

文 | 螳螂观察 作者 | 图霖 直播电商迈入第七个发展年头&#xff0c;来到了新周期的变革前夜。 行业竞争逐年加剧&#xff0c;但截至2022年已迅速攀升至35000亿元的直播电商市场交易规模&#xff0c;仍诱惑着新玩家挤进这张拥堵的牌桌。 美团方面&#xff0c;继今年1月底在…

局域网唤醒工具UpSnap

什么是 UpSnap &#xff1f; UpSnap 是使用 SvelteKit、Go、PocketBase 和 nmap 编写的简单局域网唤醒应用程序。 v3 更新日志&#xff1a; ⚙️ 后端&#xff1a; 用 Go 重写。之前的版本是 Python 写的&#xff1b;不再支持不同的数据库。后端现在使用基于 SQLite 的 PocketB…

Qt+QtWebApp开发笔记(三):http服务器动态html连接跳转基础交互

若该文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/130840894 红胖子网络科技博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬…

电脑密码忘了怎么解除?试试这3个方法!

案例&#xff1a;我的电脑太久没有使用&#xff0c;导致我忘记了密码&#xff0c;试了好几次还是显示密码错误。怎样才能找回电脑的开机密码&#xff1f; 【我忘记了电脑密码&#xff0c;导致我无法使用电脑&#xff0c;给我的生活带来了很大的困扰。有没有小伙伴遇到过相同的…