mapreduce
1、map进行统计:相同的值会统一的放入一组,丢给reduce进行计算
2、reduce进行计算:对map传来的一组值进行累加输出
小结:
Job中的入口不要设置错,是否return job视情况而定
单个job可以直接输出,多个job需要添加线程依赖
没有mainRun方法,需要写完整路径名来访问job。简化:在自己pom文件设置job访问入口
job读取文件的方式有5种,都会输出<k,v>
1)TextInputFormat:默认,按照文件切分,按行读取
2)NLineInputFormat:按设置的行切分,按行读取
3)KeyValueTextInputFormat:按照文件切分,按行读取,主要用于处理数据中具有明显的key-value样式的数据
map数量多少根据文件切分而来
reduce数量的多少可以通过人工setNumReduceTasks设置(默认为1个)。一个reduce任务的输入往往来自于所有 mapper 的输出, reduce 按照 key 对升序进行排序 ,可以重写排序方法 ,进行自定义排序
job里设置多个reduce时,可能会产生数据倾斜的问题,默认用哈希值来setPartitionerClass进行解决,也可以根据实际情况设置分区
读入文件的操作由 hadoop内部完成,我们只需利用FileInputFormat 告知输入/输出的文件目录即可
要事先想好map与reduce的I/O值是什么类型,在Job里设置时也不要出错
map与reduce中间可以setCombinerClass进行计算优化
map与reduce之间有自己的排序方法shuffle,可以继承Comparator类重写它的排序方法,根据key值进行顺/逆序;或是自定义排序类,继承WritableComparator类重写排序规则,在job中setSortComparatorClass设置自己的排序方法
Shuffle的key只起指定reduce 的作用,Shuffle的key产生的机制有 partitioner 负责
建议
1、讲课吐字不清淅,有时候听不清他在说什么。建议练练普通话
2、讲课逻辑混乱,没有第一步、第二步这种一步一步的节奏,有时候突然跳到其他的地方,直接看不懂。建议跟张焱老师后面学学讲课节奏
3、课程安排不合理,Linux基本命令都不会,直接就硬操作虚拟机真的一脸懵逼。衔接的这么混乱,对我们造成的损失是否会有相应的赔偿
4、有时候抽象的知识他不画图,总是指望一张图能解释所有概念,理解起来很费解。建议多画图
5、上课不备课,有时候上课突然卡住卡半节不讲话课,再讲时思路直接断掉。建议给我们上课时备备课,别老翻车
6、讲解代码时不敲代码,直接复制粘贴一大段,我们自己手敲还要理解消化根本跟不上。建议手敲代码,别老复制,边敲的时候边讲解更利于理解消化
7、笔记做的太乱了,没有条理,没有标注,只有他自己能看懂,跟他说了到现在还没改。建议天天都写个课程笔记,方便我们理解
scala与java区别:
mian函数形式上有区别
语句结尾可以不加分号
不需要定义数据类型,Scala自动判断
使用关键词 "var" 声明变量,使用关键词 "val" 声明常量
支持多个变/常量同时声明:val xmax,ymax,mmax,nmax =100
Scala
Scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。
Scala 源代码被编译成 Java 字节码,所以它可以运行于 JVM 之上,并可以调用现有的 Java 类库
数组:不可变(可变:ArrayBuffer)
object Test { def main(args: Array[String]) { var myList = Array(1.9, 2.9, 3.4, 3.5) // 输出所有数组元素 for ( x <- myList ) { println( x ) } // 计算数组所有元素的总和 var total = 0.0; for ( i <- 0 to (myList.length - 1)) { total += myList(i); } println("总和为 " + total); // 查找数组中的最大元素 var max = myList(0); for ( i <- 1 to (myList.length - 1) ) { if (myList(i) > max) max = myList(i); } println("最大值为 " + max); // 创建矩阵 for (i <- 0 to 2) { for ( j <- 0 to 2) { myMatrix(i)(j) = j; } } // 打印二维阵列 for (i <- 0 to 2) { for ( j <- 0 to 2) { print(" " + myMatrix(i)(j)); } println(); } //合并数组 var myList1 = Array(1.9, 2.9, 3.4, 3.5) var myList2 = Array(8.9, 7.9, 0.4, 1.5) var myList3 = concat( myList1, myList2) // 输出所有数组元素 for ( x <- myList3 ) { println( x ) } //区间数组 var myList1 = range(10, 20, 2) var myList2 = range(10,20) // 输出所有数组元素 for ( x <- myList1 ) { print( " " + x ) } println() for ( x <- myList2 ) { print( " " + x ) } } }
Scala Collection
1、List(列表):不可变、值一旦被定义了就不能改变,否则地址改变(可变List:ListBuffer) object Test { def main(args: Array[String]) { // 字符串列表 val site0: List[String] = List("Runoob", "Google", "Baidu") val site = "Runoob" :: ("Google" :: ("Baidu" :: Nil)) val nums = Nil println( "第一网站是 : " + site.head ) println( "最后一个网站是 : " + site.tail ) println( "查看列表 site 是否为空 : " + site.isEmpty ) println( "查看 nums 是否为空 : " + nums.isEmpty ) //连接列表 val site1 = "Runoob" :: ("Google" :: ("Baidu" :: Nil)) val site2 = "Facebook" :: ("Taobao" :: Nil) // 使用 ::: 运算符 var fruit = site1 ::: site2 println( "site1 ::: site2 : " + fruit ) // 使用 List.:::() 方法 fruit = site1.:::(site2) println( "site1.:::(site2) : " + fruit ) // 使用 concat 方法 fruit = List.concat(site1, site2) println( "List.concat(site1, site2) : " + fruit ) //使用 List.fill() 方法来创建一个指定重复数量的元素列表 val site = List.fill(3)("Runoob") // 重复 Runoob 3次 println( "site : " + site ) val num = List.fill(10)(2) // 重复元素 2, 10 次 println( "num : " + num ) //List.reverse 用于将列表的顺序反转 val site = "Runoob" :: ("Google" :: ("Baidu" :: Nil)) println( "site 反转前 : " + site ) println( "site 反转后 : " + site.reverse ) } } 2、Set(集合):分为可变和不可变的 默认情况下,Scala 使用的是不可变集合,如果你想使用可变集合,需要引用 scala.collection.mutable.Set 包。默认引用 scala.collection.immutable.Set object Test { def main(args: Array[String]) { val site = Set("Runoob", "Google", "Baidu") val nums: Set[Int] = Set() println( "第一网站是 : " + site.head ) println( "最后一个网站是 : " + site.tail ) println( "查看列表 site 是否为空 : " + site.isEmpty ) println( "查看 nums 是否为空 : " + nums.isEmpty ) //连接集合 val site1 = Set("Runoob", "Google", "Baidu") val site2 = Set("Faceboook", "Taobao") // ++ 作为运算符使用 var site = site1 ++ site2 println( "site1 ++ site2 : " + site ) // ++ 作为方法使用 site = site1.++(site2) println( "site1.++(site2) : " + site ) // 查找集合中最大与最小元素 val num = Set(5,6,9,20,30,45) println( "Set(5,6,9,20,30,45) 集合中的最小元素是 : " + num.min ) println( "Set(5,6,9,20,30,45) 集合中的最大元素是 : " + num.max ) //使用 Set.& 方法或 Set.intersect 方法来查看两个集合的交集元素 val num1 = Set(5,6,9,20,30,45) val num2 = Set(50,60,9,20,35,55) // 交集 println( "num1.&(num2) : " + num1.&(num2) ) println( "num1.intersect(num2) : " + num1.intersect(num2) ) } } 3、Map(映射):可变与不可变。默认情况下 Scala 使用不可变 Map。如果你需要使用可变集合,你需要显式的引入 import scala.collection.mutable.Map 类 object Test { def main(args: Array[String]) { val colors = Map("red" -> "#FF0000", "azure" -> "#F0FFFF", "peru" -> "#CD853F") val nums: Map[Int, Int] = Map() println( "colors 中的键为 : " + colors.keys ) println( "colors 中的值为 : " + colors.values ) println( "检测 colors 是否为空 : " + colors.isEmpty ) println( "检测 nums 是否为空 : " + nums.isEmpty ) //使用 ++ 运算符或 Map.++() 方法来连接两个 Map,Map 合并时会移除重复的 key val colors1 = Map("red" -> "#FF0000", "azure" -> "#F0FFFF", "peru" -> "#CD853F") val colors2 = Map("blue" -> "#0033FF", "yellow" -> "#FFFF00", "red" -> "#FF0000") // ++ 作为运算符 var colors = colors1 ++ colors2 println( "colors1 ++ colors2 : " + colors ) // ++ 作为方法 colors = colors1.++(colors2) println( "colors1.++(colors2) : " + colors ) //通过 foreach 循环输出 Map 中的 keys 和 values val sites = Map("runoob" -> "http://www.runoob.com", "baidu" -> "http://www.baidu.com", "taobao" -> "http://www.taobao.com") sites.keys.foreach{ i => print( "Key = " + i ) println(" Value = " + sites(i) )} } } 4、元组:不可变,下标从1开始 object Test { def main(args: Array[String]) { val t = (4,3,2,1) val sum = t._1 + t._2 + t._3 + t._4 println( "元素之和为: " + sum ) //遍历 t.productIterator.foreach(println(_)) t.productIterator.foreach(x => print(x + " ")) for (x <- t.productIterator) { print(x + "|") } //元素拼接 println(t.productIterator.mkString("|")) //使用 Tuple.toString() 方法将元组的所有元素组合成一个字符串 val t = new Tuple3(1, "hello", Console) println("连接后的字符串为: " + t.toString() ) //使用 Tuple.swap 方法来交换元组的元素。只有Tuple2生效 val t = new Tuple2("www.google.com", "www.runoob.com") println("交换后的元组: " + t.swap ) } }
Scala中的类不声明为public,一个Scala源文件中可以有多个类
在scala类中,与类名相同的对象叫做伴生对象,类和伴生对象之间可以相互访问私有的方法和属性
Scala 中没有 static ,但是它也为我们提供了单例模式的实现方法,那就是使用关键字 object
Scala Trait(特征) 相当于 Java 的接口
Scala 模式匹配
match 对应 Java 里的 switch,但是写在选择器表达式之后。即: 选择器 match {备选项} match 表达式通过以代码编写的先后次序尝试每个模式来完成计算,只要发现有一个匹配的case,剩下的case不会继续匹配。 object Test { def main(args: Array[String]) { println(matchTest("two")) println(matchTest("test")) println(matchTest(1)) println(matchTest(6)) } def matchTest(x: Any): Any = x match { case 1 => "one" case "two" => 2 case y: Int => "scala.Int" case _ => "many" } } //使用了case关键字的类定义就是样例类(case classes),样例类是种特殊的类,经过优化以用于模式匹配 object Test { def main(args: Array[String]) { val alice = new Person("Alice", 25) val bob = new Person("Bob", 32) val charlie = new Person("Charlie", 32) for (person <- List(alice, bob, charlie)) { person match { case Person("Alice", 25) => println("Hi Alice!") case Person("Bob", 32) => println("Hi Bob!") case Person(name, age) => println("Age: " + age + " year, name: " + name + "?") } } } // 样例类 case class Person(name: String, age: Int) }
jar、瘦包(没有依赖)->shade、胖包(会将所需要的依赖一起打包)->assembly、自定义胖包(可以让输出的结构清晰而标准化,需要自定义配置)
combineByKey
createCombiner: V => C ,生成初始化 值 是区间内要形成的数据形式实例 mergeValue: (C, V) => C,分区内 计算逻辑 mergeCombiners: (C, C) => C, 不同分区间 计算逻辑
.combineByKey( (v:(String,Int) ) => ( mutable.SetString , v.2 ), ( c:(mutable.Set[String], Int) , v: (String,Int) ) => { c.1.add(v.1) val count = c.2 + v.2 (c.1,count) }, (c1: (mutable.Set[String], Int), c2: (mutable.Set[String], Int)) => { c1.1 ++= c2.1 val count = c1.2 + c2.2 (c1._1,count) } )
aggregateByKey:combineByKey进阶版,简化初始值操作
.aggregateByKey((mutable.SetString , 0) )( ( c:(mutable.Set[String], Int) , v: (String,Int) ) => { c.1.add(v.1) val count = c.2 + v.2 (c.1,count) }, (c1: (mutable.Set[String], Int), c2: (mutable.Set[String], Int)) => { c1.1 ++= c2.1 val count = c1.2 + c2.2 (c1.1,count) } )
foldByKey:aggregateByKey 的简化操作,只有seqop 和combop 相同可使用
reduceByKey:分区聚合,常用
reduceByKey与groupByKey区别:reduceByKey多一次预聚合操作
sortBy排序
1)自带sort、自定义sort比较 val a = List("01 hadoop","06 spark", "02 flume","03 hive") println(a) for (elem <- a) {println(elem)} a.sorted.reverse.foreach(println) println("05 ff".compareTo("06 ee")) 2)先比较第2个,再比较第1个 val a = List((1, "aa"), (2, "aa"), (6, "bb"), (3, "bb"), (86, "gg"), (0, "gg")) a.sortBy(x => (x._2, x._1)) .foreach(println)
数据是否发生倾斜:看执行速度是否快,快则无倾斜
数据倾斜解决方案:先对数据加前缀做一次MR,再把前缀去掉做一次MR