ELK之Elasticsearch&Kibana安装/学习

编程入门 行业动态 更新时间:2024-10-27 12:30:11

目录

零、ELKB技术栈

一、ES相关概念

1.1、ES简介 ←→ MYSQL

1.2、ES相关的基本概念(官网)

注:Elasticsearch与关系型数据库的类比

18、路由(_routing)机制

二、ES的安装

2.1、源码安装

2.2、docker安装

三、Kibana的安装

3.1、源码安装

3.2、docker安装

四、ES聚合相关(Metric/Bucket/Pipeline)

4.1、Metric聚合(最大值/最小值/平均值/中位值等)

1、创建数据集

2、单值分析——只输出一个min/max/avg/sum/cardinality分析结果

3、 查看针对price去重后的数据条数——cardinality

4、多值分析——输出多个分析结果

4.2、Bucket聚合

0、造数据

1、terms单字段聚合 ——terms

2、多字段聚合 multi_terms

3、直方图分组(Histogram)聚合  histogram

4、时间分组(Date Histogram)聚合

5、范围(range)聚合

6、Composite聚合

4.3、Pipeline聚合

4.4、更多聚合语句实例

五、ES的分词器(安装分词器)

5.0、基本概念(Analysis与Analyzer)

5.1、ES内置分词器及效果测试

5.2、创建索引设置分词

5.3、中文分词器(IK分词器)安装

5.4、中文分词器(IK分词器)使用

5.5、扩展词、停用词配置

5.6、ngram tokenizer 详解    官网

5.7、可以给某个字段设置多个分词器

六、ES 修改setting常用操作

6.0、REST语法

6.1、修改备份数

6.2、设置索引读写属性



零、ELKB技术栈

ELK Stack 是Elasticsearch、Logstash、Kibana(通常还会包括beats)三个开源软件组合的技术栈。在实时数据检索和分析的场合中,几者之间通常是配合使用;又由于他们都归于Elastic.co公司名下,故有此简称。

关于ELKB elastic在csdn的官方账号有很多资料  Elastic 中国社区官方博客的博客_CSDN博客-Elastic,Elasticsearch,Kibana领域博主

①Elasticsearch 是搜索和分析引擎,他也是整个Elastic Stack的核心组件。

②Kibana 允许用户将Elasticsearch中的数据可视化。Kibana也在不断地完善,例如它可以对Elastic  Stack进行监控、管理;同时它也集成许多的应用,包括Logs,Metrics,机器学习,Maps等。

③Logstash 是一个开源的数据收集引擎。它具有实时的数据传输能力,可以按照我们定制的规范来做数据的收集、解析和存储。也就是说Logstash有3个核心组成部分,分别是数据收集、数据解析和数据转存。这个三个部分组成了一个类似于管道的数据流,由输入端进行数据的采集,管道本身做数据的过滤和解析,输出端把过滤和解析后的数据输出到目标数据库中。 更多关于Logstash参见  这里

④Beats 为此网上也有一种说法将ELKB,这里的B是的就是Beats。总的来讲Beats和Logstash一样都是为了收集和摄取数据,但是目前来讲Beats更轻量些(资源利用高效/无依赖/小型)。不过Beats也一直在迭代和增强,目前两者的差距在逐渐拉小。

关于 Beats参见 这里

一、ES相关概念

 手册路径:官网→最上方“learn→docs”→下翻至Guide→然后就可以看到各版本的指令文档了。

搜索:对于以下找不到的关键词(如template)点击右上方的“🔍”就可以搜索相关内容了。 

如下为5.3版本直达链接: 这里

官方手册。右侧选择版本后就可以选择关心的api手册内容了。

1.1、ES简介 ←→ MYSQL

Elasticsearch(ES)是一个基于Lucene构建的开源、分布式、RESTful接口的全文搜索引擎。ES还是一个分布式文档数据库,其中每个字段均是被索引的数据且可被搜索。它能够扩展至数以百计的服务器存储已经处理PB级别的数据。

ES与Lucene的关系。ES是基于Lucene的,他的很多基础性组件都是由Apache Lucene提供的,而es则提供了更高层次的封装以及分布式方面的增强与扩展。

1) Elasticsearch基于Lucene构建,Elasticsearch利用Lucene做实际的工作;
2) ELasticsearch中的每个分片都是一个分离的Lucene实例;
3) Elasticsearch在Lucene基础上(即利用Lucene的功能)提供了一个分布式的、基于JSON的REST API 来更方便地使用Lucene的功能;
4) Elasticsearch提供其他支持功能,如线程池,队列,节点/集群监控API,数据监控API,集群管理等。

1.2、ES相关的基本概念(官网)

ElasticSearch 集群可以包含多个索引(indices),每个索引可以包含多个类型(types),每一个类型包含多个文档(documents),每个文档包含多个字段(Fields)。

1、近实时(Near RealTime)

ElasticSearch是一个准实时的搜索平台。这意味着,从插入一个文档到这个文档能够被搜索到只有很小的延迟(通常是1秒)。

注:ES默认的refresh_interval是1s,即doc被写入后最多1秒钟就可以被搜索到。对于实时性要求不是那么高的场合例如日志场景等建议将索引模版的refresh_interval设置大一点例如30s,来避免过多的小 segment 文件的生成及段合并的操作。

2、集群(cluster)

(1)集群就是由一个或多个拥有相同cluster.name配置的节点组成的,所有的节点共同承担数据和负载的压力。当有节点加入集群或从集群移除节点时,集群会重新平均分布所有的数据。

(2)集群中有多个节点(node)其中有一个为主节点,这个主节点是可以通过选举产生的;注意这个主节点是对集群内部来说的。es的一个概念就是去中心化字面上理解就是无中心节点;这个无中心是对集群外部来说的,从外部来看es集群在逻辑上是个整体。也就是说你与任何一个节点的通信与整个es集群通信是等价的。

(3)作为用户我们可以将请求发送到集群中的任何节点,包括主节点。每个节点都知道任意文档所处的位置,并且能够将我们的请求直接转发到文档的存储节点。无论我们将请求发送到哪个节点,它都能收集到数据并返回给客户端。ES对这一切的管理都是透明的。

(4)ES利用分片将数据分发到集群各处。文档就保存在分片内,分片又被分配到集群内的各个节点里。当集群规模扩大或者缩小时,ES会自动的在各个节点中迁移分片,使得数据仍然均匀分布在集群中

(5)一个分片可以是主分片或者副本分片。索引内任意文档都属于一个主分片,所以主分片的数据决定了索引能够保存的最大数据量。

3、索引(Index) ←→ Database

        索引这个词在ElasticSearch中有三种意思(  ES中的“索引”非传统索引的含义,是ES中的一个概念词汇):

(1)索引(名词)。类比到关系型数据库,索引就是数据库(Database)。例如"create database mydb"。ES中的索引就理解为db,我们可以向索引写入文档或者从索引中读取文档。ElasticSearch将它的数据存储在一个或多个索引中;在数据量较大的应用中一个月或者一天就创建一个索引不在少数。另外,索引名称必须全部小写,不建议写成驼峰式。

(2)索引(动词)。保存一个文档到索引(名词)的过程。类似于Sql语句中的insert关键词,如果该文档已经存在那就相当于数据库的update。

(3)倒排索引。对于mysql或mongodb来说利用B+树提升数据检索速度。相对应地 ElasticSearch使用了一个叫做“倒排索引”的结构来达到相同的目的。

注:一定程度上es的索引(index)也有些mysql的表(table)的潜质。因为一般情况下我们会把相同特征(Filed数量和类型基本相同)的文档放到同一个索引里面。这样方便提前通过mapping来规定各个Filed的类型。

4、类型(Type)

类比到关系型数据库,类型(Type)就是表(Table)。之前的版本中索引和文档中间还有类型的概念,即每个索引下可以建立多个类型,文档存储的时候需要指定index的type(类似于每个database和每条数据之间还要有个Table)。从6.0.0以后单个索引中只能有一个类型了,7.0.0以后不建议使用,8.0.0以后将完全不支持。注:这样做的目的主要是为了提高查询效率。

5、文档(Document)

Index里面单条记录称为Document(文档),等同于关系型数据库表中的行;关于doc这个命名ES和MongoDB很类似。Document是ElasticSearch中的主要实体,对ES的搜索最终都归结为对文档的搜索。文档由字段构成;文档是无模式的、即并非所有的文档都需要拥有相同的字段,他们不限于一种模式(schema)。下面看看一条文档数据有哪些字段。

(1)_index:文档所属索引的名称。

(2)_type:文档所属类型名。

(3)_id:主键ID  即docid。在写入的时候我们可以指定该Doc的ID值;如果不指定 系统会自动生成一个唯一的UUID。

(4)_version:文档的版本信息,用于冲突处理。ES使用version来保证对文档的变更能以正确的顺序执行,避免乱序造成数数据错误。  更多细节 参见 这里

