Elasticsearch

Elasticsearch

ELK技术栈简介

1)ElasticSearch:ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。我们建立一个网站或应用程序,并要添加搜索功能,但是想要完成搜索工作的创建是非常困难的。我们希望搜索解决方案要运行速度快,我们希望能有一个零配置和一个完全免费的搜索模式,我们希望能够简单地使用JSON通过HTTP来索引数据,我们希望我们的搜索服务器始终可用,我们希望能够从一台开始并扩展到数百台,我们要实时搜索,我们要简单的多租户,我们希望建立一个云的解决方案。因此我们利用Elasticsearch来解决所有这些问题及可能出现的更多其它问题。Elasticsearch为开源的、分布式、基于Restful API、支持PB甚至更高数量级的搜索引擎工具。传统的关系型数据库虽然能支持类型like模糊语句匹配,但无法进行全文检索(分词检索)。非关系型数据库Mongo虽能进行简单的全文检索,但对中文支持的不好、数据量大性能会有问题,这点是在实际应用中总结出的。

2)Logstash:Logstash是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的存储库中。Logstash就是一根具备实时数据传输能力的管道,负责将数据信息从管道的输入端传输到管道的输出端,与此同时这根管道还可以让你根据自己的需求在中间加上滤网,Logstash提供里很多功能强大的滤网以满足你的各种应用场景。Logstash能够动态地采集、转换和传输数据,不受格式或复杂度的影响。Logstash常用于日志关系系统中做日志采集工具。包括但不限于:
1、本地或远程文件
2、Kafka实时数据流,核心插件有:logstashinputkafka/logstashoutputkafka
3、MySQL、Oracle等关系型数据库,核心插件有:logstashinputjdbc/logstashouputjdbc
4、Mongo非关系型数据库,核心插件有:logstashinputmongo/logstashoutputmongo
5、Redis数据流

3)Beats:Beats是一个开源的用来构建轻量级数据汇集的平台,可用于将各种类型的数据发送至Elasticsearch与Logstash。Beats目前有官方支持的多个子产品,如下:
1、Packetbeat:用于监控局域网内服务器之间的网络流量信息。
2、Filebeat:收集服务器上的日志信息,它是用来替代Logstash Forwarder的下一代Logstash收集器,是为了更快速稳定轻量低耗地进行收集工作,它可以很方便地与Logstash还有直接与Elasticsearch进行对接。
3、新推出的Metricbeat,可以定期获取外部系统的监控指标信息。除了以上三个核心产品外,还有:Winlogbeat(Windows事件日志轻量级工具)、Auditbeat(审计数据的轻量级工具)、Heartbeat(用于时间监控的轻量级工具)。除此以外,你还可以非常方便的基于libbeat框架来构建你属于自己的专属Beat。

4)Kibana:Kibana是ES大数据的图形化展示工具。集成了DSL命令行查看、数据处理插件、继承了x-pack(收费)安全管理插件等。

Elasticsearch使用场景

主要功能:
1)海量数据的分布式存储以及集群管理,达到了服务与数据的高可用以及水平扩展;
2)近实时搜索,性能卓越。对结构化、全文、地理位置等类型数据的处理;
3)海量数据的近实时分析(聚合功能)

使用场景:
1)网站搜索、垂直搜索、代码搜索;
2)日志管理与分析、安全指标监控、应用性能监控、Web抓取舆情分析;

Elasticsearch核心概念

Cluster:集群。ES可以作为一个独立的单个搜索服务器。不过,为了处理大型数据集,实现容错和高可用性,ES可以运行在许多互相合作的服务器上。这些服务器的集合称为集群。

Node:节点。形成集群的每个服务器称为节点。

Shard:分片。当有大量的文档时,由于内存的限制、磁盘处理能力不足、无法足够快的响应客户端的请求等,一个节点可能不够。这种情况下,数据可以分为较小的分片。每个分片放到不同的服务器上。当你查询的索引分布在多个分片上时,ES会把查询发送给每个相关的分片,并将结果组合在一起,而应用程序并不知道分片的存在。即:这个过程对用户来说是透明的。

Replia:副本。为提高查询吞吐量或实现高可用性,可以使用分片副本。副本是一个分片的精确复制,每个分片可以有零个或多个副本。ES中可以有许多相同的分片,其中之一被选择更改索引操作,这种特殊的分片称为主分片。当主分片丢失时,如:该分片所在的数据不可用时,集群将副本提升为新的主分片。

全文检索:全文检索就是对一篇文章进行索引,可以根据关键字搜索,类似于Mysql里的like语句。全文索引就是把内容根据词的意义进行分词,然后分别创建索引,例如(你们的激情是因为什么事情来的)可能会被分词成:(你们、激情、什么事情、来)等token,这样当你搜索(你们或者激情)都会把这句搜出来。

