……

第一章、Elasticsearch入门

Elasticsearch(简称ES)是一个基于Apache Lucene(TM)的开源搜索引擎,无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。

一、Elasticsearch简介

1、应用场景
  • 海量数据分析引擎

  • 站内搜索引擎

  • 数据仓库

一线公司应用场景

  • 实时分析公众对文章的回应

  • GitHub-站内实时搜索

  • 百度-日志监控平台

2、Elasticsearch是什么

Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎,无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。 但是,Lucene只是一个库。想要发挥其强大的作用,你需使用Java并要将其集成到你的应用中。Lucene非常复杂,你需要深入的了解检索相关知识来理解它是如何工作的。 Elasticsearch也是使用Java编写并使用Lucene来建立索引并实现搜索功能,但是它的目的是通过简单连贯的RESTful API让全文搜索变得简单并隐藏Lucene的复杂性。 不过,Elasticsearch不仅仅是Lucene和全文搜索引擎,它还提供:

  • 分布式的实时文件存储,每个字段都被索引并可被搜索

  • 实时分析的分布式搜索引擎

  • 可以扩展到上百台服务器,处理PB级结构化或非结构化数据

而且,所有的这些功能被集成到一台服务器,你的应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。上手Elasticsearch非常简单,它提供了许多合理的缺省值,并对初学者隐藏了复杂的搜索引擎理论。它开箱即用(安装即可使用),只需很少的学习既可在生产环境中使用。Elasticsearch在Apache 2 license下许可使用,可以免费下载、使用和修改。 随着知识的积累,你可以根据不同的问题领域定制Elasticsearch的高级特性,这一切都是可配置的,并且配置非常灵活。

3、Elasticsearch中涉及到的重要概念

Elasticsearch有几个核心概念。从一开始理解这些概念会对整个学习过程有莫大的帮助。

(1) 接近实时(NRT) Elasticsearch是一个接近实时的搜索平台。这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(通常是1秒)。

(2) 集群(cluster) 一个集群就是由一个或多个节点组织在一起,它们共同持有你整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是“elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。在产品环境中显式地设定这个名字是一个好习惯,但是使用默认值来进行测试/开发也是不错的。

(3) 节点(node) 一个节点是你集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你会去确定网络中的哪些服务器对应于Elasticsearch集群中的哪些节点。

一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。

在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。

(4) 索引(index) 一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。索引类似于关系型数据库中Database的概念。在一个集群中,如果你想,可以定义任意多的索引。

(5) 类型(type) 在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。比如说,我们假设你运营一个博客平台并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类型,当然,也可以为评论数据定义另一个类型。类型类似于关系型数据库中Table的概念。

