一、介绍
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: 更新操作(partial update),相当于 POST /索引名/_update/唯一ID{doc:{字段名:字段值}}。
-
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
(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
}