拒嫁豪门:少奶奶99次出逃之我要学会Spark操作方法

目录

一:Scala基础

1.定义与使用常量

2.定义与使用数组

3.定义与使用元组

4.使用函数组合器

1.map()方法

2.foreach()

3.filter()方法

4.flatten()方法

5.flatMap()方法

6.groupBy()方法

二:Spark编程基础

1.创建RDD与应用RDD

1.1 从内存中读取数据创建RDD

1.parallelize() 

2.makeRDD()

1.2从外部存储系统中读取数据创建RDD

(1)通过HDFS文件创建RDD

(2)通过Linux本地文件创建RDD

1.3使用RDD的基本操作

1.使用map()方法转换数据

2.使用sortBy()方法进行排序

3.使用collect()方法查询数据

4.使用flatMap()方法

RDD之间的操作

1.使用union()方法合并多个RDD

2.使用filter()方法进行过滤

3.使用distinct()方法进行去重

3.3使用简单的集合操作

1.Spark中的集合操作常用方法(转换操作)

(2)subtract()方法

(3)cartesian()方法

三:Spark SQL—结构化数据文件处理

​编辑3.1 DataFrame基础操作

1.DataFrame的创建

2.使用SparkSession方式创建DataFrame

3.数据准备

4.通过文件直接创建DataFrame

5.RDD直接转换为DataFrame

3.2 DataFrame的常用操作

1.DataFrame的方法

2.直接在DataFrame对象上进行查询的方法

3.DataFrame操作方法

1.where()/filter()方法

(2)filter()方法

2.select()/selectExpr()/col()/apply()方法

(3)col()/apply()方法

4.orderBy()/sort()方法

5.groupBy()方法


一:Scala基础

1.定义与使用常量

(1)常量:用 val关键字定义一个常量

(2)变量:用var关键字定义一个变量

2.定义与使用数组

(1)数组是Scala中常用的一种数据结构,数组是一种存储了相同类型元素的固定大小的顺序集合

(2)定义数组的两个方式

#1

var arr:Array[String] = new Array[String](num)

#2

var arr:Array[String] = Array(元素1,元素2,......)

(3)数组操作的常用方法

#查看数组z的长度

z.length

#查看数组z的第一个元素

z.head

#查看数组z中除了第一个元素外的其他元素

z.tail

#判断数组z是否为空

z.isEmpty

#判断数组z是否包含元素"baidu"

z.contains("baidu")

(4) 连接两个数组可以使用操作符“++”,还可以使用concat()方法

#通过concat()方法连接数组

        importArray._

        val arr4=concat(arr1,arr2)

(5)使用range()创建区间数组

#创建区间数组,生成数组(1,3,5,7,9)

        val arr=range(1,10,2)

(6)定义与使用函数

函数是Scala的重要组成部分,Scala作为支持函数式编程的语言Scala函数的以将函数作为对象,定义函数的语法格式如下。

        def functionName(参数列表):[returntype]={}

函数的定义由一个def关键字开始,紧接着是函数名称和可选的参数列表,其次悬个冒号“:”和函数的返回类型,之后是赋值运算符“一”,最后是方法体。其中,参数外中需要指定参数名称和参数类型。函数的返回类型[returntype]可以是任意合法的ScalaySca据类型。若函数无返回值,则函数的返回类型为“Unit”。

例如,定义一个函数add,实现两个数相加的功能,函数返回类型为Int,两个数概的结果作为返回值。在Java中,函数需要使用return关键字指明返回值,而Scala函数义个可以不加returm关键字指明返回值。

#定义两个整数相加的代码1

        def add(a:Int,b:Int):Int=(a+b}

Scala也可以使用“return”关键字指明返回的结果,如代码2-8所示。

#定义两个整数相加的代码2

        def add(a:Int,b:Int):Int=(varsum=0;sum=a+b;return sum)

Scala提供了多种不同的函数调用方式,以下是调用函数的标准格式。

functionName(参数列表)

3.定义与使用元组

