知识巩固

简单排序
        冒泡排序
        选择排序
        快速排序
        二分查找&二叉树
Hadoop
        hdfs上传流程
        hdfs读取数据
        mr运行流程
        Shuffle原理
        TextInputFormat作用
        Hadoop会有哪些重大故障

YARN
        yarn工作流程
SPARK
        SPARK 运行流程
zookeeper
Hbase
        hbase读写流程
        hbase存储结构
        hbase优缺点
        hbase与传统数据库区别
        hbaseShell
        hbaseJava
数据库与数据仓库的区别
Scala
        函数定义方式
        Case
        元组
        zip与zipWithIndex
        数组
        List集合
        Map与MapValues
        集合操作
        scala面向对象
Liux
        command
其他
        数据库 OLAP OLTP的介绍和比较

冒泡排序     ▲  
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。

// 比较相邻的元素,发现两个数据元素的次序相反时即进行交换,直到没有反序的数据元素为止.
public class BubbleSort implements IArraySort {

    @Override
    public int[] sort(int[] sourceArray) throws Exception {
        // 对 arr 进行拷贝,不改变参数内容
        int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

        for (int i = 1; i < arr.length; i++) {
            // 设定一个标记,若为true,则表示此次循环没有进行交换,也就是待排序列已经有序,排序已经完成。
            boolean flag = true;

            for (int j = 0; j < arr.length - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int tmp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = tmp;

                    flag = false;
                }
            }

            if (flag) {
                break;
            }
        }
        return arr;
    }
}

选择排序     ▲  

1.找到数组中最小的那个元素
2.将最小的这个元素和数组中第一个元素交换位置
3.在剩下的元素中找到最小的元素,与数组第二个元素交换位置
重复以上步骤,既可以得到有序数组。

public class SelectionSort implements IArraySort {

    @Override
    public int[] sort(int[] sourceArray) throws Exception {
        int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

        // 总共要经过 N-1 轮比较
        for (int i = 0; i < arr.length - 1; i++) {
            int min = i;

            // 每轮需要比较的次数 N-i
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[j] < arr[min]) {
                    // 记录目前能找到的最小值元素的下标
                    min = j;
                }
            }

            // 将找到的最小值和i位置所在的值进行交换
            if (i != min) {
                int tmp = arr[i];
                arr[i] = arr[min];
                arr[min] = tmp;
            }

        }
        return arr;
    }
}

快速排序     ▲  

  1. 从数列中挑出一个元素,称为 “基准”(pivot);
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;
public class QuickSort implements IArraySort {

    @Override
    public int[] sort(int[] sourceArray) throws Exception {
        // 对 arr 进行拷贝,不改变参数内容
        int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

        return quickSort(arr, 0, arr.length - 1);
    }

    private int[] quickSort(int[] arr, int left, int right) {
        if (left < right) {
            int partitionIndex = partition(arr, left, right);
            quickSort(arr, left, partitionIndex - 1);
            quickSort(arr, partitionIndex + 1, right);
        }
        return arr;
    }

    private int partition(int[] arr, int left, int right) {
        // 设定基准值(pivot)
        int pivot = left;
        int index = pivot + 1;
        for (int i = index; i <= right; i++) {
            if (arr[i] < arr[pivot]) {
                swap(arr, i, index);
                index++;
            }
        }
        swap(arr, pivot, index - 1);
        return index - 1;
    }

    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

}

二分查找&二叉树     ▲  
又称折半查找,采用分治策略,跟二叉树的查找一样,如果大于就在右边找,小于就在左边找,等于就表示找到了。优点是比较次数少,查找速度快,平均性能好;其缺点是要求待查表为有序表,且插入删除困难。因此,折半查找方法适用于不经常变动而查找频繁的有序列表。

public int Binary_Search(int[] arr, int key)
{
    int low = 0;
    int high = arr.length - 1;
    int mid;
 
    while (low <= high)
    {
        mid = (low + high) / 2;
        if (key < arr[mid])
        {
            high = mid - 1;
        } else if (key > arr[mid])
        {
            low = mid + 1;
        } else
        {
            return mid;
        }
    }
 
    return -1; // 表中不存在 key
}