ElasticSearch采用乐观并发控制。Elasticsearch是分布式的,当文档被创建、更新或删除,文档的新版本会被复制到集群的其它节点。Elasticsearch即是同步的又是异步的,意思是这些复制请求都是平行发送的,并无序(out of sequence)的到达目的地。这就需要一种方法确保老版本的文档永远不会覆盖新的版本。
这时就用到了元数据“_version”,每个文档都有一个_version号码,这个号码在文档被改变时加1,Elasticsearch使用这个_version保证所有修改都被正确排序。当一个旧版本出现在新版本之后,它会被简单的忽略。

(5)_seq_no:严格递增的顺序号。每个文档一个,Shard级别的严格递增,后写入Doc的_seq_no大于先写入的Doc的_seq_no。

(6)_primary_term:和_seq_no一样是一个整数,每当Primary Shard发生重新分配时,比如重启,Primary选举等,_primary_term会递增1.

(7)found:查询ID正确就为true;如果ID不正确就查不到数据,found字段就是false。

(8)_source:文档原始的JSON数据。默认情况下源文档被存储在_source这个字段中,查询的时候也是返回这个字段。这允许你可以从搜索结果中访问原始的对象,这个对象返回一个精确的Json字符串,这个对象不显示索引分析后的其他任何数据。

6、settings

索引的settings信息分为静态信息和动态信息两部分。静态信息不可更改,例如分片数;动态信息只可以修改的信息。参见官网  这里 。

REST访问语句:

#更新特定索引
PUT /myindex/_settings
{
    #具体操作
}


#更新所有索引
PUT */_settings
{
 "index.blocks.read": true   #具体操作
} 

7、映射(mappings)

mapping类似于关系型数据库中的表结构定义(注:es不会像sql那样限制的那么死)。就是对索引库中索引的字段名称及数据类型进行定义,类似于mysql中的表结构信息。当然不指定mapping也是可以的,因为ES会自动根据数据格式识别它的类型。如果你需要对某些字段添加特殊属性(例如:定义使用其他分词器、是否分词、是否存储等)就必须手动添加mapping。注:实际使用都会指定mapping。

在ES中添加数据不指定数据类型时,ES会有自动映射机制;对字符串映射为string,数字映射为long。

索引中的每个文档都有一个类型Type(Sql中的table),每个类型(Type)拥有自己的映射(mapping)或者叫模式定义(schema definition)。  映射除了前面说的定义了字段名称、字段数据类型以外还定义字段被ES处理的方式。例如 所有Doc在写进索引之前都会先进行分析,如何将输入的文本分割为词条、哪些词条又会被过滤等都是映射(mapping)的一部分。

查看mapping:

#没有type_name可以
GET /index_name/_mapping
#有type_name也可以
GET /index_name/type_name/_mapping

ES的数据类型:

字符串类型: keyword、text
数字类型: interger long
小数类型: float double
布尔类型: boolean
日期类型: date


注:keyword一般用于关键词、关键词;text存储一段文本。
两者的本质区别是text会分词,keyword不会分词。

注:ElasticSearch与关系型数据库的类比

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


8、主分片(primary shards)     关于分片与副本参见另一篇  文章

        一台服务器上无法存储大量数据,ES把一个index里面的数据分成多个shard分布式的存储在多个服务器上(即对大的索引分片,拆成多个,分不到不同的节点上)。ES就通过shard来解决节点的容量上限问题,通过分片可以将数据分布到集群内的其他节点上。主分片数是在索引创建时指定的,一般不允许修改,除非Reindex。一个索引中的数据保存在多个分片中(默认为一个)相当于水平分表。一个分片表示一个Lucene的实例,它本身就是一个完整的搜索引擎。我们的文档被存储在分片内,这些对应用程序是透明的,即应用程序直接与索引交互而不感知分片的存在。

9、副分片(Replica Shard)

在ES集群中同一份数据可能会有多个备份。其中有一个会作为primary shard,其余作为replica shard。

副本有两个重要的作用:

(1)服务高可用:如果数据只有一份,这个node挂了那存在上面的数据就丢了;如果有了replicas,只要不是存储这条数据的所有node全挂数据就不会丢。因此分片副本不会与主分片分配到同一个节点。

(2)扩展性能:通过在所有的replicas上并行搜索提高搜索性能。由于replicas上的数据是近实时(near realtime)的,因此所有 replica都能提供搜索功能,通过设置合理的replicas数量可以极高的提高搜索吞吐量。

ES数据写入流程

1)客户端选择一个node发送请求过去,这个node就是coordinating node(协调节点);
2)coordinating node,对document进行路由,将请求转发给对应的node(有primary shard);
3)实际的node上的primary shard处理请求,然后将数据同步到replica node;
4)coordinating node,如果发现primary node和所有replica node都搞定之后,就返回响应结果给客户端。
 

ES数据拉取流程

1)客户端发送请求到任意一个node,成为coordinate node;
2)coordinate node对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮询算法,在primary shard以及其所有replica中随机选择一个,让读请求负载均衡;
3)接收请求的node返回document给coordinate node;
4)coordinate node返回document给客户端。

分片:一份数据被分开保存在N台机器上,N个机器上的数据组合起来是一份数据。

副本集:同一份数据被保存在N台机器上,每台机器上都有一份数据。

两者是可以嵌套存在的,在高可用场景每个分片又是作为副本集来部署是很常见的。例如腾讯云的cmongo等就是如此。

10、数据恢复(recovery)

(1)数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。

(2)查看集群状态

GET /_cat/health

11、数据源(river)

代表ES的一个数据源,也是其他存储方式(其他数据库)同步数据到es的一个方法。它是以插件方式存在的一个ES服务,通过读取river中数据并把它索引(insert)到ES中。现在官方的river支持的源数据库有couchDB、RabbitMQ、Twitter等。

12、网关(gateway)

在ES中gateway的主要职责是用来对数据进行长持久化;除此之外,整个集群重启之后也可以通过gateway重新恢复数据。由于ES是专门为分布式环境而设计的,所以怎么去对所有节点的索引信息进行持久化是个问题。其实除了索引信息以外,还有ClusterState(集群信息)、mapping、索引碎片信息,以及transactionlog等信息也需要进行持久化;0.11之后的版本新加了LocalGateway(并且是默认的配置),加上之前的fs(使用共享文件系统)、hdfs(hadoop 分布式文件系统)、cloud(ec2之类的云存储)ES已经支持至少四种持久化方式。0.11之前默认的是None,也就是不进行持久化,这样的话如果服务器都挂了,就会造成数据丢失。LocalGateway就是节点各自保存自身状态,这样节点就可以从本地存储来恢复节点状态和索引信息了。

ES默认是先把索引存放到内存中,当内存满了后再持久化到硬盘。当集群重新启动时就会从gateway中读取索引数据。ES支持多种用类型的gateway,上面已经列出了。

13、自动发现(discovery)

代表ES的节点自动发现机制。ES是一个基于p2p的系统,它先通过广播寻找存在的节点,在通过多播协议来进行节点之间的通信,同时也支持点对点的交互。

14、通信(Transport)

代表ES内部节点或集群与客户端的交互方式,默认内部使用tcp协议进行交互,同时也支持http协议(json格式)、thrift、servlet、memcached、zeroMQ等的传输协议(通过插件方式集成)。

15、索引别名(aliases)

一个索引别名可以映射到多个真实索引。

Elasticsearch Index Aliases详解_中间件兴趣圈-CSDN博客_is_write_index

16、索引模板(_template)

实际工作中对于源源不断产生的大量数据周期性的创建新索引是非常正常的操作。如果每次都手动指定索引库的配置信息(settings和mappings)的话会非常麻烦。这个时候就有创建索引模板的必要了!

索引可使用预定义的模板进行创建,这个模板称为Index templates。模板设置包括settings、mappings这些东西,通过模式匹配的方式可以实现所有索引重用一个模板。

模板样例:

{
  "order": 0,                               // 模板优先级
  "template": "sample_info*",               // 模板匹配的名称方式
  "settings": {...},                        // 索引设置
  "mappings": {...},                        // 索引中各字段的映射定义
  "aliases": {...}                          // 索引的别名
}

#实际创建模板的时候将其上面一坨put进行就好了如
PUT /_template/es_qidian_flow_oa_template
{
    #上面那一坨
}

关于order:

有的时候会有多个模板,如果恰好匹配上了两个或多个模板那么要怎么生成索引呢? 

ES 会按照一定的规则来尝试自动 merge 多个都匹配上了的模板规则,最终运用给到索引上。在某些方面命中的两个模板配置可能是不一样的这个时候应该用谁的呢?其实template 是可以设置 order 参数的!不写这个参数,默认的 order 值就是 0。order 值越大,在 merge 规则的时候优先级越高。

17、倒排索引

根据key定位value就是通常数据库所用的正向索引;与之对应的,根据value寻找key就是倒排索引了。