(6)文档(document) 一个文档是一个可被索引的基础信息单元。比如,你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON(Javascript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。 在一个index/type里面,只要你想,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type。文档类似于关系型数据库中Record的概念。实际上一个文档除了用户定义的数据外,还包括_index_type_id字段。

(7) 分片和复制(shards & replicas) 一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。

为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。 分片之所以重要,主要有两方面的原因:

  • 允许你水平分割/扩展你的内容容量

  • 允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量

至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。

在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了。这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。复制之所以重要,主要有两方面的原因:

  • 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。

  • 扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行

总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制数量,但是不能改变分片的数量。

默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。一个索引的多个分片可以存放在集群中的一台主机上,也可以存放在多台主机上,这取决于你的集群机器数量。主分片和复制分片的具体位置是由ES内在的策略所决定的。

以上部分内容转自Elasticsearch基础教程,并对其进行了补充。

二、Elasticsearch安装与配置

1、安装与运行

(1) 从这里下载Elasticsearch安装包。一共提供4种格式的安装包(ZIP、TAR.GZ、DEB和RPM),可以根据自己所使用的系统平台选择相应格式的安装包进行下载。(建议使用Linux系统,本人在2台windows机器上尝试启动过,一台机器上无法正常启动,另外一台可以)

(2) 对下载的安装包进行解压缩即可完成安装操作。下面以在Ubuntu操作系统下使用TAR.GZ格式的1.5.0版本的安装包为例进行安装。在Linux shell中输入下面的命令解压缩。

tar –vxf elasticsearch-1.5.0.tar.gz

安装成功,下面运行ES。

   注意:Elasticsearch需要Java虚拟机的支持,在运行之前保证机器上安装了JDK,并且JDK版本不能低于1.7_55。

 

(3) 现在可以直接使用默认配置启动Elasticsearch了。 假设安装包解压后的目录路径为【/home/elasticsearch/elasticsearch-1.5.0】,下面军用$ES_HOME来表示这个路径。执行下面的命令:

 cd /home/elasticsearch/elasticsearch-1.5.0/bin/
chmod +x *
./elasticsearch

 

如果出现如图所示的界面(最后打印出started),则说明Elasticsearch启动成功。 启动成功界面

下面来验证一下是否真的启动成功。打开浏览器,访问网址 http://host:9200(这里的host是ES的安装主机地址,如果安装在本机,就是http://127.0.0.1:9200)。如果显示下面的信息,则表示ES安装成功。

{
"status" : 200,
"name" : "Captain Zero",
"cluster_name" : "elasticsearch",
"version" : {
  "number" : "1.5.0",
  "build_hash" : "544816042d40151d3ce4ba4f95399d7860dc2e92",
  "build_timestamp" : "2015-03-23T14:30:58Z",
  "build_snapshot" : false,
  "lucene_version" : "4.10.4"
},
"tagline" : "You Know, for Search"
}

 

上面是前台启动方式,一旦关闭Linux shell,ES服务就会停止。所以是实际使用过程中,绝对不会使用这种方式去启动ES。除了上面的启动方式外,还可以加上一定的启动参数。例如:

 ./elasticsearch –d #在后台运行Elasticsearch
./elasticsearch -d -Xmx2g -Xms2g #后台启动,启动时指定内存大小(2G)
./elasticsearch -d -Des.logger.level=DEBUG  #可以在日志中打印出更加详细的信息。

 

2、ES的配置

配置文件所在的目录路径如下:$ES_HOME/config/elasticsearch.yml。 下面介绍一些重要的配置项及其含义。

(1)cluster.name: elasticsearch

配置elasticsearch的集群名称,默认是elasticsearch。elasticsearch会自动发现在同一网段下的集群名为elasticsearch的主机,如果在同一网段下有多个集群,就可以用这个属性来区分不同的集群。生成环境时建议更改。

(2)node.name: “Franz Kafka”

节点名,默认随机指定一个name列表中名字,该列表在elasticsearch的jar包中config文件夹里name.txt文件中,其中有很多作者添加的有趣名字,大部分是漫威动漫里面的人物名字。生成环境中建议更改以能方便的指定集群中的节点对应的机器

(3)node.master: true

指定该节点是否有资格被选举成为node,默认是true,elasticsearch默认集群中的第一台启动的机器为master,如果这台机挂了就会重新选举master。

(4)node.data: true

指定该节点是否存储索引数据,默认为true。如果节点配置node.master:false并且node.data: false,则该节点将起到负载均衡的作用

(5)index.number_of_shards: 5

设置默认索引分片个数,默认为5片。经本人测试,索引分片对ES的查询性能有很大的影响,在应用环境,应该选择适合的分片大小。

(6)index.number_of_replicas:

设置默认索引副本个数,默认为1个副本。此处的1个副本是指index.number_of_shards的一个完全拷贝;默认5个分片1个拷贝;即总分片数为10。

(7)path.conf: /path/to/conf

设置配置文件的存储路径,默认是es根目录下的config文件夹。

(8)path.data:/path/to/data1,/path/to/data2

设置索引数据的存储路径,默认是es根目录下的data文件夹,可以设置多个存储路径,用逗号隔开。

(9)path.work:/path/to/work

设置临时文件的存储路径,默认是es根目录下的work文件夹。

(10)path.logs: /path/to/logs

设置日志文件的存储路径,默认是es根目录下的logs文件夹

(11)path.plugins: /path/to/plugins

设置插件的存放路径,默认是es根目录下的plugins文件夹

(12)bootstrap.mlockall: true

设置为true来锁住内存。因为当jvm开始swapping时es的效率会降低,所以要保证它不swap,可以把ES_MIN_MEM和ES_MAX_MEM两个环境变量设置成同一个值,并且保证机器有足够的内存分配给es。同时也要允许elasticsearch的进程可以锁住内存,linux下可以通过ulimit -l unlimited命令。

(13)network.bind_host: 192.168.0.1

设置绑定的ip地址,可以是ipv4或ipv6的,默认为0.0.0.0。

(14)network.publish_host: 192.168.0.1

设置其它节点和该节点交互的ip地址,如果不设置它会自动判断,值必须是个真实的ip地址。

(15)network.host: 192.168.0.1

这个参数是用来同时设置bind_host和publish_host上面两个参数。

(16)transport.tcp.port: 9300

设置节点间交互的tcp端口,默认是9300。

(17)transport.tcp.compress: true

设置是否压缩tcp传输时的数据,默认为false,不压缩。

(18)http.port: 9200

设置对外服务的http端口,默认为9200。

(19)http.max_content_length: 100mb

设置内容的最大容量,默认100mb

(20)http.enabled: false

是否使用http协议对外提供服务,默认为true,开启。

(21)gateway.type: local

gateway的类型,默认为local即为本地文件系统,可以设置为本地文件系统,分布式文件系统,hadoop的HDFS,和amazon的s3服务器,其它文件系统的设置。

(22)gateway.recover_after_nodes: 1

设置集群中N个节点启动时进行数据恢复,默认为1。

(23)gateway.recover_after_time: 5m

设置初始化数据恢复进程的超时时间,默认是5分钟。

(24)gateway.expected_nodes: 2

设置这个集群中节点的数量,默认为2,一旦这N个节点启动,就会立即进行数据恢复。

(25)cluster.routing.allocation.node_initial_primaries_recoveries: 4

初始化数据恢复时,并发恢复线程的个数,默认为4。

(26)cluster.routing.allocation.node_concurrent_recoveries: 2

添加删除节点或负载均衡时并发恢复线程的个数,默认为4。

(27)indices.recovery.max_size_per_sec: 0

设置数据恢复时限制的带宽,如入100mb,默认为0,即无限制。

(28)indices.recovery.concurrent_streams: 5

设置这个参数来限制从其它分片恢复数据时最大同时打开并发流的个数,默认为5。

(29)discovery.zen.minimum_master_nodes: 1

设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1,对于大的集群来说,可以设置大一点的值(2-4)

(30)discovery.zen.ping.timeout: 3s

设置集群中自动发现其它节点时ping连接超时时间,默认为3秒,对于比较差的网络环境可以高点的值来防止自动发现时出错。

(31)discovery.zen.ping.multicast.enabled: false

设置是否打开多播发现节点,默认是true。

(32)discovery.zen.ping.unicast.hosts: [“host1”, “host2:port”, “host3 [portX-portY] “]

设置集群中master节点的初始列表,可以通过这些节点来自动发现新加入集群的节点。

除了上面的在安装时配置文件中就自带的配置项外,本人在实际使用过程还使用到了下面的配置:

threadpool:
  search:
      type: fixed
      min: 60
      max: 80
      queue_size: 1000
// 配置es服务器的执行查询操作时所用线程池,fix固定线程数的线程池。

 

index :
  store:
      type: memory
// 表示索引存储在内存中,当然es不太建议这么做。经本人测试,做查询时,使用内存索引并不会比正常的索引快。

 

index.mapper.dynamic: false
// 禁止自动创建mapping。默认情况下,es可以根据数据类型自动创建mapping。配置成这样,可以禁止自动创建mapping的行为。至于什么是mapping,在之后的博文中再介绍。

 

index.query.parse.allow_unmapped_fields: false 
// 不能查找没有在mapping中定义的属性

 

以上总结介绍了Elasticsearch中的一些基础知识,包括其中的一些核心概念。只有理解了ES中的这些核心概念,才能对更加得心应手地使用ES,发挥其强大的搜索能力。同时,也介绍了ES的安装和运行,ES的安装和运行是很简单的,只需要极少的简单步骤,就可以开始体验ES。ES的配置非常丰富,安装时自带的配置文件只包含一部分比较核心的配置项,更多的配置内容需要自己去阅读ES的源码时才能被发现。

 

3、单实例安装
  • elasticSearch下载地址

  • wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.5.2.tar.gz
    • wget命令可以直接通过http协议下载,当然我们也可以在网页下载

  • tar -vxf 解压

  • cd elasticsearch-5.5.2
    • 核心文件有

    • config,modules,plugins

  • 启动命令:./bin/elasticseatch

  • 出现下图界面,started启动成功, 默认9200端口

img

es1.png

  • 访问url,es默认返回的 *json* 数据格式

img

es2.png

  • 插件安装

    • head插件,提供了友好的web界面,基本信息查看

    • head插件下载地址

    • 下载完文件为master.zip文件,进行解压unzip master.zip

    • 进入解压完成的文件cd elasticsearch-head-master

    • node -v可以看到版本号

    • npm install安装

    • npm run start服务启动

    img

    es3.png

  • 访问浏览器效果:

    img

    es4.png

此时连接是未连接,因为我刚刚将es服务停了,现在需要配置几个东西。

  • 修改配置

    • 原因:es和head属于两个进程,其之间的访问具备跨域问题,所以需要配置修改

    • 进入elasticsearch-5.5.2 修改 yml

      img

      es5.png

  • 添加最后两行

  • 启动 加 -d参数 ./bin/elasticsearch -d 后台启动

  • 重新启动headcd elasticsearch-head-masternpm run start

  • 刷新浏览器,连接状态green

三、ES Restful API基本使用:

ES为开发者提供了非常丰富的基于HTTP协议的Rest API,只需要向ES服务端发送简单的Rest请求,就可以实现非常强大的功能。本篇文章主要介绍ES中常用操作的Rest API的使用,同时会讲解ES的源代码工程中的API接口文档,通过了解这个API文档的接口描述结构,就基本上可以实现ES中的绝大部分功能。

注意:查询是ES的核心。作为一个先进的搜索引擎,ES中提供了多种查询接口。本篇仅仅会涉及查询API的结构,而具体如何使用ES所提供的各种查询API,会在接下来的博文中做详细介绍。

1、基础知识

如果之前没有用过类似于ES这样的索引数据库(暂且将ES归为数据库类,与传统的数据库有较大的区别),要理解本篇博文介绍的API是有些难度的。本节先介绍一些基础知识,对理解全文有很帮助。

2、Rest介绍

笔者在学习软件开发过程中,多次听到过Rest Http这个概念,但在很长的一段时间里,死活搞不懂这玩意到底是个什么东西。刚开始看相关资料时,看得云里雾里,完全不知所云 _。这玩意太过于抽象和理论,心里觉得有必要搞这么复杂么。随着自己动手开发的东西越来越多,才开始对它有了一丢丢感觉。

Rest完全不是三言两语就能将清楚的,它有自己的一套体系,所以笔者打算以后单独写一些有关Rest的博文。在这里推荐一篇优秀的文章,它对Rest讲的相当清楚,本人看完之后真有醍醐灌顶的感觉!

3、Mapping详解

Mapping是ES中的一个很重要的内容,它类似于传统关系型数据中table的schema,用于定义一个索引(index)的某个类型(type)的数据的结构。

在传统关系型数据库,我们必须首先创建table并同时定义其schema,如下面的SQL语句。下面代码中小括号内的代码的作用就是定义person_info的schema(模式)。

create table person_info
(
  name varchar(20),
  age tinyint
)

 

在ES中,我们无需手动创建type(相当于table)和mapping(相关与schema)。在默认配置下,ES可以根据插入的数据自动地创建type及其mapping。在下面的API介绍部分中,会做相关的试验。当然,在实际使用过程中我们可能就想硬性规定mapping,可以通过配置文件关闭ES的自动创建mapping功能。

mapping中主要包括字段名、字段数据类型和字段索引类型这3个方面的定义。

字段名:这就不用说了,与传统数据库字段名作用一样,就是给字段起个唯一的名字,好让系统和用户能识别。

字段数据类型:定义该字段保存的数据的类型,不符合数据类型定义的数据不能保存到ES中。下表列出的是ES中所支持的数据类型。(大类是对所有类型的一种归类,小类是实际使用的类型。)

大类包含的小类
String string
Whole number byte, short, integer, long
Floating point float, double
Boolean boolean
Date date

字段索引类型:索引是ES中的核心,ES之所以能够实现实时搜索,完全归功于Lucene这个优秀的Java开源索引。在传统数据库中,如果字段上建立索引,我们仍然能够以它作为查询条件进行查询,只不过查询速度慢点。而在ES中,字段如果不建立索引,则就不能以这个字段作为查询条件来搜索。也就是说,不建立索引的字段仅仅能起到数据载体的作用。string类型的数据肯定是日常使用得最多的数据类型,下面介绍mapping中string类型字段可以配置的索引类型。

索引类型解释
analyzed 首先分析这个字符串,然后再建立索引。换言之,以全文形式索引此字段。
not_analyzed 索引这个字段,使之可以被搜索,但是索引内容和指定值一样。不分析此字段。
no 不索引这个字段。这个字段不能被搜索到。

如果索引类型设置为analyzed,在表示ES会先对这个字段进行分析(一般来说,就是自然语言中的分词),ES内置了不少分析器(analyser),如果觉得它们对中文的支持不好,也可以使用第三方分析器。由于笔者在实际项目中仅仅将ES用作普通的数据查询引擎,所以并没有研究过这些分析器。如果将ES当做真正的搜索引擎,那么挑选正确的分析器是至关重要的。

mapping中除了上面介绍的3个主要的内容外,还有其他的定义内容,详见官网文档

四、常用的Rest API介绍

下面介绍一下ES中的一些常用的Rest API。掌握了这些API的用法,基本上就可以简单地使用ES了。

我们需要借助能够发送HTTP请求的工具调用这些API,工具是可以任意的,包括网页浏览器。这里利用Linux上的curl命令来发送HTTP请求。基本的命令结构为:

  curl <-Xaction> url -d 'body'
 # 这里的action表示HTTP协议中的各种动作,包括GET、POST、PUT、DELETE等。

 

注意。文中的示例代码里面包含了用户注释的文字,就是 # 号后面的文字。运行代码时,请注意删除这些注释。

1、查看集群(Cluster)信息相关API

(1)查看集群健康信息。

  curl -XGET "localhost:9200/_cat/heath?v"

返回结果为:

epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks 
1440206633 18:23:53 elasticsearch green           1         1     0   0   0   0       0             0

 

返回结果的主要字段意义:

  • cluster:集群名,是在ES的配置文件中配置的cluster.name的值。

  • status:集群状态。集群共有green、yellow或red中的三种状态。green代表一切正常(集群功能齐全),yellow意味着所有的数据都是可用的,但是某些复制没有被分配(集群功能齐全),red则代表因为某些原因,某些数据不可用。如果是red状态,则要引起高度注意,数据很有可能已经丢失。

  • node.total:集群中的节点数。

  • node.data:集群中的数据节点数。

  • shards:集群中总的分片数量。

  • pri:主分片数量,英文全称为private。

  • relo:复制分片总数。

  • unassign:未指定的分片数量,是应有分片数和现有的分片数的差值(包括主分片和复制分片)。

我们也可以在请求中添加help参数来查看每个操作返回结果字段的意义。

  curl -XGET "localhost:9200/_cat/heath?help"

返回结果如下:

epoch         | t,time                                   | seconds since 1970-01-01 00:00:00  
timestamp     | ts,hms,hhmmss                           | time in HH:MM:SS                  
cluster       | cl                                       | cluster name                      
status       | st                                       | health status                      
node.total   | nt,nodeTotal                             | total number of nodes              
node.data     | nd,nodeData                             | number of nodes that can store data
shards       | t,sh,shards.total,shardsTotal           | total number of shards            
pri           | p,shards.primary,shardsPrimary           | number of primary shards          
relo         | r,shards.relocating,shardsRelocating     | number of relocating nodes        
init         | i,shards.initializing,shardsInitializing | number of initializing nodes      
unassign     | u,shards.unassigned,shardsUnassigned     | number of unassigned shards        
pending_tasks | pt,pendingTasks                         | number of pending tasks  

 

确实是很好很强大。有了这个东东,就可以减少看文档的时间。ES中许多API都可以添加help参数来显示字段含义,哪些可以这么做呢?每个API都试试就知道了。

当然,如果你觉得返回的东西太多,看着眼烦,我们也可以人为地指定返回的字段。

  curl -XGET "localhost:9200/_cat/health?h=cluster,pri,relo&v"

这次的返回结果就简单很多罗。对于患有严重强迫症的患者来说,这是福音啊!

cluster       pri relo 
elasticsearch   0   0

(2)查看集群中的节点信息。

  curl -XGET "localhost:9200/_cat/nodes?v"

返回节点的详细信息如下:

host          ip            heap.percent ram.percent load node.role master name    
master.hadoop localhost           3         35 0.00 d         *     Ezekiel

 

(3)查看集群中的索引信息。

  curl -XGET "localhost:9200/_cat/indices?v"

 

返回集群中的索引信息如下:

health status index      pri rep docs.count docs.deleted store.size pri.store.size 
yellow open   index_test   5   1         0           0       575b           575b

 

更多的查看和监视ES的API参见官网文档

2、索引(Index)相关API

(1)创建一个新的索引。

curl -XPUT "localhost:9200/index_test"

如果返回下面的信息,则说明索引创建成功。如果不是,则ES会返回相应的异常信息。通常可以通过异常信息的最后一项推断出失败的原因。

{
  "acknowledged": true
}

上面的操作使用默认的配置信息创建一个索引。大多数情况下,我们想在索引创建的时候就将我们所需的mapping和其他配置确定好。下面的操作就可以在创建索引的同时,创建settings和mapping。

curl -XPUT "localhost:9200/index_test" -d ' # 注意这里的'号
{
"settings": {
  "index": {
    "number_of_replicas": "1", # 设置复制数
    "number_of_shards": "5" # 设置主分片数
  }
},
"mappings": { # 创建mapping
  "test_type": { # 在index中创建一个新的type(相当于table)
    "properties": {
      "name": { # 创建一个字段(string类型数据,使用普通索引)
        "type": "string",
        "index": "not_analyzed"
      },
      "age": {
        "type": "integer"
      }
    }
  }
}
}'

 

(2)删除一个索引。

curl -XDELETE "localhost:9200/index_test"

如果返回与创建索引同样的信息,则说明删除成功。反之,则返回相应的异常信息。

3、映射(Mapping)相关API

(1)创建索引的mapping。

curl -XPUT 'localhost:9200/index_test/_mapping/test_type' -d ' 
{
"test_type": { # 注意,这里的test_type与url上的test_type名保存一致
    "properties": {
      "name": {
        "type": "string",
        "index": "not_analyzed"
      },
      "age": {
        "type": "integer"
      }
    }
  }
}'

 

如果不想单独创建mapping,可以使用上一节的方法(创建索引时创建mappings)。

假设我们的项目中有多个环境(开发环境、测试环境等),那每一个环境的mapping总要一致的吧,那每次创建一次mappings就比较麻烦了,而且还容易导致数据不一致。莫急,ES还给我们准备另外一种创建mapping的方式。可以按照下面的步骤来做。

步骤1 创建一个扩展名为test_type.json的文件名,其中type_test就是mapping所对应的type名。

步骤2 在test_type.json中输入mapping信息。假设你的mapping如下:

{
 "test_type": { # 注意,这里的test_type与json文件名必须一致
     "properties": {
       "name": {
         "type": "string",
         "index": "not_analyzed"
      },
       "age": {
         "type": "integer"
      }
    }
  }
}

 

步骤3 在$ES_HOME/config/路径下创建mappings/index_test子目录,这里的index_test目录名必须与我们要建立的索引名一致。将test_type.json文件拷贝到index_tes目录下。

步骤4 创建index_test索引。操作如下:

curl -XPUT "localhost:9200/index_test" # 注意,这里的索引名必须与mappings下新建的index_test目录名一致

这样我们就创建了一个新的索引,并且使用了test_type.json所定义的mapping作为索引的mapping。就是这么简单方便!

(2)删除mapping。

curl -XDELETE 'localhost:9200/index_test/_mapping/test_type'

(3)查看索引的mapping。

curl -XGET 'localhost:9200/index_test/_mapping/test_type'
4、文档(document)相关API

(1)新增一个文档。

curl -XPUT 'localhost:9200/index_test/test_type/1?pretty' -d ' # 这里的pretty参数的作用是使得返回的json显示地更加好看。1是文档的id值(唯一键)。
{
   "name": "zhangsan",
   "age" : "12"
}'

 

(2)更新一个文档

curl -XPOST 'localhost:9200/index_test/test_type/1?pretty' -d ' # 这里的1必须是索引中已经存在id,否则就会变成新增文档操作
{
   "name": "lisi",
   "age" : "12"
}'

 

(3)删除一个文档

curl -XDELETE 'localhost:9200/index_test/test_type/1?pretty' # 这里的1必须是索引中已经存在id

 

(4)查询单个文档

curl -XGET 'localhost:9200/index_test/test_type/1?pretty'

 

上面的操作仅仅查询id为1的一条文档,这样看似乎ES的查询也太弱了。前面已经说过了,查询操作是ES中的核心,是其立身的根本。但是本文的重点并不在这里,为了防止文章的篇幅过长,之后将专本介绍ES中的查询操作。

5、源代码中提供的Rest API文档结构

ES的源代码托管在Github上。将源代码下载下来之后,里面有一个文件夹专门存放ES中绝大部分的Rest API。有了这些文档,就不必每次都要到官网上查询接口文档了(PS:ES的官网真的很慢)。 下面以cat.health.json文件为例简单地介绍这些Rest API文档的结构。一旦结构搞清楚了,文档看起来就比较顺心,ES用起来就更加得心应手了!

{
"cat.health": {
  "documentation": "http://www.elastic.co/guide/en/elasticsearch/reference/master/cat-health.html", # 该文档对应的官方站点
  "methods": ["GET"],
  "url": { # url部分可选
    "path": "/_cat/health",  
    "paths": ["/_cat/health"],
    "parts": {
    },
    "params": {
      "local": {
        "type" : "boolean",
        "description" : "Return local information, do not retrieve the state from master node (default: false)"
      },
      "master_timeout": {
        "type" : "time",
        "description" : "Explicit operation timeout for connection to master node"
      },
      "h": {
          "type": "list",
          "description" : "Comma-separated list of column names to display"
      },
      "help": {
        "type": "boolean",
        "description": "Return help information",
        "default": false
      },
      "ts": {
        "type": "boolean",
        "description": "Set to false to disable timestamping",
        "default": true
      },
      "v": {
        "type": "boolean",
        "description": "Verbose mode. Display column headers",
        "default": true
      }
    }
  },
  "body": null
}
}

 

 

上面文档接口所对应的Reqeust操作如下:

curl -XGET "localhost:9200/_cat/health?v" -d 'body'

 

该操作命令可划分为5个部分,下面把这5个部分与文档对应起来。通过这个例子,就可以在阅读其他文档后,使用正确的操作了。

  1. 第1部分(-XGET):对应文档中methods所包含的GET操作。

  2. 第2部分(localhost:9200):是ES服务端所在主机的hostname和port。

  3. 第3部分(/_cat/health):对应文档中的url。其中path是最简单的url;paths是除了path之外的其他url;parts描述和解释paths里面的url的可变部分(通常用{}包裹,如{index})。

  4. 第4部分v:表示参数,对应文档中的params。像“v”这种boolean类型的参数,不需要特意指定其布尔值(true或者false),出现即表示true,否则为false。

  5. 第5部分body:表示要传递的数据主体,对应文档中的body。如果body里面指明“required=true”,则表示必须传入body数据。具体body里面需要传怎样的数据,则可以访问文档中的documentation字段所指明的官方站点进行查询。

第二章、ElasticSearch实战

一、 Elasticsearch史上最全最常用工具清单

1、题记 工欲善其事必先利其器,ELK Stack的学习和实战更是如此,特将工作中用到的“高效”工具分享给大家。

希望能借助“工具”提高开发、运维效率!

2、工具分类概览 2.1 基础类工具 1、Head插件

1)功能概述:

ES集群状态查看、索引数据查看、ES DSL实现(增、删、改、查操作) 比较实用的地方:json串的格式化

这里写图片描述

2)地址:http://mobz.github.io/elasticsearch-head/

2、Kibana工具

除了支持各种数据的可视化之外,最重要的是:支持Dev Tool进行RESTFUL API增删改查操作。 ——比Postman工具和curl都方便很多。

这里写图片描述

地址:https://www.elastic.co/products/kibana

3、ElasticHD工具

强势功能——支持sql转DSL,不要完全依赖,可以借鉴用。

这里写图片描述

地址:https://github.com/360EntSecGroup-Skylar/ElasticHD

2.2 集群监控工具 4、cerebro工具

这里写图片描述

地址:https://github.com/lmenezes/cerebro

5、Elaticsearch-HQ工具

image

管理elasticsearch集群以及通过web界面来进行查询操作

地址:https://github.com/royrusso/elasticsearch-HQ

2.3 集群迁移工具 6、Elasticsearch-migration工具

支持多个版本间的数据迁移,使用scroll+bulk

地址:https://github.com/medcl/elasticsearch-migration

7、Elasticsearch-Exporter

将ES中的数据向其他导出的简单脚本实现。

地址:https://github.com/mallocator/Elasticsearch-Exporter

8、Elasticsearch-dump

移动和保存索引的工具。

地址:https://github.com/taskrabbit/elasticsearch-dump

2.4 集群数据处理工具 9、elasticsearch-curator

elasticsearch官方工具,能实现诸如数据只保留前七天的数据的功能。

地址: https://pypi.python.org/pypi/elasticsearch-curator

另外 ES6.3(还未上线) 有一个 Index LifeCycle Management 可以很方便的管理索引的保存期限。

2.5 安全类工具 10、x-pack工具

image

地址:https://www.elastic.co/downloads/x-pack

11、search-guard 第三方工具

Search Guard 是 Elasticsearch 的安全插件。它为后端系统(如LDAP或Kerberos)提供身份验证和授权,并向Elasticsearch添加审核日志记录和文档/字段级安全性。

Search Guard所有基本安全功能(非全部)都是免费的,并且内置在Search Guard中。 Search Guard支持OpenSSL并与Kibana和logstash配合使用。

地址:https://github.com/floragunncom/search-guard

2.6 可视化类工具 12、grafana工具

这里写图片描述

地址:https://grafana.com/grafana

grafana工具与kibana可视化的区别:

如果你的业务线数据较少且单一,可以用kibana做出很棒很直观的数据分析。 而如果你的数据源很多并且业务线也多,建议使用grafana,可以减少你的工作量

对比: https://www.zhihu.com/question/54388690 2.7 自动化运维工具 elasticsearch免费的自动化运维工具

13、Ansible

https://github.com/elastic/ansible-elasticsearch

14、Puppet

https://github.com/elastic/puppet-elasticsearch

15、Cookbook

https://github.com/elastic/cookbook-elasticsearch

以上三个工具来自medcl大神社区问题的回复,我没有实践过三个工具。

2.8 类SQl查询工具 16、Elasticsearch-sql 工具

sql 一款国人NLP-china团队写的通过类似sql语法进行查询的工具

地址:https://github.com/NLPchina/elasticsearch-sql

ES6.3+以后的新版本会集成sql。

2.9 增强类工具 17、Conveyor 工具

kibna插件——图形化数据导入工具

地址:http://t.cn/REOhwGT

18、kibana_markdown_doc_view 工具

Kibana文档查看强化插件,以markdown格式展示文档

地址:http://t.cn/REOhKgB

19、 indices_view工具

indices_view 是新蛋网开源的一个 kibana APP 插件项目,可以安装在 kibana 中,快速、高效、便捷的查看elasticsearch 中 indices 相关信息

地址:https://gitee.com/newegg/indices_view

20、dremio 工具

image

image

  • 支持sql转DSL,

  • 支持elasticsearch、mysql、oracle、mongo、csv等多种格式可视化处理;

  • 支持ES多表的Join操作

地址:https://www.dremio.com/

2.10 报警类 1、elastalert ElastAlert 是 Yelp 公司开源的一套用 Python2.6 写的报警框架。属于后来 Elastic.co 公司出品的 Watcher 同类产品。官网地址见:http://elastalert.readthedocs.org/

使用举例:当我们把ELK搭建好、病顺利的收集到日志,但是日志里发生了什么事,我们并不能第一时间知道日志里到底发生了什么,运维需要第一时间知道日志发生了什么事,所以就有了ElastAlert的邮件报警。

2、sentinl SENTINL 6扩展了Siren Investigate和Kibana的警报和报告功能,使用标准查询,可编程验证器和各种可配置操作来监控,通知和报告数据系列更改 - 将其视为一个独立的“Watcher” “报告”功能(支持PNG / PDF快照)。

SENTINL还旨在简化在Siren Investigate / Kibana 6.x中通过其本地应用程序界面创建和管理警报和报告的过程,或通过在Kibana 6.x +中使用本地监视工具来创建和管理警报和报告的过程。

二、索引

1、Elasticsearch(ES)创建索引

欢迎关注博主公众号“小哈学Java”,专注于分享Java领域干货文章,关注回复“资源”,免费领取全网最热的Java架构师学习PDF,转载请注明出处https:// www .exception.site / elasticsearch / elasticsearch-create-index

一,开始创建索引

您可以通过Elasticsearch的RESTFul API来创建索引:

PUT http://127.0.0.1:9200/commodity

注意:最小情况下,创建的索引分片数量是5个,副本数量是1个。

您可以通过以下参数来指定分片数,副本数量:

{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
}
}

1.1实战演示

通过CURL命令来上手操作一下,我们尝试创建一个商品索引,看下效果:

curl -X PUT "localhost:9200/commodity?pretty"

索引创建成功会返回以下出参:

{
 "acknowledged" : true,
 "shards_acknowledged" : true,
 "index" : "commodity"
}

如下图所示:

img

二,创建带有类型,映射的索引

其实,我们可以在创建索引的时候,同时将索引的类型,以及映射一并创建好:

curl -X PUT "localhost:9200/commodity?pretty"

入参:

{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 2
},
"mapping": {
"_doc": {
"properties": {
"commodity_id": {
"type": "long"
},
"commodity_name": {
"type": "text"
},
"picture_url": {
"type": "keyword"
},
"price": {
"type": "double"
}
}
}
}
}

我们创建了一个分片数为3,副本数为2的索引,同时,定义了一个_doc的类型,里面包含了4个段落,类型各不相同。

接下来,我们用Postman工具来一次性创建带有类型,映射的索引(索引):

img

这里应为笔者通过CURL创建索引,由于带入参,出现了格式错误的问题,改用了Postman工具,效果相同。

三,修改索引的副本数

我们可以通过如下API来修改索引的副本数:

PUT http://127.0.0.1:9200/commodity/_settings

入参:

{
"number_of_replicas": 3
}

我们将commodity索引副本数更新为了3:

img

2、Elasticsearch(ES)删除索引

欢迎关注博主公众号“小哈学Java”,专注于分享Java领域干货文章,关注回复“资源”,免费领取全网最热的Java架构师学习PDF,转载请注明出处https:// www .exception.site / elasticsearch / elasticsearch-delete-index

一,开始删除索引

通过如下Elasticserach API来删除索引:

PUT http://127.0.0.1:9200/commodity

如上示例,删除了名称为commodity的索引。另外指定名称删除外,我们还可以通过索引别名或通配符来删除。

注意:要谨慎使用_all*去删除全部索引。

生产环境中,为了防止索引被误删,我们可以将elasticsearch.yml配置文件中的action.destructive_requires_name配置项设置为true,以达到强制使用索引名,别名才能删除索引的效果。

二,实战操作

接下来,我们通过CURL命令来删除commodity索引:

curl -X DELETE "localhost:9200/commodity?pretty"

img

3、Elasticsearch(ES) 获取索引信息
一、通过具体索引名称来获取索引信息

通过 Elasticsearch 提供的接口,我们可以获取一个或多个索引信息。

GET http://127.0.0.1:9200/commodity

这里,我们用 CURL 命令来演示一下,来获取 commodity 索引的具体信息:

curl -X GET http://127.0.0.1:9200/commodity?pretty

效果如下:

img

如图所示,结果中包含了索引的映射信息,以及一些配置信息。

注意:若索引中是空的,也就是没有一条文档的话,映射(mapping)信息将是空的。

二、通过通配符来获取索引信息

除了上面说到的,通过具体索引名称来获取索引信息外,我们还可以通过别名通配符来获取。

通过通配符来或者 _all* 来多个索引的信息。

三、添加筛选条件来获取索引信息

我们可以在 URL 中指定筛选条件,只获取自己想要的信息,比如只想要 commodity 索引的映射信息,操作如下:

GET http://127.0.0.1:9200/commodity/_mappings

通过 CURL 命令来演示下:

curl -X GET http://127.0.0.1:9200/commodity/_mappings?pretty

img

可以看到,只返回了索引的映射信息。

如果你只想获取索引的配置信息,通过如下接口即可:

GET http://127.0.0.1:9200/commodity/_settings

img

4、Elasticsearch(ES) 打开/关闭索引

什么是 Elasticsearch 打开/关闭索引? 先说说什么是关闭索引?一旦索引被关闭,那么这个索引只能显示元数据信息,不能够进行读写操作。

再说说打开索引就好理解了。就是打开被关闭的索引,允许进行读写操作。

通过 /{索引名}/_close 关闭索引
通过 /{索引名}/_open 打开索引
一、关闭索引

比如说,我们想关闭 commodity 索引:

POST http://127.0.0.1:9200/commodity/_close

CURL 命令如下:

curl -X POST http://127.0.0.1:9200/commodity/_close?pretty

img

索引已经被关闭成功,这个时候,我们再向 commodity 添加一条文档信息,看看结果如何:

img

可以看到,返回了一个索引已被关闭的异常,文档无法被正常创建。

二、打开索引

通过如下请求,我们可以打开一个被关闭的索引:

POST http://127.0.0.1:9200/commodity/_open

接下来,我们通过 CURL 命令来打开刚刚被关闭的 commodity 索引:

curl -X POST http://127.0.0.1:9200/commodity/_open?pretty

img

文档被打开成功后,我们就可以愉快的对索引进行读写操作了。

三、映射、

1、Elasticsearch(ES) 添加/更新映射

通过 Elasticsearch API 可以向索引(Index) 添加文档类型(Type), 或者向文档类型(Type) 中添加/更新字段(Field)。

PUT http://127.0.0.1:9200/commodity

入参:

{
"mappings": {
"_doc": {
"properties": {
"commodity_id": {
"type": "long"
},
"commodity_name": {
"type": "text"
},
"picture_url": {
"type": "keyword"
}
}
}
}
}

接下来,通过 Postman 工具来实际操作一下:

img

通过上面 API, 我们创建了一个名称为 commodity(商品) 的索引,类型为_doc, 且包含了三个字段(field), 分别为 commodity_id(商品id)、commodity_name (商品名称)、picture_url(商品图片)。

一、向已存在的类型中添加字段

commodity 索引创建成功后,我们还可以向其中添加新的字段,下面添加一个 price(价格)字段:

PUT http://127.0.0.1:9200/commodity/_mapping/_doc

入参:

{
"properties": {
"price": {
"type": "double"
}
}
}

用 Postman 工具演示一下:

img

二、同时向多个索引设置映射

Elasticsearch 允许同时向多个索引添加文档类型。

PUT http://127.0.0.1:9200/{index}/_mapping/{type}

{body}
  • {index}

    : 索引可以有多种指定方式:

    • 逗号分隔符,比如: comodity1,commodity2

    • _all: 表示所有索引;

    • commodity*:表示以 commodity 为前缀的所有索引;

  • {type}: 需要添加或更新的文档类型;

  • {body}:需要添加的字段或字段类型;

接下来,我们测试一下,先创建两个未设置映射的空索引 commodity1commodity2:

PUT http://127.0.0.1:9200/commodity1
PUT http://127.0.0.1:9200/commodity1

然后向这两个索引同时添加映射:

PUT http://localhost:9200/commodity1,commodity2/_mapping/_doc

入参:

{
"properties": {
"commodity_id": {
"type": "long"
},
"commodity_name": {
"type": "text"
},
"picture_url": {
"type": "keyword"
}
}
}

使用 Postman 执行请求:

img

设置映射信息成功!

2、Elasticsearch(ES)获取映射信息

Elasticsearch(ES)允许我们通过索引,或者是索引联合类型来获取映射信息:

GET http://127.0.0.1:9200/commodity/_mapping/_doc

img

我们还可以一次性获取多个索引或文档的映射信息。接口形式通常如下:

GET http://127.0.0.1:9200/{index}/_mapping/{type}

{index}{type}均可以指定多个,中间用,分隔,另外,我们也可以使用_all表示全部索引,示例如下:

GET http://127.0.0.1:9200/_mapping/_doc1,_doc2
GET http://127.0.0.1:9200/_all/_mapping/_doc1,_doc2

第二个带有_all,第一个没有,但是它们是等价的,均表示获取全部索引。

三、更新字段映射

一些情况下,我们需要对某个索引当前类型进行更新,比如:

  • 添加一个新的字段;

  • 更改原有的某个字段;

  • 禁用 doc_values(默认情况是开启的);

  • 添加 ignore_above 参数;

  • ...

Note:关于 ignore_above 参数,若字段长度超过指定的值,则该字段不会被索引起来,也就是说查询不到。

接下来,为了演示,我们先删除之前 commodity 索引,重新建立:

PUT http://127.0.0.1:9200/commdoty

入参:

{
"mappings": {
"_doc": {
"properties": {
"commodity_id": {
"type": "long"
},
"commodity_name": {
"properties": {
"first": {"type": "text"}
}
},
"picture_url": {
"type": "keyword"
}
}
}
}
}

需要注意,commodity_name 字段是一个对象数据类型(Object datatype)。

对象类型指的是,这个字段是个对象,它里面还可以存储多个属性字段。

接着,索引映射新建成功后,我们尝试去更新:

PUT http://127.0.0.1:9200/commdoty/_mapping/_doc

入参:

{
"properties": {
"commodity_id": {
"type": "long"
},
"commodity_name": {
"properties": {
"last": {
"type": "text"
}
}
},
"picture_url": {
"type": "keyword",
"ignore_above": 500
}
}
}

上述请求中,我们对 commodity_name 对象数据类型增加了一个 last 属性,并且修改了 picture_url 字段,将 ignore_above设置成了 500。

img

 

四、搜寻

1、Elasticsearch(ES)查询指定返回细分

Elasticsearch(ES)API允许在查询时指定返回细分,也就是仅返回部分细分。

按需索取,能够提高Elasticsearch的响应速度。

一,仅显示部分分段

入参格式,如下:

{
 "_source": [
   "commodity_id",
   "commodity_name"
],
 "query": {
   "query_string": {
     "query": "荣耀"
  }
}
}

通过_source细分来指定需要返回的细分,此处我们仅显示commodity_idcommodity_name细分。

通过HEAD插件,看下实际效果:

img

二,不显示原始基线

_source设置为false,可以不显示原始细分,部分特殊场景下会用到。

{
 "_source": false,
 "query": {
   "query_string": {
     "query": "荣耀"
  }
}
}

img

三,包含或排除某些长度

我们可以同时指定需要显示的细分的,和需要排除显示的细分:

{
 "_source": {
   "include": [
     "commodity_id",
     "commodity_name"
  ],
   "exclude": [
     "picture_url"
  ]
},
 "query": {
   "query_string": {
     "query": "双卡"
  }
}
}

上面这段入参,就指定了只需要显示commodity_idcommodity_name,排除掉picture_url

img

五、ElasticSearch精通

1、Elasticsearch的特点

1)可以作为一个大型分布式集群(数百台服务器)技术,处理PB级数据,服务大公司;也可以运行在单机上,服务小公司 2)Elasticsearch不是什么新技术,主要是将全文检索、数据分析以及分布式技术,合并在了一起,才形成了独一无二的ES;lucene(全文检索),商用的数据分析软件(也是有的),分布式数据库(mycat) 3)对用户而言,是开箱即用的,非常简单,作为中小型的应用,直接3分钟部署一下ES,就可以作为生产环境的系统来使用了,数据量不大,操作不是太复杂 4)数据库的功能面对很多领域是不够用的(事务,还有各种联机事务型的操作);特殊的功能,比如全文检索,同义词处理,相关度排名,复杂数据分析,海量数据的近实时处理;Elasticsearch作为传统数据库的一个补充,提供了数据库所不能提供的很多功能

什么是搜索? 1)百度,谷歌,必应。我们可以通过他们去搜索我们需要的东西。但是我们的搜索不只是包含这些,还有京东站内搜索啊。

2)互联网的搜索:电商网站。招聘网站。新闻网站。各种APP(百度外卖,美团等等)

3)windows系统的搜索,OA软件,淘宝SSM网站,前后台的搜索功能