二叉树
若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值;
作为一种经典的数据结构,它既有链表的快速插入与删除操作的特点,又有数组快速查找的优势。
二叉排序树的删除操作相对复杂,因为不能因为删除了结点,让这颗二叉排序树变得不满足二叉排序树的性质,所以对于二叉排序树的删除存在三种情况:

  • 叶子结点;(很容易实现删除操作,直接删除结点即可)
  • 仅有左或者右子树的结点;(容易实现删除操作,删除结点后,将它的左子树或者右子树整个移动到删除结点的位置)
  • 左右子树都有的结点。(找到需要删除的结点p的直接前驱(或直接后继)s,用s来替换结点p,然后再删除此结点s)

    在这里插入图片描述

HADOOP

Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
Hadoop实现了一个可扩展、容错、高性能、可靠、低成本的分布式文件系统(Hadoop Distributed File System),简称HDFS。
Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,而MapReduce则为海量的数据提供了计算。
HDFS是Google File System(GFS)的开源实现。
MapReduce是Google MapReduce的开源实现。】

三个datanode中当有一个datanode出现错误时会怎样?
答:Namenode会通过心跳机制感知到datanode下线
会将这个datanode上的block块在集群中重新复制一份,恢复文件的副本数量
会引发运维团队快速响应,派出同事对下线datanode进行检测和修复,然后重新上线
请列出你所知道的hadoop调度器,并简要说明其工作方法?
比较流行的三种调度器有:默认调度器FIFO,计算能力调度器CapacityScheduler,公平调度器Fair Scheduler
1.默认调度器FIFO:hadoop中默认的调度器,采用先进先出的原则
2.计算能力调度器CapacityScheduler:选择占用资源小,优先级高的先执行
3.公平调度器FairScheduler:同一队列中的作业公平共享队列中所有资源

HDFS上传流程    ▲  
① 由客户端 向 NameNode节点 发出请求
②NameNode 向Client返回可以可以存数据的 DataNode 这里遵循 机架感应原则
③客户端 首先 根据返回的信息 先将 文件分块(Hadoop2.X版本 每一个block为 128M 而之前的版本为 64M
④然后客户端向nameNode发出RPC请求上传第一个block,nameNode返回信息 直接发送给DataNode 并且是 流式写入 同时 会复制到其他两台机器(保证数据传输的完整性一般是通过CRC32这种校验法)
⑤dataNode 向 Client通信 表示已经传完 数据块 同时向NameNode报告
⑥依照上面(④到⑤)的原理将 所有的数据块都上传结束 向 NameNode 报告 表明 已经传完所有的数据块 。
       机架感应原则:
HDFS数据块备份过程中:第一个block副本放在和client所在的node里(如果client不在集群范围内,则这第一个node是随机选取的,系统会尽量避免存储太满和太忙的节点),第二个节点选择于第一个节点不同机架的DN,第三个选择放在第二个DN同一个机架的另一个DN上

HDFS读取数据 ▲  
1)客户端向namenode请求下载文件,namenode通过查询元数据,找到文件块所在的datanode地址。
2)挑选一台datanode(就近原则,然后随机)服务器,请求读取数据。
3)datanode开始传输数据给客户端(从磁盘里面读取数据放入流,以数据包packet为单位来做校验)。
4)客户端以packet为单位接收,先在本地缓存,然后写入目标文件。

读取完一个block都会进行checksum验证, 如果读取datanode时出现错误, 客户端会通知Namenode, 然后再从下一个拥有该block拷贝的datanode继续读。

MR运行流程    ▲  

  1. [input阶段]   获取SplitInput 输入分片数据作为map的输入
  2. [map 阶段]   过程对某种输入格式的一条记录解析成一条或多条记录
  3. [shffle阶段]   对中间数据的控制,作为reduce的输入
  4. [reduce阶段]  对相同key的数据进行合并
  5. [output阶段]  按照格式输出到指定目录