18、路由(_routing)机制

(1)、一条数据是如何落到对应的shard(分片)上的?

当索引一个文档的时候,文档会被存储到一个主分片中。ES如何知道一个文档应该存放到哪个分片呢?

显然是要有个分配方式的,这个分配方法类似下面公式:

shard_num = hash(_routing) % num_primary_shards

其中_routing是一个可变值,默认是docid,当然也可以设置为一个自定义的值。它会将文档的ID值作为依据将其哈希到相应的主分片上,这种算法基本上会保持所有的数据在所有分片上的相对平均的分布,不会产生热点数据。  
 

(2)、路由机制

假如你有一个100个分片的索引(database),当一个请求打到集群处理大致如下:

(1)这个搜索的请求会被发送到一个确定的节点;

(2)接收到这个请求的节点会将这个查询广播到这个索引的每个分片(可能是主分片,也可能是副本分片);

(3)每个分片执行这个搜索查询并返回结果;

(4)所有的结果在通道节点上合并、排序并返回给用户。

默认情况下ES使用docid(如果不指定的话ES会自己生成一个随机值)进行路由将文档平均的分布在所有的分片上。这导致ES不能确定文档的位置,所以就必须将这个请求广播到所有的100个分片去执行。这也解释了为什么主分片的数量在索引创建的时候就固定下来了,并且永远不能改变。如果分片的数量改变了,所有先前的路由值都变成非法的话,文档也就相当于丢失了(???)。 所以它必须将这个请求广播到所有的N个分片上去执行;显然这种操作会给集群带来较大的负担。

(3)、为什么需要自定义Routing模式?

默认的Routing在多数情况下是能够满足需求的——平均的数据分布、对用户透明、大多情况下性能尚可。但是在深入理解业务特征(数据的搜索应用场景),使用自动以的Routing模式会给我们带来更好的性能。

具体来说通过自定义Routing,可以使我们的查询更具目的性,而不是盲目的广播查询。举个例子:

(1)没有routing:帮我查询满足condition1的文档有哪些?——所有分片都要查。

(2)自定义routing:帮我查询满足condition1的文档有哪些,它就在shard1分片上(其他分片就不要扫描了)。——查shard1即可。

(4)、routing带来的问题

(1)docid不再全局唯一。在routing的这个分片可以有一个文档id为docid1的记录,在其他分片依然可以存在一个文档id为docid1的记录。

ES shard的是指是一个Lucene的索引,即每个分片都是一个功能完善的倒排索引。ES能保证docid全局唯一的原因是其默认采用docid来路由,即同样的docid肯定会路由到同一个分片上;如果docid重复,其效果就是update或者抛异常。显然这是可以保证集群内部docid唯一的。但是如果换用了其他值做routing,显然就保证不了了。如果用户还需要docid唯一,那就必须自己保证。

(2)容易造成负载不均衡。为此ES提供了一种将数据路由到一组shard而不是一个的机制。只需要在创建索引的时候设置index.routing_partition_size,默认值是1,即只路由到1个shard,可以将其设置为大于1且小于索引shard总数的某个值,就可以路由到一组shard了。值越大数据越均匀。当然,从设置就能看出来这个设置是针对单个索引的,可以加入到动态模板中,以对多个索引生效。指定后shard的计算方式变为:

shard_num = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards

对于同一个routing值,hash(_routing)的结果固定的,hash(_id) % routing_partition_size的结果有 routing_partition_size 个可能的值,两个组合在一起,对于同一个routing值的不同doc,也就能计算出 routing_partition_size 可能的shard num了,即一个shard集合。但要注意这样做以后有两个限制:

1)索引的mapping中不能再定义join关系的字段,原因是join强制要求关联的doc必须路由到同一个shard,如果采用shard集合,这个是保证不了的。
2)索引mapping中_routing的required必须设置为true。

(5)、注意事项

网上有一堆设置routing的教程,其中大部分类似于如下在mapping中加入_routing,required,path等参数工作的,但是使用后发现有错误。如下: reason": Mapping definition for [_routing] has unsupported parameters:  [path : category]"。

查看官网后发现: 原来在es2.0之后就不支持这种方式了(注:required还是认的,但path已经不认了)。

"required" : true 的效果就是插入数据和查询数据都必须带上”?routing=xxxxx“,否则就抱错。

关于routing使用、效果可以参见 ElasticSearch——路由(_routing)机制 - 曹伟雄 - 博客园

19、索引别名(alias)——对多个索引的读操作

类似于数据库的视图,其实就是给索引创建别名。例如为索引my_index创建一个别名my_index_alias,这样对my_index_alias的操作就和直接对my_index操作一样。别名不仅仅可以关联一个索引,他能聚合多个索引。例如,为my_index_1和my_index_2创建一个别名my_index_alias,这样对my_index_alias的操作(仅限于读操作)会操作my_index_1和my_index_alias,类似于聚合了这两个索引。另外值得注意的是我们不能对my_index_alias进行写操作,因为当有多个索引时alias不能区分到底操作哪一个。

这里最常见的用法就是将不同的索引建立在同一个索引别名下,这样就可以实现统一的对外索引名称、实现查询统一等。如下列出关于别名的一些操作:

#查看所有别名
GET /_alias

#查看某个别名下的索引
GET /_alias/alias_name
GET /_alias/es_qidian_flow_oa


#查看某个索引的别名
GET /index_name/_alias

#添加并删除别名

#将别名与多个索引相关联

二、ES的安装

2.1、源码安装

0、注意事项

(1)elasticsearch不能用root用户启动,建议最开始就创建一个普通用户;后续wget安装包、安装/配置jdk等都用这个用户,避免后续因为文件权限、拥有者不匹配引发不必要麻烦。

(2)es7之后对jdk版本有一定要求,例如es7要求jdk版本在11以后才行。如果本机jdk版本不满足也没关系,具体操作的时候本机jdk可以默认不动,/etc/profile里面配置es启用安装包的这个jdk就可以了。

(3)另外值得注意的是es安装包内部也提供了对应的jdk,这个版本是最稳妥的。

1、创建普通用户

首先创建一个root以外的普通用户,如下:

#添加一个用户
useradd shuozhuo

#设置密码
passwd shuozhuo

注:我这里设为为Zs+qq

之后所有的操作都用这个用户,除非修改/etc/配置。

2、下载相应安装包

(1)搜索elasticsearch找到官网   这里

(2)点击下载→查看历史版本→选择对应的版本→下载→选择linux_64右键赋值链接

注:我这里下载的是7.14.0版本。

 

 

3、下载解压

#下载安装包
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.14.0-linux-x86_64.tar.gz

#解压安装包
tar zxvf elasticsearch-7.14.0-linux-x86_64.tar.gz

解压后相应文件如下。 

①bin:启动ES服务脚本的目录
②config:ES配置文件目录,其中常用的就是 elasticsearch.yml 文件
③data: ES的数据存放目录
④jdk:ES提供的需要指定的jdk目录。注:建议指定ES就用这个jdk。
⑤lib:ES依赖的第三方库的目录
⑥logs:ES的日志目录
⑦modules:ES各模块目录
⑧plugins:插件目录,ik分词器之类的应该就是安装在这里。

7.14.0内置的jdk版本为16.0.1,如下:

4、配置环境变量

需要把ES中的JDK配置到JAVA_HOME中;同时在对应的/etc/profile中把路径配置给环境变量ES_JAVA_HOME。

注:ES_JAVA_HOME是ES默认的引用jdk的环境变量,最好配一下。

#注意:我这里的解压包的jdk的路径为 '/home/shuozhuo/elastic/elasticsearch-7.14.0/jdk
'
export JAVA_HOME=/home/shuozhuo/elastic/elasticsearch-7.14.0/jdk

export ES_JAVA_HOME=/home/shuozhuo/elastic/elasticsearch-7.14.0/jdk
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
export PATH=$PATH:$JAVA_HOME/bin

#使之生效
source /etc/profile

或者直接 vim /etc/profile  进行编辑也是可以的。

5、启动

#跳转到bin目录下
cd bin

#执行启动
./elasticsearch

#后台启动
./elasticsearch -d

#关闭
kill -9 pid

如下:

没有报错刷出一定量的日志应该就是成功了。ps查看也是有进程的。

6、验证是否正常启动

#新开一个终端执行
curl 127.0.0.1:9200   或者 
curl localhost:9200
curl http://localhost:9200

出现如下json如下说明es运行是完全正常的。 

7、开启远程访问

1、关闭ES

2、vim elasticsearch.yml将其中的network.host修改为如下
network.host: 0.0.0.0

注:0.0.0.0表示允许任何位置的任何ip访问。

之后启动发现出现如下报错。 

关于这个错误说明一下。一旦开启外部连接模式ES会默认会以集群的方式启动,对于这个问题我们修改使之单节点启动即可。报错提示的就是缺少默认参数,这个三个默认参数的含义如下。