总结:搜索无处不在。通过一些关键字,给我们查询出来跟这些关键字相关的信息 什么是全文检索 全文检索是指计算机索引程序通过扫描文章中的每一个词,对每一个词建立一个索引,指明该词在文章中出现的次数和位置,当用户查询时,检索程序就根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。

全文检索的方法主要分为按字检索和按词检索两种。按字检索是指对于文章中的每一个字都建立索引,检索时将词分解为字的组合。对于各种不同的语言而言,字有不同的含义,比如英文中字与词实际上是合一的,而中文中字与词有很大分别。按词检索指对文章中的词,即语义单位建立索引,检索时按词检索,并且可以处理同义项等。英文等西方文字由于按照空白切分词,因此实现上与按字处理类似,添加同义处理也很容易。中文等东方文字则需要切分字词,以达到按词索引的目的,关于这方面的问题,是当前全文检索技术尤其是中文全文检索技术中的难点,在此不做详述。 什么是倒排索引 以前是根据ID查内容,倒排索引之后是根据内容查ID,然后再拿着ID去查询出来真正需要的东西。

img

image.png

什么是Lucene Lucene就是一个jar包,里面包含了各种建立倒排索引的方法,java开发的时候只需要导入这个jar包就可以开发了。Lucene的介绍及使用 典型的用空间换时间。ES 和 Lucene的区别 Lucene不是分布式的。

ES的底层就是Lucene,ES是分布式的 为什么不用数据库去实现搜索功能? 我们用搜索“牙膏”商品为例

img

image.png

如果用我们平时数据库来实现搜索的功能在性能上就很差。ES的由来 因为Lucene有两个难以解决的问题,

1)数据越大,存不下来,那我就需要多台服务器存数据,那么我的Lucene不支持分布式的,那就需要安装多个Lucene然后通过代码来合并搜索结果。这样很不好

2)数据要考虑安全性,一台服务器挂了,那么上面的数据不就消失了。

ES就是分布式的集群,每一个节点其实就是Lucene,当用户搜索的时候,会随机挑一台,然后这台机器自己知道数据在哪,不用我们管这些底层、

img

image.png

ES的优点 1.分布式的功能

2、数据高可用,集群高可用

3.API更简单

4.API更高级。

5.支持的语言很多

6.支持PB级别的数据

7.完成搜索的功能和分析功能

基于Lucene,隐藏了Lucene的复杂性,提供简单的API

ES的性能比HBase高,咱们的竞价引擎最后还是要存到ES中的。 搜索引擎原理 反向索引又叫倒排索引,是根据文章内容中的关键字建立索引。 搜索引擎原理就是建立反向索引。 Elasticsearch 在 Lucene 的基础上进行封装,实现了分布式搜索引擎。 Elasticsearch 中的索引、类型和文档的概念比较重要,类似于 MySQL 中的数据库、表和行。 Elasticsearch 也是 Master-slave 架构,也实现了数据的分片和备份。 Elasticsearch 一个典型应用就是 ELK 日志分析系统。 ES的作用 1)全文检索:

类似 select * from product where product_name like '%牙膏%'

类似百度效果(电商搜索的效果)

2)结构化搜索:

类似 select * from product where product_id = '1'

3)数据分析

类似 select count (*) from product ES的安装 参考https://www.jianshu.com/p/198a874cc14f 直接解压就能用(针对中小型项目),大型项目还是要调一调参数的

2.用数据库实现搜素的功能

img

image.png

3.ES的核心概念

3.1 NRT(Near Realtime)近实时

 

img

image.png

 

3.2 cluster集群,ES是一个分布式的系统 ES直接解压不需要配置就可以使用,在hadoop1上解压一个ES,在hadoop2上解压了一个ES,接下来把这两个ES启动起来。他们就构成了一个集群。

在ES里面默认有一个配置,clustername 默认值就是ElasticSearch,如果这个值是一样的就属于同一个集群,不一样的值就是不一样的集群。

3.3 Node节点,就是集群中的一台服务器 3.4 Index(索引-数据库) 我们为什么使用ES?因为想把数据存进去,然后再查询出来。

我们在使用Mysql或者Oracle的时候,为了区分数据,我们会建立不同的数据库,库下面还有表的。

其实ES功能就像一个关系型数据库,在这个数据库我们可以往里面添加数据,查询数据。

ES中的索引非传统索引的含义,ES中的索引是存放数据的地方,是ES中的一个概念词汇

index类似于我们Mysql里面的一个数据库 create database user; 好比就是一个索引库

3.5 Type(类型-表) ES6以后一个index只能有一个type,为了提高查询效率。

3.6 Document(文档-行) 文档就是最终的数据了,可以认为一个文档就是一条记录。

是ES里面最小的数据单元,就好比表里面的一条数据

3.7 Field(字段-列) 好比关系型数据库中列的概念,一个document有一个或者多个field组成。

3.8 mapping(映射-约束) 数据如何存放到索引对象上,需要有一个映射配置,包括:数据类型、是否存储、是否分词等。

1、elasticsearch与数据库的类比
关系型数据库(比如Mysql)非关系型数据库(Elasticsearch)
数据库Database 索引Index
表Table 类型Type
数据行Row 文档Document
数据列Column 字段Field
约束 Schema 映射Mapping

3.9 shard:分片 一台服务器,无法存储大量的数据,ES把一个index里面的数据,分为多个shard,分布式的存储在各个服务器上面。

kafka:为什么支持分布式的功能,因为里面是有topic,支持分区的概念。所以topic A可以存在不同的节点上面。就可以支持海量数据和高并发,提升性能和吞吐量

3.10 replica:副本 一个分布式的集群,难免会有一台或者多台服务器宕机,如果我们没有副本这个概念。就会造成我们的shard发生故障,无法提供正常服务。

我们为了保证数据的安全,我们引入了replica的概念,跟hdfs里面的概念是一个意思。

可以保证我们数据的安全。

在ES集群中,我们一模一样的数据有多份,能正常提供查询和插入的分片我们叫做 primary shard,其余的我们就管他们叫做 replica shard(备份的分片)

当我们去查询数据的时候,我们数据是有备份的,它会同时发出命令让我们有数据的机器去查询结果,最后谁的查询结果快,我们就要谁的数据(这个不需要我们去控制,它内部就自己控制了)

2、总结:

在默认情况下,我们创建一个库的时候,默认会帮我们创建5个主分片(primary shrad)和5个副分片(replica shard),所以说正常情况下是有10个分片的。

同一个节点上面,副本和主分片是一定不会在一台机器上面的,就是拥有相同数据的分片,是不会在同一个节点上面的。

所以当你有一个节点的时候,这个分片是不会把副本存在这仅有的一个节点上的,当你新加入了一台节点,ES会自动的给你在新机器上创建一个之前分片的副本。

 

img

image.png

 

3.11 举例

比如一首诗,有诗题、作者、朝代、字数、诗内容等字段,那么首先,我们可以建立一个名叫 Poems 的索引,然后创建一个名叫 Poem 的类型,类型是通过 Mapping 来定义每个字段的类型。

比如诗题、作者、朝代都是 Keyword 类型,诗内容是 Text 类型,而字数是 Integer 类型,最后就是把数据组织成 Json 格式存放进去了。

img

image.png

Keyword 类型是不会分词的,直接根据字符串内容建立反向索引,Text 类型在存入 Elasticsearch 的时候,会先分词,然后根据分词后的内容建立反向索引。

img

image.png

 

4. ES集群的安装

以后补充

5. 安装 Kibana

https://www.jianshu.com/p/198a874cc14f

6. ES的相关命令

GET _cat/health 查看集群的健康状况

GET _all

PUT 类似于SQL中的增

DELETE 类似于SQL中的删

POST 类似于SQL中的改

GET 类似于SQL中的查

index的操作:

PUT /aura_index 增加一个aura_index的index库

 

img

image.png

 

GET _cat/indices 命令查询ES中所有的index索引库

 

img

image.png

5:代表的是 primary shard的个数

DELETE /aura_index 删除一个aura_index的index库

 

img

image.png

7. ES的CURD操作

通过演示一个电商的例子,感受到ES的语法特点

1)插入一条商品数据

 

img

image.png

 

注意:我们插入数据的时候,如果我们的语句中指明了index和type,如果ES里面不存在,默认帮我们自动创建

2)查询商品数据 使用这种语法: GET /index/type/id

 

img

image.png

 

3)修改商品数据

使用POST来修改数据,其实使用PUT也可以实现修改数据,原理和hbase比较像。POST的修改数据的方法在第4条中

 

img

image.png

 

img

image.png

 

换个方式,下面这种操作也是成功的,会丢数据,是全局的修改

 

img

image.png

 

img

image.png

4)删除商品数据

img

image.png

 

再次插入之前的数据,发现version是5,这就说明跟hbase是类似的,不会立刻删除,会在合适的时机进行删除。

 

img

image.png

这次我们使用POST的方式进行修改数据,POST是局部更新数据,别的数据不动。PUT是全局更新

img

image.png

 

img

image.png

5)接着插入两条数据

img

image.png

 

img

image.png

现在查看所有数据,类似于全表扫描

img

image.png

took:耗费了6毫秒

hits:获取到的数据的情况

total:3 总的数据条数

max_score:1 所有数据里面打分最高的分数

_index:"ecommerce" index名称

_type:"product" type的名称

_id:"2" id号

_score:1 分数,这个分数越大越靠前出来,百度也是这样。除非是花钱。否则匹配度越高越靠前

 

img

image.png

 

img

image.png

8.DSL语言

ES最主要是用来做搜索和分析的。所以DSL还是对于ES很重要的

下面我们写的代码都是RESTful风格

query DSL:domain Specialed Lanaguage 在特定领域的语言

案例:我们要进行全表扫描使用DSL语言,查询所有的商品

 

img

image.png

 

使用match_all 可以查询到所有文档,是没有查询条件下的默认语句。

案例:查询所有名称里面包含chenyi的商品,同时按价格进行降序排序

如上图所示,name为dior chenyi的数据会在ES中进行倒排索引分词的操作,这样的数据也会被查询出来。

 

img

image.png

 

match查询是一个标准查询,不管你需要全文本查询还是精确查询基本上都要用到它。

下面我们按照价格进行排序:因为不属于查询的范围了。所以要写一个 逗号

 

img

image.png

 

这样我们的排序就完成了

案例:实现分页查询

条件:根据查询结果(包含chenyi的商品),再进行每页展示2个商品

 

img

image.png

 

案例:进行全表扫面,但返回指定字段的数据

现在的情况是把所有的数据都返回了,但是我们想返回指定字段的数据内容就需要下面的方法了

 

img

image.png

 

案例:搜索名称里面包含chenyi的,并且价格大于250元的商品

相当于 select * form product where name like %chenyi% and price >250;

因为有两个查询条件,我们就需要使用下面的查询方式

如果需要多个查询条件拼接在一起就需要使用bool

bool 过滤可以用来合并多个过滤条件查询结果的布尔逻辑,它包含以下操作符:

 

must :: 多个查询条件的完全匹配,相当于 and。

must_not :: 多个查询条件的相反匹配,相当于 not。

should :: 至少有一个查询条件匹配, 相当于 or。

这些参数可以分别继承一个过滤条件或者一个过滤条件的数组

img

image.png

 

案例:展示一个全文检索的效果

 

img

image.png

 

首先查询条件也会进行分词

