一、介绍

ELK其实并不是一款软件,而是一整套解决方案,是三个软件产品的首字母缩写,Elasticsearch,Logstash 和 Kibana。这三款软件都是开源软件,通常是配合使用,而且又先后归于 Elastic.co 公司名下,故被简称为ELK技术栈。

  • Elasticsearch:Elasticsearch是一个实时的分布式搜索和分析引擎,它可以用于全文搜索,结构化搜索以及分析。它是一个建立在全文搜索引擎Apache Lucene基础上的搜索引擎,使用Java语言编写。
  • Kibana:Kibana是一个免费且开放的用户界面,能够让您对Elasticsearch数据进行可视化。Kibana是一款基于Apache开源协议的可视化Web管理平台。它可以在Elasticsearch的索引中查找,交互数据,并生成各种维度的表图。
  • Logstash:Logstash 是免费且开放的服务器端数据处理管道,能够从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的“存储库”中。使用JRuby语言编写。其作者是世界著名的运维工程师乔丹西塞 (JordanSissel)

 二、Elasticsearch

(1)介绍

Elasticsearch是一个基于Lucene的搜索服务器。它提供了一个分布式的全文搜索引擎,其对外服务是基于RESTful web接口发布的。Elasticsearch是用Java开发的应用,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到近实时搜索,稳定,可靠,快速,安装使用方便。

(2)主要功能

Elasticsearch具备两个主要功能:

  • 搜索:代替目前(海量数据)的MySQL模糊查询。
  • 分析:结合LogStash使用。类似数据库中的聚合统计查询。

(3)核心概念

1.Cluster

集群:Elasticsearch集群由一或多个节点组成,其中有一个主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。Elasticsearch的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部看Elasticsearch集群,在逻辑上是个整体,你与集群中的任何一个节点通信和与整个Elasticsearch集群通信是等价的。也就是说,主节点的存在不会产生单点安全隐患、并发访问瓶颈等问题。

2.Index(表)

索引:相当于关系型数据库中的表。其中存储若干相似结构的Document数据。如:客户索引,订单索引,商品索引等。Elasticsearch中的索引不像数据库表格一样有强制的数据结构约束,在理论上,可以存储任意结构的数据。但了为更好的为业务提供搜索

3.Shards(主分片)

Primary Shard:代表索引的主分片,Elasticsearch可以把一个完整的索引分成多个primary shard,这样的好处是可以把一个大的索引拆分成多个分片,分布存储在不同的Elasticsearch节点上,从而形成分布式存储,并为搜索访问提供分布式服务,提高并发处理能。primary shard的数量只能在索引创建时指定,并且索引创建后不能再更改primary shard数量。

 4.Replicas(副本)

Replica Shard:代表索引主分片的副本,Elasticsearch可以设置多个replica shard。replica shard的作用:一是提高系统的容错性,当某个节点某个primary shard损坏或丢失时可以从副本中恢复。二是提高Elasticsearch的查询效率,Elasticsearch会自动对搜索请求进行负载均衡,将并发的搜索请求发送给合适的节点,增强并发处理能力。

5.Type(逻辑分类)

类型:每个索引中都必须有唯一的一个Type,Type是Index中的一个逻辑分类。Elasticsearch中的数据Document是存储在索引下的Type中的。

6.Document(一条数据)

文档:Elasticsearch中的最小数据单元。一个Document就是一条数据,一般使用JSON数据结构表示。每个Index下的Type中都可以存储多个Document。一个Document中可定义多个field,field就是数据字段。如:学生数据({"name":"张三", "age":20, "gender":"男"})。

 7.MetaData(有特殊含义的属性,可以理解为关键字)

元数据:在Elasticsearch中所有以“_”开头的属性都成为元数据,都有着自己特定的含义。

8.Inverted Index(优化检索的关键)

