Elastic Stack简介及es简单操作

如果你没有听说过 Elastic Stack ,那你一定听说过 ELK ,实际上 ELK 是三款软件的简称,分别是 Elasticsearch
Logstash Kibana 组成,在发展的过程中,又有新成员 Beats 的加入,所以就形成了 Elastic Stack 。所以说, ELK
是旧的称呼, Elastic Stack 是新的名字。
 

全系的Elastic Stack技术栈包括:

Elasticsearch
Elasticsearch 基于 java ,是个开源分布式搜索引擎,它的特点有:分布式,零配置,自动发现,索引自动分片,索
引副本机制, restful 风格接口,多数据源,自动搜索负载等。
Logstash
Logstash 基于 java ,是一个开源的用于收集 , 分析和存储日志的工具。
Kibana
Kibana 基于 nodejs ,也是一个开源和免费的工具, Kibana 可以为 Logstash ElasticSearch 提供的日志分析友好
Web 界面,可以汇总、分析和搜索重要数据日志。
Beats
Beats elastic 公司开源的一款采集系统监控数据的代理 agent ,是在被监控服务器上以客户端形式运行的数据收集
器的统称,可以直接把数据发送给 Elasticsearch 或者通过 Logstash 发送给 Elasticsearch ,然后进行后续的数据分析
活动。
Beats 由如下组成 :
Packetbeat :是一个网络数据包分析器,用于监控、收集网络流量信息, Packetbeat 嗅探服务器之间的流
量,解析应用层协议,并关联到消息的处理,其支 持 ICMP (v4 and v6) DNS HTTP Mysql
PostgreSQL Redis MongoDB Memcache 等协议;
Filebeat :用于监控、收集服务器日志文件,其已取代 logstash forwarder
Metricbeat :可定期获取外部系统的监控指标信息,其可以监控、收集 Apache HAProxy MongoDB
MySQL Nginx PostgreSQL Redis System Zookeeper 等服务;
Winlogbeat :用于监控、收集 Windows 系统的日志信息;
 
2 Elasticsearch
2.1 、简介

官网:https://www.elastic.co/cn/products/elasticsearch

 

功能lasticsearch的功能

(1)分布式搜索和分析引擎

(2)全文检索,结构化检索,数据分析

(3)对海量数据进行近实时的处理

分布式:ES自动可以将海量数据分散到多台服务器上存储和检索

海量数据的处理:分布式以后,就可以采用大量的服务器去存储和检索数据,自然而然就可以实现海量数据的处理了

跟分布式/海量数据相反的,lucene,单机应用,只能在单台服务器上使用,最多只能处理单台服务器可以处理的数据量。

近实时:在秒级别对数据进行搜索和分析​​​​​​​

yin

应用: 

的适用11yingyong 场景

(1)维基百科,全文检索,高亮,搜索推荐

(2)新闻网站,用户日志+社交网络数据,分析

(3)Stack Overflow(国外的程序异常讨论论坛),全文检索,搜索相关问题和答案

(4)GitHub(开源代码管理),搜索上亿行代码

(5)电商网站,检索商品

(6)日志数据分析,logstash采集日志,ES进行复杂的数据分析

(7)商品价格监控网站,用户设定某商品的价格阈值,当低于该阈值的时候,发视消息给用户

(8)BI系统,ES执行数据分析和挖掘,Kibana进行数据可视化

(9)国内,站内搜索(电商,招聘,门户)

(10)BI 系统,商业智能,分析用户消费趋势和用户群体的组成构成。

特点 

  1. asticsearch的特点

(1)可以作为一个大型分布式集群(数百台服务器)技术,处理PB级数据,服务大公司,也可以运行在单机上,服务小公司

(2)Elasticsearch不是什么新技术,主要是将全文检索,数据分析以及分布式技术,合并在一起,才形成了独一无二的ES,lucene(全文检索)

(3)对用户而言,是开箱即用的,非常简单,作为中小型的应用,直接3分钟部署一下ES,就可以作为生产环境的系统来使用了,数据量不大,操作不是太复杂

