摘要
本文主要介绍了 Elasticsearch(ES)的基本原理,包括其特点、基础概念、Elastic Stack 组件、容器下载与部署以及查询和聚合查询的相关内容。通过具体示例展示了如何使用 ES 进行单个查询、批量查询、分页查询以及聚合查询等操作,并提供了相关的参考资源。
1. ElasticSearch的特点
ElasticSearch是一款非常强大的、基于Lucene的开源搜索及分析引擎;它是一个实时的分布式搜索分析引擎,它能让你以前所未有的速度和规模,去探索你的数据。
它被用作全文检索、结构化搜索、分析以及这三个功能的组合:
- 使用 Elasticsearch 提供带有高亮片段的全文搜索,还有 search-as-you-type 和 did-you-mean 的建议。
- 使用 Elasticsearch 将网络社交数据结合到访客日志中,为它的编辑们提供公众对于新文章的实时反馈。
- **将地理位置查询融入全文检索中去,并且使用 more-like-this 接口去查找相关的问题和回答。
- **使用 Elasticsearch 对1300亿行代码进行查询。
除了搜索,结合Kibana、Logstash、Beats开源产品,Elastic Stack(简称ELK)还被广泛运用在大数据近实时分析领域,包括:日志分析、指标监控、信息安全等。它可以帮助你探索海量结构化、非结构化数据,按需创建可视化报表,对监控数据设置报警阈值,通过使用机器学习,自动识别异常状况。ElasticSearch是基于Restful WebApi,使用Java语言开发的搜索引擎库类,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。其客户端在Java、C#、PHP、Python等许多语言中都是可用的。
1.1. Lucene搜索引擎
Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库。但是 Lucene 仅仅只是一个库。为了充分发挥其功能,你需要使用 Java 并将 Lucene 直接集成到应用程序中。 您可能需要获得信息检索学位才能了解其工作原理。Lucene 非常复杂。Elasticsearch 也是使用 Java 编写的,它的内部使用 Lucene 做索引与搜索,但是它的目的是使全文检索变得简单,通过隐藏 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTful API。然而,Elasticsearch 不仅仅是 Lucene,并且也不仅仅只是一个全文搜索引擎。 它可以被下面这样准确的形容:
- 一个分布式的实时文档存储,每个字段 可以被索引与搜索。
- 一个分布式实时分析搜索引擎。
- 能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据。
1.2. ElasticSearch的主要功能及应用场景
主要功能:
- 海量数据的分布式存储以及集群管理,达到了服务与数据的高可用以及水平扩展;
- 近实时搜索,性能卓越。对结构化、全文、地理位置等类型数据的处理;
- 海量数据的近实时分析(聚合功能)
应用场景:
- 网站搜索、垂直搜索、代码搜索;
- 日志管理与分析、安全指标监控、应用性能监控、Web抓取舆情分析;
2. ElasticSearch基础概念
- Near Realtime(NRT) 近实时。数据提交索引后,立马就可以搜索到。
- Cluster 集群,一个集群由一个唯一的名字标识,默认为“elasticsearch”。集群名称非常重要,具有相同集群名的节点才会组成一个集群。集群名称可以在配置文件中指定。
- Node 节点:存储集群的数据,参与集群的索引和搜索功能。像集群有名字,节点也有自己的名称,默认在启动时会以一个随机的UUID的前七个字符作为节点的名字,你可以为其指定任意的名字。通过集群名在网络中发现同伴组成集群。一个节点也可是集群。
- Index 索引: 一个索引是一个文档的集合(等同于solr中的集合)。每个索引有唯一的名字,通过这个名字来操作它。一个集群中可以有任意多个索引。
- Type 类型:指在一个索引中,可以索引不同类型的文档,如用户数据、博客数据。从6.0.0 版本起已废弃,一个索引中只存放一类数据。
- Document 文档:被索引的一条数据,索引的基本信息单元,以JSON格式来表示。
- Shard 分片:在创建一个索引时可以指定分成多少个分片来存储。每个分片本身也是一个功能完善且独立的“索引”,可以被放置在集群的任意节点上。
- Replication 备份: 一个分片可以有多个备份(副本)
3. Elastic Stack组件简介
3.1. ES相关组件
Beats + Logstash + ElasticSearch + Kibana
如下是我从官方博客中找到图,这张图展示了ELK生态以及基于ELK的场景(最上方)。
3.1.1. Beats组件
Beats是一个面向轻量型采集器的平台,这些采集器可以从边缘机器向Logstash、ElasticSearch发送数据,它是由Go语言进行开发的,运行效率方面比较快。从下图中可以看出,不同Beats的套件是针对不同的数据源。
3.1.2. Logstash
Logstash是动态数据收集管道,拥有可扩展的插件生态系统,支持从不同来源采集数据,转换数据,并将数据发送到不同的存储库中。其能够与ElasticSearch产生强大的协同作用,后被Elastic公司在2013年收购。它具有如下特性:1. 实时解析和转换数据;2. 可扩展,具有200多个插件;3. 可靠性、安全性。Logstash会通过持久化队列来保证至少将运行中的事件送达一次,同时将数据进行传输加密;4. 监控;
3.1.3. ElasticSearch
ElasticSearch对数据进行搜索、分析和存储,其是基于JSON的分布式搜索和分析引擎,专门为实现水平可扩展性、高可靠性和管理便捷性而设计的。它的实现原理主要分为以下几个步骤:
- 首先用户将数据提交到ElasticSearch数据库中;
- 再通过分词控制器将对应的语句分词;
- 将分词结果及其权重一并存入,以备用户在搜索数据时,根据权重将结果排名和打分,将返回结果呈现给用户;
3.1.4. Kibana
Kibana实现数据可视化,其作用就是在ElasticSearch中进行民航。Kibana能够以图表的形式呈现数据,并且具有可扩展的用户界面,可以全方位的配置和管理ElasticSearch。Kibana最早的时候是基于Logstash创建的工具,后被Elastic公司在2013年收购。Kibana可以提供各种可视化的图表;可以通过机器学习的技术,对异常情况进行检测,用于提前发现可疑问题;
3.2. ES实践项目
基本的日志系统
增加数据源,和使用MQ
3.2.1. Metric收集和APM性能监控
3.2.2. 多数据中心方案
通过冗余实现数据高可用
两个数据采集中心(比如采集两个工厂的数据),采集数据后的汇聚
数据分散,跨集群的搜索
4. ES 容器下载与部署
docker pull elasticsearch:7.12.1
docker run -d \
--name elasticsearch \
-e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
-e "discovery.type=single-node" \
-v es-data:/usr/share/elasticsearch/data \
-v es-plugins:/usr/share/elasticsearch/plugins \
--privileged \
--restart=always
-p 9200:9200 \
-p 9300:9300 \
elasticsearch:7.12.1
在浏览器中输入:http://ip:9200 即可看到elasticsearch的响应结果:
docker pull kibana:7.12.1
docker run -d \
--name kibana \
-e ELASTICSEARCH_HOSTS=http://es:9200 \
-p 5601:5601 \
kibana:7.12.1
此时,在浏览器输入地址访问:http://ip:5601,即可看到结果
5. 查询和聚合查询
5.1. 单个查询
PUT /customer/_doc/1
{
"name": "John Doe"
}
查询刚才插入的文档
GET /customer/_doc/1
5.2. 批量查询
数据是index为bank,accounts.json 下载地址:📎accounts.rar (如果你无法下载,也可以clone ES的官方仓库,然后进入/docs/src/test/resources/accounts.json目录获取)
curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/_bulk?pretty&refresh" --data-binary "@/opt/accounts.json"
match_all表示查询所有的数据, sort即按照什么字段排序
GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
]
}
5.3. 分页查询(from+size)
本质上就是from和size两个字段
GET /bank/_search
{
"query": { "match_all": {} },
"sort": [
{ "account_number": "asc" }
],
"from": 10,
"size": 10
}
结果
5.3.1. 指定字段查询:match
如果要在字段中搜索特定字词,可以使用match; 如下语句将查询address 字段中包含 mill 或者 lane的数据
GET /bank/_search
{
"query": { "match": { "address": "mill lane" } }
}
结果
(由于ES底层是按照分词索引的,所以上述查询结果是address 字段中包含 mill 或者 lane的数据)
5.3.2. 查询段落匹配:match_phrase
如果我们希望查询的条件是 address字段中包含 “mill lane”,则可以使用match_phrase
GET /bank/_search
{
"query": { "match_phrase": { "address": "mill lane" } }
}
结果
5.3.3. 多条件查询: bool
如果要构造更复杂的查询,可以使用bool查询来组合多个查询条件。
例如,以下请求在bank索引中搜索40岁客户的帐户,但不包括居住在爱达荷州(ID)的任何人
GET /bank/_search
{
"query": {
"bool": {
"must": [
{ "match": { "age": "40" } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
}
结果
must, should, must_not 和 filter 都是bool查询的子句。那么filter和上述query子句有啥区别呢?
GET your_index/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"field1": "value1"
}
},
{
"range": {
"field2": {
"gte": 10,
"lte": 20
}
}
}
],
"should": [
{
"term": {
"field3": "optional_value1"
}
},
{
"term": {
"field4": "optional_value2"
}
}
],
"must_not": [
{
"term": {
"field5": "excluded_value"
}
}
],
"filter": [
{
"term": {
"field6": "filtered_value"
}
}
]
}
}
}
解释:
must:文档必须匹配的条件,类似于 SQL 的 AND。例如:
-
field1必须包含value1。field2必须在[10, 20]范围内。
should:非必须条件,匹配的条件越多,相关性得分(_score)越高。至少有一个条件匹配时,文档会更相关。
-
field3或field4中匹配一个即可加分。
must_not:文档不能包含的条件,类似于 SQL 的 NOT。
-
- 排除
field5等于excluded_value的文档。
- 排除
filter:过滤条件,类似于must,但不影响相关性评分(_score),性能较高。
-
field6必须为filtered_value。
5.3.4. 查询条件:query or filter
先看下如下查询, 在bool查询的子句中同时具备query/must 和 filter
GET /bank/_search
{
"query": {
"bool": {
"must": [
{
"match": {
"state": "ND"
}
}
],
"filter": [
{
"term": {
"age": "40"
}
},
{
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
]
}
}
}
结果
两者都可以写查询条件,而且语法也类似。区别在于,query 上下文的条件是用来给文档打分的,匹配越好 _score 越高;filter 的条件只产生两种结果:符合与不符合,后者被过滤掉。
所以,我们进一步看只包含filter的查询
GET /bank/_search
{
"query": {
"bool": {
"filter": [
{
"term": {
"age": "40"
}
},
{
"range": {
"balance": {
"gte": 20000,
"lte": 30000
}
}
}
]
}
}
}
结果,显然无_score
5.4. 聚合查询:Aggregation
我们知道SQL中有group by,在ES中它叫Aggregation,即聚合运算。
5.4.1. 简单聚合
比如我们希望计算出account每个州的统计数量, 使用aggs关键字对state字段聚合,被聚合的字段无需对分词统计,所以使用state.keyword对整个字段统计
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
}
}
}
}
结果
因为无需返回条件的具体数据, 所以设置size=0,返回hits为空。
doc_count表示bucket中每个州的数据条数。
5.4.2. 嵌套聚合
ES还可以处理个聚合条件的嵌套。
比如承接上个例子, 计算每个州的平均结余。涉及到的就是在对state分组的基础上,嵌套计算avg(balance):
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
结果
5.4.3. 对聚合结果排序
可以通过在aggs中对嵌套聚合的结果进行排序
比如承接上个例子, 对嵌套计算出的avg(balance),这里是average_balance,进行排序
GET /bank/_search
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword",
"order": {
"average_balance": "desc"
}
},
"aggs": {
"average_balance": {
"avg": {
"field": "balance"
}
}
}
}
}
}
结果
博文参考
- [dockr部署单点elasticsearch] www.zhaojun.ink/archives/10…
- [elasticSearch官方网站] www.elastic.co/elasticsear…
- www.elastic.co/cn/elastics…
- www.elastic.co/pdf/archite…
- www.elastic.co/guide/en/lo…
- www.cnblogs.com/supersnowya…
- blog.51cto.com/wutengfei/2…
- www.elastic.co/guide/cn/el…
- www.elastic.co/guide/cn/el…
- www.cnblogs.com/leeSmall/p/…