倒排索引:对数据进行分析,抽取出数据中的词条,以词条作为key,对应数据的存储位置作为value,实现索引的存储。这种索引称为倒排索引。倒排索引是Document写入Elasticsearch时分析维护的。

 三、安装Elasticsearch和Kibana

(1)拉取Elasticsearch镜像

docker pull elasticsearch:7.6.2

(2)创建并启动Elasticsearch容器

9200是基于http协议的服务端口,9300是基于TCP协议的服务端口

docker run --name elasticsearch -d -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.6.2

(3)拉取Kibana镜像

docker pull kibana:7.6.2

(4)创建并启动Kibana容器

端口5601

docker run -d --name kibana --link elasticsearch:elasticsearch -p 5601:5601 kibana:7.6.2

四、常见Elasticsearch管理操作

 (1)查看健康状态

GET /_cat/health?v

含义

表头

数据

编号

epoch

1640140938

时间戳

timestamp

02:42:18

集群名称

cluster

docker-cluster

健康状态

status

green

节点总数

node.total

1

数据节点数

node.data

1

总分片数

shards

5

主分片数量

pri

5

备份分片数量

relo

0

正在初始化的分片

init

0

未分配的分片

unassign

0

正在等待执行的任务

pending_tasks

0

挂起任务的等待时间

max_task_wait_time

-

活动的分片的占有百分比

active_shards_percent

100.0%

健康状态含义说明

 status值包括:green、yellow、red

- green:每个索引的primary shard和replica shard都是active的。
- yellow:每个索引的primary shard都是active的,但部分的replica shard不是active的。
- red:不是所有的索引的primary shard都是active状态的。

 (2)查看节点信息

GET /_cat/nodes?v

含义

表头

数据

ES主机地址

ip

172.17.0.5

堆占用率

heap.percent

13

内存占用率

ram.percent

96

CPU占用率

cpu

2

每分钟平均运行命令

load_1m

0.46

每5分钟平均运行命令

load_5m

0.21

每15分钟平均运行命令

load_15m

0.20

ES节点权限

node.role

dilm

是否是主节点

master

*

ES节点名称

name

dd99a098c1f0

(3)查看Elasticsearch中的全部索引 

GET /_cat/indices?v

含义

表头

数据

健康状态

health

green

索引是否可用

status

open

索引名称

index

.kibana_1

索引唯一键

uuid

3opvkLJPQdaDCYuEBGZFRA

主分片数量

pri

1

副本分片数量

rep

0

索引中文档总数

docs.count

16

索引中已删除文档数

docs.deleted

0

索引总计占用空间

store.size

23kb

索引主分片占用空间

pri.store.size

23kb

(4)查看分片信息

 GET /_cat/shards?v

含义

表头

数据

索引名称

index

.kibana_1

分片编号(从0开始自然数递增)

shard

0

主分片(p)或副本分片(r)

prirep

p

分片状态

state

STARTED

分片中文档数

docs

16

分片占用存储空间

store

26kb

分片所在ES服务器IP

ip

172.17.0.5

分片所在ES服务器名称

node

dd99a098c1f0

(5)创建索引

命令语法:PUT 索引名{索引配置参数} index名称必须是小写的,且不能以下划线'_','-','+'开头。 ElasticSearch7.x版本中,默认创建索引时,分配一个Primary Shard,每个Primary Shard分配一个Replica Shard。在Elasticsearch6.x及更早版本中,默认的创建索引的时候,会分配五个Primary Shard,并为每个Primary Shard分配一个Replica Shard。在Elasticsearch中,默认的限制是:如果磁盘空间不足15%的时候,不分配Replica Shard。如果磁盘空间不足5%的时候,不再分配任何的Primary Shard。Elasticsearch中对shard的分布是有要求的。Elasticsearch尽可能保证Primary Shard平均分布在多个节点上。Replica Shard会保证不和他备份的那个Primary Shard分配在同一个节点上,且每个节点中不会存在相同的备份Replica Shard。

PUT /index_test_1 

(6)创建索引并指定配置