(4)数据库的功能面对很多领域是不够的,优势:事务,各种联机事务型的操作,特殊的功能,比如全文检索,同义词处理,相关度排名,复杂数据分析,海量数据的近实时处理,Elasticsearch作为传统数据库的一个补充,提供了数据库所不能提供的很多功能。

2.2 、安装
2.2.1 、版本说明
Elasticsearch 的发展是非常快速的,所以在 ES5.0 之前, ELK 的各个版本都不统一,出现了版本号混乱的状态,所以
5.0 开始,所有 Elastic Stack中的项目全部统一版本号。现最新版本为7.9.2。
 
2.2.2 、下载
地址: https://www.elastic.co/cn/downloads/elasticsearch
 
安装步骤略
 
2.2.3 elasticsearch-head
由于 ES 官方并没有为 ES 提供界面管理工具,仅仅是提供了后台的服务。 elasticsearch-head 是一个为 ES 开发的一个
页面客户端工具,其源码托管于 GitHub ,地址为: https://github.com/mobz/elasticsearch-head
head 提供了 4 种安装方式:
源码安装,通过 npm run start 启动(不推荐)
通过 docker 安装(推荐)
通过 chrome 插件安装(推荐)
通过 ES plugin 方式安装(不推荐)
 
docker安装注意:
由于前后端分离开发,所以会存在跨域问题,需要在服务端做 CORS 的配置,如下:
vim elasticsearch.yml
http.cors.enabled: true http.cors.allow-origin: "*"
通过 chrome 插件的方式安装不存在该问题。
chrome 插件的方式安装
打开 chrome 的应用商店,即可安装 https://chrome.google.com/webstore/detail/elasticsearch-head/ffffmkiejjme
colpflfloofpjologoblkegm
 
 
2.3 、基本概念
索引
索引( index )是 Elasticsearch 对逻辑数据的逻辑存储,所以它可以分为更小的部分。
可以把索引看成关系型数据库的表,索引的结构是为快速有效的全文索引准备的,特别是它不存储原始值。
可以把 Elasticsearch 的索引看成 MongoDB 里的一个集合。
Elasticsearch 可以把索引存放在一台机器或者分散在多台服务器上,每个索引有一或多个分片( shard ),每
个分片可以有多个副本( replica )。
文档
存储在 Elasticsearch 中的主要实体叫文档( document )。用关系型数据库来类比的话,一个文档相当于数据
库表中的一行记录。
Elasticsearch MongoDB 中的文档类似,都可以有不同的结构,但 Elasticsearch 的文档中,相同字段必须有
相同类型。
文档由多个字段组成,每个字段可能多次出现在一个文档里,这样的字段叫多值字段( multivalued )。
每个字段的类型,可以是文本、数值、日期等。字段类型也可以是复杂类型,一个字段包含其他子文档或者
数组。
映射
所有文档写进索引之前都会先进行分析,如何将输入的文本分割为词条、哪些词条又会被过滤,这种行为叫
做映射( mapping )。一般由用户自己定义规则。
文档类型
Elasticsearch 中,一个索引对象可以存储很多不同用途的对象。例如,一个博客应用程序可以保存文章和
评论。
每个文档可以有不同的结构。
不同的文档类型不能为相同的属性设置不同的类型。例如,在同一索引中的所有文档类型中,一个叫 title 的字
段必须具有相同的类型。
2.4 RESTful API
Elasticsearch 中,提供了功能丰富的 RESTful API 的操作,包括基本的 CRUD 、创建索引、删除索引等操作。
2.4.1 、创建非结构化索引
Lucene 中,创建索引是需要定义字段名称以及字段的类型的,在 Elasticsearch 中提供了非结构化的索引,就是
不需要创建索引结构,即可写入数据到索引中,实际上在 Elasticsearch 底层会进行结构化操作,此操作对用户是透
明的。
创建空索引
PUT http://127.0.0.1/test
{
"settings" : {
"index" : {
"number_of_shards" : "2" , # 分片数
"number_of_replicas" : "0" # 副本数
}
}
}

 

 