元组(Tuple)是一种类似于列表的结构,但是元组可以包含不同类型的元素,元组的值是通过将单个的值包含在圆括号种构成的

val t=(1,3.14,"a")

val t-new Tuple3(1,3.14,"a")

4.使用函数组合器

Scala为各种数据结构提供了很多函数组合器,函数组合器的参数都是一个函数,运用函数组合器的操作会对集合中的每个元素分别应用一个函数。以列表为例,介绍常用的的数组合器的用法。

1.map()方法

map()方法可通过一个函数重新计算列表scala>valnum:List[Int]=List(1,2,3,4,5)中的所有元素,并且返回一个包含相同数目元num:List[Int]=List(1,2,3,4,5)素的新列表。例如,定义一个Int类型列表,列scala>num.map(x=>x*x)表中的元素为1~5,使用map()方法对列表中的元素进行平方计算。

val num:List[Int]=List(1,2,3,4,5)

num.map(x=>x*x)

2.foreach()

方法foreach()方法和map()方法类似,但是foreach()方法没有返回值,只用于对参数的结果进行输出。例如,使用foreach方法对num中的元素进行平方计算并输出.

val num:List[Int]=List(1,2,3,4,5)

num.foreach(x=>print(x*x+"/t")

3.filter()方法

使用filter()方法可以移除传入函数的返回值为false的元素。例如,过滤列表num中的奇数,得到只包含偶数的列表.

val num:List[Int]=List(1,2,3,4,5)

num.filter(x=>x%2==0)

4.flatten()方法

flatten()方法可以将嵌套的结构晨开,即flatten()方法可以将一个二维的列表展开成一个一维的列表。定义一个二维列表list,通过flattenO方法可以将list展开为一维列表。

val list=List(List(1,2,3),List(4,5,6))

list.flatten

5.flatMap()方法

flatMap()方法结合了map0方法和flatten()方法的功能,接收一个可以处理嵌套列表的函数,再对返回结果进行连接。

val str=List("a:b:c","d:e:f")

str.flatMap(x=>x.split(";"))的使用

6.groupBy()方法

groupBy0方法可对集合中的元素进行分组操作,返回的结果是一个映射。对1~1据奇偶性进行分组,因此groupBv0方法传入的参数是一个计算偶数的函数,得到的结一个映射,包含两个键值对,键为false对应的值为奇数列表,键为true对应的值为偶表,如图2-41所示。val num:list[Intl=list(1.2.3,4.5,6,7,8,9,10)

num.groupBy(x=>x%2==0)

二:Spark编程基础

1.创建RDD与应用RDD

1.1 从内存中读取数据创建RDD
1.parallelize() 

有两个输入参)

(1)要转化的集合:必须是Sep集合,指的是一类具有一定长度的可迭代访问的对象,每个数据元素均带有一个从0开始的,固定的序列

(2)分区数:若不设分区数,则RDD的分区数默认为该程序分配到的资源的CPU核心数通过parallelize0方法用一个数组的数据创建RDD,并设置分区数为4,如代码3-1所示,创建后查看该RDD的分区数。

parallelize()方法创建RDD及查看分区个数

#定义一个数组

val data=Array(1,2,3,4,5)

#使用parallelize()方法创建RDD

val distData=sc.parallelize(data)

#查看RDD默认分区个数

distData.partitions.size

#设置分区个数为4后创建RDD

val distData=sc.parallelize(data,4)

#再次查看RDD分区个数

distData.partitions.size

2.makeRDD()

makeRDDO方法有两种使用方式,第一种使用方式与parallelize()方法一致; 第二种方式是通过接收一个Seq[(T,Seq[String])]参数类型创建RDD。第二种方式生成的RDD中保存的是T的值,Scq[String]部分的数据会按照Seq[(TSeq[String])]的顺序存放到各个分区中,一个Scq[String]对应存放至一个分区,并为数据提供位置信息,通过preferredLocationsO方法可以根据位置信息查看每一个分区的值。调用makeRDD)时不可以直接指定RDD的分区个数,分区的个数与Seq[String]参数的个数是保持一致的。使用makeRDDO方法创建RDD,并根据位置信息查看每一个分区的值。