kama

chenyi

并集

案例:不要把条件分词,要精确匹配

但是我们现有有一种需求我就是想查询kama chenyi不要分词,要精确匹配到

 

img

image.png

 

百度就类似于这样

案例:把查询结果进行高亮展示

 

img

image.png

 

kama这个标签是默认的标签,是可以自定义的进行替换的,比如我们可以替换成kama,把这个输出到网页上,自然而然就是红色的了。

9.聚合分析

案例:计算每个标签tag下商品的数量

按标签进行分组类似于 select count(*) from product group by tag;

 

img

image.png

 

img

image.png

 

terms 跟 term 有点类似,但 terms 允许指定多个匹配条件。 如果某个字段指定了多个值,那么文档需要一起去做匹配

error是报错,但是这个语句是对的,这个报错在ES2之前是没有的,在ES5以后才有的,在5中fielddata=true 默认是false,以前都是true

group_by_tag是个名字随意取

所以我们需要先执行下面的代码进行一下设置的修改:

 

img

image.png

 

再次执行一次

 

img

image.png

如果不想显示具体内容,加上"size":0

案例:对商品名称里面包含chenyi的,计算每个tag下商品的数量

 

img

image.png

 

案例:查询商品名称里面包含chenyi的数据,并且按照tag进行分组,计算每个分组下的平均价格

 

img

image.png

案例:查询商品名称里面包含chenyi的数据,并且按照tag进行分组,计算每个分组下的平均价格,按照平均价格进行降序排序

img

image.png

 

注意写的位置

案例:查询出producer里面包含producer的数据,按照指定的价格区间进行分组,在每个组内再按tag进行分组,分完组以后再求每个组的平均价格,并且按照降序进行排序

range过滤允许我们按照指定范围查找一批数据

 

img

image.png

 

img

image.png

10、Elasticsearch对复杂分布式机制的透明隐藏特性

1)Elasticsearch是一套分布式系统,分布式是为了应对大数据量,隐藏了复杂的分布式机制

分片机制(我们之前随随便便就将一些document插入到es集群中,我们没有关心过数据是怎么进行分片的,数据到哪个shard中去)

cluster discovery(集群发现机制,我们之前做集群status从yellow转green,直接启动第二个es进程,那个进程直接作为一个node自动就发现了集群,并且加入了进去,还接受了部分数据,replica shard)

shard负载均衡(假设现在有3个node,总共有25个shard要分配到3个节点上去,es会自动进行均匀分配,以保持每个节点的均衡的读写负载请求)

shard副本`,`请求路由`,`集群扩容`,`shard重分配

2)Elasticsearch的垂直扩容与水平扩容

垂直扩容:采购更强大的服务器,成本高昂,会有瓶颈

水平扩容:业界经常采用的方式,采购越来越多的普通服务器,性能比较一般,但是很多普通服务器组织在一起,就能构成强大的计算和存储能力。

3)增加或减少节点时的数据rebalance: 比如现在有3个节点,4个shard。这样肯定有一台节点上存储2个shard,总会有那么一台节点负荷重一点,当增加一个节点时,es集群会自动把有2个shard的节点分出一个shard给新增加的节点,保持负载均衡。

4)master节点 管理es集群的元数据:比如创建或删除index,维护索引元数据,节点的增加和删除,维护集群的元数据。

默认情况下,会自动选择出一台节点,作为master节点。

master节点不承载所有的请求,所以不会是一个单点瓶颈。

5)节点对等的分布式架构 节点对等,每个节点都能接收所有的请求

自动请求路由(如果请求要找的数据不在这台节点上,这个节点会自动把请求路由到数据所在的节点)

响应收集(数据所在节点会接收到其他节点发送的请求,并且响应回client)

11、shard&replica机制梳理

(1)index包含多个shard (2)每个shard都是一个最小工作单元,承载部分数据,lucene实例,完整的建立索引和处理请求的能力 (3)增减节点时,shard会自动在nodes中负载均衡 (4)primary shard和replica shard,每个document肯定只存在于某一个primary shard以及其对应的replica shard中,不可能存在于多个primary shard (5)replica shard是primary shard的副本,负责容错,以及承担读请求负载 (6)primary shard的数量在创建索引的时候就固定了,replica shard数量可以随时修改 (7)primary shard的默认数量是5,replica默认是1,默认有10个shard,5个primary shard,5个replica shard (8)primary shard不能和自己的replica shard放在同一个节点上(否则节点宕机,primary shard和副本全部丢失,起不到容错作用),但是可以和其他primary shard的replica shard放在同一个节点

12、单node环境下创建index是什么样子

(1)单node环境下,创建一个index,有3个primary shard,3个replica shard (2)集群status是yellow (3)这个时候,只会将3个primary shard分配到仅有的一台node上去,另外3个replica shard无法分配 (4)集群可以正常工作,但是一旦出现节点宕机,数据全部丢失,而且集群不可用,无法承载任何请求

 

PUT /test_index
{
 "settings": {
   "number_of_shards": 3,
   "number_of_replicas": 1
}
}

第三章、ElasticSearch面试

1、es 读数据过程

可以通过 doc id 来查询,会根据 doc id 进行 hash,判断出来当时把 doc id 分配到了哪个 shard 上面去,从那个 shard 去查询。

  • 客户端发送请求到任意一个 node,成为 coordinate node

  • coordinate nodedoc id 进行哈希路由,将请求转发到对应的 node,此时会使用 round-robin随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡。

  • 接收请求的 node 返回 document 给 coordinate node

  • coordinate node 返回 document 给客户端。img

  • es 读数据过程

    可以通过 doc id 来查询,会根据 doc id 进行 hash,判断出来当时把 doc id 分配到了哪个 shard 上面去,从那个 shard 去查询。

    • 客户端发送请求到任意一个 node,成为 coordinate node

    • coordinate nodedoc id 进行哈希路由,将请求转发到对应的 node,此时会使用 round-robin随机轮询算法,在 primary shard 以及其所有 replica 中随机选择一个,让读请求负载均衡。

    • 接收请求的 node 返回 document 给 coordinate node

    • coordinate node 返回 document 给客户端。

    写请求是写入 primary shard,然后同步给所有的 replica shard;读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法

 

2、写数据底层原理

1)document先写入导内存buffer中,同时写translog日志

 

2))近实时搜索

随着按段(per-segment)搜索的发展,一个新的文档从索引到可被搜索的迭代显着降低了。新文档在几分钟之内即可被检索,但这样还是不够快。

磁盘在这里成为了瓶颈提交(Commiting)一个新的段到磁盘需要一个。 fsync来确保段被物理性地写入磁盘,这样在断电的时候就不会丢失数据但是。fsync操作代价很大; 如果每次索引一个文档都去执行一次的话会造成很大的性能问题。

我们需要的是一个更轻量的方式来使一个文档可被搜索,这意味着fsync要从整个过程中被删除。

之前描述的一样,在内存索引索引(图19,“在内存磁盘中包含了新文档的Lucene索引”)中的文档会被写入到一个新的段中(图20,“快照的内容已经被写入一个可被搜索的段中,但还没有进行进行”)。但是这里新段会被先写入到文件系统缓存—此步代价会比较低,稍后再被刷新到磁盘—这一步代价比较高。不过只要文件已经在缓存中,就可以像其他文件一样被打开和读取了。

在内存缓冲区中具有新文档的Lucene索引

图19.在内存缓冲区中包含了新文档的Lucene索引

Lucene允许新段被写入和打开—-包含的文档在未进行一次完整提交时便对搜索可见。这种方式比进行一次提交代价要小得多,并且在不影响性能的方面下可以被过多地执行。

缓冲区内容已被写入可搜索但尚未提交的段

图20.犯罪的内容已经被写入一个可被搜索的段中,但还没有进行进行提交

刷新API

在Elasticsearch中,写入和打开一个新段的轻量的过程叫做刷新默认情况下每个分片会每秒自动刷新一次这就是为什么我们说Elasticsearch是。实时搜索:文档的变化并不是立即对搜索可见,但会在一秒钟之内可以看到。

这些行为可能导致新用户造成混乱:他们索引了一个文档然后尝试搜索它,却没有搜到。这个问题的解决方法是用refreshAPI执行一次手动刷新:

开机自检/ _刷新
POST / 博客/ _refresh
 刷新(Refresh)所有的索引。
  只刷新(Refresh)blogs索引。

尽管刷新是比提交轻量很多的操作,它还是会有性能消耗。当写测试的时候,手动刷新很有用,但是不要在生产环境下每次索引一个文档都去手动刷新。相反,你的应用需要考虑Elasticsearch的近实时的性质,并接受它的不足。

并非所有情况下都需要重新刷新。可能您正在使用Elasticsearch索引大量的日志文件,您可能想优化索引速度而不是近实时搜索,可以通过设置refresh_interval,减少每个索引的刷新频率:

PUT / my_logs
{ settings” :{ refresh_interval” :“ 30s”
 
     
} }
 每30秒刷新my_logs索引。
   

refresh_interval 在生产环境中,当您正在建立一个大的新索引时,可以先关闭自动刷新,待开始使用该索引时,再把它们调回来:可以在既存索引上进行动态更新。

PUT / my_logs / _settings
{ refresh_interval” - 1 }    

PUT / my_logs / _settings
{ refresh_interval” :“ 1s” }    
 关闭自动刷新。
  每秒自动刷新。

refresh_interval需要一个持续时间值,例如1s(1秒)或2m(2分钟)。一个绝对值1表示的是1毫秒 -完全可能会使您陷入瘫痪。

 

refresh操作所以近实时搜索:写入和打开一个新段(一个追加的倒排索引)的轻量的过程叫做 *refresh*每隔一秒钟把buffer中的数据创建一个新的segment,这里新段会被先写入到文件系统缓存--这一步代价会比较低,稍后再被刷新到磁盘--这一步代价比较高。不过只要文件已经在缓存中, 就可以像其它文件一样被打开和读取了,内存buffer被清空。此时,新segment 中的文件就可以被搜索了,这就意味着document从被写入到可以被搜索需要一秒种,如果要更改这个属性,可以执行以下操作

 

PUT /my_index { "settings": { "refresh_interval": "30s" } } 3)持久化变化

如果没有用fsync把数据从文件系统缓存刷到(刷新)到硬盘,我们不能保证数据在断电甚至是程序正常退出之后依然存在。为了保证Elasticsearch的可靠性,需要确保数据变化被持久化到磁盘。

动态更新索引,我们说一次完整的提交提交段刷到磁盘,并写入一个包含所有段列表的提交点。Elasticsearch在启动或重新打开一个索引的过程中使用这个提交点来估计其中段所属属于当前分片。

即使通过每秒刷新(refresh)实现了近实时搜索,我们仍然需要经常进行完整提交来确保能从失败中恢复。但在两次提交之间发生变化的文档怎么办?我们也不希望丢失掉这些数据。

