Java Hadoop mapreduce 2文件过滤?

Java Hadoop mapreduce 2文件过滤?,java,hadoop,mapreduce,mapper,Java,Hadoop,Mapreduce,Mapper,我需要打印出那些没有订单号的客户的“姓名”。我知道我必须使用映射器方法来实例化变量。我必须使用2个映射器,因为有2个输入文件。在缩减阶段,我必须过滤掉没有订单的客户。否。但是,如何筛选出没有订单号的客户 File1.txt Cust.No. Name 1 Adam 2 Abe 3 Alex 4 Jones Order.Num. Cust.No. Price 01 1

我需要打印出那些没有订单号的客户的“姓名”。我知道我必须使用映射器方法来实例化变量。我必须使用2个映射器,因为有2个输入文件。在缩减阶段,我必须过滤掉没有订单的客户。否。但是,如何筛选出没有订单号的客户

File1.txt

 Cust.No. Name

 1        Adam
 2        Abe
 3        Alex
 4        Jones
    Order.Num.    Cust.No.     Price
    01            1            5422
    02            1            23
    03            2            1265
    04            3            127
Cust.No Name
1       Adam
2       Abe
3       Alex
4       Jones
Order.Num.  Cust.No.    Price
01          1           5422
02          1           23
03          2           1265
04          3           127
File2.txt

 Cust.No. Name

 1        Adam
 2        Abe
 3        Alex
 4        Jones
    Order.Num.    Cust.No.     Price
    01            1            5422
    02            1            23
    03            2            1265
    04            3            127
Cust.No Name
1       Adam
2       Abe
3       Alex
4       Jones
Order.Num.  Cust.No.    Price
01          1           5422
02          1           23
03          2           1265
04          3           127
我所做的

最初,在reducer方法中,我对键进行了循环,并检查它是否与现有键匹配:

if (!(Data[0].equals("key")))
    {
        System.out.println(Data[1]);
    }

但是,它会打印每一行。

看起来像是一个常规的reduce-side连接,因此它可能是一个简单的用例,但是这些类型的计算往往会在工作负载方面变得非常残酷。这意味着我们必须找到捷径,以确保应用程序能够很好地扩展到更大的输入规模

为应用程序的执行节省时间/空间的最常见方法是,尝试设计可能的几个MR作业,使我们可以“剪切”一个或多个作业,同时保留所有功能,或者尝试最小化将在输入数据处实现的(自定义)映射器的数量。这两个函数中的后一个对于您尝试实现的这种过滤非常常见,因为我们可以轻松地使用一个Map函数,它的每个实例将检查它当前读取的文件的名称以相应地执行操作

更具体地说,我们可以在映射程序开始运行Map类的
setup
函数之前获取
File1.txt
File2.txt
文件名,并使用要读取的当前文件名来确定如何将文件中的数据切分并存储到键值对中。对于您的问题,此映射函数将输出两种类型的键值对:

  • (用于
    File1.txt
    中的数据)

  • (用于
    文件2.txt中的数据)

然后,Reduce函数的实例将针对每个客户运行(当然,因为客户ID和名称是唯一的),并访问分组值,这些分组值只不过是一些保存此客户名称或订单ID的
文本
对象。我们只想输出记录中没有任何订单的客户,因此,我们所要做的就是检查这个值列表的长度是否为
1
(也就是说,如果这个客户没有一对值,而另一个客户有他的名字)

为了展示这一点,我将两个输入文件都放在HDFS中的目录
/input
(我对
File1.txt
中的列使用了两个制表符分隔符,对
File2.txt
中的列使用了三个制表符分隔符。如果您的文件在列之间有不同的制表符或空格,您可以相应地更改它们):

File1.txt

 Cust.No. Name

 1        Adam
 2        Abe
 3        Alex
 4        Jones
    Order.Num.    Cust.No.     Price
    01            1            5422
    02            1            23
    03            2            1265
    04            3            127
Cust.No Name
1       Adam
2       Abe
3       Alex
4       Jones
Order.Num.  Cust.No.    Price
01          1           5422
02          1           23
03          2           1265
04          3           127
File2.txt

 Cust.No. Name

 1        Adam
 2        Abe
 3        Alex
 4        Jones
    Order.Num.    Cust.No.     Price
    01            1            5422
    02            1            23
    03            2            1265
    04            3            127