使用makeRDD()方法创建RDD并查看各分区的值

#定义一个序列seq

val seq=Seq((1,Seq("iteblog.com","sparkhost1.com")),(3,Seq("itebolg.com","sparkhost2.com")),

(2,Seq("iteblog.com","sparkhost3.com")))

#使用makeRDD()方法创建RDD

val iteblog=sc.makeRDD(seq)

#查看RDD的值

iteblog.collect

#查看分区个数

iteblog.partitioner

iteblog.partitions.size

#根据位置信息查看每一个分区的值

iteblog.preferredLocations(iteblog.partitions(0))

iteblog.preferredLocations(iteblog.partitions(1))

iteblog.preferredLocations(iteblog.partitions(2))

1.2从外部存储系统中读取数据创建RDD

从外部存储系统中读取数据创建RDD是指直接读取存放在文件系统中的数据文件创建RDD。从内存中读取数据创建RDD的方法常用于测试,从外部存储系统中读取数据创建RDD才是用于实践操作的常用方法。

从外部存储系统中读取数据创建RDD的方法可以有很多种数据来源,可通过SparkConte对象的textFile()方法读取数据集。textFile()方法支持多种类型的数据集,如目录、文本文件、压缩文件和通配符匹配的文件等,并且允许设定分区个数,分别读取HDFS文件和Linu本地文件的数据并创建RDD,具体操作如下。

(1)通过HDFS文件创建RDD

这种方式较为简单和常用,直接通过textFile()方法读取HDFS文件的位置即可。在HDFS的/user/root目录下有一个文件test.txt,读取该文件创建一个RDD。

通过HDFS文件创建RDD

val test=sc.textFile("/user/root/test.txt")

(2)通过Linux本地文件创建RDD

本地文件的读取也是通过sc.textFile("路径)的方法实现的,在路径前面加上“file://”表示从Linux本地文件系统读取。在IntelliJIDEA开发环境中可以直接读取本地文件;但在spark-shell中,要求在所有节点的相同位置保存该文件才可以读取它,例如,在Linux的/opt目录下创建一个文件test.txt,任意输入4行数据并保存,将test.txt文件远程传输至所有节点的/opt目录下,才可以读取文件test.txt。读取test.txt文件,并且统计文件的数据行数。

通过Linux本地文件创建RDD

#读取本地文件test.txt

val test=sc.textFile("file:///opt/test.txt")

#统计test.txt文件的数据行数

test.count

1.3使用RDD的基本操作
1.使用map()方法转换数据

map()方法是一种基础的RDD转换操作,可以对RDD中的每一个数据元素通过某种函数进行转换并返回新的RDD。map()方法是懒操作,不会立即进行计算。

转换操作是创建RDD的第二种方法,通过转换已有RDD生成新的RDD。因为RDD是一个不可变的集合,所以如果对RDD数据进行了某种转换,那么会生成一个新的RDD。例如,通过一个存放了5个Int类型的数据元素的列表创建一个RDD,可通过map0方法对每一个元素进行平方运算,结果会生成一个新的RDD。

map()方法示例

#创建RDD

val distData=sc.parallelize(List(1,3,45,3,76))

#map()方法求平方值

val sq_dist=distData.map(x->x*x)

2.使用sortBy()方法进行排序

sortBy()方法用于对标准RDD进行排序,有3个可输入参数,说明如下。

(1)第1个参数是一个函数f(T)=>K,左边是要被排序对象中的每一个元素,右边返回的值是元素中要进行排序的值。

(2)第2个参数是ascending,决定排序后RDD中的元素是升序的还是降序的,默认是true,即升序排序,如果需要降序排序则需要将参数的值设置为false。

(3)第3个参数是numPartitions,决定排序后的RDD的分区个数,默认排序后的分区个数和排序之前的分区个数相等,即this.partitions.size。

第一个参数是必须输入的,而后面的两个参数可以不输入。例如,通过一个存放了3个二元组的列表创建一个RDD,对元组的第二个值进行降序排序,分区个数设置为1。

#创建RDD

val data=sc.parallelize(List(1,3),(45,3),(7,6)))