1. 首先map task会从本地文件系统读取数据,转换成key-value形式的键值对集合
2. 使用的是hadoop内置的数据类型,比如longwritable、text等
3. 将键值对集合输入mapper进行业务处理过程,将其转换成需要的key-value在输出
4. 之后会进行一个partition分区操作,默认使用的是hashpartitioner,可以通过重写hashpartitioner的getpartition方法来自定义分区规则
5. 之后会对key进行进行sort排序,grouping分组操作将相同key的value合并分组输出,在这里可以使用自定义的数据类型,重写WritableComparator的Comparator方法来自定义排序规则,重写RawComparator的compara方法来自定义分组规则
6. 之后进行一个combiner归约操作,其实就是一个本地段的reduce预处理,以减小后面shufle和reducer的工作量
7. reduce task会通过网络将各个数据收集进行reduce处理,最后将数据保存或者显示,结束整个job

shuffle原理    ▲  
Map端:
    1、通过Inputsplit读入DataNode中的数据,以<k,v>形式放入环形内存缓冲区。默认大小100MB(io.sort.mb属性),一旦达到伐值80%(io.sort.spil l.percent),通过spill(溢写)把内容写入磁盘.
    2、写入磁盘前会进行分区(partition),将不同数据看是处理,之后对分区数据进行排序(sort),如果有Combiner,还要对排序后数据进行合并,将全部文件溢写文件合并为一个分区且排序的文件。
    3、将磁盘的数据送到Reduce中
Reduce端:
    1、Copy阶段:reducer通过http方式得到输出文件分区,从 n个map中获取数据
    2、Merge阶段:从map端复制来的数据首先写到缓存中,同样达到伐值将数据写入磁盘。同样会进行partition、sort、combine等过程。如果形成多个磁盘文件还会进行合并,最后一次合并作为reduce的输入而不是写入磁盘中。
    3、将合并的结果作为输入传入Reduce任务中,存到HDFS上。
在这里插入图片描述

TextInputFormat作用是什么,如何自定义实现     ▲  
InputFormat会在map操作之前对数据进行两方面的预处理

  1. 有getSplits,返回的是InputSplit数组,对数据进行split分片,每片交给map操作一次
  2. getRecordReader,返回的是RecordReader对象,对每个split分片进行转换为key-value键值对格式传递给map
  3. 常用的InputFormat是TextInputFormat,使用的是LineRecordReader对每个分片进行键值对的转换,以行偏移量作为键,行内容作为值
    自定义类继承InputFormat接口,重写createRecordReader和isSplitable方法
    在createRecordReader中可以自定义分隔符

Hadoop会有哪些重大故障,如何应对?至少给出 5个。     ▲  
1、namenode 单点故障:通过zookeeper 搭建 HA 高可用,可自动切换 namenode。
2、ResourceManager单点故障:可通过配置YARN的HA,并在配置的namenode上手动启动ResourceManager作为Slave,在Master故障后,Slave会自动切换为Master。
3、reduce阶段内存溢出:是由于单个reduce任务处理的数据量过多,通过增大reducetasks数目、优化partition 规则使数据分布均匀进行解决。
4、datanode内存溢出:是由于创建的线程过多,通过调整linux的maxuserprocesses参数,增大可用线程数进行解决。
5、集群间时间不同步导致运行异常:通过配置内网时间同步服务器进行解决。

YARN    ▲  
是Hadoop2.0版本引进的资源管理,系统直接从MR1演化而来。
核心思想:将MR1中的JobTracker的资源管理和作业调度两个功能分开,分别由ResourceManager和ApplicationMaster进程实现。
ResourceManager:负责整个集群的资源管理和调度 ApplicationMaster:负责应用程序相关事务, YARN的出现,使得多个计算框架可以运行在同一个集群之中。
目前可以支持多种计算框架运行在YARN上面,比如MapReduce、storm、Spark、Flink。

Yarn的流程    ▲  
1、客户端向RM中提交程序 Rm根据想关信息内容返回信息
2、客户端根据返回信息生成资源文件,并将资源文件提交到路径(hdfs)
3、RM向NM中分配一个container,并在该container中启动AM
4、AM向RM注册(它将为各个任务申请资源,并监控它的运行状态,直到运行结束)
5、AM采用轮询的方式通过RPC协议向RM申请和领取资源,资源的协调通过异步完成
6、AM申请到资源后,便与对应的NM通信,要求它启动任务
7、NM为任务设置好运行环境(包括环境变量、JAR包、二进制程序等)后,启动任务
8、各个任务通过某个RPC协议向AM汇报自己的状态和进度,以让AM随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务
9、应用程序运行完成后,AM向RM注销并关闭自己