1 discovery.seed_hosts:  集群主机列表
2 discovery.seed_providers: 基于配置文件配置集群主机列表
3 cluster.initial_master_nodes: 启动时初始化的参与选主的node,生产环境必填

接下来配置单节点模式启动。 

#打开配置文件
vim elasticsearch.yml

#将其中的如下语句
cluster.initial_master_nodes: ["node-1", "node-2"]

改为
cluster.initial_master_nodes: ["node-1"]

注:其含义是使用一个节点去初始化集群;其中的node-1是节点名称。当前节点默认就是node-1如下。

然后重新启动ES就可以了。

之后在网络配置畅通的情况下在浏览器访问IP:9200应该也是通的,如下就说明ok了。

8、相关问题与报错

①默认启动的ES服务是不允许远程访问的

②默认ES监听的web(Restful)端口是9200,TCP端口是9300。启动日志也可以看到相应记录如下:

③注意启动ES的时候不能使用root用户,否则会有如下报错。

④如果没有权限的话执行会包如下错误

⑤另外还会有些内存不足等问题,直接网上搜一般都能搜出原因。

2.2、docker安装

前言:安装包的方式太复杂了,使用docker更简单。

0、安装docker

1、获取镜像

docker pull elasticsearch:7.14.0

百度“dockerhub” →找到镜像库官网 → 搜索elasticsearch → Tag处搜索目标版本

2、运行ES

docker run -d -p 9200:9200 -p 9300:9300 -e "discover.type=single-node" elasticsearch:7.14.0

①-p:通过外部的宿主机访问容器

②-d:后台运行

③9200:9200:宿主机的9200映射到docker的9200;宿主机的9300映射到docker的9300.

④-e “discoverXXX”: 以单节点启动

3、访问ES

http://ip:9200

三、Kibana的安装

3.1、源码安装

0、注意事项:

① Kibana版本一定要和es版本完全匹配!!!

② Kibana的安装要求es服务运行起来!!

1、ES官网下载对应版本的Kibana   这里

复制如下链接地址,Linux机器下载。

#下载对应版本
wget https://artifacts.elastic.co/downloads/kibana/kibana-7.14.0-linux-x86_64.tar.gz

#解压缩
tar zxvf kibana-7.14.0-linux-x86_64.tar.gz

2、编辑配置文件

编辑kibana配置文件 vim ./kibana/kibana.yml ;按如下方式修改。

#开启kibana远程访问
server.host: "0.0.0.0"

#指定kibana连接本机的es
elasticsearch.hosts: ["http://localhost:9200"]

 

注:我这里也修改了下默认端口。 

3、启动kibana

之后到bin目录下执行  ./kibana 启动kibana;如下应该就可以了。

注:可以看到其对应的端口是5601. 

4、验证访问与连接

如下图说明kibana启动正常

左侧边栏 Home → Dev Tools →执行默认的语句;如下就是ok的。

3.2、docker安装

类似ES

四、ES聚合相关(Metric/Bucket/Pipeline)

参见官网:Aggregations | Elasticsearch Guide [8.4] | Elastic 

注意:拉到最下面看聚合结果!!!

注意:composite/bucket_sort 两种聚合都需要6.1版本之后才能支持!!!

Elasticsearch将聚合分为三类,分别是:

①Metric aggregations:指标分析类型,例如比较简单的最大值、最小值、平均值等分析结果;

②Bucket aggregations:将数据分成桶(bucket),也可以称为箱(bins),类似于sql语法中的group by;

③Pipeline aggregations:管道分析类型,基于上一级的聚合分析结果再进行分析。

注:这里说的bucket(桶)概念上和组(group)一个意思;只不过在ES中统一使用桶(bucket)这个术语罢了。

4.1、Metric聚合(最大值/最小值/平均值/中位值等)

1、创建数据集

#创建 products 索引
PUT products
{
  "settings":{
    "number_of_shards": 1,
    "number_of_replicas": 0
  },
  "mappings":{
    "properties": {
      "id":{
        "type":"integer"
      },
      "title":{
        "type":"keyword"
      },
      "price":{
        "type":"double"
      },
      "create_at":{
        "type":"date"
      },
      "description":{
        "type":"text",
        "analyzer": "ik_max_word"
      }
    }
  }
}
#添加如下测试数据集
POST /products/_doc/1
{
  "id":1,
  "title":"小浣熊",
  "price":1,
  "create_at":"2022-11-11",
  "description":"小浣熊很好吃!!"
}

POST /products/_doc/
{
  "title":"日本豆",
  "price":2,
  "create_at":"2022-11-11",
  "description":"日本豆很好吃!!"
}

POST /products/_doc/
{
  "title":"鱼豆腐",
  "price":1,
  "create_at":"2022-11-11",
  "description":"鱼豆腐nice!!很好吃!!"
}

POST /products/_doc/2
{
  "id":2,
  "title":"唐僧肉",
  "price":1,
  "create_at":"2022-11-11",
  "description":"唐僧肉真不错!!很好吃!!"
}

POST /products/_doc/8
{
  "id":8,
  "title":"大辣片",
  "price":1,
  "create_at":"2022-11-11",
  "description":"大辣片好好吃!!很好吃!!"
}

POST /products/_doc/
{
  "title":"大鸡腿",
  "price":10,
  "create_at":"2022-11-11",
  "description":"good chicken tui"
}

POST /products/_doc/
{
  "title":"大鸡翅",
  "price":10,
  "create_at":"2022-11-11",
  "description":"good chicken chi"
}

接下来验证各种聚合效果。注:针对 price 字段验证各种聚合效果。

_source指定你需要ES返回哪些字段:

  "_source":[
    "price"
  ],

2、单值分析——只输出一个min/max/avg/sum/cardinality分析结果

GET /products/_search
{
  "_source":[
    "price"
  ],
  "query":{
    "match_all": {}
  },
  "aggs": {
    "price_aggs": {
      "min": {
        "field": "price"
      }
    }
  }
}

注:将其中的"min"换成max/avg/sum/cardinality即可得到响应结果。

注: cardinality计算数目,类似于sql中的distinct count;如下。

3、 查看针对price去重后的数据条数——cardinality

GET /products/_search
{
  "_source":[
    "price"
  ],
  "query":{
    "match_all": {}
  },
  "aggs": {
    "price_aggs": {
      "cardinality": {
        "field": "price"
      }
    }
  }
}

4、多值分析——输出多个分析结果

多值stats——返回一些列数值类型的统计值(min/max/avg/sum/count)

GET /products/_search
{
  "_source":[
    "price"
  ],
  "query":{
    "match_all": {}
  },
  "aggs": {
    "price_aggs": {
      "stats": {
        "field": "price"
      }
    }
  }
}

(2)多值Extended Stats——stats的扩展,包含更多方差/标准差之类的统计数据

GET /products/_search
{
  "_source":[
    "price"
  ],
  "query":{
    "match_all": {}
  },
  "aggs": {
    "price_aggs": {
      "extended_stats": {
        "field": "price"
      }
    }
  }
}

 (3)多值percentile——百分数统计(关键词 percentiles)

例如计算90%、50%价格在多少以下。

GET /products/_search
{
  "size":0,
  "aggs":{
    "per_price":{
      "percentiles": {
        "field": "price",
        "percents": [
          1,
          5,
          25,
          50,
          75,
          95,
          99
        ]
      }
    }
  }
}

 (4)多值percentile_ranks

例如或许价格在2块钱、8块钱及以下的商品分别占的比例。

  (5)多值top hits

多值分析值top hits,一般用于分桶后获取该桶内最匹配的顶部文档列表。举个例子: 对于消息记录搜索的ES数据,首先根据session_id对数据进行分桶(分组);分完之后分别取出每个桶里面的消息时间flow_time最大的两条数据。聚合指令如下。

GET es_qidian_flow_oa_20220906/session/_search?
{
  "query":{
    "bool": {
      "must": [
        {
          "range": {
            "flow_time": {
              "gte": 1662445031,
              "lte": 1662447031
            }
          }
        },
        {
          "bool":{
            "must_not":{
              "term":{
                "session_id":""
              }
            }
          }
        }
      ]
    }
  },
  "aggs":{
    "group_sessionid":{
      "terms": {
        "field": "session_id",
        "size": 10
      },
      "aggs":{
        "my_top_data":{
          "top_hits": {
            "size": 2,
            "sort": [
              {
                "flow_time":{
                  "order": "desc"
                }
              }
            ]
          }
        }
      }
    }
  }
}

4.2、Bucket聚合

0、造数据

#创建索引如下
PUT my-products
{
  "mappings": {
    "properties": {
      "brand": {
        "type": "keyword"
      },
      "mkttime": {
        "type": "date"
      },
      "name": {
        "type": "keyword"
      },
      "color": {
        "type": "keyword"
      },
      "price":{
        "type":"integer"
      }
    }
  }
}