# 删除索引
DELETE http://127.0.0.1:9200/test
{
"acknowledged" : true
}
 
 
2.4.2 、插入数据
URL 规则:
POST http://127.0.0.1:9200/ { 索引 }/{ 类型 }/{id}
 
 
POST http://localhost:9200/haoke/user/1001
# 数据
{
"id" :1001,
"name" : " 张三 " ,
"age" :20,
"sex" : " "
}
# 响应
{
"_index" : "test" ,
"_type" : "user" ,
"_id" : "1" ,
"_version" : 1 ,
"result" : "created" ,
"_shards" : {
"total" : 1 ,
"successful" : 1 ,
"failed" : 0
},
"_seq_no" : 0 ,
"_primary_term" : 1
}
 
不指定 id 插入数据:

{

"id":1002,

"name":"张三2",

"age":20,

"sex":"男"

}

{

    "_index": "test",

    "_type": "user",

    "_id": "GD3qC3UBKjIIyQSLnnMI",

    "_version": 1,

    "result": "created",

    "_shards": {

        "total": 1,

        "successful": 1,

        "failed": 0

    },

    "_seq_no": 1,

    "_primary_term": 1

}

2.4.3 、更新数据
Elasticsearch 中,文档数据是不为修改的,但是可以通过覆盖的方式进行更新。
 

 

 

可以看到数据已经被覆盖了。
问题来了,可以局部更新吗? -- 可以的。
前面不是说,文档数据不能更新吗? 其实是这样的:
在内部,依然会查询到这个文档数据,然后进行覆盖操作,步骤如下:
1. 从旧文档中检索 JSON
2. 修改它
3. 删除旧文档
4. 索引新文档
 
 

 

 

2.4.4 、删除数据
Elasticsearch 中,删除文档数据,只需要发起 DELETE 请求即可。

 

说明:
删除一个文档也不会立即从磁盘上移除,它只是被标记成已删除。 Elasticsearch 将会在你之后添加更多索引
的时候才会在后台进行删除内容的清理。
 
2.4.5 、搜索数据
根据 id 搜索数据
 

 

搜索全部数据

条件查询 年龄等于20的

2.4.6 DSL 搜索
Elasticsearch 提供丰富且灵活的查询语言叫做 DSL 查询 (Query DSL) , 它允许你构建更加复杂、强大的查询。
DSL(Domain Specifific Language 特定领域语言 ) JSON 请求体的形式出现。
 

 

 高亮查询

{ "query": { "match": { "name": "张三 李四"} },"highlight": { "fields": { "name": {} } } }

 

Elasticsearch中,支持聚合操作,类似SQL中的group by操作。

{ "aggs": { "all_interests": { "terms": { "field": "age" } } } }

 

从结果可以看出,年龄20的有2条数据 

 

3 、核心详解
3.1 、文档
Elasticsearch 中,文档以 JSON 格式进行存储,可以是复杂的结构,如:
 
{
"_index" : "haoke" ,
"_type" : "user" ,
"_id" : "1005" ,
"_version" : 1 ,
"_score" : 1 ,
"_source" : {
"id" : 1005 ,
"name" : " 孙七 " ,
"age" : 37 ,
"sex" : " " ,
"card" : {
"card_number" : "123456789"
}
}
}
 