倒排索引:倒排索引是实现(单词-文档矩阵)的一种具体存储形式,通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。倒排索引主要由两个部分组成:单词词典和倒排文件。

Elasticsearch与RDBMS

image-20230213153504323

对应名称比较如下:

1、MySQL中的数据库DataBase,等价于ES中的索引Index。

2、MySQL中一个数据库下面有N张表Table,等价于1个索引Index下面有N多类型Type。这个在新的Elasticsearch版本已经废除(在以前的Elasticsearch版本,一个Index下支持多个Type有点类似于消息队列一个topic下多个group的概念)

3、MySQL中一个数据库表Table下的数据由多行Row多列column、属性组成,等价于1个Type由多个文档Document和多个Field组成。

4、MySQL中定义表结构、设定字段类型等价于ES中的Mapping。举例说明,在一个关系型数据库里面,Schema定义了表、每个表的字段,还有表和字段之间的关系。与之对应的,在ES中,Mapping定义了索引下的Type的字段处理规则,即索引如何建立、索引类型、是否保存原始索引JSON文档、是否压缩原始JSON文档、是否需要分词处理、如何进行分词处理等。

5、MySQL中的增insert、删delete、改update、查search操作等价于ES中的增PUT/POST、删Delete、改_update、查GET。其中的修改指定条件的更新update等价于ES中的update_by_query,指定条件的删除等价于ES中的delete_by_query。

6、MySQL中的group by、avg、sum等函数类似于ES中的Aggregations的部分特性。

7、MySQL中的去重distinct类似ES中的cardinality操作。

8、MySQL中的数据迁移等价于ES中的reindex操作。

Elasticsearch版本整合

image-20230210151203536

Elasticsearch常用接口

-- 创建索引库
-- number_of_shards:分片,number_of_replicas:副本
PUT http://localhost:9200/item_course(数据库:item_course)
{
	"settings":{
		"index":{
			"number_of_shards":1,
			"number_of_replicas":0
		}
	}
}

-- 创建类型与字段
-- 这个接口可以新增或更新映射(字段),但是字段类型是无法修改的,所以只能删除索引库重新生成。
PUT http://localhost:9200/item_course/course/_mapping(表:course)
{
	"properties":{
		"name":{
			"type":"text" //字段类型
		},
		"description":{
			"type":"text"
		},
		"studymodel":{
			"type":"keyword"
		}
	}
}

-- 创建文档
PUT http://localhost:9200/item_course/course/1001(主键ID:1001)
{
	"name":"张三",
	"description":"内容描述",
	"studymodel":"1001"
}

-- 创建带分词器的映射
PUT http://localhost:9200/item_course/course/_mapping(表:course)
{
	"properties":{
		"name":{
			"type":"text",
			"analyzer":"ik_max_word",
			"search_analyzer":"ik_smart"
		},
		"description":{
			"type":"text",
			"analyzer":"ik_max_word",
			"search_analyzer":"ik_smart"
		},
		"pic":{
			"type":"keyword",
			"index":false
		},
		"studymodel":{
			"type":"text"
		},
		"timestamp":{
            "type":"date",
            "format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd"
		}
	}
}

注意:一般创建索引用细分,搜索的关键字用粗分
"type":"text", //字段类型
"analyzer":"ik_max_word", //字段细分
"search_analyzer":"ik_smart" //搜索粗分
"type":"keyword", //关键字搜索,设置这个字段精确匹配
"index":false //是否可以索引
"format":"yyyy-MM-dd HH:mm:ss||yyyy-MM-dd" //时间搜索支持的格式

-- 删除索引库
DELETE http://localhost:9200/item_course

-- 根据主键删除文档
DELETE http://localhost:9200/item_course/course/1001(主键ID:1001)

-- 修改文档
POST http://localhost:9200/item_course/course/1001/_update/(主键ID:1001)
{
    "doc": {
        "name": "李四",
        "description": "测试修改"
    }
}

Elasticsearch查询接口

-- 查询所有
GET http://localhost:9200/item_course/course/_search

-- ID查询
GET	http://localhost:9200/item_course/course/1001

-- 模糊查询
GET http://localhost:9200/item_course/course/_search?q=name:李

-- 条件查询
-- 查询description包含指定内容的数据,注意这里的内容会分词查询
GET http://localhost:9200/item_course/course/_search
{
    "query": {
        "match": {
            "description": "看看这句话能不能查询到测试数据"
        }
    }
}

