MapReduce功能实现六---最大值(Max)、求和(Sum)、平均值(Avg)

MapReduce功能实现系列:

MapReduce功能实现一---Hbase和Hdfs之间数据相互转换

MapReduce功能实现二---排序

MapReduce功能实现三---Top N

MapReduce功能实现四---小综合(从hbase中读取数据统计并在hdfs中降序输出Top 3)

MapReduce功能实现五---去重(Distinct)、计数(Count)

MapReduce功能实现六---最大值(Max)、求和(Sum)、平均值(Avg)

MapReduce功能实现七---小综合(多个job串行处理计算平均值)

MapReduce功能实现八---分区(Partition)

MapReduce功能实现九---Pv、Uv

MapReduce功能实现十---倒排索引(Inverted Index)

MapReduce功能实现十一---join


一、最大值(Max)

情况1:

[plain]  view plain  copy
  1. [hadoop@h71 q1]$ vi ql.txt  
  2. aa 111  
  3. 22 555  
  4. [hadoop@h71 q1]$ hadoop fs -put ql.txt /input  

java代码:

[java]  view plain  copy
  1. import java.io.IOException;  
  2. import org.apache.hadoop.conf.Configuration;   
  3. import org.apache.hadoop.conf.Configured;   
  4. import org.apache.hadoop.fs.Path;   
  5. import org.apache.hadoop.io.LongWritable;   
  6. import org.apache.hadoop.io.IntWritable;   
  7. import org.apache.hadoop.io.Text;   
  8. import org.apache.hadoop.mapreduce.Job;   
  9. import org.apache.hadoop.mapreduce.Mapper;   
  10. import org.apache.hadoop.mapreduce.Reducer;   
  11. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;   
  12. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;   
  13. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;   
  14. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;   
  15. import org.apache.hadoop.util.Tool;   
  16. import org.apache.hadoop.util.ToolRunner;   
  17.   
  18. public class MaxValue extends Configured implements Tool {   
  19.       
  20.     public static class MapClass extends Mapper<LongWritable, Text, Text, IntWritable> {   
  21.         private int maxNum = 0;   
  22.         public void map(LongWritable key, Text value, Context context)   
  23.                 throws IOException, InterruptedException {   
  24.             String[] str = value.toString().split(" ");   
  25.             try {// 对于非数字字符我们忽略掉  
  26.                 for(int i=0;i<str.length;i++){  
  27.                     int temp = Integer.parseInt(str[i]);   
  28.                     if (temp > maxNum) {  
  29.                         maxNum = temp;   
  30.                     }  
  31.                 }  
  32.             } catch (NumberFormatException e) {   
  33.             }   
  34.         }   
  35.         @Override   
  36.         protected void cleanup(Context context) throws IOException,   
  37.         InterruptedException {   
  38.             context.write(new Text("Max"), new IntWritable(maxNum));   
  39.         }   
  40.     }   
  41.   
  42.     public static class Reduce extends Reducer<Text, IntWritable, Text, IntWritable> {   
  43.         private int maxNum = 0;   
  44.         private Text one = new Text();  
  45.         public void reduce(Text key, Iterable<IntWritable> values, Context context)   
  46.                 throws IOException, InterruptedException {   
  47.             for (IntWritable val : values) {   
  48.                 if ( val.get() > maxNum) {   
  49.                     maxNum = val.get();   
  50.                 }   
  51.             }   
  52.             one = key;  
  53.         }   
  54.         @Override   
  55.         protected void cleanup(Context context) throws IOException,   
  56.         InterruptedException {   
  57.             context.write(one, new IntWritable(maxNum));  
  58.         }   
  59.     }   
  60.   
  61.     public int run(String[] args) throws Exception {   
  62.         Configuration conf = getConf();   
  63.         conf.set("mapred.jar","mv.jar");  
  64.         Job job = new Job(conf, "MaxNum");   
  65.         job.setJarByClass(MaxValue.class);   
  66.         FileInputFormat.setInputPaths(job, new Path(args[0]));   
  67.         FileOutputFormat.setOutputPath(job, new Path(args[1]));   
  68.         job.setMapperClass(MapClass.class);   
  69.         job.setCombinerClass(Reduce.class);   
  70.         job.setReducerClass(Reduce.class);   
  71.         job.setInputFormatClass(TextInputFormat.class);   
  72.         job.setOutputFormatClass(TextOutputFormat.class);   
  73.         job.setOutputKeyClass(Text.class);   
  74.         job.setOutputValueClass(IntWritable.class);   
  75.         System.exit(job.waitForCompletion(true) ? 0 : 1);   
  76.         return 0;   
  77.     }   
  78.   
  79.     public static void main(String[] args) throws Exception {   
  80.         long start = System.nanoTime();   
  81.         int res = ToolRunner.run(new Configuration(), new MaxValue(), args);   
  82.         System.out.println(System.nanoTime()-start);   
  83.         System.exit(res);   
  84.     }   
  85. }  