其中, card 是一个复杂对象,嵌套的 Card 对象。
元数据( metadata
一个文档不只有数据。它还包含了元数据 (metadata)—— 关于文档的信息。三个必须的元数据节点是:
_index
索引 (index) 类似于关系型数据库里的 数据库 ”—— 它是我们存储和索引关联数据的地方。
提示:
事实上,我们的数据被存储和索引在 分片 (shards) 中,索引只是一个把一个或多个分片分组在一起的逻辑空
间。然而,这只是一些内部细节 —— 我们的程序完全不用关心分片。对于我们的程序而言,文档存储在 索引
(index) 中。剩下的细节由 Elasticsearch 关心既可。
_type
在应用中,我们使用对象表示一些 事物 ,例如一个用户、一篇博客、一个评论,或者一封邮件。每个对象都属于
一个 (class) ,这个类定义了属性或与对象关联的数据。 user 类的对象可能包含姓名、性别、年龄和 Email
址。
在关系型数据库中,我们经常将相同类的对象存储在一个表里,因为它们有着相同的结构。同理,在 Elasticsearch
中,我们使用相同 类型 (type) 的文档表示相同的 事物 ,因为他们的数据结构也是相同的。
每个 类型 (type) 都有自己的 映射 (mapping) 或者结构定义,就像传统数据库表中的列一样。所有类型下的文档被存
储在同一个索引下,但是类型的 映射 (mapping) 会告诉 Elasticsearch 不同的文档如何被索引。
_type 的名字可以是大写或小写,不能包含下划线或逗号。我们将使用 blog 做为类型名。
_id
id 仅仅是一个字符串,它与 _index _type 组合时,就可以在 Elasticsearch 中唯一标识一个文档。当创建一个
文档,你可以自定义 _id ,也可以让 Elasticsearch 帮你自动生成( 32 位长度)。
3.2 、查询响应
 
3.2.1 pretty
可以在查询 url 后面添加 pretty 参数,使得返回的 json 更易查看。
 
3.2.2 、指定响应字段
在响应的数据中,如果我们不需要全部的字段,可以指定某些需要的字段进行返回。
3.3 、判断文档是否存在
如果我们只需要判断文档是否存在,而不是查询文档内容,那么可以这样:

 

 

当然,这只表示你在查询的那一刻文档不存在,但并不表示几毫秒后依旧不存在。另一个进程在这期间可能
创建新文档。
3.4 、批量操作
有些情况下可以通过批量操作以减少网络请求。如:批量查询、批量插入数据。
3.4.1 、批量查询
 

 

 

3.4.2 _bulk 操作
Elasticsearch 中,支持批量的插入、修改、删除操作,都是通过 _bulk api 完成的。
请求格式如下:(请求格式不同寻常)
批量插入数据:
 

{"create":{"_index":"haoke","_type":"user","_id":2001}}

{"id":2001,"name":"name1","age": 20,"sex": "男"}

{"create":{"_index":"haoke","_type":"user","_id":2002}}

{"id":2002,"name":"name2","age": 20,"sex": "男"}

{"create":{"_index":"haoke","_type":"user","_id":2003}}

{"id":2003,"name":"name3","age": 20,"sex": "男"}

 

批量删除

{"delete":{"_index":"haoke","_type":"user","_id":2001}}

{"delete":{"_index":"haoke","_type":"user","_id":2002}}

{"delete":{"_index":"haoke","_type":"user","_id":2003}}

 

 

其他操作就类似了。
一次请求多少性能最高?
整个批量请求需要被加载到接受我们请求节点的内存里,所以请求越大,给其它请求可用的内存就越小。有
一个最佳的 bulk 请求大小。超过这个大小,性能不再提升而且可能降低。
最佳大小,当然并不是一个固定的数字。它完全取决于你的硬件、你文档的大小和复杂度以及索引和搜索的
负载。
幸运的是,这个最佳点 (sweetspot) 还是容易找到的:试着批量索引标准的文档,随着大小的增长,当性能开
始降低,说明你每个批次的大小太大了。开始的数量可以在 1000~5000 个文档之间,如果你的文档非常大,
可以使用较小的批次。
通常着眼于你请求批次的物理大小是非常有用的。一千个 1kB 的文档和一千个 1MB 的文档大不相同。一个好的
批次最好保持在 5-15MB 大小间。
 
3.5 、分页
SQL 使用 LIMIT 关键字返回只有一页的结果一样, Elasticsearch 接受 from size 参数:
如果你想每页显示 5 个结果,页码从 1 3 ,那请求如下:
GET / _search ? size = 5
GET / _search ? size = 5 & from = 5
GET / _search ? size = 5 & from = 10
 
应该当心分页太深或者一次请求太多的结果。结果在返回前会被排序。但是记住一个搜索请求常常涉及多个
分片。每个分片生成自己排好序的结果,它们接着需要集中起来排序以确保整体排序正确
 
 
 
在集群系统中深度分页
为了理解为什么深度分页是有问题的,让我们假设在一个有 5 个主分片的索引中搜索。当我们请求结果的第一
页(结果 1 10 )时,每个分片产生自己最顶端 10 个结果然后返回它们给 请求节点 (requesting node) ,它
再排序这所有的 50 个结果以选出顶端的 10 个结果。
现在假设我们请求第 1000 —— 结果 10001 10010 。工作方式都相同,不同的是每个分片都必须产生顶端
10010 个结果。然后请求节点排序这 50050 个结果并丢弃 50040 个!
 
你可以看到在分布式系统中,排序结果的花费随着分页的深入而成倍增长。这也是为什么网络搜索引擎中任
何语句不能返回多于 1000 个结果的原因。
 
 
3.6 、映射
前面我们创建的索引以及插入数据,都是由 Elasticsearch 进行自动判断类型,有些时候我们是需要进行明确字段类
型的,否则,自动判断的类型和实际需求是不相符的。
自动判断的规则如下:

 
string 类型在 ElasticSearch 旧版本中使用较多,从 ElasticSearch 5.x 开始不再支持 string ,由 text
keyword 类型替代。
text 类型,当一个字段是要被全文搜索的,比如 Email 内容、产品描述,应该使用 text 类型。设置 text
型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分析器分成一个一个词项。 text 类型的
字段不用于排序,很少用于聚合。
keyword 类型适用于索引结构化的字段,比如 email 地址、主机名、状态码和标签。如果字段需要进行
过滤 ( 比如查找已发布博客中 status 属性为 published 的文章 ) 、排序、聚合。 keyword 类型的字段只能通
过精确值搜索到。
 
创建明确类型的索引:

 

 

{

    "settings": {

        "index": {

            "number_of_shards": "2",

            "number_of_replicas": "0"

        }

    },

    "mappings": {

        "properties": {

            "name": {

                "type": "text"

            },

            "age": {

                "type": "integer"

            },

            "mail": {

                "type": "keyword"

            },

            "hobby": {

                "type": "text"

            }

        }

    }

}

查看映射:

1 GET /person/_mapping

  效果如下:

  

  插入数据:

复制代码

 1 POST /person/_bulk
 2 
 3 {"index":{"_index":"person"}}
 4 {"name":"张三","age": 20,"mail": "111@qq.com","hobby":"羽毛球、乒乓球、足球"} 
 5 {"index":{"_index":"person"}}
 6 {"name":"李四","age": 21,"mail": "222@qq.com","hobby":"羽毛球、乒乓球、足球、篮球"} 
 7 {"index":{"_index":"person"}}
 8 {"name":"王五","age": 22,"mail": "333@qq.com","hobby":"羽毛球、篮球、游泳、听音乐"} 
 9 {"index":{"_index":"person"}}
10 {"name":"赵六","age": 23,"mail": "444@qq.com","hobby":"跑步、游泳"} 
11 {"index":{"_index":"person"}}
12 {"name":"孙七","age": 24,"mail": "555@qq.com","hobby":"听音乐、看电影"}

复制代码

  测试搜索:

复制代码

1 POST /person/_search
2 
3 {
4     "query": {
5         "match": {
6             "hobby": "音乐"
7         }
8     }
9 }

复制代码

  效果如下:  

    

7、结构化查询

7.1、term查询

  term 主要用于精确匹配哪些值,比如数字,日期,布尔值或 not_analyzed 的字符串(未经分析的文本数据类型):

1 { "term": { "age": 26 }} 
2 { "term": { "date": "2014-09-01" }} 
3 { "term": { "public": true }} 
4 { "term": { "tag": "full_text" }}

  示例:

复制代码

1 POST /person/_search
2 
3 {
4     "query": {
5         "term": {
6             "age": 20
7         }
8     }
9 }

复制代码

  效果如下:

  

7.2、terms查询

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

  格式:

复制代码

1 {
2     "terms": {
3         "tag": [
4             "search",
5             "full_text",
6             "nosql"
7         ]
8     }
9 }

复制代码

  示例:

复制代码

1 POST /person/_search
2 
3 {
4     "query": {
5         "terms": {
6             "age": [20, 21]
7         }
8     }
9 }

复制代码

  效果如下:

  

 7.3、range查询

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

复制代码

1 {
2     "range": {
3         "age": {
4             "gt": 20,
5             "lt": 30
6         }
7     }
8 }

复制代码

  范围操作符包含:

  • gt ::大于
  • gte :: 大于等于 
  • lt ::小于
  • lte :: 小于等于

  示例:

示例:

复制代码

 1 POST /person/_search
 2 
 3 {
 4     "query": {
 5         "range": {
 6             "age": {
 7                 "gt": 20,
 8                 "lt": 30
 9             }
10         }
11     }
12 }

复制代码

  效果如下:

  

7.4、exists 查询

  exists 查询可以用于查找文档中是否包含指定字段或没有某个字段,类似于SQL语句中的IS_NULL条件

1 {
2     "exists": {
3         "field": "title"
4     }
5 }

  示例:

复制代码

1 POST /person/_search
2 
3 {
4     "query": {
5         "exists": {
6             "field": "name"
7         }
8     }
9 }

复制代码

  效果如下:

  

6.5、match查询

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

  如果你使用 match 查询一个全文本字段,它会在真正查询之前用分析器先分析 match 一下查询字符:

1 {
2     "match": {
3         "tweet": "About Search"
4     }
5 }

  如果用match下指定了一个确切值,在遇到数字,日期,布尔值或者not_analyzed 的字符串时,它将为你搜索你 给定的值:

  示例:

复制代码

1 POST /person/_search
2 
3 {
4     "query": {
5         "match": {
6             "name": "孙七"
7         }
8     }
9 }

复制代码

  效果如下:

  

7.6、bool查询

  • bool 查询可以用来合并多个条件查询结果的布尔逻辑,它包含一下操作符: must :: 多个查询条件的完全匹配,相当于 and 。
  • must_not :: 多个查询条件的相反匹配,相当于 not 。
  • should :: 至少有一个查询条件匹配, 相当于 or 。
  • 这些参数可以分别继承一个查询条件或者一个查询条件的数组:

复制代码

 1 {
 2     "bool": {
 3         "must": {
 4             "term": {
 5                 "folder": "inbox"
 6             }
 7         },
 8         "must_not": {
 9             "term": {
10                 "tag": "spam"
11             }
12         },
13         "should": []
14     }
15 }

复制代码

  示例效果:

  

7.7、过滤查询

  前面讲过结构化查询,Elasticsearch也支持过滤查询,如term、range、match等。

  示例:查询年龄为20岁的用户。

  

  查询和过滤的对比

  • 一条过滤语句会询问每个文档的字段值是否包含着特定值。
  • 查询语句会询问每个文档的字段值与特定值的匹配程度如何。
    • 一条查询语句会计算每个文档与查询语句的相关性,会给出一个相关性评分 _score,并且 按照相关性对匹配到的文档进行排序。 这种评分方式非常适用于一个没有完全配置结果的全文本搜索。
  • 一个简单的文档列表,快速匹配运算并存入内存是十分方便的, 每个文档仅需要1个字节。这些缓存的过滤结果 集与后续请求的结合使用是非常高效的。
  • 查询语句不仅要查找相匹配的文档,还需要计算每个文档的相关性,所以一般来说查询语句要比 过滤语句更耗 时,并且查询结果也不可缓存。

  建议:

  做精确匹配搜索时,最好用过滤语句,因为过滤语句可以缓存数据。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值