#各个字段解释如下
①brand:品牌 (耐克/李宁/鸿星尔克等)
②color:颜色
③mkttime:上市时间
④price:价格
#批量插入如下数据
PUT my-products/_bulk
{"index":{"_id":1}}
{"brand":"nike","mkttime":"2021-01-01","name":"product_01","color":"red","price":600}
{"index":{"_id":2}}
{"brand":"erke","mkttime":"2021-02-01","name":"product_02","color":"red","price":200}
{"index":{"_id":3}}
{"brand":"li-ning","mkttime":"2021-03-01","name":"product_03","color":"green","price":300}
{"index":{"_id":4}}
{"brand":"li-ning","mkttime":"2021-02-01","name":"product_04","color":"green","price":450}
{"index":{"_id":5}}
{"brand":"erke","mkttime":"2021-04-01","name":"product_05","color":"blue","price":180}
{"index":{"_id":6}}
{"brand":"erke","mkttime":"2021-02-01","name":"product_06","color":"yellow","price":165}
{"index":{"_id":7}}
{"brand":"erke","mkttime":"2021-02-01","name":"product_07","color":"yellow":"price":190}
{"index":{"_id":8}}
{"brand":"li-ning","mkttime":"2021-04-01","name":"product_08","color":"blue","price":500}
{"index":{"_id":9}}
{"brand":"nike","mkttime":"2021-01-01","name":"product_09","color":"blue","price":1000}



#查看插入的数据
GET /my-products/_search
{
  "query": {
    "match_all": {}
  }
}

1、terms单字段聚合 ——terms

查看去重后的结果。

#以品牌brand字段进行分桶聚合(brand字段的聚合统计各brand的数量)

POST my-products/_search
{
  "size":0,
  "aggs":{
    "brand_terms":{
      "terms":{
        "field": "brand",
        "size":10      #bucket显示多少项
      }
    }
  }
}



#以颜色聚合
POST my-products/_search
{
  "size":0,
  "aggs":{
    "brand_terms":{
      "terms":{
        "field": "color",
        "size":10      
      }
    }
  }
}

2、多字段聚合 multi_terms

Elasticsearch支持多字段聚合multi-terms。multi-terms是单字段聚合terms的引申,顾名思义这里支持的是多个关键字的聚合。等价于将多个字段组合成一个复合key进行聚合。

注:需要很新的版本才能支持,看起来至少是7.12版本才行。 这里

#如下为按照品牌brands和颜色color两个字段的两字段聚合
POST my-products/_search
{
  "size":0,
  "aggs":{
    "brands_and_colors_aggs":{
      "multi_terms":{
        "terms":[
          {
            "field":"brand"
          },
          {
            "field":"color"
          }
        ]
      }
    }
  }
}

 如下图即为复合key。

3、直方图分组(Histogram)聚合  histogram

histogram(直方图)聚合就是根据数值间隔分组进行聚合。例如价格按照100间隔分组,0,100,200,300等进行聚合。

POST my-products/_search
{
  "size":0,
  "aggs":{
    "myprice":{            #聚合查询名字随便去一个就好
      "histogram": {       #聚合类型为 histogram
        "field": "price",  #根据price字段分桶
        "interval": 50     #分桶间隔为50,即将price字段的数值按50间隔分组
      }
    }
  }
}

4、时间分组(Date Histogram)聚合

按照时间间隔进行分组,例如按日、月、天、时等。

POST my-products/_search
{
  "size":0,
  "aggs":{
    "market_time":{                   #聚合查询名字,随便取
      "date_histogram": {             #聚合类型 date_histogram
        "field": "mkttime",           #根据mkttime字段分组
        "calendar_interval": "month", #分组间隔:month(月)、minute(分钟)、hour(小时)、day(天)、week(周)、year(年)
        "format": "yyyy-MM-dd",       #设置返回结果中桶key的时间格式
        "time_zone": "Asia/Shanghai"  #设置时区
      }
    }
  }
}

5、范围(range)聚合

按数值范围分组,例如 0~50一组、50~150一组、150~200一组。

POST my-products/_search
{
  "size":0,
  "aggs":{
    "price_range_group":{           #聚合查询名字,随便取一个 
      "range": {                    #聚合类型为range
        "field": "price",           #根据price字段分桶
        "ranges": [                 #如下为范围设置
          {"to": 200},              #price≤200归为一组
          {"from": 200, "to": 400}, #price>200 and price<400归为一个分组
          {"from": 400}             #price>400归为一个分组
        ]
      }
    }
  }
}


#为每个分组指定名字
POST my-products/_search
{
  "size":0,
  "aggs":{
    "price_range_group":{
      "range": {
        "field": "price",
        "ranges": [
          {"key":"cheap", "to": 200},
          {"key":"middle","from": 200, "to": 400},
          {"key":"expensive","from": 400}
        ]
      }
    }
  }
}

6、Composite聚合

多字段聚合,可以从不同来源创建复合桶。支持的聚合方式有 terms(特定关键字聚合)、histogram(区间聚合)、date histogram(日期区间聚合)、geotile grid geo(地理位置聚合)。

它与前面说的各种聚合最大的不同在于composite聚合能够对多级聚合中的所有同进行分页。即composite聚合提供了一种流式传输特定聚合的所有桶的方法,类似于Scroll检索

Composite 聚合较其他聚合的核心不同点如下:

①支持多类型组合桶聚合。打破传统多桶单类型聚合的壁垒,支持:Terms、Histogram、Data histogram、GeoTile grid Geo 聚合。

②支持聚合后分页。类似:scroll 检索的,仅支持向后翻页,不支持随机翻页。

#第一把拉取
GET my-products/_search
{
  "size":0,
  "aggs":{
    "my_buckets":{
      "composite": {
        "size":5,             #单次返回条数
        "sources": [
          {
            "brand_terms": {
              "terms": {
                "field": "brand",
                "order":"asc"
              }
            }
          },
          {
            "color_terms":{
              "terms": {
                "field": "color"
              }
            }
          }
        ]
      }
    }
  }
}

GET my-products/_search
{
  "size":0,
  "aggs":{
    "my_buckets":{
      "composite": {
        "size":5,
        "sources": [
          {
            "brand_terms": {
              "terms": {
                "field": "brand",
                "order":"asc"
              }
            }
          },
          {
            "color_terms":{
              "terms": {
                "field": "color"
              }
            }
          }
        ],
        "after":{
          "brand_terms" : "li-ning",
          "color_terms" : "green"
        }
      }
    }
  }
}

注:相比较而言 bucket_sort 应该还是要比 composite 要更好些。主要原始是composite看起来只能逐次翻页,但是bucket_sort的from/size机制看起来可以比较随意的翻页。

4.3、Pipeline聚合

4.4、更多聚合语句实例

1、聚合嵌套(对sessionid字段聚合后在对msg_direction字段聚合)

注意:内层aggs和外层aggs的terms字段并平齐。

GET es_qidian_flow_oa_v2_202208/session/_search?routing=2852199659
{
  "_source":[
    "session_id",
    "msg_direction"
  ],
  "query": {
    "bool": {
      "must_not": [
        {"term": {"session_id":""}}
      ]
    }
  },
  "aggs":{
    "session_group":{
      "terms":{
        "field": "session_id",
        "size":4
      },
      "aggs":{
        "dir_group":{
          "terms": {
            "field": "msg_direction",
            "size": 2
          }
        }
      }      
    }
  }
}

输出如下:最外层有个key为session_id的buckets(项数上限为外层aggs指定的size);然后在其中的每一项里面又有key为msg_direction的小buckets(项数上限为内层aggs指定的size)。

  "aggregations" : {
    "session_group" : {
      "doc_count_error_upper_bound" : 23,
      "sum_other_doc_count" : 7438,
      "buckets" : [
        {
          "key" : "inter_wx_2854099014_oUiVIt9h3vzYTMNT6CCBdifHFKbM_1661341204",
          "doc_count" : 54,
          "dir_group" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : 2,
                "doc_count" : 54
              }
            ]
          }
        },
        {
          "key" : "webim_2852199330_176559421771636_1659421822429",
          "doc_count" : 51,
          "dir_group" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : 2,
                "doc_count" : 50
              },
              {
                "key" : 1,
                "doc_count" : 1
              }
            ]
          }
        },
        {
          "key" : "commonsession_ssc_2852199135_1330_wwf4189a3f653433d0_wonGLYDAAAp8m3URfPjRnXAeVJTY1_kA_1659946913566",
          "doc_count" : 48,
          "dir_group" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : 2,
                "doc_count" : 34
              },
              {
                "key" : 1,
                "doc_count" : 14
              }
            ]
          }
        },
        {
          "key" : "inter_wx_2852199659_ooIli6MKbzOp_j6o7bmnk8ZXVPds_1661311009",
          "doc_count" : 30,
          "dir_group" : {
            "doc_count_error_upper_bound" : 0,
            "sum_other_doc_count" : 0,
            "buckets" : [
              {
                "key" : 1,
                "doc_count" : 15
              },
              {
                "key" : 2,
                "doc_count" : 15
              }
            ]
          }
        }
      ]
    }
  }