PUT /index_test_1
 {
   "settings":{
     "number_of_shards" : 2, #主分片数量
     "number_of_replicas" : 0 #每个主分片的副本分片数量
   }
 }

(7)修改索引

PUT /index_test_2/_settings
 {
   "number_of_replicas" : 2
 }

(8)查看索引详情 

GET /index_test_1

(9)删除索引

DELETE /index_test_1,index_test_2 

(10)PUT新增文档(_doc)

PUT语法新增文档时,默认逻辑是:如果主键_id不存在,则新增数据;存在则覆盖旧数据。

PUT /index_test_1/_doc/1
 {
   "name":"张三",
   "address":"北京亦庄"
 }

(11)PUT强制新增(_create)

PUT语法新增文档时,可以通过参数实现强制新增。其逻辑是:如果主键_id不存在,则新增数据;存在则抛出异常。

PUT /index_test_1/_create/2
 {
   "name":"李四",
   "address":"北京亦庄"
 }

(12)POST文档新增

POST语法新增文档特性和PUT语法新增文档一致,只是POST允许主键自动生成。

POST /index_test_1/_doc
 {
   "name":"王五",
   "address":"北京亦庄"
 }

(13)GET根据主键查询文档(_doc)

GET /index_test_1/_doc/1

(14)GET根据主键批量查询文档(_mget)

GET /index_test_1/_mget
 {
   "docs":[
     {
       "_id":1
     },
     {
       "_id":2
     }
   ]
 }

(15)GET查询全部(_search)

GET /index_test_1/_search

(16)全文替换

和新增的PUT|POST语法是一致。

PUT /index_test_1/_doc/1
 {
   "name":"张三",
   "address":"北京亦庄"
 }