1. Spark Yarn Client向YARN的ResourceManager申请启动Application Master。同时在SparkContent初始化中将创建DAGScheduler和TASKScheduler等,由于我们选择的是Yarn-Client模式,程序会选择YarnClientClusterScheduler和YarnClientSchedulerBackend;
2. ResourceManager收到请求后,在集群中选择一个NodeManager,为该应用程序分配第一个Container,要求它在这个Container中启动应用程序的ApplicationMaster,与YARN-Cluster区别的是在 该ApplicationMaster不运行SparkContext,只与SparkContext进行联系进行资源的分派;
3. Client中的SparkContext初始化完毕后,与ApplicationMaster建立通讯,向ResourceManager注册,根据任务信息向ResourceManager申请资源(Container);
4. 一旦ApplicationMaster申请到资源(也就是Container)后,便与对应的NodeManager通信,要求它在获得的Container中启动启动CoarseGrainedExecutorBackend,CoarseGrainedExecutorBackend启动后会向Client中的SparkContext注册并申请Task;
5. Client中的SparkContext分配Task给CoarseGrainedExecutorBackend执行,CoarseGrainedExecutorBackend运行Task 并向Driver汇报运行的状态和进度,以让Client随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任;
6. 应用程序运行完成后,Client的SparkContext向ResourceManager申请注销并关闭自己。

在这里插入图片描述

SPARK    ▲  
运行流程

  1. 构建Spark Application的运行环境(启动SparkContext),SparkContext向资源管理器(可以是Standalone、Mesos或YARN)注册并申请运行Executor资源;
  2. 资源管理器分配Executor资源并启动StandaloneExecutorBackend,Executor运行情况将随着心跳发送到资源管理器上;
  3. SparkContext构建成DAG图,将DAG图分解成Stage,并把Taskset发送给Task Scheduler。Executor向SparkContext申请Task,Task Scheduler将Task发放给Executor运行同时SparkContext将应用程序代码发放给Executor。
  4. Task在Executor上运行,运行完毕释放所有资源在这里插入图片描述

on Standalone

spark-submit --master spark://plus1:7077 
--name myWordCount --class hs.org.WordCount 
/home/data/MySpark-1.0-SNAPSHOT.jar 
hdfs://plus1:8020/in hdfs://plus1:8020/b

1.spark-submit命令提交程序之后, 会在本地启动一个Driver进程 用于控制整个流程
2.运行程序的main() (反射(.invoke)调用提交的jar包中的函数)创建SparkContext,构建出DakScheduler,TaskScheduler.
3.DagScheduer 先按照action将程序划分为一至多个job(每一个job对应一个Dag), 之后对DagScheduer按照是否进行shuffer,将job划分为多个Stage 每个Stage过程都是taskset , dag 将taskset交给taskScheduler,由Work中的Executor去执行
4.TaskScheduler去连接master,master 收到信息之后,会调用自己的资源调度算法,在spark集群的work上,启动Executor,executor反向向Driver申请task任务

on Yarn
根据Dirver在集群中的位置分为两种模式
一种是Yarn-Client模式,另一种是Yarn-Cluster模式

yarn-cluster模式下,Dirver运行在ApplicationMaster中,负责申请资源并监控task运行状态和重试失败的task,当用户提交了作业之后就可以关掉client,作业会继续在yarn中运行;

yarn-client模式下,Dirver运行在本地客户端,client不能离开。

自定义分区器-->自定义类继承Partition 重写override def numPartitions,
			override def getPartition(key: Any)。传递参数可用构造器!!!
join算子-->1、对于带有分区器的或者不同的RDD。join操作按照分区数多的为主
		  2、两个只有一个为带有分区器的RDD,则按照分区器为主

在这里插入图片描述