2、聚合嵌套2

要求:对account_aggr_field字段进行聚合,返回5条关于account_aggr_field的聚合记录;且要求每个聚合的bucket中要返回flow_time最大的1条原始数据、指定原始数据返回"msg_content"/"flow_type"/"flow_time"/"kfext"字段。


GET es_qidian_flow_oa_v2_202208/session/_search?routing=2852199659
{
  "size":0,
  "query": {
    "bool": {
      "must_not": [
        {"term": {"session_id":""}}
      ]
    }
  },  
  "aggs":{
    "customer_msgnum_aggs" : {
        "terms" : {
            "field": "account_aggr_field",
            "size" : 5,
            "collect_mode" : "breadth_first",
            "execution_hint": "map",
            "order": {
              "customer_max_time": "desc"
            }
        },
        "aggs":{
          "customer_max_time":{
            "max":{
              "field": "flow_time"
            }
          },
          "customer_msg":{
            "top_hits" :{
              "size" : 1, 
              "sort":{"flow_time":{"order":"desc"}},
              "_source" : {
                "includes" : [ 
                  "msg_content", "flow_type", "flow_time", "relation_type", "kfext"
                ]
              }
            }
          }          
      }
    }
  }
}

(1)最外层的customer_msgnum_aggs就是关于account_aggr_field字段的聚合。要求返回前5条数据、而且排序方式为关于customer_max_time的降序排列。

(2)其中customer_max_time又是一个自定义子聚合;其返回的是每一个customer_msgnum_aggs聚合所有数据中flow_time最大的那条数据。显然这里的效果就是:根据account_aggr_field聚合返回flow_time最大的前五个桶的聚合结果。

(3)下面的customer_msg就是指定要求返回原始数据,层级平齐与内层aggs意思就是每个外层aggs聚合的分组(bucket中都要返回原始数据)。另外对于返回的原始数据还要求返回其按照时间戳进行降序排列,返回其中时间戳最大的1条数据。

(4)然后就是通过_source指定原始数据返回哪些字段了。具体返回如下,完全符合预期:

{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 7621,
    "max_score" : 0.0,
    "hits" : [ ]
  },
  "aggregations" : {
    "customer_msgnum_aggs" : {
      "doc_count_error_upper_bound" : -1,
      "sum_other_doc_count" : 7021,
      "buckets" : [
        {
          "key" : "3_wxe45114479e6aad47_oGLpW1RVLfVQ_1QFaVdr9aoDpdeE",
          "doc_count" : 3,
          "customer_max_time" : {
            "value" : 1.661960573E12,
            "value_as_string" : "1661960573"
          },
          "customer_msg" : {
            "hits" : {
              "total" : 3,
              "max_score" : null,
              "hits" : [
                {
                  "_index" : "es_qidian_flow_oa_v2_202208",
                  "_type" : "session",
                  "_id" : "a4KR9IIB3-Y9Ecgp05QG",
                  "_score" : null,
                  "_routing" : "2852199659",
                  "_source" : {
                    "flow_type" : 7,
                    "kfext" : 0,
                    "flow_time" : 1661960573,
                    "msg_content" : "发发发",
                    "relation_type" : 0
                  },
                  "sort" : [
                    1661960573000
                  ]
                }
              ]
            }
          }
        },
        {
          "key" : "3_wx7f91af06eeead6cf_ooIli6MKbzOp_j6o7bmnk8ZXVPds",
          "doc_count" : 30,
          "customer_max_time" : {
            "value" : 1.661953779E12,
            "value_as_string" : "1661953779"
          },
          "customer_msg" : {
            "hits" : {
              "total" : 30,
              "max_score" : null,
              "hits" : [
                {
                  "_index" : "es_qidian_flow_oa_v2_202208",
                  "_type" : "session",
                  "_id" : "JoIq9IIB3-Y9EcgpKJQD",
                  "_score" : null,
                  "_routing" : "2852199659",
                  "_source" : {
                    "flow_type" : 7,
                    "kfext" : 0,
                    "flow_time" : 1661953779,
                    "msg_content" : "autoTestNewMessage__oa",
                    "relation_type" : 0
                  },
                  "sort" : [
                    1661953779000
                  ]
                }
              ]
            }
          }
        },
        {
          "key" : "2_444208787",
          "doc_count" : 519,
          "customer_max_time" : {
            "value" : 1.661953497E12,
            "value_as_string" : "1661953497"
          },
          "customer_msg" : {
            "hits" : {
              "total" : 519,
              "max_score" : null,
              "hits" : [
                {
                  "_index" : "es_qidian_flow_oa_v2_202208",
                  "_type" : "session",
                  "_id" : "IYIl9IIB3-Y9Ecgp25T7",
                  "_score" : null,
                  "_routing" : "2854099021",
                  "_source" : {
                    "flow_type" : 1,
                    "kfext" : 2852997703,
                    "flow_time" : 1661953497,
                    "msg_content" : "",
                    "relation_type" : 0
                  },
                  "sort" : [
                    1661953497000
                  ]
                }
              ]
            }
          }
        },
        {
          "key" : "3_wx6fd01862be33d973_of0AgxNkj1_R2hcB17Gwv6FVcLt0",
          "doc_count" : 45,
          "customer_max_time" : {
            "value" : 1.66195208E12,
            "value_as_string" : "1661952080"
          },
          "customer_msg" : {
            "hits" : {
              "total" : 45,
              "max_score" : null,
              "hits" : [
                {
                  "_index" : "es_qidian_flow_oa_v2_202208",
                  "_type" : "session",
                  "_id" : "WrYQ9IIBIiE3mWX2OgvA",
                  "_score" : null,
                  "_routing" : "2852199719",
                  "_source" : {
                    "flow_type" : 4,
                    "kfext" : 3007443423,
                    "flow_time" : 1661952080,
                    "msg_content" : "",
                    "relation_type" : 0
                  },
                  "sort" : [
                    1661952080000
                  ]
                }
              ]
            }
          }
        },
        {
          "key" : "1_274761951881149",
          "doc_count" : 3,
          "customer_max_time" : {
            "value" : 1.661951894E12,
            "value_as_string" : "1661951894"
          },
          "customer_msg" : {
            "hits" : {
              "total" : 3,
              "max_score" : null,
              "hits" : [
                {
                  "_index" : "es_qidian_flow_oa_v2_202208",
                  "_type" : "session",
                  "_id" : "l44N9IIBAQnYPCaoaIVD",
                  "_score" : null,
                  "_routing" : "2852199719",
                  "_source" : {
                    "flow_type" : 5,
                    "kfext" : 3007443423,
                    "flow_time" : 1661951894,
                    "msg_content" : "aaa",
                    "relation_type" : 0
                  },
                  "sort" : [
                    1661951894000
                  ]
                }
              ]
            }
          }
        }
      ]
    }
  }
}

五、ES的分词器(安装分词器)

5.0、基本概念(Analysis与Analyzer)

Analysis:文本分析是指把全文本转换成一系列单词(term/token)的过程,也叫分词。

Analyzer:分词器。Analysis是由Analyzer实现的。分词就是将文档通过Analyzer分成一个个Term(关键词),每个Term都指向包含这个Term的文档。

分词器(Analyzer)组成:执行也按照如下顺序。不同分词器实现不同,一般②是必须有的。

①字符过滤器(character filter):对文本分词之前进行预处理,例如过滤掉html的标签等特殊字符、把&转换成and之类的。
②分词器(tokenizers):英文分词就根据空格将单词分开;中文比较复杂,可以采用机器学习算法来分词。
③token过滤器(Token filters):将切分的单词进行加工。如大小写转换、去掉停用词(如a、the这种)、加入同义词。 

总结:总的来讲就是字符过滤后的结果交给分词器tokenizers,它会将一串文本根据词典分成一个个的词,输出的是tokens数据流(一个analyzer有且只有一个tokenizer)。token filter则是对分词之后的结果进行处理,例如大小写转换、关联同义词、去掉停用词、不同语言映射等(一个analyzer可以有0个或多个filter)。每个tokenizer或者token filter都还有自己独特的配置。

一般情况下我们会使用自定义的analyzer,同时也会自定义其中的tokenizer部分。

 如下为一个自定义的例子,接下来会对ngram分词器以及自定义分词器进行解释。