#使用sortBy()方法对元组的第二个值进行降序排序,分区个数设置为1

val sort_data=data.sortBy(x => x._2,false,1)

3.使用collect()方法查询数据

collect()方法是一种行动操作,可以将RDD中所有元素转换成数组并返回到Driver端适用于返回处理后的少量数据。因为需要从集群各个节点收集数据到本地,经过网络传输并且加载到Driver内存中,所以如果数据量比较大,会给网络传输造成很大的压力。因此,数据量较大时,尽量不使用collect()方法,否则可能导致Driver端出现内存溢出问题。collect()方法有以下两种操作方式。

(1)collect:直接调用collect返回该RDD中的所有元素,返回类型是一个Array[T]数组,这是较为常用的一种方式。

使用collect()方法查看sq_dist和sort_data的结果,分别返回了经过平方运算后的Int类型的数组和对元组第二个值进行降序排列后的数组。

collect()方法示例查看sq_dist和sort_data的结果

sq_dist.collect
sort_data.collect

(2)collect[U:ClassTag](f:PartialFunction[T,Ul):RDD[U]。这种方式需要提供一个标准的偏函数,将元素保存至一个RDD中。首先定义一个函数one,用于将collect方法得到的数组中数值为1的值替换为“one”,将其他值替换为“other”。创建一个只有3个Int类型数据的RDD,在使用collect()方法时将one函数作为参数,如代码3-9所示,结果如图3-4所示。

collect(PartialFunction)方法示例

#定义一个函数one
val one:PartialFunction[Int,String]=[casel->"one";case"other"}

#创建RDD
val data=sc.parallelize(List(2,3.1))

#使用collect()方法,将one函数作为参数
data.collect(one).collect

4.使用flatMap()方法

转换数据flatMap()方法将函数参数应用于RDD之中的每一个元素,将返回的迭代器(如数组、列表等)中的所有元素构成新的RDD。使用flatMap()方法时先进行map(映射)再进行flat(扁平化)操作,数据会先经过跟map()方法一样的操作,为每一条输入返回一个迭代器(可迭代的数据类型),然后将所得到的不同级别的迭代器中的元素全部当成同级别的元素,返回一个元素级别全部相同的RDD。这个转换操作通常用来切分单词。
例如,分别用map()方法和flatMap()方法分割字符串。用map0方法分割后,每个元素对应返回一个迭代器,即数组。flatMap()方法在进行同map()方法一样的操作后,将3个迭代器的元素扁平化(压成同一级别),保存在新RDD中。
flatMap()方法示例
#创建RDD
val test=sc.parallelize(List("How are you","I am fine","What about you"))
#查看RDD
test.collect
#使用map分割字符串后,再查看RDD
test.map(x=>x.split("")).collect
#使用flatMap分割字符串后,再查看RDD
test.flatMap(x=>x.split("")).collect

take(N)方法用于获取RDD的前N个元素,返回数据为数组。take()与collect()方法的获取RDD的原理相似,collect()方法用于获取全部数据,take()方法获取指定个数的数据。
take()方法示例
#创建RDD
val data=sc.parallelize(1 to 10)
#获取RDD的前5个元素
data.take(5)

RDD之间的操作

1.使用union()方法合并多个RDD


union()方法是一种转换操作,用于将两个RDD合并成一个,不进行去重操作,而且两个RDD中每个元素中的值的个数、数据类型需要保持一致。创建两个存放二元组的RDD,通过union()方法合并两个RDD,不处理重复数据,并且每个二元组的值的个数、数据类型都是一致的。
union()方法示例

#创建RDD
val rdd1=sc.parallelize(List(('a',1),('b',2),('c',3)))
val rdd2=sc.parallelize(List(('a'r1),('d',4),('e',5)))
#通过union()方法合并两个RDD
rddl.union(rdd2).collect

2.使用filter()方法进行过滤

filter()方法是一种转换操作,用于过滤RDD中的元素。filter()方法需要个参数是一个用于过滤的函数,该函数的返回值为Boolean类型。filter()方法将返回值为t的元素保留,将返回值为false的元素过滤掉,最后返回一个存储符合过滤条件的所有元素的新RDD。
创建一个RDD,并且过滤掉每个元组第二个值小于等于1的元素,其中第一个filter()方法中使用了“.2”,第一个“”与第二个filter()方法中的“x”一样,均表示RDD的每一个元素。
filter()方法示例
#创建RDD
val rdd1=sc.parallelize(List(('a',1),('b',2),('c'3)))
创建一个RDD,并且过滤掉每个元组第二个值小于等于1的元素,其中第一个filter()方法中使用了“.2”,第一个“”与第二个filter()方法中的“x”一样,均表示RDD的每一个元素。
filter()方法示例
#创建RDD
val rdd1=sc.parallelize(List(('a',1),('b',2),('c'3)))
#通过filter()方法过滤其中每个元组第二个值小于等于1的元素
rdd1.filter(_.2>1).collect
rdd1.filter(x=>x.2>1).collect

3.使用distinct()方法进行去重


distinct()方法是一种转换操作,用于RDD的数据去重,去除两个完全相同的元素,费有参数。创建一个带有重复数据的RDD,并使用distinct()方法去重,通过collect()方法查看结果,其中重复的数据('a',1)已经被删除。
distinct()方法示例
#创建RDD
val rdd=sc.makeRDD(List(('a',1),('a',1),('b',1),('c',1)))
#使用distinct()方法对RDD进行去重
rdd.distinct().collect

3.3使用简单的集合操作
1.Spark中的集合操作常用方法(转换操作)


(1)intersection()方法

intersection()方法用于求出两个RDD的共同元素,即找出两个RDD的交集,参数是另一个RDD,先后顺序与结果无关。创建两个RDD,其中有相同的元素,通过intersection()方法求出两个RDD的交集

(2)subtract()方法

subtract()方法用于将前一个RDD中在后一个RDD出现的元素删除,可以认为是求补集的操作,返回值为前一个RDD去除与后一个RDD相同元素后的剩余值所组成的新的RDD。两个RDD的顺序会影响结果。创建两个RDD,分别为rdd1和rdd2,包含相同元素和不同元素,通过subtract()方法求rdd1和rdd2彼此的补集。

(3)cartesian()方法

cartesian()方法可将两个集合的元素两两组合成一组,即求笛卡儿积。创建两个RDD,分别有4个元素,通过cartesian()方法求两个RDD的笛卡儿积。

三:Spark SQL—结构化数据文件处理

3.1 DataFrame基础操作

1.DataFrame的创建

2.使用SparkSession方式创建DataFrame

可以使用spark.read从不同类型的文件中加载数据创建DataFrame。spark.read的具体操作,在创建Dataframe之前,为了支持RDD转换成Dataframe及后续的SQL操作,需要导入import.spark.implicits._包启用隐式转换。若使用SparkSession方式创建Dataframe,可以使用spark.read操作,从不同类型的文件中加载数据创建DataFrame.

3.数据准备

在HDFS文件系统中的/spark目录中有一个person.txt文件,内容如下

1 zhangsan 20

2 lisi 29

3 wangwu 25

4 zhaoliu 30

5 tianqi 35

6 jerry 40

4.通过文件直接创建DataFrame

我们通过Spark读取数据源的方式进行创建DataFrame

5.RDD直接转换为DataFrame

3.2 DataFrame的常用操作
1.DataFrame的方法

2.直接在DataFrame对象上进行查询的方法

创建DataFrame对象rating和user
#定义样例类Rating
case classRating(userId:Int,movieId:Int,rating:Int,tímestamp:Long)
#读取ratings.dat数据创建RDD ratingData
val ratingData=sc.textFile(m/user/root/sparkSql/ratings.dat").map(_.split("::"))
#将ratingData转换成DataFrame
val rating=ratingData.map(r=>Rating(r(0).trim.toInt,
r(1).trim.toInt,
r(2).trim.toInt,
r(3).trim.toLong)).toDF()
#定义样例类User
case classUser(userId:Int,gender:String,age:Int,occupation:Int,zip:String)
#读取users.dat数据创建RDDuserData
val userData=sc.textFile("/user/root/sparkSgl/users.dat").map(.split("::"))#将userData转换成DataFrame
val user=userData.map(u=>User(u(0).trim,toInt,
u(1),
u(2).trim.toInt,
u(3).trim.toInt,
u(4))).toDF()

3.DataFrame操作方法
1.where()/filter()方法


使用where()或filter()方法可以查询数据中符合条件的所有字段的信息。
(1)where()方法DataFrame可以使用where(conditionExpr:String)方法查询符合指定条件的数据,参数中可以使用and或or。where()方法的返回结果仍然为DataFrame。查询user对象中性别为女日年龄为18岁的用户信息,使用show方法显示前3条查询结果。
where()方法查询
#使用where查询user对象中性别为女且年龄为18岁的用户信息
val userWhere=user.where("gender='F' and age=18")
#查看查询结果的前3条信息
userWhere.show(3)

(2)filter()方法


DataFrame还可以使用filter()方法筛选出符合条件的数据,使用filter()方法查询user对象中性别为女且年龄为18的用户信息,显示前3条查询结果。
filter()方法查询
#使用filter()方法查询user对象中性别为女并且年龄为18岁的用户信息
val userFilter=user.filter("gender='F' and age=18")
#查看查询结果的前3条信息
userFilter.show(3)

2.select()/selectExpr()/col()/apply()方法


但是有时用户只需要查询where()和filter()方法查询的数据包含的是所有字段的信息,部分字段的值即可,DataFrame提供了查询指定字段的值的方法,如select、selectExptcol和apply)方法等,用法介绍如下。
(1)select()方法:获取指定字段值
select()方法根据传人的String类型字段名获取对应的值,并返回一个DataFrame对象查询user对象中userId和gender字段的数据。
select()方法查询
#使用select()方法查询user对象中userId及gender字段的数据
val userSelect=user.select("userId","gender")
#查看查询结果的前3条信息
userSelect.show(3)

(2)selectExpr()方法:对指定字段进行特殊处理
在实际业务中,可能需要对某些字段进行特殊处理,如为某个字段取别名、对某个字段的数据进行四舍五入等。DataFrame提供了selectExpr()方法,可以对指定字段取别名或调用UDF函数对其进行其他处理。selectExpr()方法传入String类型的参数,返回一个DataFrame对象。
DataFrame例如,定义一个函数replace,对user对象中gender字段的值进行转换selectExpr()。将gender字段的值为“M”则替换为“0”gender方法字段的值为“F”则替换为“1”。

定义函数

spark.udf,register("replace",(x:String)=>

x match{
case"M"=>0
case"F"=>1
}
})
使用selectExpr()方法查询user对象中userId、gender和age字段的数据,对gender字段使用replace函数并取别名为sex。
selectExpr()方法查询
val userSelectExpr=user.selectExpr(
"userId","replace(gender)as sex","age")
#查看查询结果的前3条信息
userSelectExpr.show(3)