[plain]  view plain  copy
  1. [hadoop@h71 q1]$ /usr/jdk1.7.0_25/bin/javac MaxValue.java  
  2. [hadoop@h71 q1]$ /usr/jdk1.7.0_25/bin/jar cvf xx.jar MaxValue*class  
  3. [hadoop@h71 q1]$ hadoop jar xx.jar MaxValue /input/ql.txt /output  
  4. [hadoop@h71 q1]$ hadoop fs -cat /user/hadoop/output/part-r-00000  
  5. Max     555  

*************
setup(),此方法被MapReduce框架仅且执行一次,在执行Map任务前,进行相关变量或者资源的集中初始化工作。若是将资源初始化工作放在方法map()中,导致Mapper任务在解析每一行输入时都会进行资源初始化工作,导致重复,程序运行效率不高!
cleanup(),此方法被MapReduce框架仅且执行一次,在执行完毕Map任务后,进行相关变量或资源的释放工作。若是将释放资源工作放入方法map()中,也会导致Mapper任务在解析、处理每一行文本后释放资源,而且在下一行文本解析前还要重复初始化,导致反复重复,程序运行效率不高!
*************


情况2:
[hadoop@h71 q1]$ vi ceshi.txt
2
8
8
3
2
3
5
3
0
2
7
[hadoop@h71 q1]$ hadoop fs -put ceshi.txt /input


java代码:

[java]  view plain  copy
  1. import java.io.IOException;  
  2.   
  3. import org.apache.hadoop.conf.Configuration;  
  4. import org.apache.hadoop.fs.Path;  
  5. import org.apache.hadoop.io.LongWritable;  
  6. import org.apache.hadoop.io.NullWritable;  
  7. import org.apache.hadoop.io.Text;  
  8. import org.apache.hadoop.mapreduce.Job;  
  9. import org.apache.hadoop.mapreduce.Mapper;  
  10. import org.apache.hadoop.mapreduce.Reducer;  
  11. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  12. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  13. import org.apache.hadoop.util.GenericOptionsParser;  
  14.   
  15. public class Max {  
  16.       
  17.     public static class MaxMapper extends Mapper<LongWritable, Text, LongWritable, NullWritable> {  
  18.         public long max = Long.MIN_VALUE;  
  19.         public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {  
  20.             max = Math.max(Long.parseLong(value.toString()), max);  
  21.         }  
  22.         protected void cleanup(Mapper.Context context) throws IOException, InterruptedException {  
  23.             context.write(new LongWritable(max), NullWritable.get());  
  24.         }  
  25.     }  
  26.   
  27.     public static class MaxReducer extends Reducer<LongWritable, NullWritable, LongWritable, NullWritable> {  
  28.         public long max = Long.MIN_VALUE;  
  29.         public void reduce(LongWritable key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {  
  30.             max = Math.max(max, key.get());  
  31.         }  
  32.         protected void cleanup(Reducer.Context context) throws IOException, InterruptedException {  
  33.             context.write(new LongWritable(max), NullWritable.get());  
  34.         }  
  35.     }  
  36.   
  37.     public static void main(String[] args) throws Exception {  
  38.         Configuration conf = new Configuration();  
  39.         String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();  
  40.         if (otherArgs.length < 2) {  
  41.             System.err.println("Usage: Max <in> [<in>...] <out>");  
  42.             System.exit(2);  
  43.         }  
  44.   
  45.         Job job = Job.getInstance(conf, "Max");  
  46.         job.setJarByClass(Max.class);  
  47.         job.setMapperClass(MaxMapper.class);  
  48.         job.setCombinerClass(MaxReducer.class);  
  49.         job.setReducerClass(MaxReducer.class);  
  50.         job.setOutputKeyClass(LongWritable.class);  
  51.         job.setOutputValueClass(NullWritable.class);  
  52.   
  53.         for (int i = 0; i < otherArgs.length - 1; ++i) {  
  54.             FileInputFormat.addInputPath(job, new Path(otherArgs[i]));  
  55.         }  
  56.         FileOutputFormat.setOutputPath(job,  
  57.                 new Path(otherArgs[otherArgs.length - 1]));  
  58.         System.exit(job.waitForCompletion(true) ? 0 : 1);  
  59.     }  
  60. }  

[hadoop@h71 q1]$ /usr/jdk1.7.0_25/bin/javac Max.java
[hadoop@h71 q1]$ /usr/jdk1.7.0_25/bin/jar cvf xx.jar Max*class
[hadoop@h71 q1]$ hadoop jar xx.jar Max /input/ceshi.txt /output

[hadoop@h71 q1]$ hadoop fs -cat /output/part-r-00000
8


二、求和(Sum)

[hadoop@h71 q1]$ vi ceshi.txt
2
8
8
3
2
3
5
3
0
2
7
[hadoop@h71 q1]$ hadoop fs -put ceshi.txt /input


java代码:

[java]  view plain  copy
  1. import java.io.IOException;  
  2.   
  3. import org.apache.hadoop.conf.Configuration;  
  4. import org.apache.hadoop.fs.Path;  
  5. import org.apache.hadoop.io.LongWritable;  
  6. import org.apache.hadoop.io.NullWritable;  
  7. import org.apache.hadoop.io.Text;  
  8. import org.apache.hadoop.mapreduce.Job;  
  9. import org.apache.hadoop.mapreduce.Mapper;  
  10. import org.apache.hadoop.mapreduce.Reducer;  
  11. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  12. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  13. import org.apache.hadoop.util.GenericOptionsParser;  
  14.   
  15. public class Sum {  
  16.   
  17.     public static class SumMapper extends Mapper<LongWritable, Text, LongWritable, NullWritable> {  
  18.         public long sum = 0;  
  19.         public void map(LongWritable key, Text value, Context context)  
  20.                 throws IOException, InterruptedException {  
  21.             sum += Long.parseLong(value.toString());  
  22.         }  
  23.         protected void cleanup(Context context) throws IOException, InterruptedException {  
  24.             context.write(new LongWritable(sum), NullWritable.get());  
  25.         }  
  26.     }  
  27.   
  28.     public static class SumReducer extends Reducer<LongWritable, NullWritable, LongWritable, NullWritable> {  
  29.         public long sum = 0;  
  30.         public void reduce(LongWritable key, Iterable<NullWritable> values, Context context)  
  31.                 throws IOException, InterruptedException {  
  32.             sum += key.get();  
  33.         }  
  34.         protected void cleanup(Context context) throws IOException, InterruptedException {  
  35.             context.write(new LongWritable(sum), NullWritable.get());  
  36.         }  
  37.     }  
  38.   
  39.     public static void main(String[] args) throws Exception {  
  40.         Configuration conf = new Configuration();  
  41.         String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();  
  42.         if (otherArgs.length < 2) {  
  43.             System.err.println("Usage: Sum <in> [<in>...] <out>");  
  44.             System.exit(2);  
  45.         }  
  46.   
  47.         Job job = Job.getInstance(conf, "Sum");  
  48.         job.setJarByClass(Sum.class);  
  49.         job.setMapperClass(SumMapper.class);  
  50.         job.setCombinerClass(SumReducer.class);  
  51.         job.setReducerClass(SumReducer.class);  
  52.         job.setOutputKeyClass(LongWritable.class);  
  53.         job.setOutputValueClass(NullWritable.class);  
  54.   
  55.         for (int i = 0; i < otherArgs.length - 1; ++i) {  
  56.             FileInputFormat.addInputPath(job, new Path(otherArgs[i]));  
  57.         }  
  58.         FileOutputFormat.setOutputPath(job,  
  59.                 new Path(otherArgs[otherArgs.length - 1]));  
  60.         System.exit(job.waitForCompletion(true) ? 0 : 1);  
  61.     }  
  62. }  

[hadoop@h71 q1]$ hadoop fs -cat /output/part-r-00000
43


三、平均值(Avg)
情况1:
[hadoop@h71 q1]$ vi math.txt
zs 80
ls 90
ww 95
[hadoop@h71 q1]$ vi china.txt
zs 60
ls 65
ww 90
[hadoop@h71 q1]$ hadoop fs -put math.txt /input
[hadoop@h71 q1]$ hadoop fs -put china.txt /input


java代码:

[java]  view plain  copy
  1. import java.io.IOException;  
  2. import java.util.Iterator;  
  3. import java.util.StringTokenizer;  
  4.   
  5. import org.apache.hadoop.conf.Configuration;  
  6. import org.apache.hadoop.fs.Path;  
  7. import org.apache.hadoop.io.IntWritable;  
  8. import org.apache.hadoop.io.LongWritable;  
  9. import org.apache.hadoop.io.Text;  
  10. import org.apache.hadoop.mapreduce.Job;  
  11. import org.apache.hadoop.mapreduce.Mapper;  
  12. import org.apache.hadoop.mapreduce.Reducer;  
  13. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  14. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;  
  15. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  16. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  17.    
  18. public class Score {  
  19.    
  20.     public static class Map extends Mapper<LongWritable, Text, Text, IntWritable> {  
  21.         // 实现map函数  
  22.         public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {  
  23.             // 将输入的纯文本文件的数据转化成String  
  24.             String line = value.toString();  
  25.             // 将输入的数据首先按行进行分割  
  26.             StringTokenizer tokenizerArticle = new StringTokenizer(line, "\n");  
  27.             // 分别对每一行进行处理  
  28.             while (tokenizerArticle.hasMoreElements()) {  
  29.                 // 每行按空格划分  
  30.                 StringTokenizer tokenizerLine = new StringTokenizer(tokenizerArticle.nextToken());  
  31.                 String strName = tokenizerLine.nextToken();// 学生姓名部分  
  32.                 String strScore = tokenizerLine.nextToken();// 成绩部分  
  33.                 Text name = new Text(strName);  
  34.                 int scoreInt = Integer.parseInt(strScore);  
  35.                 // 输出姓名和成绩  
  36.                 context.write(name, new IntWritable(scoreInt));  
  37.             }  
  38.         }  
  39.     }  
  40.    
  41.     public static class Reduce extends Reducer<Text, IntWritable, Text, IntWritable> {  
  42.         // 实现reduce函数  
  43.         public void reduce(Text key, Iterable<IntWritable> values,  
  44.                 Context context) throws IOException, InterruptedException {  
  45.             int sum = 0;  
  46.             int count = 0;  
  47.             Iterator<IntWritable> iterator = values.iterator();  
  48.             while (iterator.hasNext()) {  
  49.                 sum += iterator.next().get();// 计算总分  
  50.                 count++;// 统计总的科目数  
  51.             }  
  52.             int average = (int) sum / count;// 计算平均成绩  
  53.             context.write(key, new IntWritable(average));  
  54.         }  
  55.     }  
  56.    
  57.     public static void main(String[] args) throws Exception {  
  58.         Configuration conf = new Configuration();  
  59.         conf.set("mapred.jar","Score.jar");  
  60.           
  61.         Job job = new Job(conf, "Score Average");  
  62.         job.setJarByClass(Score.class);  
  63.    
  64.         // 设置Map、Combine和Reduce处理类  
  65.         job.setMapperClass(Map.class);  
  66.         job.setCombinerClass(Reduce.class);  
  67.         job.setReducerClass(Reduce.class);  
  68.    
  69.         // 设置输出类型  
  70.         job.setOutputKeyClass(Text.class);  
  71.         job.setOutputValueClass(IntWritable.class);  
  72.    
  73.         // 将输入的数据集分割成小数据块splites,提供一个RecordReder的实现  
  74.         job.setInputFormatClass(TextInputFormat.class);  
  75.         // 提供一个RecordWriter的实现,负责数据输出  
  76.         job.setOutputFormatClass(TextOutputFormat.class);  
  77.    
  78.         // 设置输入和输出目录  
  79.         FileInputFormat.setInputPaths(job, new Path(args[0]));  
  80.         FileOutputFormat.setOutputPath(job, new Path(args[1]));  
  81.         System.exit(job.waitForCompletion(true) ? 0 : 1);  
  82.     }  
  83. }  

[hadoop@h71 q1]$ /usr/jdk1.7.0_25/bin/javac Score.java 
[hadoop@h71 q1]$ /usr/jdk1.7.0_25/bin/jar cvf xx.jar Score*class
[hadoop@h71 q1]$ hadoop jar xx.jar Score /input/* /output

[hadoop@h71 q1]$ hadoop fs -cat /output/part-r-00000
ls      77
ww      92
zs      70


补充:迭代器(Iterator)
  迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。迭代器通常被称为“轻量级”对象,因为创建它的代价小。
  Java中的Iterator功能比较简单,并且只能单向移动:
  (1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
  (2) 使用next()获得序列中的下一个元素。
  (3) 使用hasNext()检查序列中是否还有元素。
  (4) 使用remove()将迭代器新返回的元素删除。
  Iterator是Java迭代器最简单的实现,为List设计的ListIterator具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
1.创建集合:
Collection c = new ArrayList<String>();
2.添加元素:
c.add("hehehe");
c.add("huhuhu");
c.add("wawawa");
3.获取集合的迭代器:
Iterator iterator = c.iterator();
4.进行遍历:
while(iterator.hasNext())//如果仍有元素可以迭代,则返回 true
{
System.out.println(iterator.next());//返回迭代的下一个元素。
}


情况2:

[hadoop@h71 q1]$ vi ceshi.txt
2
8
8
3
2
3
5
3
0
2
7
[hadoop@h71 q1]$ hadoop fs -put ceshi.txt /input


java代码:

[java]  view plain  copy
  1. import java.io.IOException;  
  2.   
  3. import org.apache.hadoop.conf.Configuration;  
  4. import org.apache.hadoop.fs.Path;  
  5. import org.apache.hadoop.io.DoubleWritable;  
  6. import org.apache.hadoop.io.LongWritable;  
  7. import org.apache.hadoop.io.NullWritable;  
  8. import org.apache.hadoop.io.Text;  
  9. import org.apache.hadoop.mapreduce.Job;  
  10. import org.apache.hadoop.mapreduce.Mapper;  
  11. import org.apache.hadoop.mapreduce.Reducer;  
  12. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  13. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  14. import org.apache.hadoop.util.GenericOptionsParser;  
  15.   
  16. public class Average {  
  17.       
  18.     public static class AvgMapper extends Mapper<LongWritable, Text, LongWritable, LongWritable> {  
  19.         public long sum = 0;  
  20.         public long count = 0;  
  21.         public void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {  
  22.             sum += Long.parseLong(value.toString());  
  23.             count += 1;  
  24.         }  
  25.         protected void cleanup(Context context) throws IOException, InterruptedException {  
  26.             context.write(new LongWritable(sum), new LongWritable(count));  
  27.         }  
  28.     }  
  29.   
  30.     public static class AvgCombiner extends Reducer<LongWritable, LongWritable, LongWritable, LongWritable> {  
  31.         public long sum = 0;  
  32.         public long count = 0;  
  33.         public void reduce(LongWritable key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {  
  34.             sum += key.get();  
  35.             for (LongWritable v : values) {  
  36.                 count += v.get();  
  37.             }  
  38.         }  
  39.         protected void cleanup(Context context) throws IOException, InterruptedException {  
  40.             context.write(new LongWritable(sum), new LongWritable(count));  
  41.         }  
  42.     }  
  43.   
  44.     public static class AvgReducer extends Reducer<LongWritable, LongWritable, DoubleWritable, NullWritable> {  
  45.         public long sum = 0;  
  46.         public long count = 0;  
  47.         public void reduce(LongWritable key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {  
  48.             sum += key.get();  
  49.             for (LongWritable v : values) {  
  50.                 count += v.get();  
  51.             }  
  52.         }  
  53.         protected void cleanup(Context context) throws IOException, InterruptedException {  
  54.             context.write(new DoubleWritable(new Double(sum)/count), NullWritable.get());  
  55.         }  
  56.     }  
  57.   
  58.     public static void main(String[] args) throws Exception {  
  59.         Configuration conf = new Configuration();  
  60.         String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();  
  61.         if (otherArgs.length < 2) {  
  62.             System.err.println("Usage: Avg <in> [<in>...] <out>");  
  63.             System.exit(2);  
  64.         }  
  65.   
  66.         Job job = Job.getInstance(conf, "Avg");  
  67.         job.setJarByClass(Average.class);  
  68.         job.setMapperClass(AvgMapper.class);  
  69.         job.setCombinerClass(AvgCombiner.class);  
  70.         job.setReducerClass(AvgReducer.class);  
  71.   
  72.         //注意这里:由于Mapper与Reducer的输出Key,Value类型不同,所以要单独为Mapper设置类型  
  73.         job.setMapOutputKeyClass(LongWritable.class);  
  74.         job.setMapOutputValueClass(LongWritable.class);  
  75.   
  76.         job.setOutputKeyClass(DoubleWritable.class);  
  77.         job.setOutputValueClass(NullWritable.class);  
  78.   
  79.         for (int i = 0; i < otherArgs.length - 1; ++i) {  
  80.             FileInputFormat.addInputPath(job, new Path(otherArgs[i]));  
  81.         }  
  82.         FileOutputFormat.setOutputPath(job,  
  83.                 new Path(otherArgs[otherArgs.length - 1]));  
  84.         System.exit(job.waitForCompletion(true) ? 0 : 1);  
  85.     }  
  86. }  

[hadoop@h71 q1]$ /usr/jdk1.7.0_25/bin/javac Average.java 
[hadoop@h71 q1]$ /usr/jdk1.7.0_25/bin/jar cvf xx.jar Average*class
[hadoop@h71 q1]$ hadoop jar xx.jar Average /input/ceshi.txt /output

[hadoop@h71 q1]$ hadoop fs -cat /output/part-r-00000
3.909090909090909

版权声明:本文为博主原创文章,请尊重劳动成果,觉得不错就在文章下方顶一下呗,转载请标明原地址。 https://blog.csdn.net/m0_37739193/article/details/76169108
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值