"settings" : {
  "index" : {
    "routing" : {
      "allocation" : {
        "include" : {
          "temperature" : "hot"
        }
      }
    },
    "refresh_interval" : "30s",
    "number_of_shards" : "9",
    "routing_partition_size" : "2",
    "translog" : {
      "sync_interval" : "5s",
      "durability" : "async"
    },
    "analysis" : {    #固定格式,表示接下来是分词设置
      "tokenizer" : { #表示接下来是分词器的设置;就是三部分之一的tokenizers
        "my_ngram_tokenizer" : {  #自定义的分词器的名称为"my_ngram_tokenizer";mappings中设置对应字段的分词器analyzer时就应该填这个名字。
          #指定生成的token序列中应该包含哪些类型的字符。默认为[],意味保留所有字符;这个时候就是纯粹的长度为n的滑动窗口。经过测试有过滤的效果。按照纯粹滑动窗口分词得到token流;在此基础上仅保留指定的类型,即token流中包含未指定的类型的token会被过滤掉。(貌似是这个意思)。
          "token_chars" : [ 
            "digit", #数字:如 3,4
            "letter" #
          ],
          "type" : "ngram",  #指定类型就是"ngram"类型tokenizer(注:这里的自定义其实就是在ngram基础上定制了一些配置)
          "min_gram" : "1",  #以gram为单位的最小字符长度,默认为1。注:ngram tokenizer接受的参数之一
          "max_gram" : "1"   #以gram为单位的最大字符长度,默认为2。注:ngram tokenizer接受的参数之一
        }
      },
      "analyzer" : {  #固定格式,表示接下来是分词设置
        "my_ngram_analyzer" : { #自定义analyzer名称为"my_ngram_analyzer"
          "tokenizer" : my_ngram_tokenizer" #其采用的tokenizer为"my_ngram_tokenizer",显然这个也是自定义的
        }
      },
      "filter":[ #应该就是Token filters部分了,这里指定都转换为小写形式
        "lowercase"
      ]
    },
    "number_of_replicas" : "1"
  }
}

5.1、ES内置分词器及效果测试

①Standard Analyzer(标准分词器):英文按单词切分,小写处理、中文单字处理。 为默认分词器。

②Simple Analyzer(简单分词器):按照单词切分(符号被过滤),小写处理、中文按空格分词。

③Stop Analyzer: 小写处理,停用词过滤。

④Whiltespace Analyzer:按照空格切分,不转小写

⑤Keyword Analyzer:不分词,直接将输入作为输出。

分词器测试分词效果:

#标准分词器
POST /_analyze
{
  "analyzer": "standard",
  "text":"I love you, 问世间情为何物"
}


#简单分词器
POST /_analyze
{
  "analyzer": "simple",
  "text":"I love you, 问世间情为何物"
}
注:中文就是按照空格分词

5.2、创建索引设置分词


#无非就是指定数据类型平齐的位置也指定下分词器就好了
PUT /test
{
  "mappings": {
    "properties": {
      "title":{
        "type":"text",
        "analyzer": "keyword"
      }
    }
  }
}

5.3、中文分词器(IK分词器)安装

根据前面知道ES内置的分词器都是不适应于中文的;为此需要使用专门的中文分词器。

常用的中文分词器有 smartCN、IK等,这里推荐最常见的IK分词器(Lucene时期就存在、对中文的处理也更智能)。

注意:IK分词器的版本要和ES的版本完全一致(小版本号也要完全一致)。

(0)在ES安装路径的plugins目录下新建ik目录

#叫什么名字无所谓;ES会自动扫描plugins路径中的信息,发现插件后会自动加载。
mkdir ik
cd ik

(1)选择对应的版本,并下载。

wget https://github/medcl/elasticsearch-analysis-ik/releases/download/v7.14.0/elasticsearch-analysis-ik-7.14.0.zip

 github现在对应版本: IK

(2)解压

unzip elasticsearch-analysis-ik-7.14.0.zip

注:如果没有unzip需要用yum install -y unzip 安装

(3)重启ES就可以了。

5.4、中文分词器(IK分词器)使用

IK分词器有两种颗粒度的拆分,两种分词简名分别是ik_smart和ik_max_word:

ik_smart:最粗粒度的拆分。

ik_max_word:会将文本做最细粒度的拆分。注:该分词器不会对英文和数字进行分词。

如下实际测试就可以直观看到分词效果。 

POST /_analyze
{
  "text":"中华人民",
  "analyzer": "ik_smart"
}
输出如下:
{
  "tokens": [
    {
      "token": "中华人民",
      "start_offset": 0,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 0
    }
  ]
}



POST /_analyze
{
  "text":"中华人民",
  "analyzer": "ik_max_word"
}
输出如下:
{
  "tokens": [
    {
      "token": "中华人民",
      "start_offset": 0,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 0
    },
    {
      "token": "中华",
      "start_offset": 0,
      "end_offset": 2,
      "type": "CN_WORD",
      "position": 1
    },
    {
      "token": "华人",
      "start_offset": 1,
      "end_offset": 3,
      "type": "CN_WORD",
      "position": 2
    },
    {
      "token": "人民",
      "start_offset": 2,
      "end_offset": 4,
      "type": "CN_WORD",
      "position": 3
    }
  ]
}

5.5、扩展词、停用词配置

IK支持自定义 扩展词典 和 停用词典。

扩展词典:有些词并不是关键词,但是也希望被ES用来作为检索的关键词,可以将这些词加入扩展词典。

停用词典:有些此是关键词,但是出于业务需要不想这些关键词被检索到,可以将这些词放入停用词典。

举个例子:现在有一家公司名称为“全知科技”,另外有一个员工叫做“谭锦黎”。默认情况下即便是ik_max_word也不知道"全知"、“谭锦黎”是一个单独的词,但是我又有这种“全知  谭锦黎”的搜索需求。这个时候我们就可以借助扩展词配置来实现。

具体配置:

(0)分词器下有如下文件“分词器/config/IKAnalyzer.cfg.xml”,内容如下。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun/dtd/properties.dtd">
<properties>
        <comment>IK Analyzer 扩展配置</comment>
        <!--用户可以在这里配置自己的扩展字典 -->
        <entry key="ext_dict"></entry>
         <!--用户可以在这里配置自己的扩展停止词字典-->
        <entry key="ext_stopwords"></entry>
        <!--用户可以在这里配置远程扩展字典 -->
        <!-- <entry key="remote_ext_dict">words_location</entry> -->
        <!--用户可以在这里配置远程扩展停止词字典-->
        <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>

(1)在配置文件中指定扩展字典文件名称为 shuozhuoext.dict

(2)然后在此路径下创建shuozhuoext.dic文件,并在文件中添加你想要扩展的关键词,如下。

(3)然后重启ES 

(4)验证效果如下

 (5)另外分词器/config目录下也给我们预先配置好了诸多生僻的词组,存与对应的.dic文件中。

通常扩展词典/停用词典分别就在默认的extra_main.dic和extra_stopword.dic中扩展就行了。

必要的时候再自己创建词典。

5.6、ngram tokenizer 详解    官网

        ngram是一种类型的tokenizer,这里作为tokenizer的一个代表讲解下。ngram代表的是n个字符的序列。可以把ngram理解成长度为n的滑动窗口,在文档中滑动产生的序列。如下,查看“Hello world”的ngram输出。注:默认情况下ngram会产生最小长度为1,最大长度为2的N-gram序列。

         一般情况如果想实现模糊查询通常会采用ngram分词器。以金融为例模糊查询的大致一般为:查询基金/A股/港股等金融数据,要求可以根据字段拼音首字母部分拼音全称进行联想查询。常用的模糊查询如wildcard、fuzzy等由于性能原因一般不建议使用。通常会采用更加灵活的分词器来解决多条件模糊查询问题。

        ngram 分词器与传统的 standard 分词器或者是 ik 分词器相比,他的优点是可以分词出特殊字符,因此,在对字段查询时可以采用 ngram 分词器;而对拼音全称以及首字母查询时,可以使用 keyword 与 拼音 结合的自定义分词。注:具体用的时候可以多搜搜ngram使用案例,学习研究。

POST _analyze
{
  "tokenizer": "ngram",
  "text": "Hello world"
}

上述语句输出的序列为:

[H,He,e,el,l,ll,l,lo,o,"o "," "," w",w,wo,o,or,r,rl,l,ld,d]

 我们也可以自定义ngram tokenizer的一些配置:

1、min_gram:指定产生的最小长度的字符序列,默认为1
2、max_gram:指定产生的最常长度字符序列,默认为2
3、token_chars:指定生成的token序列中应该包含哪些类型的字符。默认为[],意味保留所有字符;这个时候就是纯粹的长度为n的滑动窗口。经过测试有过滤的效果。按照纯粹滑动窗口分词得到token流;在此基础上仅保留指定的类型,即token流中包含未指定的类型的token会被过滤掉。(貌似是这个意思)
字符类型如下:
    letter - eg: a, b, 字
    digit - eg: 3,7
    whitespace - eg: " ", "\n"
    punctuation - eg: ! or "
    symbol - eg: $,√

调整一些配置查看效果。

