声明:面经从网络上搜集,自己补充了答案,不保证准确。
作者:蓝荆凌
链接:https://www.nowcoder.com/discuss/285388?type=all&order=recall&pos=&page=1&ncTraceId=&channel=-1&source_id=search_all_nctrack&gio_id=7ECACE7605534464872AA4CD0FF6C741-1658975042162
来源:牛客网
最近秋招启动的公司越来越多了。现在开始每天刷刷面经。欢迎点击此处关注公众号。
标准 | Spark Datasets | Spark Dataframes | Spark RDDs |
---|---|---|---|
数据表示 | Spark Datasets 是 Dataframe 和 RDD 的组合,具有静态类型安全和面向对象接口等特性。 | Spark Dataframe 是组织成命名列的分布式数据集合。 | Spark RDD 是一个没有模式的分布式数据集合。 |
优化 | Datasets 使用催化剂优化器进行优化。 | Dataframes 使用催化剂优化器进行优化。 | 没有内置的优化引擎。 |
模式投影 | Datasets 使用 SQL 引擎自动查找模式。 | Dataframes 也会自动找到模式。 | Schema 需要在 RDD 中手动定义。 |
聚合速度 | 数据集聚合比 RDD 快,但比 Dataframes 慢。 | 由于提供了简单而强大的 API,Dataframe 中的聚合速度更快。 | 在执行数据分组等简单操作时,RDD 比数据帧和数据集都慢。 |
rdd=sc.parallelize([1,2,3])
rdd.collect()
# [1,2,3]
rdd1=rdd.map(lambda:range(x,3))
rdd1.collect()
# [[1,2],[2],[]]
rdd2=rdd.flatMap(lambda:range(x,3))
rdd2.collect()
# [1,2,2]
groupByKey 和 reduceByKey:
reduceByKey 和 aggregateByKey:
过程:
排序:一次快速排序,两次归并排序。
分类:
包括 inner join、left outer join、right outer join、full outer join 类似其他数据库的操作。
还有下面讲一些使用较少的:
left semi join:返回左表的记录,前提是该记录在右表存在。例如:
# 例如下面的语法,Hive 中是不支持的
select s.ymd,s.symbol,s.price_close from stocks s
where s.ymd,s.symbol in
(select d.ymd, d.symbol from dividends d);
# Hive 中实现
select s.ymd,s.symbol,s.price_close
from stocks s left semi join dividends
on s.ymd = d.ymd and s.symbol=d.symbol;
笛卡尔积 join:错误的连接可能导致笛卡尔积,它会产生大量的数据,无法优化。设置hive.mapred.mod
为 strict 会阻止笛卡尔积。
map-side join:设置开启 map-side join,并设置使用这个优化时小表的大小:
# 开启 map-side join
set hive.auto.convert.join=true;
# 设置小表大小
set hive.mapjoin.smalltable.filesize=25000000
# 分桶存储的大表也是可以使用的
set hive.optimize.bucketmapJOIN=true;
如果所有的表有相同的分桶数,且数据是按照连接键或桶的键排序的,那么可以使用更快的分类-合并连接(sort-merge JOIN):
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
set hive.optimize.bucektmapjoin=true;
set hive.optimize.bucketmapjoin.sortedmerge=true;
优化:
分层:
java 虚拟机主要分为以下几个区:
a. 有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生 GC,在这里进行的 GC 主要是对方法区里的常量池和对类型的卸载
b. 方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后的代码等数据。
c. 该区域是被线程共享的。
d. 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量池中。
a. 虚拟机栈也就是我们平常所称的栈内存,它为 java 方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。
b. 虚拟机栈是线程私有的,它的生命周期与线程相同。
c. 局部变量表里存储的是基本数据类型、returnAddress 类型(指向一条字节码指令的地址)和对象引用,这个对象引用有可能是指向对象起始地址的一个指针,也有可能是代表对象的句柄或者与对象相关联的位置。局部变量所需的内存空间在编译器间确定
d. 操作数栈的作用主要用来存储运算结果以及运算的操作数,它不同于局部变量表通过索引来访问,而是压栈和出栈的方式
e. 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接.动态链接就是将常量池中的符号引用在运行期转化为直接引用。
本地方法栈:
本地方法栈和虚拟机栈类似,只不过本地方法栈为 Native 方法服务。
堆:
java 堆是所有线程所共享的一块内存,在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。
5) 程序计数器:
内存空间小,字节码解释器工作时通过改变这个计数值可以选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。该内存区域是唯一一个java虚拟机规范没有规定任何OOM情况的区域。
1.GC 算法:
2.如何判断对象是否可以被回收:
3.内存回收
对象优先在堆的Eden区分配。
大对象直接进入老年代。
长期存活的对象将直接进入老年代。
当 Eden 区没有足够的空间进行分配时,虚拟机会执行一次 Minor GC. Minor GC 通常发生在新生代的 Eden 区,在这个区的对象生存期短,往往发生 GC 的频率较高,回收速度比较快;Full Gc/Major GC 发生在老年代,一般情况下,触发老年代GC的时候不会触发Minor GC,但是通过配置,可以在Full GC之前进行一次Minor GC这样可以加快老年代的回收速度。
CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,基于并发“标记清理”实现,在标记清理过程中不会导致用户线程无法定位引用对象。仅作用于老年代收集。
G1 收集器弱化了 CMS 原有的分代模型(分代可以是不连续的空间),将堆内存划分成一个 个Region 1MB~32MB,默认 2048 个分区),这么做的目的是在进行收集时不必在全堆范围内进行。它主要特点在于达到可控的停顿时间,用户可以指定收集操作在多长时间内完成,即 G1提供了接近实时的收集特性。它的步骤如下:
JVM 中提供了三层的 ClassLoader:
Bootstrap classLoader:主要负责加载核心的类库(java.lang.*等),构造 ExtClassLoader 和 APPClassLoader。
ExtClassLoader:主要负责加载 jre/lib/ext 目录下的一些扩展的 jar。
AppClassLoader:主要负责加载应用程序的主函数类。
当一个类收到了类加载请求,它不会尝试自己去加载,而是把这个请求委派给父类完成。每一层都是如此。只有当父类加载器反馈自己无法完成这个请求的时候子类加载器才会尝试自己去加载。
优点:防止核心库被随意篡改;避免类的重复加载。
不支持。
区别:
抽象类:
接口:
HashMap:
ConcurrentHashMap:
二叉搜索树:根节点的值大于其左子树任意节点的值,小于其右子树任意节点的值。这一规则适用于二叉查找树中的每一个节点。且没有键值相等的节点。
平衡二叉树:每个节点的左右子树的高度差的绝对值最大为1。平衡二叉搜索树,又被称为AVL树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
二叉搜索树变成一个平衡二叉树:通过左右旋转来实现。
【一篇文章搞定排序】
力扣160. 相交链表
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
int lenA = getLength(headA);
int lenB = getLength(headB);
ListNode a = headA, b = headB;
int k = lenA - lenB;
if (k > 0) a = move(a, k);
else if (k < 0) b = move(b, -k);
while (a != null) {
if (a == b) return a;
a = a.next;
b = b.next;
}
return null;
}
private int getLength(ListNode head) {
int len = 0;
while (head !=null) {
len++;
head = head.next;
}
return len;
}
private ListNode move(ListNode head, int k) {
while (k-- > 0) head = head.next;
return head;
}
}
【网络八股文3】
TCP/IP | UDP |
---|---|
面向连接的协议 | 无连接协议 |
更可靠 | 不太可靠 |
传输速度较慢 | 更快的传输 |
数据包顺序可以保留或重新排列 | 数据包顺序不固定,数据包相互独立 |
使用三种方式握手模型进行连接 | 无需握手即可建立连接 |
TCP 数据包是重量级的 | UDP数据包是轻量级的 |
提供错误检查机制 | 没有错误检查机制 |
HTTP、FTP、Telnet、SMTP、HTTPS 等协议在传输层使用 TCP | DNS、RIP、SNMP、RTP、BOOTP、TFTP、NIP 等协议在传输层使用 UDP |
HTTP 是超文本传输协议,它定义了有关如何在万维网 (WWW) 上传输信息的规则和标准。它有助于网络浏览器和网络服务器进行通信。这是一个“无状态协议”,其中每个命令相对于前一个命令是独立的。HTTP 是建立在 TCP 之上的应用层协议。它默认使用端口 80。
HTTPS 是超文本传输协议安全或安全 HTTP。它是 HTTP 的高级和安全版本。在 HTTP 之上,SSL/TLS 协议用于提供安全性。它通过加密通信来实现安全交易,还有助于安全地识别网络服务器。它默认使用端口 443。
子网是通过称为子网划分的过程实现的网络内部的网络,该过程有助于将网络划分为子网。用于获得更高的路由效率,增强网络的安全性。它减少了从路由表中提取主机地址的时间。
子网掩码(subnet mask)用来指明一个 IP 地址的哪些位标识的是主机所在的子网,以及哪些位标识的是主机的位掩码。子网掩码不能单独存在,它必须结合 IP 地址一起使用。
进程:资源分配的基本单位。进程基本上是一个当前正在执行的程序。操作系统的主要功能是管理和处理所有这些进程。当一个程序被加载到内存中并成为一个进程时,它可以分为四个部分——堆栈、堆、文本和数据。
线程:独立调度的基本单位。线程是由程序计数器、线程 ID、堆栈和进程内的一组寄存器组成的执行路径。它是 CPU 利用率的基本单位,它使通信更加有效和高效,使多处理器体系结构的利用率能够达到更大的规模和更高的效率,并减少上下文切换所需的时间。它只是提供了一种通过并行性来改进和提高应用程序性能的方法。线程有时被称为轻量级进程,因为它们有自己的堆栈但可以访问共享数据。
在一个进程中运行的多个线程共享进程的地址空间、堆、静态数据、代码段、文件描述符、全局变量、子进程、待定警报、信号和信号处理程序。
每个线程都有自己的程序计数器、寄存器、堆栈和状态。
进程 | 线程 |
---|---|
它是一个正在执行的计算机程序。 | 它是进程的组件或实体,是最小的执行单元。 |
重量级。 | 轻量级。 |
它有自己的内存空间。 | 它使用它们所属进程的内存。 |
与创建线程相比,创建进程更难。 | 与创建进程相比,创建线程更容易。 |
与线程相比,它需要更多资源。 | 与流程相比,它需要更少的资源。 |
与线程相比,创建和终止进程需要更多时间。 | 与进程相比,创建和终止线程所需的时间更少。 |
它通常运行在单独的内存空间中。 | 它通常运行在共享内存空间中。 |
它不共享数据。 | 它彼此共享数据。 |
它可以分为多个线程。 | 不能再细分了。 |
IPC(进程间通信) 是一种需要使用共享资源(如在进程或线程之间共享的内存)的机制。通过 IPC,操作系统允许不同的进程相互通信。它仅用于在一个或多个程序或进程中的多个线程之间交换数据。在这种机制中,不同的进程可以在操作系统的批准下相互通信。
不同的 IPC 机制:
死锁通常是一组进程被阻塞的情况,因为每个进程都持有资源并等待获取另一个进程持有的资源。在这种情况下,两个或多个进程只是尝试同时执行并等待每个进程完成它们的执行,因为它们相互依赖。
死锁的必要条件
死锁的必要条件基本上有以下四个:
定义:事务是逻辑上的一组数据库操作,要么都执行,要么都不执行。
特性:
原子性:事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;例如转账的这两个关键操作(将张三的余额减少200元,将李四的余额增加200元)要么全部完成,要么全部失败。
一致性: 确保从一个正确的状态转换到另外一个正确的状态,这就是一致性。例如转账业务中,将张三的余额减少200元,中间发生断电情况,李四的余额没有增加200元,这个就是不正确的状态,违反一致性。又比如表更新事务,一部分数据更新了,但一部分数据没有更新,这也是违反一致性的;
隔离性:并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
持久性:一个事务被提交之后,对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
B树和B+树:
聚簇索引和非聚集索引:
稠密索引和稀疏索引:
MyISAM:
InnoDB:
Redis 与 Memchache 都是分布式缓存系统。
数据存储介质: Memchache缓存的数据都是存放在内存中,一旦内存失效,数据就丢失,无法恢复;Redis缓存的数据存放在内存和硬盘中,能够达到持久化存储,Redis能够利用快照和AOF把数据存放到硬盘中,当内存失效,也可以从磁盘中抽取出来,调入内存中,当物理内存使用完毕后,也可以自动的持久化的磁盘中。
数据存储方式:Redis与Memchache都是以键值对的方式存储,而Redis对于值 使用比较丰富,支持Set,Hash,List,Zet(有序集合)等数据结构的存储,Memchache只支持字符串,不过Memchache也可以缓存图片、视频等非结构化数据。
从架构层次:Redis支持Master-Slave(主从)模式的应用,应用在单核上, Memchache支持分布式,应用在多核上
存储数据大小:对于Redis单个Value存储的数据最大为1G,而Memchache存储的最大为1MB,而存储的Value数据值大于100K时,性能会更好
Redis只支持单核,而Memchache支持多核。
简单 Hash 的缺点:当机器数量发生变动的时候,几乎所有的数据都会移动。
需求:当增加或者删除节点时,对于大多数记录,保证原来分配到的某个节点,现在仍然应该分配到那个节点,将数据迁移量的降到最低。
一致性 Hash:
问题:一致性 Hash 算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜(被缓存的对象大部分集中缓存在某一台服务器上)问题。比如只有 2 台机器,这 2 台机器离的很近,那么顺时针第一个机器节点上将存在大量的数据,第二个机器节点上数据会很少。
虚拟节点解决数据倾斜问题:
常用命令:
命令 | 命令解释 |
---|---|
top | 查看内存 |
df -h | 查看磁盘存储情况 |
iotop | 查看磁盘IO读写(yum install iotop安装) |
iotop -o | 直接查看比较高的磁盘读写程序 |
netstat -tunlp | grep 端口号 | 查看端口占用情况 |
uptime | 查看报告系统运行时长及平均负载 |
ps -ef | 查看进程 |
在正常模式下输入ngg
或者 nG
,n
为指定的行数;如输入 100gg
或者 100G
跳转到第100行。
输入 gg
跳转到当前文件的第一行。
输入 G
跳转光标到当前文件的最后一行。
输入 dd
删除光标所在行
如:
String str="abcaxc";
Patter p="ab*c";
贪婪匹配: 正则表达式一般趋向于最大长度匹配,也就是所谓的贪婪匹配。如上面使用模式p匹配字符串str,结果就是匹配到:abcaxc(ab*c)。
非贪婪匹配:就是匹配到结果就好,就少的匹配字符。如上面使用模式p匹配字符串str,结果就是匹配到:abc(ab*c)。
默认是贪婪模式;在量词后面直接加上一个问号?就是非贪婪模式。
String rule1="content:\".+\""; //贪婪模式
String rule2="content:\".+?\""; //非贪婪模式