RDD 是什么
弹性分布式数据集,是spark中最基本的数据抽象,可以存于内存中或者磁盘中,分布式存储可用于分布式计算
一个不可变,可分区,里面的数据可并行计算的集合

spark调优
避免创建重复RDD
尽可能复用同一个RDD
对多次使用的RDD进行持久化
避免使用shuffle算子
使用map-side预聚合shuffle操作
使用高性能的算子
广播大变量
使用Kryo序列化
优化数据结构

Zookeeper:    ▲  
    一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现
分布式应用程序(hadoop, hbase,flume集群,kafaka集群)可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。
    每台pc上配置zookeeper环境变量,在zookeeper下的conf文件夹下创建zoo.cfg文件(配置信息可参考统计目录下的zoo_sample.cfg文件),再到zookeeper下新建data文件夹,创建myid,在文件里添加上server的ip地址。再启动(zkserver.sh start)便ok了✁✁✁详情

Hbase的读写流程    ▲  
写流程:
1.client向hregionserver发送写请求。
2.hregionserver将数据写到hlog(write ahead log)。为了数据的持久化 和恢复。
3.hregionserver将数据写到内存(memstore)反馈client写成功。
读流程:
1.通过zookeeper和-ROOT- .META.表定位hregionserver。
2.数据从内存和硬盘合并后返回给client
3.数据块会缓存

hbaase存储结构    ▲  
在这里插入图片描述
HBase中的存储包括HMaster、HRegionServer、HRegion、Store、MemStore、StoreFile、HFile、HLog等
client访问hbase上的数据并不需要master参与,数据读写访问region server
region server将数据写到hlog
HRegionServer存取一个子表时,会创建一个HRegion对象
Hregion由一个或者多个store组成,每个store保存一个columns family
每个store又由一个memstroe 和 0-多个的storeFIle 组成
storeFIle以HFile格式保存在hdfs上

HMaster

  • 为Region server分配region
  • 负责Region server的负载均衡
  • 发现失效的Region server并重新分配其上的region
  • HDFS上的垃圾文件回收
  • 处理schema更新请求

HRegion server

  • 维护master分配给他的region,处理对这些region的io请求
  • 负责切分正在运行过程中变的过大的region

HFile
Hbase中KeyValue数据的存储格式,是hadoop的二进制格式文件。

Hbase的优缺点     ▲  
优点:
1 列的可以动态增加,并且列为空就不存储数据,节省存储空间.
2 Hbase自动切分数据,使得数据存储自动具有水平扩展(scalability).
3 Hbase可以提供高并发读写操作的支持

缺点:
1 不能支持条件查询,只支持按照Row key来查询.
2 暂时不能支持Master server的故障切换,当Master宕机后,整个存储系统就会挂掉.

hbase与传统数据库区别    ▲  
    1.数据类型:Hbase只有简单的数据类型,只保留字符串;传统数据库有丰富的数据类型。
    2.数据操作:Hbase只有简单的插入、查询、删除、清空等操作,表和表之间是分离的,没有复杂的表和表之间的关系;传统数据库通常有各式各样的函数和连接操作。
    3.存储模式:Hbase是基于列存储的,每个列族都由几个文件保存,不同列族的文件是分离的,这样的好处是数据即是索引,访问查询涉及的列大量降低系统的I/O,并且每一列由一个线索来处理,可以实现查询的并发处理;传统数据库是基于表格结构和行存储,其没有建立索引将耗费大量的I/O并且建立索引和物化试图需要耗费大量的时间和资源。
    4.数据维护:Hbase的更新实际上是插入了新的数据;传统数据库只是替换和修改。
    5.可伸缩性:Hbase可以轻松的增加或减少硬件的数目,并且对错误的兼容性比较高;传统数据库需要增加中间层才能实现这样的功能。
    6.事务:Hbase只可以实现单行的事务性,意味着行与行之间、表与表之前不必满足事务性;传统数据库是可以实现跨行的事务性。

hadoop生态圈
没有固定答案,主要从hdfs底层存储,hbase数据库,hive数据仓库,flume收集,Kafka缓存,zookeeper分布式协调服务,spark大数据分析,sqoop数据互转来说。

HbaseShell    ▲  