#设置min_gram、max_gram均为4;

PUT my_index1
{
   "settings": {
      "analysis": {
         "tokenizer": {
            "my_ngram_tokenizer": {
               "type": "ngram",
               "min_gram": 4,
               "max_gram": 4,
               "token_chars": []
            }
         },
         "analyzer": {
            "my_ngram_tokenizer": {
               "type": "custom",
               "tokenizer": "my_ngram_tokenizer",
               "filter": [
                  "lowercase"
               ]
            }
         }
      }
   }
}


#执行如下分词语句
POST my_index1/_analyze
{
  "analyzer": "my_ngram_tokenizer",
  "text": "Hello World"
}

结果如下。果然就是长度为4的窗口滑动。
["Hell","ello","llo ","lo W","o Wo"," Wor","Worl","orld"]

#另外将token_chars设置为 [ "letter", "digit" ] 

PUT my_index1
{
   "settings": {
      "analysis": {
         "tokenizer": {
            "my_ngram_tokenizer": {
               "type": "ngram",
               "min_gram": 4,
               "max_gram": 4,
               "token_chars": [ "letter", "digit" ]
            }
         },
         "analyzer": {
            "my_ngram_tokenizer": {
               "type": "custom",
               "tokenizer": "my_ngram_tokenizer",
               "filter": [
                  "lowercase"
               ]
            }
         }
      }
   }
}

同样执行上述分词语句,结果如下。注:其中含有空格"whitespace"的全部被过滤掉了。
["Hell",ello,Worl,orld]

官网上有如下建议:

通常会将min_gram和max_gram设为同样的值。值越小,匹配的文档越多,但是匹配的质量也会越差;与之对应,值越大,越能匹配到指定的文档。一般max_gram越大空间占用也越大,相当于更耗费存储资源。

It usually makes sense to set min_gram and max_gram to the same value. The smaller the length, the more documents will match but the lower the quality of the matches. The longer the length, the more specific the matches. A tri-gram (length 3) is a good place to start.

5.7、可以给某个字段设置多个分词器

下文中的msg_content字段其实就定义了两个分词器。默认用的就是自定义的分词器“my_ngram_analyzer”。

{
  "es_flow_oa_template" : {
    "order" : 0,
    "index_patterns" : [
      "es_flow_oa_v2_*"
    ],
    "setting":{
        xxx
        xxx
    },
    "mappings" : {
      "session" : {
        "_routing" : {
          "required" : true
        },
        "properties" : {
          "msg_content" : {
            "type" : "text",   #text类型,毕竟要分词嘛
            "analyzer" : "my_ngram_analyzer", #上文中出现的自定义分词器
            "fields" : {  #第二个ik分词器
              "ik" : {  #自己取的一个名字,引用的话需要指定,即"msg_content.ik"
                "type" : "text",
                "analyzer" : "ik_max_word"  #ik分词器中的 ik_max_word
              }
            }
          }
        }
      }
    },
    "aliases" : {
      "es_flow_oa" : { }
    }
  }
}
#指定其中的ik分词器
{
    "size" : 100,
    "query" : { 
        "bool" : {
            "must" : {
                "bool" : {
                    "should" : [
                        {"match_phrase" : { "msg_content.ik" : {"query" : "hello word", "slop" : 0}}}
                    ],
                    "minimum_should_match" : 1
                }
            }
        }
    }    
}

#使用默认的 自定义分词器
{
    "size" : 100,
    "query" : { 
        "bool" : {
            "must" : {
                "bool" : {
                    "should" : [
                        {"match_phrase" : { "msg_content" : {"query" : "hello word", "slop" : 0}}}
                    ],
                    "minimum_should_match" : 1
                }
            }
        }
    }    
}

单字段设置多分词器测试。

#1、首先创建如下索引。注意其中的description字段设置了两个分词器。
①my_ngram_analyzer:为一个自定义分词器,其实实际效果就是单字(单字母)切分;如下测试其分词效果:
POST my_index1/_analyze
{
  "analyzer": "my_ngram_analyzer",
  "text": "我的联系方式17367078333"
}

②ik分词器,这里取名为zsik。

#索引如下:
PUT my_index1
{
   "settings": {
      "analysis": {
         "tokenizer": {
            "my_ngram_tokenizer": {
               "type": "ngram",
               "min_gram": 1,
               "max_gram": 1,
               "token_chars": [ "letter", "digit"]
            }
         },
        "analyzer" : {
            "my_ngram_analyzer" : {
              "tokenizer" : "my_ngram_tokenizer"
            }
        }
      }
   },
  "mappings": {
    "properties": {
      "title":{
        "type":"keyword"
      },
      "price":{
        "type":"double" 
      },
      "description":{
        "type":"text",
        "analyzer": "my_ngram_analyzer",
        "fields": {
          "zsik":{
            "type":"text",
            "analyzer":"ik_max_word"
          }
        }
      }
    }
  }
}


#2、插入如下数据
POST my_index1/_bulk
{"index":{}}
  {"title":"面包","price":19.9,"description":"小面包很好吃"}
{"index":{}}
  {"title":"大白兔","price":29.9,"description":"大白兔奶糖好吃"}
{"index":{}}
  {"title":"日本豆","price":19.9,"description":"日本豆非常好吃"}
{"index":{}}
  {"title":"旺仔小馒头","price":19.9,"description":"旺仔小曼斗很甜"}
{"index":{}}
  {"title":"大辣片","price":9.9,"description":"大辣片很诱人"}
{"index":{}}
  {"title":"脆司令","price":19.9,"description":"脆司令很管饿"}
{"index":{}}
  {"title":"喜之郎果冻","price":19.9,"description":"小时候的味道"}


#3、使用ik分词器搜索关键词
//"非常"、"好吃"、"小时候"等关键词都是可以搜到的
//但是"人"、"诱"、"吃"、"非"等单个字都是搜不到的.
分析: 显然即便是 ik_max_word 也不会达到这种单字级别的分词,所以搜不到。
GET /my_index1/_search   #搜得到
{
  "query": {
    "match": {
      "description.zsik": "非常"
    }
  }
}

GET /my_index1/_search    #搜不到
{
  "query": {
    "match": {
      "description.zsik": "非"
    }
  }
}


#4、使用默认的自定义的分词器搜
//"人"、"诱"、"吃"、"非"等单个字都可以搜到了;符合预期。
//搜关键字,例如“小时候”则会吧包含"小"、"时"、"候"任何一个字的都给搜出来;也是符合预期的
分析:由分词结果知道任意单字都是可以搜到的。

GET /my_index1/_search 
{
  "query": {
    "match": {
      "description": "非"
    }
  }
}


GET /my_index1/_search
{
  "query": {
    "match": {
      "description": "小吃货"
    }
  }
}

六、ES 修改setting常用操作

6.0、REST语法

#更新某个特定索引
PUT /myindex/_settings
{
    #具体操作
}


#更新所有索引
PUT */_settings
{
 "index.blocks.read": true   #具体操作
} 

6.1、修改备份数

#修改备份数
PUT /myindex/_settings
{
  "index":{
    "number_of_replicas":2
  }  
}

6.2、设置索引读写属性

主要就是设置索引的读写属性。可读、可写、禁读、禁写。

#给某索引设置禁读
PUT es_qidian_flow_oa_20210502/_settings
{
  "index.blocks.read":true
}

#取消该索引的禁读
PUT es_qidian_flow_oa_20210502/_settings
{
  "index.blocks.read":false
}

#正则匹配索引也是ok的
PUT es_qidian_flow_oa_202105*/_settings
{
  "index.blocks.read":true
}


#对整个ES全量禁流(全量索引 禁止读  禁止写)  注:慎重
PUT */_settings
{
 "index.blocks.read": true,
 "index.blocks.write": true
}


#取消全员禁流
PUT */_settings
{
 "index.blocks.read": false,
 "index.blocks.write": false
}



相关属性如下:

index.blocks.read_only:设为true,则索引以及索引的元数据只可读

index.blocks.read_only_allow_delete:设为true,只读时允许删除。

index.blocks.read:设为true,则不可读。

index.blocks.write:设为true,则不可写。

index.blocks.metadata:设为true,则索引元数据不可读写。

实测如下:

①选择索引es_qidian_flow_oa_20210502,实测可以访问

GET es_qidian_flow_oa_20210502/session/_search
{
  "size":100,
  "query": {
    "match_all": {}
  }
}

②设置禁读

PUT es_qidian_flow_oa_20210502/_settings
{
  "index.blocks.read":true
}

 ③尝试访问

重复执行①的查询语句,提示如下报错。

④取消禁读 后又可以访问了

PUT es_qidian_flow_oa_20210502/_settings
{
  "index.blocks.read":false
}

更多推荐

ELK之Elasticsearch&Kibana安装/学习

本文发布于:2023-06-13 21:45:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1408781.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Elasticsearch   ELK   Kibana   amp

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!