Elasticsearch增加了一个translog,或者每一次对Elasticsearch进行操作时均进行了日志记录。通过translog,整个流程看起来是下面这样:

  1. 一个文档被索引之后,就会被添加到内存缓冲区,并且追加到了超越对,正如图21中的“新的文档被添加到内存缓冲区并且被追加到了事务日志”描述的一样。

    新文档将添加到内存缓冲区中,并附加到事务日志中

    图21.新的文档被添加到内存堆栈和被追加到了事务日志

  2. 刷新(refresh)使分片位于图22中,“刷新(refresh)完成后,缓存被清空但事务日志不会”描述的状态,分片每秒被刷新(refresh)一次:

    • 这些在内存正极的文档被写入到一个新的段中,且没有进行fsync操作。

    • 这个段被打开,有助于可被搜索。

    • 内存正极被清空。

    刷新后,将清除缓冲区,但不会清除事务日志

    图22.刷新(刷新)完成后,缓存被清空但事务日志不会

  3. 这个进程继续工作,更多的文档被添加到内存副本和追加到事务日志(参见图23,“事务日志不断积累文档”)。

    交易日志不断累积文件

    图23.事务日志不断积累文档

  4. 每隔间隔—例如Translog变得越来越大—索引被刷新(Flush);一个新的Translog被创建,并且一个全量提交被执行(参见图24,“在刷新(Flush)之后,段”被全量提交,和事务日志被清空”):

    • 所有在内存容量的文档都被写入一个新的段。

    • 上方被清空。

    • 一个提交点被写入硬盘。

    • 文件系统缓存通过fsync被刷新(flush)。

    • 老的translog被删除。

当Elasticsearch启动的时候,它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重新连接translog中所有在最后一次提交后发生的变更操作。

当您试着通过ID查询,更新,删除一个文档,它会在尝试从相应的段中检索之前,首先检查translog任何最近的变更。这意味着它总是能够实时地获取到文档的最新版本。

刷新后,将完全提交段,并清除事务日志

图24.在刷新(flush)之后,段被全量提交,并且事务日志被清空

冲洗API

这个执行一个提交并且截断超越对的行为在Elasticsearch被称作一次冲洗。分片每30分钟被自动刷新(刷新),或者在超越对太大的时候也会刷新。查看请 translog文档来设置,它可以用来控制这些阈值:

flushAPI可以被用来执行一个手工的刷新(flush):

POST / 博客/ _flush

POST / _flush ?wait_for_ongoing
 刷新(flush)blogs索引。
  刷新(flush)所有的索引和并等待所有刷新在返回前完成。

你很少需要自己手动执行flush操作;通常情况下,自动刷新就足够了。

这就是说,在重启节点或关闭索引之前执行冲洗有益于你的索引。当Elasticsearch尝试恢复或重新打开一个索引,它需要重放超越对中所有的操作,所以如果日志越短,恢复越快。

 

Translog是否有多安全性?

translog的目的是保证操作不会丢失。这引出了这个问题:Translog有多安全?

文件在被fsync到磁盘前,被写入的文件在重启之后就会丢失。默认超越对是每5被秒fsync刷新到硬盘,或者在每次写请求完成之后执行(例如索引,删除,更新,散装)。最终,基本上,这意味着在整个请求被fsync到主分片和复制分片的translog之前,您的客户端不会得到一个200 OK响应。

在每次请求后都执行一个fsync会带来一些性能损失,虽然实践表明这种损耗相对较小(特别是批量导入,它在一次请求中平摊减小文档的体积)。

但是对于某些大容量的偶尔丢失几秒数据问题也不会严重的损坏,使用异步的fsync还是比较有益的。例如,写入的数据被缓存到内存中,再每5秒执行一次fsync

这个行为可以通过设置durability参数为async来启用:

PUT / my_index / _settings
{ index.translog.durability” :“异步” ,“ index.translog.sync_interval” :“ 5s” }
   
   

这个选项可以针对索引单独设置,并且可以动态进行修改。如果你决定使用异步translog的话,你需要保证在发生崩溃时,丢失掉sync_interval时间段的数据也无所谓。请在决定前知道这个特性。

如果您不确定这个行为的后果,最好是使用替代的参数("index.translog.durability": "request")来避免数据丢失。

 

flush操作导致持久化变更:执行一个提交并且截断 translog 的行为在 Elasticsearch 被称作一次 *flush。*刷新(refresh)完成后, 缓存被清空但是事务日志不会。translog日志也会越来越多,当translog日志大小大于一个阀值时候或30分钟,会出发flush操作。

 

  • 所有在内存缓冲区的文档都被写入一个新的段。

  • 缓冲区被清空。

  • 一个提交点被写入硬盘。(表明有哪些segment commit了)

  • 文件系统缓存通过 fsync 到磁盘。

  • 老的 translog 被删除。

 

分片每30分钟被自动刷新(flush),或者在 translog 太大的时候也会刷新。也可以用_flush命令手动执行

 

translog每隔5秒会被写入磁盘(所以如果这5s,数据在cache而且log没持久化会丢失)。在一次增删改操作之后translog只有在replica和primary shard都成功才会成功,如果要提高操作速度,可以设置成异步的

 

PUT /my_index { "settings": { "index.translog.durability": "async" ,

 

"index.translog.sync_interval":"5s" } }

 

所以总结是有三个批次操作,一秒做一次refresh保证近实时搜索,5秒做一次translog持久化保证数据未持久化前留底,30分钟做一次数据持久化。

 

2.基于translog和commit point的数据恢复

 

在磁盘上会有一个上次持久化的commit point,translog上有一个commit point,根据这两个commit point,会把translog中的变更记录进行回放,重新执行之前的操作

 

3.不变形下的删除和更新原理

 

动态更新索引

下一个需要被解决的问题是怎样在保留不变性的预定下实现倒排索引的更新?答案是:用更多的索引。

通过增加新的补充索引来反映新近的修改,而不是直接重新转换整个倒排索引。每一个倒排索引都会被轮流查询到—从最初的开始—查询完成后再对结果进行合并。

Elasticsearch基于Lucene的,这个java的引入库了按段搜索的概念每一。本身都是一个倒排索引,但索引在Lucene的除中表示所有的集合外,增加还了提交点的概念-一个列出了所有已知段的文件,就像在图16中,“一个Lucene索引包含一个提交点和三个段”替换的那样。如图17,“一个在内存缓存中包含新文档的Lucene索引”所示,新的文档首先被添加到内存索引缓存中,然后写入到一个基于磁盘的段,如图18中,“在一次提交后,一个新的段被添加到提交点而且缓存被清空。”所示。

带有提交点和三段的Lucene索引

图16.一个Lucene索引包含一个提交点和三个段

索引与分片的比较

被混淆的概念是,一个Lucene的索引我们在Elasticsearch称作分片。一个Elasticsearch 索引的英文分片的集合。当Elasticsearch在索引中搜索的时候,他发送查询到每一个属于索引的分片(Lucene的索引) ,,然后像执行分布式检索 提到的那样,合并每个分片的结果到一个上下的结果集。

逐段搜索会以如下流程进行工作:

  1. 新文档被收集到内存索引缓存,请参见图17,“一个在内存缓存中包含新文档的Lucene索引”

  2. 不时地,缓存被提交

    • 一个新的段—一个追加的倒排索引—被写入磁盘。

    • 一个新的包含新段名字的提交点被写入磁盘。

    • 磁盘进行同步 —所有在文件系统缓存中等待的写入都刷新到磁盘,以确保其被写入物理文件。

  3. 新的段被开启,让它包含的文档可见以被搜索。

  4. 内存缓存被清空,等待接收新的文档。

在内存缓冲区中具有新文档的Lucene索引,准备提交

图17.一个在内存缓存中包含新文档的Lucene索引

提交后,将新段添加到索引并清除缓冲区

图18.在一次提交后,一个新的段被添加到提交点而且缓存被清空。

当一个查询被触发,所有已知的段按顺序被查询。词项统计计量所有段的结果进行聚合,以保证每个词和每个文档的关联都被准确计算。这种方式可以用相对最高的成本将新文档添加到索引。

删除和更新

段是不可改变的,所以既不能从把文档从旧的段中删除,也不能修改旧的段来进行反映文档的更新。取而代之的是,每个提交点会包含一个.del文件,文件中会列出这些被删除文档的段信息。

当一个文档被“删除”时,它实际上只是在.del文件中被标记删除。一个被标记删除的文档仍然可以被查询匹配到,但它会在最终结果被返回前从结果集中移除。

文档更新也是类似的操作方式:当一个文档被更新时,旧版本文档被标记删除,文档的新版本被索引到一个新的段中。可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就已经被删除。

段合并,我们展示了一个被删除的文档是怎样被文件系统移除的。

 

 

一个文档被 “删除” 时,它实际上只是在 .del 文件中被 标记 删除。一个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。

 

文档更新也是类似的操作方式:当一个文档被更新时,旧版本文档被标记删除,文档的新版本被索引到一个新的段中。 可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就已经被移除。

 

段合并的时候会将那些旧的已删除文档 从文件系统中清除。 被删除的文档(或被更新文档的旧版本)不会被拷贝到新的大段中。

 

4.merge操作,段合并

由于自动刷新流程每秒会创建一个新的段,这样会导致短时间内的段数量暴增。而段多个会会带来干扰的麻烦。每一个段都会消耗文件句柄,内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。

Elasticsearch通过在后台进行段合并来解决这个问题。小的段被合并到大的段,然后这些大的段再被合并到更大的段。

段合并的当时重置那些旧的已删除文档从文件系统中清除。被删除的文档(或被更新文档的旧版本)不会被复制到新的大段中。

这个流程像在图25中,“两个提交了的段和一个未提交的段正在被合并到一个更大的段”中提到的一样工作:

1,当索引的时候,刷新(refresh)操作会创建新的段转换段打开以供搜索使用。

2,合并进程选择一小部分大小相似的段,并且在后台将其合并到高层的段中。这并不会中断索引和搜索。

正在合并成更大的段的过程中有两个提交的段和一个未提交的段

图25.两个提交了的段和一个未提交的段正在被合并到一个更大的段

3,图26,“一旦合并结束,老的段被删除”说明合并完成时的活动:

  • **写入一个包含新段且排除了旧的和较小的段的新提交点。

  • 新的段被打开进行搜索。

  • 老的段被删除。

一旦合并结束,老的段被删除

图26.一旦合并结束,老的段被删除

合并大的段需要消耗大量的I / O和CPU资源,如果任其发展会影响搜索性能。Elasticsearch在各种情况下下整合合并流程进行资源限制,因此搜索仍然有足够的资源很好地执行。

查看段和合并来为你的实例获取关于合并调整的建议。

优化API

optimizeAPI大可看做是强制合并的 API。它可以将一个分片强制合并到max_num_segments参数指定大小的段数。这实际上是减少段的数量(通常减少到一个),来提升搜索性能。

optimizeAPI 不应该被用在一个活跃的索引————一个正积极更新的索引。后台合并流程已经可以很好地完成工作。

在特定情况下,使用optimizeAPI相当有分量。例如在日志这种用例下,每天,每周,每月的日志被存储在一个索引中。可能会发生变化。

在这种情况下,使用optimize优化老的索引,将每一个分片合并为一个单独的段就很有用了;这样既可以节省资源,也可以使搜索更加快速:

POST / logstash - 2014 - 10 / _optimize ?max_num_segments = 1 
 合并索引中的每个分片为一个单独的段
   

请注意,使用optimizeAPI触发段合并的操作不会受到任何资源上的限制。这可能会消耗掉你例程上全部的I / O资源,从而没有余裕来处理搜索请求,从而有可能使丢失的响应。如果您想要对索引执行optimize,您需要先使用分片分配(查看迁移旧索引)把索引移到一个安全的中断,再执行。

由于每秒会把buffer刷到segment中,所以segment会很多,为了防止这种情况出现,es内部会不断把一些相似大小的segment合并,并且物理删除del的segment。