1)列出所有的表:
hbase> list
2)删除表

#分两步:首先disable,然后drop
hbase> disable 't1'
hbase> drop 't1'

3)创建与查看表

#hbase>create '表名', {NAME => 'family', VERSIONS => VERSIONS}
# 例如:创建表t1,有两个family name:f1,f2,版本数分别为1,2(默认版本为1)
hbase> create 't1',{NAME => 'f1'},{NAME => 'f2', VERSIONS => 2}
#查看表结构
hbase> describe 't1'

4)修改表结构(必须先disable)

#alter 't1', {NAME => 'f1'}, {NAME => 'f2', METHOD => 'delete'}
#修改表t1的列族(f1)的时效为180天
hbase> disable 't1'
hbase> alter 't1', {NAME=> 'f1',TTL=>15552000}
hbase> enable 't1'

5)添加数据

#put <table>,<rowkey>,<family:column>,<value>,<timestamp>(系统默认)
hbase> put 't1','rowkey','f1:name','value'

6)查询数据

hbase> get 't1','rowkey','f1:name','f2:age'
hbase> get 't1','rowkey',{COLUMN=>'f1:name'}
hbase> get 't1','rowkey

f7)扫描表

#语法:scan <table>, {COLUMNS => [ <family:column>,.... ], LIMIT => num}
hbase> scan 'tl',{LIMIT>5}

8)删除数据
a )删除行中的某个列值

#语法:delete <table>, <rowkey>,  <family:column> , <timestamp>,必须指定列名
#例如:删除表t1,rowkey中的f1:Name的数据
hbase> delete 't1','rowkey','f1:name'
注:将删除整行f1:col1列所有版本的数据

b )删除行

#语法:deleteall ’table‘, ‘rowkey', ‘family:column''timestamp',可以不指定列名,删除整行数据
#例如:删除表t1,rowk001的数据
hbase> deleteall 't1','rowkey001'

c)删除表中的所有数据

> #语法: truncate ‘表名‘’
> #其具体过程是:disable table -> drop table -> create table
> #例如:删除表t1的所有数据 hbase> truncate 't1'

    HbaseJava

HBase宕机如何处理?
答:宕机分为 HMaster 宕机和 HRegisoner 宕机
如果是 HRegisoner 宕机, HMaster 会将其所管理的region 重新分布到其他活动的 RegionServer 上,由于数据和日志都持久在 HDFS中,该操作不会导致数据丢失。所以数据的一致性和安全性是有保障的。
如果是 HMaster 宕机, HMaster 没有单点问题, HBase中可以启动多个 HMaster,通过Zookeeper 的 Master Election 机制保证总有一个 Master 运行。即ZooKeeper 会保证总会有一个 HMaster 在对外提供服务。

数据库与数据仓库的区别    ▲  

1)简单理解下数据仓库是多个数据库以一种方式组织起来

2)数据库强调范式,尽可能减少冗余

3)数据仓库强调查询分析的速度,优化读取操作,主要目的是快速做大量数据的查询

4)数据仓库定期写入新数据,但不覆盖原有数据,而是给数据加上时间戳标签

5)数据库采用行存储,数据仓库一般采用列存储

6)数据仓库的特征是面向主题、集成、相对稳定、反映历史变化,存储数历史数据;数据库是面向事务的,存储在线交易数据

7)数据仓库的两个基本元素是维表和事实表,维是看待问题的角度,比如时间、部门等,事实表放着要查询的数据

Scala

函数的定义方式    ▲  

val method1=(argsName01:Type,argsName02:Type…)=>{执行代码} val
method2:(argsType01,argsType02…)=>returnType=(argsName01,argsName02…)=>{执行代码}

case关键字 ▲  

1

 def main(args: Array[String]): Unit = {

    val model: Seq[(String, Int)] = 
    ("Jack"->19)::("Bucy"->20)::("Bob"->22)::("Nacy"->18)::Nil

   model foreach{
     case (name,age)=> println(name+":"+age)
     case _ =>println("don't match!")
   }
  }
  
Result
 Jack:19
 Bucy:20
 Bob:22
 Nacy:18