(17)POST部分文档更新(_update

POST /index_test_1/_update/1
 {
   "doc":{
     "address":"赛帝工业园",
     "age":22
   }
 }

(18)DELETE删除文档(_doc)

DELETE /index_test_1/_doc/1

(19)bulk批量增删改

使用bulk语法执行批量增删改。注意:_bulk的所有{}有强制要求,每个{}必须是一行,多个{}之间必须另起一行。语法格式如下: POST [/索引名称/_doc]/_bulk { "action_type" : { "metadata_name" : "metadata_value" } } { document datas } 语法中的action_type可选值为:

  • create:强制新增,相当于PUT /索引名/_create/主键。
  • index:
  • update:
  • delete:
POST /_bulk
 { "create" : { "_index" : "index_test_1" , "_id" : "1" } }
 { "name" : "测试create" }
 { "index" : { "_index" : "index_test_1" , "_id" : "1" } }
 { "name" : "批量新增name1" , "address" : "批量新增address1" }
 { "index" : { "_index" : "index_test_1" , "_id" : "2" } }
 { "name" : "批量新增name2" , "address":"批量新增address2" }
 { "delete" : { "_index" : "index_test_1" , "_id" : "1" } }
 { "update" : { "_index" : "index_test_1" , "_id" : "2" } }
 { "doc" : { "address" : "批量更新address3" } }

五、分词器和标准化处理

 当一个文档被索引时,每个Field都可能会创建一个倒排索引(Mapping可以设置不索引该Field)。创建倒排索引的过程就是将文档通过Analyzer分成一个一个的Term,每一个Term都指向包含这个Term的文档集合。当搜索(search)时,Elasticsearch会根据搜索类型决定是否对搜索条件进行Analysis,然后和倒排索引中的term进行相关性查询,匹配相应的文档。

(1) Elasticsearch常见的内置的分词器

1. standard

切分过程中不会忽略停止词(如:the、a、an等)。会进行单词的大小写转换、过滤连接符(-)或括号等常见符号。

GET /_analyze
 {
   "text": "Set the shape to semi-transparent by calling set_trans(5)",
   "analyzer": "standard"
 }

2.simple

就是将数据切分成一个个的单词。使用较少,经常会破坏英语语法。

GET /_analyze
 {
   "text": "Set the shape to semi-transparent by calling set_trans(5)",
   "analyzer": "simple"
 }

3.whitespace

就是根据空白符号切分数据。如:空格、制表符等。使用较少,经常会破坏英语语法。

GET /_analyze
 {
   "text": "Set the shape to semi-transparent by calling set_trans(5)",
   "analyzer": "whitespace"
 }

4.language

据英语语法分词,会忽略停止词、转换大小写、单复数转换、时态转换等。

GET /_analyze
 {
   "text": "Set the shape to semi-transparent by calling set_trans(5)",
   "analyzer": "english"
 }

(2)中文分词器 - IK

IK分词器提供了两种analyzer,分别是ik_max_word和ik_smart。

ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,国,国歌”,会穷尽各种可能的组合;

ik_smart: 会做粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”。

GET _analyze
 {
   "text" : "中华人民共和国国歌",
   "analyzer": "ik_max_word"
 }
GET _analyze
 {
   "text" : "中华人民共和国国歌",
   "analyzer": "ik_smart"
 }

六、Elasticsearch中的Mapping问题

(1)介绍

Mapping在Elasticsearch中是非常重要的一个概念。决定了一个index中的field使用什么数据格式存储,使用什么分词器解析,是否有子字段等。

(2)数据类型

只有text类型能被分词

类型

类型名称

文本(字符串)

text

整数

byte、short、integer、long

浮点型

float、double

布尔类型

boolean

日期类型

date

数组类型

array {a:[]}

对象类型

object {a:{}}

不分词的字符串(关键字)

keyword

 (3)查看索引中的Mapping

GET /index_test_1/_mapping

elk 题库 elk技术_数据

 (4)自定义映射

语法:

PUT /索引名称
 {
   "mappings":{
     "properties":{
       "字段名":{
         "type":类型,
         ["analyzer":字段的分词器(默认standard),]
         ["index":是否创建索引树(默认true,创建索引),]
         ["fields":{
           "子字段名称":{
             "type":类型,
             "ignore_above":长度限制
           }
         }]
       }
     }
   }
 }

案例:

put /index_mapping_1
 {
   "mappings":{
     "properties":{
       "id":{
         "type":"long",
         "index":false
       },
       "name":{
         "type":"text",
         "index":true,
         "analyzer":"ik_max_word"
       },
       "remark":{
         "type":"text",
         "analyzer":"ik_smart",
         "fields" : {
           "keyword" : {
             "type" : "keyword",
             "ignore_above" : 16
           }
         }
       },
       "gender":{
         "type":"keyword"
       }
     }
   }
 }

(5)为已有的索引增加新的字段Mapping

语法:

PUT /索引名/_mapping
 {
   "properties":{
     "新字段名":{
       "type":类型,
       ["analyer":字段的分词器,]
       ["index":是否创建索引树(默认true,创建索引),]
       ["fields":{
         "子字段名":{
           "type":类型,
           "ignore_above":长度
         }
       }]
     }
   }
 }

案例:

PUT /index_mapping_1/_mapping
 {
     "properties":{
       "address":{
         "type":"text",
         "analyzer":"ik_max_word"
       }
   }
 }

七、Search搜索详解

(1)搜索全部

GET /_search

timeout参数:是超时时长定义。代表每个节点上的每个shard执行搜索时最多耗时多久。不会影响响应的正常返回。只会影响返回响应中的数据数量。

GET /_search?timeout=10ms

(2)指定索引搜索

GET /index_test_1,test_search/_search

(3)索引的模糊搜索

GET /index_*/_search

GET /test_*/_search

(4) 在所有字段中搜索

GET /test_search/_search?q=sales

(5)在指定字段中搜索

GET /test_search/_search?q=+dname:sales

(6)在指定字段中搜索不存在

GET /test_search/_search?q=-dname:sales

(7)分页搜索

from代表从第几个文档开始(从0开始,自然数递增,默认0),size代表搜索多少个文档(默认10)。

GET /test_search/_search?from=0&size=2

(8)搜索结果排序

排序规则: asc(升序,默认) | desc(降序)

GET /test_search/_search?sort=eage:asc

GET /test_search/_search?sort=eage:desc

八、DSL Search搜索详解

(1)搜索全部

GET /test_search/_search
 {
    "query" : { "match_all" : {} }
 }

(2)匹配搜索(match)

GET /test_search/_search
 {
   "query": {
     "match": {
       "dname": "sales department"
     }
   }
 }

(3)短语搜索(match_phrase)

GET /test_search/_search
 {
   "query": {
     "match_phrase": {
       "dname": "sales department"
     }
   }
 }

(4)范围搜索(range)

GET /test_search/_search
 {
   "query" : {
     "range" : {
       "eage" : {
         "gte" : 20,
         "lte" : 30
       }
     }
   }
 }

(5)多条件复合搜索

GET /索引名/_search
 {
   "query": {
     "bool": {
       "must": [ #数组中的多个条件必须同时满足
         {
           "range": {
             "字段名": {
               "lt": 条件
             }
           }
         }
       ],
       "must_not":[ #数组中的多个条件必须都不满足
         {
           "match": {
             "字段名": "条件"
           }
         },
         {
           "range": {
             "字段名": {
               "gte": "搜索条件"
             }
           }
         }
       ],
       "should": [# 数组中的多个条件有任意一个满足即可。 当和must一起使用的时候,丧失意义。minimum_should_match=1设置至少满足一个条件。
         {
           "match": {
             "字段名": "条件"
           }
         },
         {
           "range": {
             "字段名": {
               "gte": "搜索条件"
             }
           }
         }
       ]
     }
   }
 } GET /test_search/_search
 {
   "query": {
     "bool": {
       "must": [ 
         {
           "range": {
             "eage": {
               "lte": 26,
               "gte": 20
             }
           }
         }
       ],
       "should": [
         {
           "match": {
             "dname": "Sales Department"
           }
         },
         {
           "match": {
             "ename": "张三"
           }
         }
       ]
     }
   }
 }

(6)排序

GET 索引名/类型名/_search
 {
   "query" : { "match_all" : {} },
   "sort": [
     {
       "gender": {
         "order": "asc"
       }
     },
     {
       "eage": {
         "order": "desc"
       }
     }
   ]
 }

(7)分页

GET 索引名称/_search
 {
   "query":{
     "match_all":{}
   },
   "from": 0,
   "size": 2
 }

(8)高亮

参数名

参数含义

fragment_size

代表字段数据如果过长,则分段,每个片段数据长度为多少。长度不是字符数量,是Elasticsearch内部的数据长度计算方式。默认不对字段做分段。

number_of_fragments

代表搜索返回的高亮片段数量,默认情况下会将拆分后的所有片段都返回。

pre_tags

高亮前缀。

post_tags

高亮后缀。

GET /索引名/_search
 {
   "query": {
     "match": {
       "字段名": "条件"
     }
   },
   "highlight": {
     "fields": {
       "要高亮显示的字段名": {
         "fragment_size": 5, #每个分段长度,默认20
         "number_of_fragments": 1 #返回多少个分段,默认3
       }
     },
     "pre_tags": ["前缀"], 
     "post_tags": ["后缀"] 
   }
 }GET /test_search/_search
 {
   "query": {
     "bool": {
       "should": [
         {
           "match": {
             "dname": "Development department"
           }
         },
         {
           "match": {
             "gender": "男性"
           }
         }
       ]
     }
   },
   "highlight": {
     "fields": {
       "dname": {
         "fragment_size": 20,
         "number_of_fragments": 1
       },
       "gender": {
         "fragment_size": 20,
         "number_of_fragments": 1
       }
     },
     "pre_tags":["<span style='color:red'>"],
     "post_tags":["</span>"]
   }, 
   "from": 2,
   "size": 2
 }