Cust.No Name
1       Adam
2       Abe
3       Alex
4       Jones
Order.Num.  Cust.No.    Price
01          1           5422
02          1           23
03          2           1265
04          3           127
执行过滤的程序可以如下所示:

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

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class OrderListFilter
{
    /* input:  <byte_offset, line_of_dataset>
     * output: <customer_ID, customer_name> OR <customer_ID, order_ID>
     */
    public static class Map extends Mapper<LongWritable, Text, Text, Text>
    {
        private String current_filename = "";

        protected void setup(Context context)
        {
            // get the name of the current to-be-read file
            InputSplit split = context.getInputSplit();
            Path path = ((FileSplit) split).getPath();
            current_filename = path.getName();
        }

        public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException
        {
            if(current_filename.equals("File1.txt"))    // if mapper is reading through the customer's file
            {
                if(value.toString().contains("Cust.No"))    // remove header
                    return;
                else
                {
                    String[] columns = value.toString().split("\t\t");  // 2 tabs as delimiter

                    // write customer ID as key and name as value
                    context.write(new Text(columns[0]), new Text(columns[1]));
                }
            }
            else if(current_filename.equals("File2.txt"))   // if mapper is reading through the order's file
            {
                if(value.toString().contains("Cust.No"))    // remove header
                    return;
                else
                {
                    String[] columns = value.toString().split("\t\t\t"); // 3 tabs as delimiter

                    // write customer ID as key and order num as value
                    context.write(new Text(columns[1]), new Text(columns[0]));
                }
            }
        }
    }

    /* input: <customer_ID, customer_name> OR <customer_ID, order_ID>
     * output: <customer_ID, customer_name>
     */
    public static class Reduce extends Reducer<Text, Text, Text, Text>
    {
        public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException
        {
            List<String> customer_records = new ArrayList<String>();

            // put all the values in a list to find the size of them
            for(Text value : values)
                customer_records.add(value.toString());

            // if there's only one record, i.e. just the ID and the customer's name in they key-value pairs,
            // write their ID and name to output
            if(customer_records.size() == 1)
                context.write(key, new Text(customer_records.get(0)));
        }
    }


    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("input");
        Path output_dir = new Path("output");

        // 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, "Order List Filter");
        job.setJarByClass(OrderListFilter.class);
        job.setMapperClass(Map.class);
        job.setReducerClass(Reduce.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(Text.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(Text.class);
        FileInputFormat.addInputPath(job, input_dir);
        FileOutputFormat.setOutputPath(job, output_dir);
        job.waitForCompletion(true);
    }
}

import org.apache.hadoop.conf.Configuration;
导入org.apache.hadoop.fs.FileSystem;
导入org.apache.hadoop.fs.Path;
导入org.apache.hadoop.io.LongWritable;
导入org.apache.hadoop.io.Text;
导入org.apache.hadoop.mapreduce.InputSplit;
导入org.apache.hadoop.mapreduce.Job;
导入org.apache.hadoop.mapreduce.Mapper;
导入org.apache.hadoop.mapreduce.Reducer;
导入org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
导入org.apache.hadoop.mapreduce.lib.input.FileSplit;
导入org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
导入java.io.IOException;
导入java.util.ArrayList;
导入java.util.List;
公共类OrderListFilter
{
/*输入:
*输出:或
*/
公共静态类映射扩展映射器
{
私有字符串当前_filename=“”;
受保护的无效设置(上下文)
{
//获取当前要读取的文件的名称
InputSplit split=context.getInputSplit();
路径路径=((FileSplit)split).getPath();
当前_filename=path.getName();
}
公共void映射(LongWritable键、文本值、上下文上下文)引发IOException、InterruptedException
{
if(current_filename.equals(“File1.txt”)//如果映射程序正在读取客户的文件
{
if(value.toString()包含(“Cust.No”)//删除标头
返回;
其他的
{
String[]columns=value.toString().split(“\t\t”);//2个制表符作为分隔符
//将客户ID写入密钥,将名称写入值
write(新文本(列[0]),新文本(列[1]);
}
}
else if(当前_filename.equals(“File2.txt”)//如果映射程序正在读取订单的文件
{
if(value.toString()包含(“Cust.No”)//删除标头
返回;
其他的
{
String[]columns=value.toString().split(“\t\t\t”);//3个制表符作为分隔符
//将客户ID写入密钥,将订单编号写入值
write(新文本(列[1]),新文本(列[0]);
}
}
}
}
/*输入:或
*输出:
*/
公共静态类Reduce扩展Reducer
{
公共void reduce(文本键、Iterable值、上下文上下文)引发IOException、InterruptedException
{
列出客户_记录=新建ArrayList();
//将所有值放在一个列表中以查找它们的大小
用于(文本值:值)
customer_records.add(value.toString());
//如果只有一条记录,即它们的键值对中只有ID和客户名称,
//写下他们的身份证