2
case也可以使用在类class前面声明为case class
class之前添加case可以自动生成equal、hashcode、toString、copy方法 和他的半生对象,并且为半生对象生成apply、unapply方法。

import scala.language.postfixOps
case class ForFun(name:String)
object fun2{
  def main(args: Array[String]): Unit = {
    val forfun = ForFun.apply("Jack")
    println(forfun.name)
    val forFun2 = new ForFun("Nacy")
    println(forFun2.name+":"+forFun2.hashCode()+":"+forFun2.toString)
    println(forfun equals forFun2)
  }
}
Result
Jack
Nacy:-1811736370:ForFun(Nacy)
false

Tuple 元组    ▲  
元组在Scala语言中是一种十分重要的数据结构,类似数据库里面的一行记录(row),它可以将不同类型的值组合成一个对象,在实际应用中十分广泛。
Tuple.productIterator() 迭代元组
若是对偶元组,可以用 .swap 进行元素交换

zip或者zipWithIndex的用法    ▲  
使用zipWithIndex或者zip方法来自动地创建一个计数器

scala> val days = Array("Sunday", "Monday", "Tuesday", "Wednesday","Thursday", "Friday", "Saturday")
scala> days.zipWithIndex.foreach{case(day,count) => println(s"${count} ——${day}")}
0 —— Sunday
1 —— Monday
2 —— Tuesday
3 —— Wednesday
4 —— Thursday
5 ——  Friday
6 —— Saturday
//创建了一个lazy view在原有的Array基础上,所以这个元组集合并不被会被创建,直到它被调用的那一刻,
//可以在调用zipWithIndex之前调用view

zipWithIndex的计数器都是从0开始,如果你想指定开始的值,那么你可以使用zip


scala> for((day,count) <- days.zip(Stream from 1)) {
     |   println(s"$count —— $day")
     | }
1 —— Sunday
2 —— Monday
3 —— Tuesday
4 —— Wednesday
5 —— Thursday
6 —— Friday
7 ——  Saturday

Array与ArrayBuffer    ▲  

#数组的两种定义和赋值
val arr=Array(elements)
val arr1=new Array(count)	arr1(0)=value

#数组可变长度的定义
import scala.collection.mutable.ArrayBuffer
var abuf=ArrayBuffer(elements)
var abuf1=new ArrayBuffer[Type]()

#数组中方法操作
++(数组拼接产生新的数组) :+(拼接新的数组)...
.insert(index,value)
.remover(index)、.remover(index.count)
isEmpty、clear、reverse、max、min、sum、sorted(此行所有方法 · 就可以)
sortBy((x=>-x))、sortWith((x,y)=>x>y)

List与ListBuffer    ▲  

#List定义,这是一个abstract(抽象类)不能实例化
val list=List(elements)
#通过 ::: 拼接为新集合
#定义可变长度的集合(ListBuffe)
import scala.collection.mutable.ListBuffer 
var lbuf=ListBuffer(elements)
var lbuf1=new ListBuffer[Type]();

val list=(1::(2::(3::Nil)))
#List集合分为两个部分,头元素+尾列表
.head可拿到第一个元素,通过 .tail(可以多次eg .tail.tail.head组合)拿到尾列表

#集合中方法操作
+=   ++=   -+   --=...
.insert(index,value)
.remover(index)、.remover(index.count)
isEmpty、clear、reverse、max、min、sum、sorted(此行所有方法 · 就可以)
sortBy((x=>-x))、sortWith((x,y)=>x>y)

MapValues    ▲  
//只操作value不管key

 override def mapValues[C](f: Int => C): scala.collection.immutable.Map[String,C]

Reduce reduceLeft reduceRight    ▲  

//参数类型和返回类型必须一致
Reduce
def reduce[A1 >: Int](op: (A1, A1) => A1): A1
reduceLeft
 override def reduceLeft[B >: Int](op: (B, A) => B): B
 reduceRight
 override def reduceRight[B >: Int](op: (A,B) => B): B
 

Fold foldLeft foldRight    ▲  

