Hadoop Mapreduce过滤器数据
假设我在CSV文件中有如下数据集:Hadoop Mapreduce过滤器数据,hadoop,mapreduce,Hadoop,Mapreduce,假设我在CSV文件中有如下数据集: Id, Patient cycle no, counseling 2345, 1, No 1234, 22, Yes 4567, 1, No 2378, 10, No 我想使用map reduce筛选出咨询为“否”的记录,这些记录的患者周期=1 如何实现这一点?有两种方法可以实现对记录的过滤: 仅使用Map功能,检查患者周期no是否等于1,咨询是否等于Yes,而无需执行任何Reduce功能,以及 使用Map函数,将患者周期号作为键,将咨询的Id作为复合值,
Id, Patient cycle no, counseling
2345, 1, No
1234, 22, Yes
4567, 1, No
2378, 10, No
我想使用map reduce筛选出咨询为“否”的记录,这些记录的患者周期=1
如何实现这一点?有两种方法可以实现对记录的过滤:
- 仅使用
功能,检查Map
是否等于患者周期no
,1
是否等于咨询
,而无需执行任何Yes
功能,以及Reduce
- 使用
函数,将Map
作为键,将患者周期号
的咨询
作为复合值,以便按照周期号对数据进行分组,这样我们就可以在Id
等于咨询
时检查每个(复合)值是
Map
和Reduce
函数更清晰(即使这个答案的逻辑在可伸缩性和执行时间的总体速度方面似乎有点低效,这取决于输入数据的大小和形式)
第一步是实现Map
功能,这里要做的就是读取每个记录并重新排列其中的列,以将患者的周期作为键。为了保护我们的手不被“弄脏”对于复合值,Id
和Id
字段将放在值字段中,以
字符作为分隔符分隔。因此映射器的输出键值对将遵循以下模式:
对于Reduce
功能,所有键值对都按键分组,具有相同键的数据都放在同一个reducer中进行处理。这基本上意味着对于每个患者周期,所有(Id,咨询)
值存储在Reduce
函数的同一个实例中,我们可以通过一个简单的for
循环逐个访问它们。这就是我们:
\uuu
分隔符拆分复合值1
患者的数据分组为周期数,如果是,检查咨询
是否等于是
以将其存储到输出Id
作为键,将患者周期no
与咨询
作为复合值(此处仅使用空格字符的分隔符
)再次重新排列数据
所有这些都是使用下面的源代码(此处的输入数据放在名为/patients
的文件夹中)完成的:
输出如下所示:
我不建议在2021年使用MapReduce;您看过Spark吗?如果您自己尝试实施一个解决方案,然后在这里发布任何问题,您会学到更多。
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import java.io.*;
import java.io.IOException;
import java.util.*;
import java.nio.charset.StandardCharsets;
public class PatientFilter
{
/* input: <byte_offset, line_of_dataset>
* output: <patient_cycle, (ID, counceling)>
*/
public static class Map extends Mapper<LongWritable, Text, IntWritable, Text>
{
public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException
{
try
{
if(value.toString().contains("Patient cycle no")) // remove header
return;
else
{
String[] columns = value.toString().split(", "); // split the columns
String id = columns[0];
int patient_cycle = Integer.parseInt(columns[1]);
String counceling = columns[2];
// rearrange the columns to put the cycles as key and the rest as a composite value
context.write(new IntWritable(patient_cycle), new Text(id + "_" + counceling));
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
/* input: <patient_cycle, (ID, counceling)>
* output: <ID, (patient_cycle, counceling)>
*/
public static class Reduce extends Reducer<IntWritable, Text, Text, Text>
{
public void reduce(IntWritable key, Iterable<Text> values, Context context) throws IOException, InterruptedException
{
// for every value grouped by key...
for(Text value : values)
{
String[] split_value = value.toString().split("_"); // split the composite value
if(key.get() == 1) // check if the key/patient cycle in this reducer is 1
{
if(split_value[1].equals("Yes")) // check if counseling for this record is equal to "Yes"
{
// for patients with just 1 cycle, only store the records that have "counseling" equal to "Yes"
context.write(new Text(split_value[0]), new Text(Integer.toString(key.get()) + " " + split_value[1]));
}
}
else // store all the other records as well
context.write(new Text(split_value[0]), new Text(Integer.toString(key.get()) + " " + split_value[1]));
}
}
}
public static void main(String[] args) throws Exception
{
// set the paths of the input and output directories in the HDFS
Path input_dir = new Path("patients");
Path output_dir = new Path("patients_out");
// in case the output directory already exists, delete it
Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
if(fs.exists(output_dir))
fs.delete(output_dir, true);
// configure the MapReduce job
Job job = Job.getInstance(conf, "Patient Filter");
job.setJarByClass(PatientFilter.class);
job.setMapperClass(Map.class);
job.setReducerClass(Reduce.class);
job.setMapOutputKeyClass(IntWritable.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
TextInputFormat.addInputPath(job, input_dir);
TextOutputFormat.setOutputPath(job, output_dir);
job.waitForCompletion(true);
}
}
Id, Patient cycle no, counseling
2345, 1, No
1234, 22, Yes
4567, 1, No
2378, 10, No
4852, 2, Yes
2510, 9, Yes
6564, 5, No
3000, 1, No
6958, 45, No
1500, 1, No