DistributedCache In Hadoop

本文深入解析了Hadoop分布式缓存DistributedCache在MapReduce环境下的工作原理及使用方法,包括缓存的创建、添加第三方库、symlink的使用等关键步骤,同时提供了注意事项,帮助开发者高效利用DistributedCache优化MapReduce任务性能。

分布式缓存在MapReduce中称之为DistributedCache,它可以方便map task之间或者reduce task之间共享一些信息,同时也可以将第三方包添加到其classpath路径中去。Hadoop会将缓存数据分发到集群的所有准备启动的节点上,复制到在mapred.temp.dir中配置的目录。

 

 

2、DistributedCache的使用

DistributedCache的使用的本质其实是添加Configuraton中的属性:mapred.cache.{files|archives}。图方便的话,可以使用DistributedCache类的静态方法。

不省事法:

conf.set("mapred.cache.files", "/data/data");

conf.set("mapred.cache. archives", "/data/data.zip");

省事法:

DistributedCacheaddCacheFile(URI, Configuration)

DistributedCache.addArchiveToClassPath(Path, Configuration, FileSystem)

需要注意的是,上面几行代码需要写在Job类初始化之前,否则在运行会中找不到文件(被折磨了很长时间),因为Job初始化时将传入Configuration对象克隆一份给了JobContext。

在MapReduce的0.21版本以后的org.apache.hadoop.mapreduce均移到org.apache.hadoop.mapred包下。但文档中提供的configure方法是重写的MapReduceBase中的,而新版本中map继承于mapper,reduce继承于reducer,所以configure方法一律改成了setup。要获得cache数据,就得在map/reduce task中的setup方法中取得cache数据,再进行相应操作:

 
  1. @Override 
  2. protected void setup(Context context) throws IOException,  
  3.         InterruptedException {  
  4.     super.setup(context);  
  5.     URI[] uris = DistributedCache.getCacheFiles(context  
  6.                 .getConfiguration());  
  7.     Path[] paths = DistributedCache.getLocalCacheFiles(context  
  8.                 .getConfiguration());  
  9.     // TODO  
  10. }  

而三方库的使用稍微简单,只需要将库上传至hdfs,再用代码添加至classpath即可:

DistributedCache.addArchiveToClassPath(new Path("/data/test.jar"), conf);

3、symlink的使用

Symlink其实就是hdfs文件的一个快捷方式,只需要在路径名后加入#linkname,之后在task中使用linkname即使用相应文件,如下:

conf.set("mapred.cache.files", "/data/data#mData");

conf.set("mapred.cache. archives", "/data/data.zip#mDataZip");

 
  1. @Override 
  2. protected void setup(Context context) throws IOException,  
  3.         InterruptedException {  
  4.     super.setup(context);  
  5.     FileReader reader = new FileReader(new File("mData"));  
  6.     BufferedReader bReader = new BufferedReader(reader);  
  7.     // TODO  

在使用symlink之前,需要告知hadoop,如下:

conf.set("mapred.create.symlink", "yes"); // 是yes,不是true

DistributedCache.createSymlink(Configuration)

4、注意事项

1)缓存文件(数据、三方库)需上传至HDFS,方能使用;

2)缓存较小的情况下,建议将数据全部读入相应节点内存,提高访问速度;

3)缓存文件是read-only的,不能修改。若要修改得重新输出,将新输出文件作为新缓存进入下一次迭代。

 