-- 不分词查询,match_phrase
GET http://localhost:9200/item_course/course/_search
{
    "query": {
        "match_phrase": {
            "description": "看看这句话能不能查询到测试数据"
        }
    }
}

-- bool多条件查询
-- 搜索menu_id包含1001,doc_content不包含Spring的数据
GET http://localhost:9200/jsbz_document/doc/_search
{
    "query": {
        "bool": {
            "must": [
                {
                    "match": {
                        "menu_id": "1001"
                    }
                }
            ],
            "must_not": [
                {
                    "match": {
                        "doc_content": "Spring"
                    }
                }
            ]
        }
    }
}

-- 排序查询
-- match_all表示查询所有的数据,sort即按照什么字段排序
GET http://localhost:9200/jsbz_document/doc/_search
{
    "query": {
        "match_all": {}
    },
    "sort": [
        {
            "doc_id": "desc"
        }
    ]
}

返回结果相关字段解释:
took:Elasticsearch运行查询所花费的时间(以毫秒为单位)
timed_out:搜索请求是否超时
_shards:搜索了多少个碎片,以及成功,失败或跳过了多少个碎片的细目分类。
max_score:找到的最相关文档的分数
hits.total.value:找到了多少个匹配的文档
hits.sort:文档的排序位置(不按相关性得分排序时)
hits._score:文档的相关性得分(使用match_all时不适用)

-- 分页查询
-- 本质上就是from和size两个字段,起始页为0
GET http://localhost:9200/jsbz_document/doc/_search
{
    "query": {
        "match_all": {}
    },
    "sort": [
        {
            "doc_id": "desc"
        }
    ],
    "from": 0,
    "size": 10
}

Elasticsearch数据结构

image-20230213152430049

ES数据结构详解:

我们输入一段文字,Elasticsearch会根据分词器对我们的那段文字进行分词,这些分词汇总起来我们叫做词典(Term Dictionary),而我们需要通过分词找到对应的记录,这些文档ID保存在倒排表(PostingList)。在词典中的词由于是非常多的,所以我们会为其进行排序,等要查找的时候就可以通过二分来查,不需要遍历整个词典。由于词典的词实在太多了,不可能把词典所有的词都放在内存中,于是Elasticsearch还抽了一层叫做Term Index,这层只存储部分词的前缀,Term Index会存在内存中(检索会特别快)。Term Index在内存中是以FST(Finite State Transducers)的形式保存的,其特点是非常节省内存。FST有两个优点:
1)空间占用小。通过对词典中单词前缀和后缀的重复利用,压缩了存储空间;
2)查询速度快。O(len(str))的查询时间复杂度。

倒排表会使用Frame Of Reference(FOR)编码技术对里边的数据进行压缩,节约磁盘空间。倒排表里边存的是文档ID,我们查的时候往往需要对这些文档ID做交集和并集的操作(比如在多条件查询时),倒排表使用Roaring Bitmaps来对文档ID进行交并集操作。使用Roaring Bitmaps的好处就是可以节省空间和快速得出交并集的结果。

Elasticsearch高可用原理

image-20230213154342149

ES集群详解:

在众多的节点中,其中会有一个Master Node,它主要负责维护索引元数据、负责切换主分片和副本分片身份等工作,如果主节点挂了,会选举出一个新的主节点。Elasticsearch最外层的是Index(相当于数据库表的概念);一个Index的数据我们可以分发到不同的Node上进行存储,这个操作就叫做分片。比如现在我集群里边有4个节点,我现在有一个Index,想将这个Index在4个节点上存储,那我们可以设置为4个分片。这4个分片的数据合起来就是Index的数据。为了实现高可用还应配置副本进行数据存储,数据写入的时候是写到主分片,副本分片会复制主分片的数据,读取的时候主分片和副本分片都可以读。如果某个节点挂了,前面所提高的Master Node就会把对应的副本分片提拔为主分片,这样即便节点挂了,数据就不会丢。前提条件:
1)只有候选主节点(master:true)的节点才能成为主节点。
2)最小主节点数(min_master_nodes)的目的是防止脑裂。核对了一下代码,核心入口为findMaster,选择主节点成功返回对应Master,否则返回null。

选举流程大致描述如下:
第一步:确认候选主节点数达标,elasticsearch.yml设置的值discovery.zen.minimum_master_nodes;
第二步:比较,先判定是否具备master资格,具备候选主节点资格的优先返回;若两节点都为候选主节点,则id小的值为主节点。注意这里的id为string类型。

Elasticsearch写入原理

image-20230213162624608

写入原理详解:

