diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index dbad3e3..1abc839 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,90 @@ -# JavaYouth -主要是Java方面面试的知识,如并发源码,AQS源码,mysql常考面试,redsi,mq等等 + + +- [Java](#java) + - [基础](#基础) + - [容器](#容器) + - [并发](#并发) + - [JVM](#JVM) + - [各版本新特性](#各版本新特性) + + + +- [计算机网络](#计算机网络) + + + +- [ElasticSearch](#ElasticSearch) + + + +# Java + +## 基础 + +1、总结【TODO】 + + + +**重难点** + +1、[泛型详解【万字长文】](docs/Java/Basis/keyAndDifficultPoints/Generic/泛型.md) + + + +## 容器 + +1、HashMap源码讲解(JDK7和JDK8)【TODO】 + +2、ConcurrentHashMap源码讲解(JDK7和JDK8)【TODO】 + + + +## 并发 + +> 这个系列全是万字长文,希望读者可以耐心看下去,相信会有很大收获。 + +1、[Java并发体系-第一阶段-多线程基础知识](docs/Java/concurrency/Java并发体系-第一阶段-多线程基础知识.md) + +2、[Java并发体系-第二阶段-锁与同步-[1]](docs/Java/concurrency/Java并发体系-第二阶段-锁与同步-[1].md) + +3、[Java并发体系-第二阶段-锁与同步-[2]](docs/Java/concurrency/Java并发体系-第二阶段-锁与同步-[2].md) + +4、[Java并发体系-第二阶段-锁与同步-[3]](docs/Java/concurrency/Java并发体系-第二阶段-锁与同步-[3].md) + +5、[Java并发体系-第三阶段-JUC并发包-[1]](docs/Java/concurrency/Java并发体系-第三阶段-JUC并发包-[1].md) + +6、[Java并发体系-第三阶段-JUC并发包-[2]](docs/Java/concurrency/Java并发体系-第三阶段-JUC并发包-[2].md) + + + +AQS,阻塞队列源码还在准备中。预计12月前可以写的差不多 + + + +## JVM + +【TODO】 + +## 各版本新特性 + +1、[Java8新特性](docs/Java/Basis/Java8_New_Features/Java8新特性.md) + + + +# 计算机网络 + +**总结篇** + +1、[计算机网络-总结-秋招篇](docs/Computer_NetWork/计算机网络-总结.md) + + + + + +# ElasticSearch + +## 用法 + +1、[ElasticSearch-入门](docs/ElasticSearch/usage/ElasticSearch-入门.md) + +2、[ElasticSearch-进阶](docs/ElasticSearch/usage/ElasticSearch-进阶.md) \ No newline at end of file diff --git a/_coverpage.md b/_coverpage.md new file mode 100644 index 0000000..a4a7008 --- /dev/null +++ b/_coverpage.md @@ -0,0 +1,13 @@ +
+
+
+
+**总结:**
+
+1、UDP的主要特点是
+
+①无连接②尽最大努力交付③面向报文④无拥塞控制⑤支持一对一,一对多,多对一和多对多的交互通信⑥首部开销小(只有四个字段:源端口,目的端口,长度和检验和)
+
+2、TCP的主要特点是
+
+①面向连接②每一条TCP连接只能是一对一的③提供可靠交付④提供全双工通信⑤面向字节流
+
+
+
+## 基于TCP的协议有哪些,基于UDP的有哪些
+
+**TCP:**
+
+HTTP, 超文本传输协议
+
+FTP, 文件传输协议
+
+SMTP,简单邮件传输协议,用来发送电子邮件
+
+SSH 安全外壳协议,用于加密安全登陆
+
+**UDP:**
+
+DHCP协议:动态主机配置协议,动态配置IP地址
+
+NTP协议:网络时间协议,用于网络时间同步
+
+RIP(路由选择协议)
+
+DNS
+
+
+
+# TCP可靠传输的保证,拥塞控制目的和过程
+
+## 如何保证可靠传输
+
+TCP通过三次握手建立可靠连接
+
+①数据被分割成 TCP 认为最适合发送的数据包。TCP 给发送的每一个包进行编号,接收方对数据包进行排序,将有序数据传送给应用层。**TCP通过序列号和确认应答提高可靠性**
+
+②校验和: TCP 将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到端的校验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
+
+③流量控制: TCP 利用滑动窗口实现流量控制。流量控制是为了控制发送方发送速率,保证接收方来得及接收。 接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。
+
+④拥塞控制: 当网络拥塞时,减少数据的发送。
+
+⑤ARQ协议:分为停止等待ARQ协议和连续ARQ协议
+
+5.1 它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。
+
+5.2 超时重传::当 TCP 发出一个报文段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。
+
+5.3 TCP 的接收端会丢弃重复的数据
+
+
+
+## ARQ
+
+- 停止等待ARQ:它的基本原理就是每发完一个分组就停止发送,等待对方确认(回复ACK)。如果过了一段时间(超时时间后),还是没有收到 ACK 确认,说明没有发送成功,需要重新发送,直到收到确认后再发下一个分组。停止等待协议中超时重传是指只要超过一段时间仍然没有收到确认,就重传前面发送过的分组(认为刚才发送过的分组丢失了)。因此每发送完一个分组需要设置一个超时计时器,其重转时间应比数据在分组传输的平均往返时间更长一些。这种自动重传方式常称为自动重传请求ARQ。另外在停止等待协议中若收到重复分组,就丢弃该分组,但同时还要发送确认。
+
+- 连续ARQ协议:(流水线的传输方式)可提高信道利用率。发送维持一个发送窗口,凡位于发送窗口内的分组可连续发送出去,而不需要等待对方确认。接收方一般采用累积确认,对按序到达的最后一个分组发送确认,表明到这个分组位置的所有分组都已经正确收到了。
+
+
+
+
+
+## 拥塞控制
+
+**目的:**
+
+拥塞控制就是为了防止过多的数据注入到网络中,这样就可以使网络中的路由器或链路不致过载。拥塞控制是一个全局性的过程,涉及到所有的主机,所有的路由器,以及与降低网络传输性能有关的所有因素。相反,流量控制往往是点对点通信量的控制,是个端到端的问题。流量控制所要做到的就是抑制发送端发送数据的速率,以便使接收端来得及接收。
+
+
+
+**过程:**
+
+为了进行拥塞控制,TCP 发送方要维持一个 拥塞窗口(cwnd) 的状态变量。拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个。**慢开始和拥塞避免都是基于窗口的拥塞控制**。
+
+
+
+**区别:**
+
+> https://blog.csdn.net/ligupeng7929/article/details/79597423
+
+* **慢开始:** 慢开始算法的思路是当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么可能会引起网络阻塞,因为现在还不知道网络的符合情况。经验表明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。cwnd初始值为1,每经过一个传播轮次,cwnd加倍。
+* **拥塞避免:** 拥塞避免算法的思路是让拥塞窗口cwnd缓慢增大,即每经过一个往返时间RTT就把发送放的cwnd加1.
+
+- 为了防止拥塞窗口cwnd增长过大引起网络拥塞,还需要设置一个慢开始门限ssthresh状态变量(如何设置ssthresh)。慢开始门限ssthresh的用法如下:
+
+ 当 cwnd < ssthresh 时,使用上述的慢开始算法。
+
+ 当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
+
+ 当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞控制避免算法。
+
+- 拥塞避免算法:让拥塞窗口cwnd缓慢地增大,即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1,而不是加倍。这样拥塞窗口cwnd按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。
+
+**快重传和快恢复:**
+
+1、**快重传**算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认(为的是使发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时才进行捎带确认。
+
+2、发送方知道现在只是丢失了个别的报文段。于是不启动慢开始,而是执行**快恢复算法**。这时,发送方调整门限值ssthresh= (cwnd/2=8,,同时设置拥塞窗口cwnd = ssthresh=8 ,并开始执行拥塞避免算法。
+
+3、请注意,也有的快恢复实现是把快恢复开始时的拥塞窗口cwnd值再增大一一些(增大3个报文段的长度),即等于新的ssthresh + 3 x MSS。这样做的理由是:既然发送方收到3个重复的确认,就表明有3个分组已经离开了网络。这3个分组不再消耗网络的资源而是停留在接收方的缓存中(接收方发送出3个重复的确认就证明了这个事实)。可见现在网络中并不是堆积了分组而是减少了3个分组。因此可以适当把拥塞窗口扩大些。
+
+
+
+在采用快恢复算法时,慢开始算法只是在TCP连接建立时和网络出现超时时才使用。
+
+
+
+
+
+
+
+
+
+## 为什么要进行流量控制
+
+一般来说,我们总是希望数据传输更快一些。但如果发送方把数据发送的过快,接收方就可能来不及接收,这就会造成数据的丢失(丢包)。
+
+
+
+
+
+# TCP粘包现象原因和解决方法
+
+
+
+## 原因
+
+1.UDP协议的保护消息边界使得每一个消息都是独立的
+
+2.而tcp是基于流的传输,流传输却把数据当作一串数据流,他不认为数据是一个一个的消息
+
+3.发送端需要等缓冲区满才发送出去,造成粘包
+
+4.接收方不及时接收缓冲区的包,造成多个包粘包
+
+具体点:
+
+(1)发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率,发送方往往要收集到足够多的数据后才发送一包数据。若连续几次发送的数据都很少,通常TCP会根据优化算法把这些数据合成一包后一次发送出去,这样接收方就收到了粘包数据。
+
+(2)接收方引起的粘包是由于接收方用户进程不及时接收数据,从而导致粘包现象。这是因为接收方先把收到的数据放在系统接收缓冲区,用户进程从该缓冲区取数据,若下一包数据到达时前一包数据尚未被用户进程取走,则下一包数据放到系统接收缓冲区时就接到前一包数据之后,而用户进程根据预先设定的缓冲区大小从系统接收缓冲区取数据,这样就一次取到了多包数据。
+
+
+
+## 解决方法
+
+(1)对于发送方引起的粘包现象,用户可通过编程设置来避免,TCP提供了强制数据立即传送的操作指令push,TCP程序收到该操作指令后,就立即将本段数据发送出去,而不必等待发送缓冲区满;
+
+(2)对于接收方引起的粘包,则可通过优化程序设计、精简接收进程工作量、提高接收进程优先级等措施,使其及时接收数据,从而尽量避免出现粘包现象;
+
+(3)由接收方控制,将一包数据按结构字段,人为控制分多次接收,然后合并,通过这种手段来避免粘包。
+
+
+
+## 为什么粘包需要处理?
+
+不是所有的粘包现象都需要处理,若传输的数据为不带结构的连续流数据(如文件传输),则不必把粘连的包分开(简称分包)。但在实际工程应用中,传输的数据一般为带结构的数据,这时就需要做分包处理。分包一般难度较大,所以尽量避免粘包
+
+
+
+
+
+# 三次握手相关问题
+
+
+
+## 过程+状态改变
+
+把**补充**里面的**第二个博客**的过程背下来。(有的地方需要参考第一个博客)
+
+
+
+## 为什么三次,两次为什么不行?
+
+### 第一种答案
+
+两次握手只能保证单向连接是畅通的。只有经过第三次握手,才能确保双向都可以接收到对方的发送的 数据。两次握手接收方这里不能确定自己的的发送是正常的,发送方的接收是正常的。
+
+**具体点:**
+
+**三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。**
+
+第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常
+
+第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常
+
+第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常
+
+所以三次握手就能确认双发收发功能都正常,缺一不可。
+
+
+
+### 第二种答案
+
+ 一句话,主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接。
+
+
+
+
+
+
+
+## 如果已经建立了连接,但是客户端突然出现故障了怎么办?
+
+
+
+
+
+## 非阻塞IO
+
+1. 当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。
+2. 从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好。用户线程需要不断地发起IO请求,直到数据到达后,才真正读取到数据,继续执行。
+3. 虽然用户线程每次发起IO请求后可以立即返回,但是为了等到数据,仍需要不断地轮询、重复请求,消耗了大量的CPU的资源。一般很少直接使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性。
+4. **所以,用户进程第一个阶段不是阻塞的,需要不断的主动询问内核数据好了没有;第二个阶段依然总是阻塞的。**
+
+
+
+
+
+
+
+## 多路复用IO
+
+1. IO多路复用模型是建立在内核提供的多路分离函数select基础之上的,使用select函数可以避免同步非阻塞IO模型中轮询等待的问题。利用了新的select系统调用,由内核来负责本来是请求进程该做的轮询操作
+2. 它的基本原理就是select /epoll这个函数会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程,正式发起read请求。
+3. 从流程上来看,使用select函数进行IO请求和同步阻塞模型没有太大的区别,甚至还多了添加监视socket,以及调用select函数的额外操作,效率更差。但是,使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个socket,然后不断地调用select读取被激活的socket(也就是数据准备好了的socket),即可达到在同一个线程内同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。
+
+
+
+
+
+### select函数的其它好处
+
+> handle_events:实现事件循环
+>
+> handle_event:进行读/写等操作
+
+1. 使用select函数的优点并不仅限于此。虽然上述方式允许单线程内处理多个IO请求,但是每个IO请求的过程还是阻塞的(在select函数上阻塞),平均时间甚至比同步阻塞IO模型还要长。
+2. 如果用户线程只注册自己感兴趣的socket或者IO请求,然后去做自己的事情,等到数据到来时再进行处理,则可以提高CPU的利用率。
+3. IO多路复用模型使用了Reactor设计模式实现了这一机制。
+4. 通过Reactor的方式,可以将用户线程轮询IO操作状态的工作统一交给handle_events事件循环进行处理。用户线程注册事件处理器之后可以继续执行做其他的工作(异步),而Reactor线程负责调用内核的select函数检查socket状态。当有socket被激活时(就是数据准备好的时候),则通知相应的用户线程(或执行用户线程的回调函数),执行handle_event进行数据读取、处理的工作。
+5. 由于select函数是阻塞的,因此多路IO复用模型也被称为异步阻塞IO模型。注意,这里的所说的阻塞是指select函数执行时线程被阻塞,而不是指socket。(一般在使用IO多路复用模型时,socket都是设置为NONBLOCK的,不过这并不会产生影响,因为用户发起IO请求时,数据已经到达了,用户线程一定不会被阻塞。)
+
+
+
+
+
+## 信号驱动IO
+
+1. 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个信号函数,然后用户线程会继续执行,当内核数据就绪时会发送一个信号给用户线程,用户线程接收到信号之后,便在信号函数中调用IO读写操作来进行实际的IO请求操作。
+2. 这个一般用于UDP中,对TCP套接口几乎是没用的,原因是该信号产生得过于频繁,并且该信号的出现并没有告诉我们发生了什么事情
+3. 信号驱动IO放佛很像异步IO,它的第一阶段不是阻塞的。但是很遗憾,它的数据拷贝阶段(第二阶段),任然是阻塞的。
+
+
+
+
+
+## 异步IO
+
+1. 真正”的异步IO需要操作系统更强的支持。在IO多路复用模型中,由用户线程自行读取数据、处理数据。
+2. 而在异步IO模型中,用户进程发起read操作之后,立刻就可以开始去做其它的事。
+3. 而另一方面,从**内核**的角度,当它受到一个异步读之后,首先它会立刻返回,所以不会对用户进程产生任何阻塞。然后,内核会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都 完成之后,**内核**会给用户进程发送一个信号,告诉它read操作完成了,用户线程直接使用即可。 在这整个过程中,进程完全没有被阻塞。
+4. 异步IO模型使用了Proactor设计模式实现了这一机制。**(具体怎么搞得,看上面的文章链接)**
+
+
+
+
+
+
+
+
+
+# select、poll、epoll的区别?
+
+> select, poll, epoll 都是I/O多路复用的具体的实现,之所以有这三个存在,其实是他们出现是有先后顺序的。
+>
+> * https://blog.csdn.net/nanxiaotao/article/details/90612404
+> * https://www.cnblogs.com/aspirant/p/9166944.html
+> * https://www.zhihu.com/question/32163005
+
+## select
+
+1. 它仅仅知道了,有I/O事件发生了,却并不知道是哪那几个流(可能有一个,多个,甚至全部),只能无差别轮询所有流,找出能读出数据,或者写入数据的流,对他们进行操作。所以**select具有O(n)的无差别轮询复杂度**,同时处理的流越多,无差别轮询时间就越长。
+2. 单个进程可监视的fd_set(监听的端口个数)数量被限制:32位机默认是1024个,64位机默认是2048。
+
+## poll
+
+poll本质上和select没有区别,采用**链表**的方式替换原有fd_set数据结构,而使其**没有连接数的限制**。
+
+## epoll
+
+1. epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll会把哪个流发生了怎样的I/O事件通知我们。所以我们说epoll实际上是事件驱动(每个事件关联上fd)的,此时我们对这些流的操作都是有意义的。(复杂度降低到了O(1))
+2. 效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数。即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。
+3. epoll通过内核和用户空间共享一块内存来实现的。select和poll都是内核需要将消息传递到用户空间,都需要内核拷贝动作
+4. epoll有EPOLLLT和EPOLLET两种触发模式。(**暂时不去记,有个印象,大致是什么样就可以**)
+
+
+
+# IO疑难点
+
+https://blog.csdn.net/m0_38109046/article/details/89449305
+
+https://www.zhihu.com/question/19732473
+
+[漫画讲IO](https://mp.weixin.qq.com/s?__biz=Mzg3MjA4MTExMw==&mid=2247484746&idx=1&sn=c0a7f9129d780786cabfcac0a8aa6bb7&source=41&scene=21#wechat_redirect)
+
diff --git a/docs/ElasticSearch/usage/ElasticSearch-入门.md b/docs/ElasticSearch/usage/ElasticSearch-入门.md
new file mode 100644
index 0000000..eca1fb7
--- /dev/null
+++ b/docs/ElasticSearch/usage/ElasticSearch-入门.md
@@ -0,0 +1,652 @@
+---
+title: ElasticSearch-入门篇
+tags:
+ - ElasticSearch
+ - ELK
+ - 全文检索
+categories:
+ - ElasticSearch
+ - 用法
+keywords: ElasticSearch,全文检索
+description: ElasticSearch-入门篇,适合做入门,或者知识回顾。
+cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/ElasticSearch/logo.jpg'
+top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg'
+abbrlink: 7f60dde9
+date: 2020-02-03 13:11:45
+---
+
+
+
+> 文章很长,喜欢的话,可以关注下博客。这段时间秋招忙完之后,会持续更新新内容
+
+# ElasticSearch介绍
+
+## 介绍
+
+1、elasticsearch是一个基于Lucene的高扩展的分布式搜索服务器,支持开箱即用。
+
+2、elasticsearch隐藏了Lucene的复杂性,对外提供Restful 接口来操作索引、搜索。
+
+
+
+**突出优点:**
+
+1. 扩展性好,可部署上百台服务器集群,处理PB级数据。
+
+2. 近实时的去索引数据、搜索数据。
+
+**es和solr选择哪个?**
+
+1. 如果你公司现在用的solr可以满足需求就不要换了。
+
+2. 如果你公司准备进行全文检索项目的开发,建议优先考虑elasticsearch,因为像Github这样大规模的搜索都在用它。
+
+
+
+## 倒排索引
+
+下图是ElasticSearch的索引结构,下边黑色部分是物理结构,上边黄色部分是逻辑结构,逻辑结构也是为了更好的 去描述ElasticSearch的工作原理及去使用物理结构中的索引文件。
+
+
+
+逻辑结构部分是一个倒排索引表:
+
+1、将要搜索的文档内容分词,所有不重复的词组成分词列表。
+
+2、将搜索的文档最终以Document方式存储起来。
+
+3、每个词和docment都有关联。
+
+如下:
+
+
+
+现在,如果我们想搜到`quick brown`我们只需要查找包含每个词条的文档:
+
+
+
+两个文档都匹配,但是第一个文档比第二个匹配度更高。如果我们使用仅计算匹配词条数量的简单 相似性算法 , 那么,我们可以说,对于我们查询的相关性来讲,第一个文档比第二个文档更佳
+
+# 基本概念
+
+
+
+1.创建索引库 --------------------->类似于:数据库的建表
+
+2.创建映射 --------------------->类似于:数据库的添加表中字段
+
+3.创建(添加)文档 --------------------->类似于:数据库的往表中添加数据。术语称这个过程为:创建索引
+
+5.搜索文档 --------------------->类似于:从数据库里查数据
+
+6.文档 --------------------->类似于:数据库中的一行记录(数据)
+
+7.Field(域) --------------------->类似于:数据库中的字段
+
+
+
+
+
+
+
+## 创建索引库
+
+### 概念:
+
+ES的索引库是一个逻辑概念,它包括了分词列表及文档列表,同一个索引库中存储了相同类型的文档。它就相当于MySQL中的表,或相当于Mongodb中的集合。
+
+索引(index)
+
+```shell
+# 索引是 ES 对逻辑数据的逻辑存储,所以可以被分为更小的部分
+
+# 可以将索引看成 MySQL 的 Table,索引的结构是为快速有效的全文索引准备的,特别是它不存储原始值
+
+# 可以将索引存放在一台机器,或分散在多台机器上
+
+# 每个索引有一或多个分片(shard),每个分片可以有多个副本(replica)
+```
+
+### 操作:
+
+使用postman这样的工具创建: put http://localhost:9200/索引库名称
+
+
+```shell
+# ES 中提供非结构化索引,实际上在底层 ES 会进行结构化操作,对用户透明
+
+PUT http://localhost:9200/索引库名称
+{
+ "settings":{
+ "index":{
+ "number_of_shards":"1", # 分片数
+ "number_of_replicas":"0" # 副本数
+ }
+ }
+}
+```
+
+- number_of_shards:设置分片的数量,在集群中通常设置多个分片,表示一个索引库将拆分成多片分别存储不同 的结点,提高了ES的处理能力和高可用性,入门程序使用单机环境,这里设置为1。
+
+- number_of_replicas:设置副本的数量,设置副本是为了提高ES的高可靠性,单机环境设置为0.
+
+
+
+## 创建映射
+
+### 概念
+
+在索引中每个文档都包括了一个或多个field,创建映射就是向索引库中创建field的过程,下边是document和field 与关系数据库的概念的类比:
+
+文档(Document)----- Row记录
+
+字段(Field)----- Columns 列
+
+注意:6.0之前的版本有type(类型)概念,type相当于关系数据库的表,ES官方将在ES9.0版本中彻底删除type。 上边讲的创建索引库相当于关系数据库中的数据库还是表?
+
+1、如果相当于数据库就表示一个索引库可以创建很多不同类型的文档,这在ES中也是允许的。
+
+2、如果相当于表就表示一个索引库只能存储相同类型的文档,ES官方建议在一个索引库中只存储相同类型的文档。
+
+3、所以索引库相当于数句酷的一个表
+
+
+
+### 操作
+
+1、我们要把课程信息存储到ES中,这里我们创建课程信息的映射,先来一个简单的映射,如下:
+
+发送:post http://localhost:9200/索引库名称/类型名称/_mapping
+
+2、创建类型为xc_course的映射,共包括三个字段:name、description、studymondel 由于ES6.0版本还没有将type彻底删除,所以暂时把type起一个没有特殊意义的名字doc。post 请求:http://localhost:9200/xc_course/doc/_mapping
+
+表示:在xc_course索引库下的doc类型下创建映射。doc是类型名,可以自定义,在ES6.0中要弱化类型的概念, 给它起一个没有具体业务意义的名称。
+
+```json
+ {
+ "properties": {
+ "name": {
+ "type": "text"
+ },
+
+ "description":{
+ "type": "text"
+ },
+
+ "studymodel":{
+ "type":"keyword"
+ }
+ }
+}
+```
+
+
+## 创建文档
+
+### 概念
+
+ES中的文档相当于MySQL数据库表中的记录。
+
+```shell
+# 存储在 ES 中的主要实体叫文档,可以看成 MySQL 的一条记录
+
+# ES 与 Mongo 的 document 类似,都可以有不同的结构,但 ES 相同字段必须有相同类型
+
+# document 由多个字段组成,每个字段可能多次出现在一个文档里,这样的字段叫多值字段(multivalued)
+
+# 每个字段的类型,可以使文本、数值、日期等。
+
+# 字段类型也可以是复杂类型,一个字段包含其他子文档或者数组
+
+# 在 ES 中,一个索引对象可以存储很多不同用途的 document,例如一个博客App中,可以保存文章和评论
+
+# 每个 document 可以有不同的结构
+
+# 不同的 document 不能为相同的属性设置不同的类型,例 : title 在同一索引中所有 Document 都应该相同数据类型
+```
+
+
+
+### 操作
+
+发送:put 或Post http://localhost:9200/xc_course/doc/id值
+
+(如果不指定id值ES会自动生成ID)
+
+http://localhost:9200/xc_course/doc/4028e58161bcf7f40161bcf8b77c0000
+
+```json
+
+{
+ "name":”Bootstrap开发框架",
+
+ "description" : "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较为广泛。此开发框架包含 了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现个不受浏览器限制的精美界面 效果。”,
+
+ "studymodel": "201001"
+
+}
+```
+
+
+
+## 搜索文档
+
+1、根据课程id查询文档
+
+发送:get http://localhost:9200/xc_course/doc/4028e58161bcf7f40161bcf8b77c0000
+
+使用postman测试:
+
+
+
+
+
+2、查询所有记录
+
+发送 get http://localhost:9200/xc_course/doc/_search
+
+
+
+
+
+3、查询名称中包括spring 关键字的的记录
+
+发送:get http://localhost:9200/xc_course/doc/_search?q=name:bootstrap
+
+
+
+
+
+4、查询学习模式为201001的记录
+
+发送 get http://localhost:9200/xc_course/doc/_search?q=studymodel:201001
+
+
+
+**查询结果分析:**
+
+```json
+{
+ "took": 1,
+ "timed_out": false,
+ "_shards": {
+ "total": 1,
+ "successful": 1,
+ "skipped": 0,
+ "failed": 0
+ },
+ "hits": {
+ "total": 1,
+ "max_score": 0.2876821,
+ "hits": [
+ {
+ "_index": "xc_course",
+ "_type": "doc",
+ "_id": "4028e58161bcf7f40161bcf8b77c0000",
+ "_score": 0.2876821,
+ "_source": {
+ "name": "Bootstrap开发框架",
+ "description": "Bootstrap是由Twitter推出的一个前台页面开发框架,在行业之中使用较 为广泛。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长页面开发的程序人员)轻松的实现 一个不受浏览器限制的精美界面效果。",
+ "studymodel": "201001"
+ }
+ }
+ ]
+ }
+}
+```
+
+**结果说明:**
+
+took:本次操作花费的时间,单位为毫秒。timed_out:请求是否超时
+
+_shards:说明本次操作共搜索了哪些分片hits:搜索命中的记录
+
+hits.total : 符合条件的文档总数 hits.hits :匹配度较高的前N个文档
+
+hits.max_score:文档匹配得分,这里为最高分
+
+_score:每个文档都有一个匹配度得分,按照降序排列。
+
+_source:显示了文档的原始内容。
+
+
+
+
+
+# 分词
+
+## 内置分词
+
+### 分词API
+
+分词是将一个文本转换成一系列单词的过程,也叫文本分析,在 ES 中称之为 Analysis
+
+例如 : 我是中国人 -> 我 | 是 | 中国人
+
+```json
+# 指定分词器进行分词
+POST http://['自己的ip 加 port']/_analyze
+{
+ "analyzer":"standard",
+ "text":"hello world"
+}
+
+# 结果中不仅可以看出分词的结果,还返回了该词在文本中的位置
+
+# 指定索引分词
+POST http://['自己的ip 加 port']/beluga/_analyze
+{
+ "analyzer":"standard",
+ "field":"hobby",
+ "text":"听音乐"
+}
+```
+
+
+
+### Standard
+
+```shell
+# Standard 标准分词,按单词切分,并且会转换成小写
+POST http://['自己的ip 加 port']/_analyze
+{
+ "analyzer":"standard",
+ "text": "A man becomes learned by asking questions."
+}
+```
+
+### Simple
+
+```shell
+# Simple 分词器,按照非单词切分,并且做小写处理
+POST http://['自己的ip 加 port']/_analyze
+{
+ "analyzer":"simple",
+ "text":"If the document does't already exist"
+}
+```
+
+### Whitespace
+
+```shell
+# Whitespace 是按照空格切分
+POST http://['自己的ip 加 port']/_analyze
+{
+ "analyzer":"whitespace",
+ "text":"If the document does't already exist"
+}
+```
+
+### Stop
+
+```shell
+# Stop 去除 Stop Word 语气助词,如 the、an 等
+POST http://['自己的ip 加 port']/_analyze
+{
+ "analyzer":"stop",
+ "text":"If the document does't already exist"
+}
+```
+
+### Keyword
+
+```shell
+# keyword 分词器,意思是传入就是关键词,不做分词处理
+POST http://['自己的ip 加 port']/_analyze
+{
+ "analyzer":"keyword",
+ "text":"If the document does't already exist"
+}
+```
+
+### 中文分词
+
+```shell
+# 中文分词的难点在于,汉语中没有明显的词汇分界点
+
+# 常用中文分词器,IK jieba THULAC 等,推荐 IK
+
+# IK Github 站点<自定义词典扩展,禁用词典扩展等>
+https://github.com/medcl/elasticsearch-analysis-ik
+```
+
+
+
+## IK分词器
+
+安装过程这里不介绍,主要是解决常见中文分词的问题
+
+Github地址:https://github.com/medcl/elasticsearch-analysis-ik
+
+### 两种分词模式
+
+ik分词器有两种分词模式:ik_max_word和ik_smart模式。
+
+ 1、ik_max_word
+
+会将文本做最细粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为“中华人民共和国、中华人民、中华、 华人、人民共和国、人民、共和国、大会堂、大会、会堂等词语。
+
+2、ik_smart
+
+会做最粗粒度的拆分,比如会将“中华人民共和国人民大会堂”拆分为中华人民共和国、人民大会堂。 测试两种分词模式:
+
+
+
+
+
+# 映射
+
+上边章节安装了ik分词器,如果在索引和搜索时去使用ik分词器呢?如何指定其它类型的field,比如日期类型、数 值类型等。本章节学习各种映射类型及映射维护方法。
+
+## 映射维护方法
+
+1、查询所有索引的映射:
+
+GET: http://localhost:9200/_mapping
+
+2、创建映射
+
+post 请求:http://localhost:9200/xc_course/doc/_mapping
+
+在上面提到过
+
+```
+ {
+ "properties": {
+ "name": {
+ "type": "text"
+ },
+
+ "description":{
+ "type": "text"
+ },
+
+ "studymodel":{
+ "type":"keyword"
+ }
+ }
+}
+```
+
+
+
+3、更新映射
+
+映射创建成功可以添加新字段,已有字段不允许更新。
+
+4、删除映射
+
+通过删除索引来删除映射。
+
+
+
+## 常用映射类型
+
+### text文本字段
+
+**1)text**
+
+字符串包括text和keyword两种类型: 通过analyzer属性指定分词器。
+
+下边指定name的字段类型为text,使用ik分词器的ik_max_word分词模式。
+
+```json
+{
+ "name": {
+ "type": "text",
+ "analyzer": "ik_max_word"
+ }
+}
+```
+
+上边指定了analyzer是指在索引和搜索都使用ik_max_word,如果单独想定义搜索时使用的分词器则可以通过search_analyzer属性。
+
+对于ik分词器建议是索引时使用ik_max_word将搜索内容进行细粒度分词,搜索时使用ik_smart提高搜索精确性。
+
+```json
+{
+ "name": {
+ "type": "text",
+ "analyzer": "ik_max_word",
+ "search_analyzer": "ik_smart"
+ }
+}
+```
+
+**2) index**
+
+通过index属性指定是否索引。
+
+默认为index=true,即要进行索引,只有进行索引才可以从索引库搜索到。
+
+但是也有一些内容不需要索引,比如:商品图片地址只被用来展示图片,不进行搜索图片,此时可以将index设置 为false。
+
+删除索引,重新创建映射,将pic的index设置为false,尝试根据pic去搜索,结果搜索不到数据
+
+```json
+{
+ "pic": {
+ "type": "text",
+ "index": false
+ }
+}
+```
+
+
+
+**3)store**
+
+是否在source之外存储,每个文档索引后会在 ES中保存一份原始文档,存放在"_source"中,一般情况下不需要设置 store为true,因为在_source中已经有一份原始文档了。
+
+
+
+### keyword关键字字段
+
+上边介绍的text文本字段在映射时要设置分词器,keyword字段为关键字字段,通常搜索keyword是按照整体搜 索,所以创建keyword字段的索引时是不进行分词的,比如:邮政编码、手机号码、身份证等。keyword字段通常 用于过虑、排序、聚合等。
+
+**测试:**
+
+更改映射:
+
+```json
+{
+ "properties": {
+ "studymodel": {
+ "type": "keyword"
+ },
+ "name": {
+ "type": "keyword"
+ }
+ }
+}
+```
+
+添加文档:
+
+```json
+{
+ "name": "java编程基础",
+ "description": "java语言是世界第一编程语言,在软件开发领域使用人数最多。",
+ "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
+ "studymodel": "201001"
+}
+```
+
+根据name查询文档。搜索:http://localhost:9200/xc_course/_search?q=name:java name是keyword类型,所以查询方式是精确查询。
+
+
+
+### 日期类型
+
+日期类型不用设置分词器。
+
+通常日期类型的字段用于排序。
+
+1)format
+
+通过format设置日期格式例子:
+
+下边的设置允许date字段存储年月日时分秒、年月日及毫秒三种格式
+
+```json
+{
+ "properties": {
+ "timestamp": {
+ "type": "date",
+ "format": "yyyy‐MM‐dd HH:mm:ss||yyyy‐MM‐dd"
+ }
+ }
+}
+```
+
+插入文档:
+
+Post :http://localhost:9200/xc_course/doc/3
+
+```json
+{
+ "name": "spring开发基础",
+ "description": "spring 在java领域非常流行,java程序员都在用。",
+ "studymodel": "201001",
+ "pic": "group1/M00/00/01/wKhlQFqO4MmAOP53AAAcwDwm6SU490.jpg",
+ "timestamp": "2018‐07‐04 18:28:58"
+}
+```
+
+
+
+### 综合例子
+
+post:http://localhost:9200/xc_course/doc/_mapping
+
+```json
+{
+ "properties": {
+ "description": {
+ "type": "text",
+ "analyzer": "ik_max_word",
+ "search_analyzer": "ik_smart"
+ },
+ "name": {
+ "type": "text",
+ "analyzer": "ik_max_word",
+ "search_analyzer": "ik_smart"
+ },
+ "pic": {
+ "type": "text",
+ "index": false
+ },
+ "price": {
+ "type": "float"
+ },
+ "studymodel": {
+ "type": "keyword"
+ },
+ "timestamp": {
+ "type": "date",
+ "format": "yyyy‐MM‐dd HH:mm:ss||yyyy‐MM‐dd||epoch_millis"
+ }
+ }
+}
+```
+
diff --git a/docs/ElasticSearch/usage/ElasticSearch-进阶.md b/docs/ElasticSearch/usage/ElasticSearch-进阶.md
new file mode 100644
index 0000000..ab20eb2
--- /dev/null
+++ b/docs/ElasticSearch/usage/ElasticSearch-进阶.md
@@ -0,0 +1,1732 @@
+---
+title: ElasticSearch-进阶篇
+tags:
+ - ElasticSearch
+ - ELK
+ - 全文检索
+categories:
+ - ElasticSearch
+ - 用法
+keywords: ElasticSearch,全文检索
+description: ElasticSearch-进阶篇,ElasticSearch的一些实战用法,集成SpringBoot。
+cover: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/ElasticSearch/logo.jpg'
+top_img: 'https://cdn.jsdelivr.net/gh/youthlql/lql_img/blog/top_img.jpg'
+abbrlink: 50e81c79
+date: 2020-02-08 18:06:23
+---
+
+
+
+# 搭建工程
+
+ES提供多种不同的客户端:
+
+1、TransportClient
+
+ES提供的传统客户端,官方计划8.0版本删除此客户端。
+
+2、RestClient
+
+RestClient是官方推荐使用的,它包括两种:Java Low Level REST Client和 Java High Level REST Client。
+
+ES在6.0之后提供 Java High Level REST Client, 两种客户端官方更推荐使用 Java High Level REST Client,不过当
+
+前它还处于完善中,有些功能还没有。
+
+
+
+我们采用SpringBoot2.x与ElasticSearch集成
+
+## Maven依赖
+
+部分依赖
+
+```maven
+
+
+
+
+# Lambda表达式
+
+## 为什么使用Lambda表达式?
+
+- Lambda 是一个**匿名函数**,我们可以把 Lambda 表达式理解为是**一段可以传递的代码**(将代码像数据一样进行传递)。使用它可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
+- 在Java8之后的很多源码里用到了Lambda表达式,不学的话可能看不懂源码。
+
+
+
+## 简单使用
+
+```java
+ @Test
+ public void test1(){
+ //原始写法
+ Runnable r1 = new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("我爱北京天安门");
+ }
+ };
+
+ r1.run();
+
+ System.out.println("***********************");
+
+ //lambda表达式,可以表达一样的意思
+ Runnable r2 = () -> System.out.println("我爱北京故宫");
+
+ r2.run();
+ }
+
+
+ @Test
+ public void test2(){
+
+ Comparator+ * 1.举例: (o1,o2) -> Integer.compare(o1,o2); + * 2.格式: + * -> :lambda操作符 或 箭头操作符 + * ->左边:lambda形参列表 (其实就是接口中的抽象方法的形参列表) + * ->右边:lambda体 (其实就是重写的抽象方法的方法体) + *
+ * 3. Lambda表达式的使用:(分为6种情况介绍) + *
+ * 总结: + * ->左边:lambda形参列表的参数类型可以省略(类型推断);如果lambda形参列表只有一个参数,其一对()也可以省略 + * ->右边:lambda体应该使用一对{}包裹;如果lambda体只有一条执行语句(可能是return语句),省略这一对{}和return关键字 + *
+ * 4.Lambda表达式的本质:作为函数式接口的实例 + *
+ * 5. 如果一个接口中,只声明了一个抽象方法,则此接口就称为函数式接口。我们可以在一个接口上使用 @FunctionalInterface 注解, + * 这样做可以检查它是否是一个函数式接口。 + *
+ * 6. 所以以前用匿名实现类表示的现在都可以用Lambda表达式来写。
+ */
+public class LambdaTest1 {
+ //语法格式一:无参,无返回值
+ @Test
+ public void test1() {
+ Runnable r1 = new Runnable() {
+ @Override
+ public void run() {
+ System.out.println("我爱北京天安门");
+ }
+ };
+
+ r1.run();
+
+ System.out.println("***********************");
+
+ Runnable r2 = () -> {
+ System.out.println("我爱北京故宫");
+ };
+
+ r2.run();
+ }
+
+ //语法格式二:Lambda 需要一个参数,但是没有返回值。
+ @Test
+ public void test2() {
+
+ Consumer
+ * 功能描述:
+ */
+public class Test_Safe {
+
+ public static void main(String[] args) {
+ test();
+ }
+
+ public static void test() {
+ List arrayList = new ArrayList();
+ arrayList.add("aaaa");
+ arrayList.add(100);
+
+ for (int i = 0; i < arrayList.size(); i++) {
+ String s = (String) arrayList.get(i);
+ System.out.println(s);
+
+ }
+ }
+}
+```
+
+结果:
+
+```
+aaaa
+Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
+ at keyAndDifficultPoints.Generic.Test_Safe.test(Test_Safe.java:25)
+ at keyAndDifficultPoints.Generic.Test_Safe.main(Test_Safe.java:16)
+```
+
+很明显的一个类型转换错误。ArrayList可以存放任意类型,例子中添加了一个String类型,添加了一个Integer类型,再使用时都以String的方式使用,因此程序崩溃了。为了解决类似这样的问题(在编译阶段就可以解决),泛型应运而生。
+
+
+
+**泛型提高安全性**
+
+将上面的代码稍微改一下
+
+```Java
+ public static void test01(){
+ List
+ * 功能描述:
+ */
+public class Test_GenericClass {
+ public static void main(String[] args) {
+ test();
+ }
+
+ public static void test(){
+ /**
+ * 1、泛型的类型参数只能是类类型(包括自定义类),不能是简单数据类型(比如int,long这些)
+ * 2、传入的实参类型需与泛型的类型参数类型相同,即为这里的Integer。
+ * 3、new 后面的泛型参数可以省略
+ */
+ Generic
+ * 功能描述:
+ */
+public class Test_GenericMethod {
+
+ public static void main(String[] args) {
+ Test_GenericMethod test_genericMethod = new Test_GenericMethod();
+ Generic01
+ * 功能描述:
+ */
+public class Test_GenericMethod01 {
+ public static void main(String[] args) {
+ Apple apple = new Apple();
+ Person person = new Person();
+
+ GenerateTest
+ * 功能描述:
+ */
+public class Test_Minutiae1 {
+}
+class Order
+ * 功能描述: 测试泛型数组
+ */
+public class Test_GenericArray {
+
+ public static void main(String[] args) {
+ test02();
+ }
+
+ public static void test() {
+ //编译错误
+// List
+
+
+
+**其它函数式接口**
+
+
+
+
+
+
+
+**Consumer**
+
+```java
+ @Test
+ public void test1(){
+
+ happyTime(500, new Consumer
+
+
+
+
+
+## 创建Stream
+
+
+
+```java
+
+public class StreamAPITest {
+
+ //创建 Stream方式一:通过集合
+ @Test
+ public void test1(){
+ List
+
+
+
+
+
+## 举例
+
+首先准备两个类
+
+```java
+
+public class Boy {
+ private Girl girl;
+
+ @Override
+ public String toString() {
+ return "Boy{" +
+ "girl=" + girl +
+ '}';
+ }
+
+ public Girl getGirl() {
+ return girl;
+ }
+
+ public void setGirl(Girl girl) {
+ this.girl = girl;
+ }
+
+ public Boy() {
+
+ }
+
+ public Boy(Girl girl) {
+
+ this.girl = girl;
+ }
+}
+```
+
+
+
+```java
+public class Girl {
+
+ private String name;
+
+ @Override
+ public String toString() {
+ return "Girl{" +
+ "name='" + name + '\'' +
+ '}';
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Girl() {
+
+ }
+
+ public Girl(String name) {
+
+ this.name = name;
+ }
+}
+```
+
+
+
+这里只是简单的测试两个API
+
+```Java
+/**
+ * Optional类:为了在程序中避免出现空指针异常而创建的。
+ *
+ * 常用的方法:ofNullable(T t)
+ * orElse(T t)
+ *
+ */
+public class OptionalTest {
+
+/*
+Optional.of(T t) : 创建一个 Optional 实例,t必须非空;
+Optional.empty() : 创建一个空的 Optional 实例
+Optional.ofNullable(T t):t可以为null
+
+ */
+ @Test
+ public void test1(){
+ Girl girl = new Girl();
+// girl = null;
+ //of(T t):保证t是非空的
+ Optional