<think>我们正在处理一个关于Hadoop减法操作的问题。在Hadoop中,并没有直接的"减法"操作符,但我们可以通过MapReduce编程模型来实现类似集合减法的操作。例如,我们可能想要实现两个数据集之间的差集(A - B),即找出在A中出现但不在B中出现的记录。 参考Hadoop的MapReduce模型,我们可以通过以下步骤实现: 1. 将两个数据集(A和B)都作为输入。 2. 在Map阶段,为每条记录标记它来自哪个数据集(例如,给来自A的记录标记为"A",来自B的记录标记为"B")。 3. 在Reduce阶段,对于相同的键(即需要比较的记录),如果该键对应的值列表中有来自A的标记而没有来自B的标记,则输出该记录(表示它在A中但不在B中)。 另外,也可以使用Hive或Pig等高层语言来实现,它们可能提供更简洁的语法。 但是,用户明确提到了“减法操作”,所以我们主要关注MapReduce的实现。 步骤详细描述: 1. 输入:两个数据集A和B,存储在HDFS上的两个目录中。 2. Map阶段: - 对于数据集A中的每条记录,输出键值对:键为记录内容(或者用于比较的字段),值为标记(如"A")。 - 对于数据集B中的每条记录,输出键值对:键为记录内容(同样用于比较的字段),值为标记(如"B")。 3. Reduce阶段: - 对于同一个键,会收到一个值的列表,包含所有标记(可能包含多个"A"和"B",但因为我们只关心存在性,所以重复也没关系,但要注意去重)。 - 我们检查这个列表:如果其中包含至少一个"A"标记,且不包含任何"B"标记,则输出这个键(即记录)。 注意:这里我们假设记录是唯一的,或者我们只关心记录是否出现,而不关心次数。如果记录有重复,那么我们需要根据需求决定输出次数(例如,如果A中有重复而B中没有,那么应该输出多次?)。但通常减法操作是集合操作,所以我们一般会去重。 另外,我们可以通过设置多个Reduce任务来并行处理。 代码示例(简化版): Mapper类(处理两个数据集): ```java public class MinusMapper extends Mapper<LongWritable, Text, Text, Text> { private Text tag = new Text(); private Text word = new Text(); public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString(); // 获取当前输入分片来自哪个文件(A或B) FileSplit fileSplit = (FileSplit)context.getInputSplit(); String filename = fileSplit.getPath().getName(); if (filename.equals("A.txt")) { // 假设A数据集的文件名为A.txt tag.set("A"); } else if (filename.equals("B.txt")) { // 假设B数据集的文件名为B.txt tag.set("B"); } word.set(line); context.write(word, tag); } } ``` Reducer类: ```java public class MinusReducer extends Reducer<Text, Text, Text, NullWritable> { public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException { boolean inA = false; boolean inB = false; for (Text val : values) { if (val.toString().equals("A")) { inA = true; } else if (val.toString().equals("B")) { inB = true; } } // 如果记录在A中且不在B中,则输出 if (inA && !inB) { context.write(key, NullWritable.get()); } } } ``` 注意:这里我们假设整个记录作为键,所以每条记录都是唯一的。如果记录有多个字段,我们可能需要根据某个字段作为键,但这里简化处理。 另外,这种方法可能遇到性能问题,因为所有记录都要通过网络传输到Reducer。对于大型数据集,我们可以考虑使用Bloom Filter等优化方法,但这里不展开。 此外,用户可能是在Hive或Pig中操作,那么可以使用更简单的SQL-like语句。 例如在Hive中: ```sql SELECT * FROM A LEFT JOIN B ON A.key = B.key WHERE B.key IS NULL; ``` 或者 ```sql SELECT * FROM A WHERE A.key NOT IN (SELECT key FROM B); ``` 在Pig中: ```pig A = LOAD 'A' AS (line:chararray); B = LOAD 'B' AS (line:chararray); Result = MINUS(A, B); -- 注意:Pig有MINUS操作符,但要求两个关系必须模式兼容,且去重。 -- 或者使用JOIN和FILTER ``` 但是,用户的问题是“Hadoop中减法的实现方法”,所以我们重点放在MapReduce上。 生成相关问题: 1. 如何优化Hadoop减法操作的性能? 2. 在Hadoop中,除了减法操作,还有哪些集合操作(如并集、交集)的实现方法? 3. 如何处理减法操作中数据倾斜的问题?</think>### Hadoop中减法操作的实现方法 在Hadoop中,没有直接的"减法操作符",但可以通过多种方式实现类似功能,主要取决于具体场景和数据结构。以下是三种常见实现方法: #### 1. **MapReduce实现集合差集(A-B)** 这是最基础的实现方式,通过两阶段MapReduce找出存在于A但不存在于B的记录: ```java // Mapper标记数据来源 public void map(LongWritable key, Text value, Context context) { String sourceTag = ((FileSplit)context.getInputSplit()).getPath().getName(); context.write(value, new Text(sourceTag)); // 值标记为"A"或"B" } // Reducer执行差集逻辑 public void reduce(Text key, Iterable<Text> values, Context context) { boolean inA = false, inB = false; for (Text val : values) { if (val.toString().equals("A")) inA = true; if (val.toString().equals("B")) inB = true; } if (inA && !inB) context.write(key, NullWritable.get()); // 输出A-B结果 } ``` **适用场景**:大规模数据集求差集,如用户行为分析中的差异检测[^1]。 #### 2. **Hive SQL实现(推荐)** 通过HiveQL可更简洁地实现: ```sql SELECT * FROM table_A WHERE id NOT IN (SELECT id FROM table_B); ``` 或使用`LEFT JOIN`: ```sql SELECT A.* FROM table_A A LEFT JOIN table_B B ON A.id = B.id WHERE B.id IS NULL; ``` **优势**:开发效率高,自动优化执行计划,支持复杂条件过滤[^2]。 #### 3. **Spark实现(高性能方案)** 使用Spark RDD或DataFrame API: ```scala val rddA = sc.textFile("hdfs:///data/A") val rddB = sc.textFile("hdfs:///data/B") val result = rddA.subtract(rddB) // 直接差集操作 result.saveAsTextFile("hdfs:///result") ``` **性能优势**:基于内存计算,比MapReduce快10-100倍,支持迭代计算[^3]。 ### 关键注意事项 1. **数据倾斜处理**:当Key分布不均时,使用`salting`技术(添加随机前缀) 2. **去重要求**:如果结果需要去重,在Reduce阶段添加`HashSet`去重逻辑 3. **成本控制**:大规模操作应启用YARN的公平调度器,避免资源抢占[^3] 4. **优化技巧**: - 将小数据集放入DistributedCache - 使用Bloom Filter预过滤 - 设置合理分区数(建议为集群核数2-3倍) ### 典型应用场景 - **用户行为分析**:找出今日新增用户(今日活跃用户 - 历史用户) - **异常检测**:正常数据全集 - 白名单 = 可疑数据 - **数据清洗**:原始数据集 - 无效记录集 = 洁净数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值