(3)col()/apply()方法


col()和apply()方法也可以获取DataFrame指定字段,但只能获取一个字段,并且返回的是一个Column对象。分别使用col()和apply()方法查询user对象中zip字段的数据。
col()/apply()方法查询
#查询user对象中zip字段的数据
val userCol=user.col("zip")
#查看查询结果
user.select(userCol).collect#查询user对象中zip字段的数据
val userApply=user.apply("zip")
#查看查询结果
user.select(userApply).collect

3.limit()方法


limit方法可以获取指定DataFrame数据的前n条记录。不同于take()方法与head()方法,limit()方法不是行动操作,因此并不会直接返回查询结果,需要结合show()方法或其他行动操作才可以显示结果。使用limit()方法查询user对象的前3条记录,并使用show()方法显示查询结果。
limit()方法查询
#查询user对象前3条记录
val userLimit=user.limit(3)
#查看查询结果
userLimit.show()

4.orderBy()/sort()方法


orderBy()方法用于根据指定字段对数据进行排序,默认为升序排序。若要求降序排序orderBy()方法的参数可以使用“desc("字段名称")”或“$"字段名称".desc”,也可以在指定字段前面加“-”。使用orderBy()方法根据userId字段对user对象进行降序排序,查看前3条记录。
orderBy()方法排序查询
#使用orderBy()方法根据userId字段对user对象进行降序排序
val userorderBy=user.orderBy(desc("userId"))
val userorderBy=user.orderBy($"userId".desc)