当然也可以手动执行

POST /my_index/_optimize?max_num_segments=1,尽量不要手动执行,让它自动默认执行就可以了

5.当你正在建立一个大的新索引时(相当于直接全部写入buffer,先不refresh,写完再refresh),可以先关闭自动刷新,待开始使用该索引时,再把它们调回来:

PUT /my_logs/_settings
{ "refresh_interval": -1 }

PUT /my_logs/_settings
{ "refresh_interval": "1s" }

 

底层 lucene

简单来说,lucene 就是一个 jar 包,里面包含了封装好的各种建立倒排索引的算法代码。我们用 Java 开发的时候,引入 lucene jar,然后基于 lucene 的 api 去开发就可以了。

通过 lucene,我们可以将已有的数据建立索引,lucene 会在本地磁盘上面,给我们组织索引的数据结构。

 

倒排索引

 

在搜索引擎中,每个文档都有一个对应的文档 ID,文档内容被表示为一系列关键词的集合。例如,文档 1 经过分词,提取了 20 个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。

 

详细描述一下Elasticsearch索引文档的过程。

  • 协调节点默认使用文档ID参与计算(也支持通过routing),以便为路由提供合适的分片

    shard = hash(document_id) % (num_of_primary_shards)

    当分片所在的节点接收到来自协调节点的请求后,会将请求写入到Memory Buffer,然后定时(默认是每隔1秒)写入到Filesystem Cache,这个从Momery Buffer到Filesystem Cache的过程就叫做refresh; 当然在某些情况下,存在Momery Buffer和Filesystem Cache的数据可能会丢失,ES是通过translog的机制来保证数据的可靠性的。其实现机制是接收到请求后,同时也会写入到translog中,当Filesystem cache中的数据写入到磁盘中时,才会清除掉,这个过程叫做flush; 在flush过程中,内存中的缓冲将被清除,内容被写入一个新段,段的fsync将创建一个新的提交点,并将内容刷新到磁盘,旧的translog将被删除并开始一个新的translog。 flush触发的时机是定时触发(默认30分钟)或者translog变得太大(默认为512M)时;

     

7.Elasticsearch在部署时,对Linux的设置有哪些优化方法?

64 GB 内存的机器是非常理想的, 但是32 GB 和16 GB 机器也是很常见的。少于8 GB 会适得其反。

如果你要在更快的 CPUs 和更多的核心之间选择,选择更多的核心更好。多个内核提供的额外并发远胜过稍微快一点点的时钟频率。

如果你负担得起 SSD,它将远远超出任何旋转介质。 基于 SSD 的节点,查询和索引性能都有提升。如果你负担得起,SSD 是一个好的选择。

即使数据中心们近在咫尺,也要避免集群跨越多个数据中心。绝对要避免集群跨越大的地理距离。

请确保运行你应用程序的 JVM 和服务器的 JVM 是完全一样的。 在 Elasticsearch 的几个地方,使用 Java 的本地序列化。

通过设置gateway.recover_after_nodes、gateway.expected_nodes、gateway.recover_after_time可以在集群重启的时候避免过多的分片交换,这可能会让数据恢复从数个小时缩短为几秒钟。

Elasticsearch 默认被配置为使用单播发现,以防止节点无意中加入集群。只有在同一台机器上运行的节点才会自动组成集群。最好使用单播代替组播。

不要随意修改垃圾回收器(CMS)和各个线程池的大小。

把你的内存的(少于)一半给 Lucene(但不要超过 32 GB!),通过ES_HEAP_SIZE 环境变量设置。

内存交换到磁盘对服务器性能来说是致命的。如果内存交换到磁盘上,一个 100 微秒的操作可能变成 10 毫秒。 再想想那么多 10 微秒的操作时延累加起来。 不难看出 swapping 对于性能是多么可怕。

Lucene 使用了大量的文件。同时,Elasticsearch 在节点和 HTTP 客户端之间进行通信也使用了大量的套接字。 所有这一切都需要足够的文件描述符。你应该增加你的文件描述符,设置一个很大的值,如 64,000。

 

 

1、elasticsearch了解多少,说说你们公司es的集群架构,索引数据大小,分片有多少,以及一些调优手段 。

面试官:想了解应聘者之前公司接触的ES使用场景、规模,有没有做过比较大规模的索引设计、规划、调优。

解答:

如实结合自己的实践场景回答即可。

比如:ES集群架构13个节点,索引根据通道不同共20+索引,根据日期,每日递增20+,索引:10分片,每日递增1亿+数据,

每个通道每天索引大小控制:150GB之内。

 

仅索引层面调优手段:

1.1、设计阶段调优

1)根据业务增量需求,采取基于日期模板创建索引,通过roll over API滚动索引;

2)使用别名进行索引管理;

3)每天凌晨定时对索引做force_merge操作,以释放空间;

4)采取冷热分离机制,热数据存储到SSD,提高检索效率;冷数据定期进行shrink操作,以缩减存储;

5)采取curator进行索引的生命周期管理;

6)仅针对需要分词的字段,合理的设置分词器;

7)Mapping阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。 …

 

1.2、写入调优

1)写入前副本数设置为0;

2)写入前关闭refresh_interval设置为-1,禁用刷新机制;

3)写入过程中:采取bulk批量写入;

4)写入后恢复副本数和刷新间隔;

5)尽量使用自动生成的id。

 

1.3、查询调优

1)禁用wildcard;

2)禁用批量terms(成百上千的场景);

3)充分利用倒排索引机制,能keyword类型尽量keyword;

4)数据量大时候,可以先基于时间敲定索引再检索;

5)设置合理的路由机制。

 

1.4、其他调优

部署调优,业务调优等。

上面的提及一部分,面试者就基本对你之前的实践或者运维经验有所评估了。

 

2、elasticsearch的倒排索引是什么?

面试官:想了解你对基础概念的认知。

解答:通俗解释一下就可以。

传统的我们的检索是通过文章,逐个遍历找到对应关键词的位置。

而倒排索引,是通过分词策略,形成了词和文章的映射关系表,这种词典+映射表即为倒排索引。

有了倒排索引,就能实现o(1)时间复杂度的效率检索文章了,极大的提高了检索效率。

 

学术的解答方式:

倒排索引,相反于一篇文章包含了哪些词,它从词出发,记载了这个词在哪些文档中出现过,由两部分组成——词典和倒排表。

加分项:倒排索引的底层实现是基于:FST(Finite State Transducer)数据结构。

lucene从4+版本后开始大量使用的数据结构是FST。FST有两个优点:

1)空间占用小。通过对词典中单词前缀和后缀的重复利用,压缩了存储空间;

2)查询速度快。O(len(str))的查询时间复杂度。

 

3、elasticsearch 索引数据多了怎么办,如何调优,部署?

面试官:想了解大数据量的运维能力。

解答:索引数据的规划,应在前期做好规划,正所谓“设计先行,编码在后”,这样才能有效的避免突如其来的数据激增导致集群处理能力不足引发的线上客户检索或者其他业务受到影响。

如何调优,正如问题1所说,这里细化一下:

3.1 动态索引层面

基于模板+时间+rollover api滚动创建索引,举例:设计阶段定义:blog索引的模板格式为:blog_index_时间戳的形式,每天递增数据。

这样做的好处:不至于数据量激增导致单个索引数据量非常大,接近于上线2的32次幂-1,索引存储达到了TB+甚至更大。

一旦单个索引很大,存储等各种风险也随之而来,所以要提前考虑+及早避免。

3.2 存储层面

冷热数据分离存储,热数据(比如最近3天或者一周的数据),其余为冷数据。

对于冷数据不会再写入新数据,可以考虑定期force_merge加shrink压缩操作,节省存储空间和检索效率。

3.3 部署层面

一旦之前没有规划,这里就属于应急策略。

结合ES自身的支持动态扩展的特点,动态新增机器的方式可以缓解集群压力,注意:如果之前主节点等规划合理,不需要重启集群也能完成动态新增的。

 

4、elasticsearch是如何实现master选举的?

面试官:想了解ES集群的底层原理,不再只关注业务层面了。

解答:

前置前提:

1)只有候选主节点(master:true)的节点才能成为主节点。

2)最小主节点数(min_master_nodes)的目的是防止脑裂。

这个我看了各种网上分析的版本和源码分析的书籍,云里雾里。

核对了一下代码,核心入口为findMaster,选择主节点成功返回对应Master,否则返回null。选举流程大致描述如下:

第一步:确认候选主节点数达标,elasticsearch.yml设置的值discovery.zen.minimum_master_nodes;

第二步:比较:先判定是否具备master资格,具备候选主节点资格的优先返回;若两节点都为候选主节点,则id小的值会主节点。注意这里的id为string类型。

题外话:获取节点id的方法。

1、GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax,id,name

2、ip port heapPercent heapMax id name

3、127.0.0.1 9300 39 1.9gb Hk9w Hk9wFwU

 

5、详细描述一下Elasticsearch索引文档的过程?

面试官:想了解ES的底层原理,不再只关注业务层面了。

解答:

这里的索引文档应该理解为文档写入ES,创建索引的过程。

文档写入包含:单文档写入和批量bulk写入,这里只解释一下:单文档写入流程。

记住官方文档中的这个图。

第一步:客户写集群某节点写入数据,发送请求。(如果没有指定路由/协调节点,请求的节点扮演路由节点的角色。)

第二步:节点1接受到请求后,使用文档_id来确定文档属于分片0。请求会被转到另外的节点,假定节点3。因此分片0的主分片分配到节点3上。

第三步:节点3在主分片上执行写操作,如果成功,则将请求并行转发到节点1和节点2的副本分片上,等待结果返回。所有的副本分片都报告成功,节点3将向协调节点(节点1)报告成功,节点1向请求客户端报告写入成功。

如果面试官再问:第二步中的文档获取分片的过程?

回答:借助路由算法获取,路由算法就是根据路由和文档id计算目标的分片id的过程。

shard = hash(_routing) % (num_of_primary_shards)

 

6、详细描述一下Elasticsearch搜索的过程?

面试官:想了解ES搜索的底层原理,不再只关注业务层面了。

解答:

搜索拆解为“query then fetch” 两个阶段。

query阶段的目的:定位到位置,但不取。

步骤拆解如下:

1)假设一个索引数据有5主+1副本 共10分片,一次请求会命中(主或者副本分片中)的一个。

2)每个分片在本地进行查询,结果返回到本地有序的优先队列中。

3)第2)步骤的结果发送到协调节点,协调节点产生一个全局的排序列表。

fetch阶段的目的:取数据。

路由节点获取所有文档,返回给客户端。

 

7、Elasticsearch在部署时,对Linux的设置有哪些优化方法?

面试官:想了解对ES集群的运维能力。

解答:

1)关闭缓存swap;

2)堆内存设置为:Min(节点内存/2, 32GB);

3)设置最大文件句柄数;

4)线程池+队列大小根据业务需要做调整;

5)磁盘存储raid方式——存储有条件使用RAID10,增加单节点性能以及避免单节点存储故障。

 

8、lucence内部结构是什么?

面试官:想了解你的知识面的广度和深度。

解答:

Lucene是有索引和搜索的两个过程,包含索引创建,索引,搜索三个要点。可以基于这个脉络展开一些。

 posted on 2020-05-11 17:19  大码王  阅读(737)  评论(1编辑  收藏  举报
复制代码