//存在两个参数第一个是初始化值,第二个是操作函数
fold
 def fold[A1 >: Int](z: A1)(op: (A1, A1) => A1): A1
 
 //两个类型不一样(初始化值,元素),会自动变成一个类型的最近的父类型
 foldLeft
 override def foldLeft[B](z: B)(op: (B, A) => B): B
 foldRight
  override def foldRight[B](z: B)(op: (A,B) => B): B

aggregate 聚合    ▲  

 def aggregate[B](z: => B)(seqop: (B, Int) => B,combop: (B, B) => B): B
Aggregate是聚合函数。聚合的内容第一个匿名函数是局部聚合,
									第二个匿名函数是全局聚合,但是在scala中不起作用

截取集合,类似字符串操作的substring    ▲  

     Take
	 override def take(n: Int): Array[Int]
     截取数据变为新的集合,参数是截取的长度
     slice
     长度从N开始到M-1
     override def slice(from: Int,until: Int): Array[Int]

查询    ▲  

var arr=Array(1,2,3,4,5,6)
find
override def find(p: Int => Boolean): Option[Int]
#找到最近符合的一个元素
arr.find(_>3).get<=>arr.find(t=>t>3).get   
Result----->4
Count
 def count(p: Int => Boolean): Int
 arr.count(_>2)
 Result--------->4
scala> val a=Array(List(1,2),List(3,4),List(5,6))
scala> a.reduce((a,b)=>a:::b)
res2: List[Int] = List(1, 2, 3, 4, 5, 6)

Scala面向对象     ▲  
1)类分为三个种类:
     Class(类) :val stu=new className
     object(对象) :val stu=objectName
     trait(特质)、 Abstract

2)在一个文件中名称一样的类和对象,互为伴生,类是对象的伴生类,对象是类的伴生对象
     在伴生对象中可以使用类的私有成员属性,apply、unapply方法
3) 类泛型是本身,对象通过 .type得到
4)通过extends (实现)App可以直接运行
5) 声明属性普遍格式 val/var name:Type=   _
6)构造器
     和类的声明在一起的那个构造器就是主构造器
     主构造器中的参数一定要用val、var进行修饰,如果不加那么就是参数,只有类内部可以使用,外部不可以使用
      辅助构造器可以有多个(重载)def this() 声明辅助构造器
     在构造器的第一行必须调用主构造器或者其他的辅助构造器,辅助构造器在多层调用以后,其实调用的还是主构造器
     作用域:主构造器的作用域是整个类,辅助构造器的作用域是这个方法
7)访问权限
     Public friendly protected private
     Private [this] 只有自己使用,伴生对象中都不可以使用
     Private [package]指定某个包下面可以使用,包只能放单个字符

class Stud private (private val name:String,private [hs/this] val age:Int)

8)Extends和with用来进行类之间的继承和实现关系的关键字

AKKA
目的:为了解决分布式编程中一系列的编程问题

13.Linux基本命令     ▲  

1)目录操作:ls、cd、mkdir、find、locate、whereis等

2)文件操作:mv、cp、rm、touch、cat、more、less

3)权限操作:chmod+rwx421

4)账号操作:su、whoami、last、who、w、id、groups等

5)查看系统:history、top

6)关机重启:shutdown、reboot

7)vim操作:i、w、w!、q、q!、wq等

其他     ▲  
1)商家特征:商家历史销量、信用、产品类别、发货快递公司等

2)用户行为特征:用户信用、下单量、转化率、下单路径、浏览店铺行为、支付账号

3)环境特征(主要是避免机器刷单):地区、ip、手机型号等

4)异常检测:ip地址经常变动、经常清空cookie信息、账号近期交易成功率上升等

5)评论文本检测:刷单的评论文本可能套路较为一致,计算与已标注评论文本的相似度作为特征

6)图片相似度检测:同理,刷单可能重复利用图片进行评论

数据库 OLAP OLTP的介绍和比较     ▲  
OLTP 联机事务处理,传统关系型数据的主要应用,用于高可用的在线系统,强调数据库内存效率,强调并发操作
OLAP 联机分析处理,数据仓库的主要应用,支持复杂的分析操作。强调数据分析,强调sql执行市场,强调磁盘IO,强调分区
在OLAP系统中,常使用分区技术,并行技术

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值