val userOrderBy=user.orderBy(-user("userId"))
#查看结果的前3条信息 userOrderBy.show(3)

sort()方法也可以根据指定字段对数据进行排序,用法与orderBy()方法一样。使用sort()方法根据userId字段对user对象进行升序排序。
sort()方法排序查询
#使用sort方法根据userId字段对user对象进行升序排序
val userSort=user.sort(asc("userId"))
val userSort=user.sort(S"userId".asc)
val userSort=user.sort(user("userId"))
#查看查询结果的前3条信息
userSort.show(3)

5.groupBy()方法


使用groupBy()方法可以根据指定字段对数据进行分组操作。groupBy()方法的输入参数既可以是String类型的字段名,也可以是Column对象。根据gender字段对user对象进行分组。
groupBy()方法分组查询
#根据gender字段对user对象进行分组
val userGroupBy=user.groupBy("gender")
val userGroupBy=user.groupBy(user("gender"))


 

  • 23
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
分发号: 济南市长河豪门物业管理有限公司 程 序 文 件 汇 编 ( 编号:HMWY—CX—A/0 ) 编制人:张文涵 2013 年 6 月 1 日 审核人:王佳祥 2013 年 6 月 1 日 批准人:王佳祥 2013 年 6 月 1 日 2013 年 6 月 1 日发布 2013 年 6 月 1 日实施 第 1 页 共 28 页 目 录 1.文件控制程序..........................................................................................................................................2 2.记录控制程序..........................................................................................................................................6 3.内部沟通控制程序..................................................................................................................................8 4.库房管理控制程序................................................................................................................................10 5.供方控制程序........................................................................................................................................13 6.外包控制程序........................................................................................................................................15 7.内部审核控制程序................................................................................................................................17 8.服务质量检查控制程序........................................................................................................................21 9.不合格品控制程序................................................................................................................................24 10.纠正和预防措施控制程序..................................................................................................................26 济南市长河豪门物业管理有限公司 编号: HMWY—CX—A/0 版本/修改状态:A/0 程序文件 目录 共 1 页 第 1 页 第 2 页 共 28 页 文件控制程序 1、目的: 统一要求,体现规范,方便使用,提高效率。 2、适用范围 公司及分公司。 3、职责: 3.1 总经理负责公司文件资料和档案管理的监督和指导,以及有关文件的审批。 3.2 管理者代表负责公司行文、文件资料和档案管理的监督、检查和指导。 3.3 行政人事部负责公司级文件管理,及公司行文及文件资料和档案管理的监督、检查和指导。 3.4 各部门及分公司负责本级范围内文件资料和档案的管理。 4、工作程序: 4.1 文件的分类 1) 内部文件:由企业内部各部门组织编写的文件。 2) 外来文件:非企业内部编写的文件。 4.2 公司行文用纸、字体字号、格式编号及封面等: 4.2.1 行文用纸:一般使用 A4 纸,特殊需要按要求选用纸张规格。 4

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值