客户端写入一条数据,到Elasticsearch集群里边就是由节点来处理这次请求。集群上的每个节点都是coordinating node(协调节点),协调节点表明这个节点可以做路由。比如节点1接收到了请求,但发现这个请求的数据应该是由节点2处理(因为主分片在节点2上),所以会把请求转发到节点2上。coodinate(协调)节点通过hash算法可以计算出是在哪个主分片上,然后路由到对应的节点。
shard = hash(document_id) % (num_of_primary_shards)

路由到对应的节点以及对应的主分片时,会做以下的事:
1、将数据写到内存缓存区
2、然后将数据写到translog缓存区
3、每隔1s数据从buffer中refresh到FileSystemCache中,生成segment文件,一旦生成segment文件,就能通过索引查询到了
4、refresh完,memory buffer就清空了
5、每隔5s,translog从buffer flush到磁盘中
6、定期/定量从FileSystemCache中,结合translog内容flush index到磁盘中

总结:Elasticsearch会把数据先写入内存缓冲区,然后每隔1s刷新到文件系统缓存区(当数据被刷新到文件系统缓冲区以后,数据才可以被检索到)。所以Elasticsearch写入的数据需要1s才能查询到。为了防止节点宕机,内存中的数据丢失,Elasticsearch会另写一份数据到日志文件上,但最开始的还是写到内存缓冲区,每隔5s才会将缓冲区的刷到磁盘中。所以Elasticsearch某个节点如果挂了,可能会造成有5s的数据丢失。等到磁盘上的translog文件大到一定程度或者超过了30分钟,会触发commit操作,将内存中的segement文件异步刷到磁盘中,完成持久化操作。说白了就是,写内存缓冲区(定时去生成segement,生成translog),能够让数据能被索引、被持久化,最后通过commit完成一次的持久化。等主分片写完了以后,会将数据并行发送到副本集节点上,等到所有的节点写入成功就返回ack(确认)给协调节点,协调节点返回ack给客户端,完成一次写入操作。

Elasticsearch更新删除原理

Elasticsearch的更新和删除操作流程:给对应的doc记录打上.del标识,如果是删除操作就打上delete状态,如果是更新操作就把原来的doc标志为delete,然后重新新写入一条数据。前面提到了,每隔1s会生成一个segement文件,那segement文件会越来越多越来越多。Elasticsearch会有一个merge任务,会将多个segement文件合并成一个segement文件。在合并的过程中,会把带有delete状态的doc给物理删除掉。

Elasticsearch查询原理

Get(通过ID去查Doc是实时的),Query(通过query去匹配Doc是近实时的)。根据ID查询具体的doc的流程是:检索内存的Translog文件、检索硬盘的Translog文件、检索硬盘的Segement文件。根据query去匹配doc的流程是:同时去查询内存和硬盘的Segement文件。因为segement文件是每隔一秒才生成一次的,所以Elasticsearch查询又分可以为三个阶段:
1)QUERY_AND_FETCH(查询完就返回整个Doc内容)
2)QUERY_THEN_FETCH(先查询出对应的Doc id,然后再根据Doc id匹配去对应的文档)
3)DFS_QUERY_THEN_FETCH(先算分,再查询)。这里的分指的是词频率和文档的频率(Term Frequency、Document Frequency)众所周知,出现频率越高,相关性就更强。

一般我们用得最多的就是QUERY_THEN_FETCH,第一种查询完就返回整个Doc内容(QUERY_AND_FETCH)只适合于只需要查一个分片的请求。QUERY_THEN_FETCH总体的流程流程大概是:
1)客户端请求发送到集群的某个节点上。集群上的每个节点都是coordinate node(协调节点)
2)然后协调节点将搜索的请求转发到所有分片上(主分片和副本分片都行)
3)每个分片将自己搜索出的结果(doc id)返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。
4)接着由协调节点根据doc id去各个节点上拉取实际的document数据,最终返回给客户端。

Query Phase阶段时节点做的事:
1)协调节点向目标分片发送查询的命令(转发请求到主分片或者副本分片上)
2)数据节点(在每个分片内做过滤、排序等等操作),返回doc id给协调节点

Fetch Phase阶段时节点做的是:
1)协调节点得到数据节点返回的doc id,对这些doc id做聚合,然后将目标数据分片发送抓取命令(希望拿到整个Doc记录)
2)数据节点按协调节点发送的doc id,拉取实际需要的数据返回给协调节点。

由于Elasticsearch是分布式的,所以需要从各个节点都拉取对应的数据,然后最终统一合成给客户端。只是Elasticsearch把这些活都干了,我们在使用的时候无感知而已。
posted @ 2023-07-06 16:40  肖德子裕  阅读(36)  评论(0编辑  收藏  举报