赞
踩
1、ES的主要应用分为两大类:
MySQL作为开源关系型数据库,应用范围非常广泛,非常适合于结构化数据存储和查询。在数据查询场景下,默认返回所有满足匹配条件的记录;如果业务数据为结构化数据,同时不需要特别关注排名和智能分词模糊匹配查询等特性,则建议采用关系型数据库如MySQL。
ES作为新生代NoSQL数据库代表之一,非常适合于非结构化文档类数据存储、更创新支持智能分词匹配模糊查询。如果业务数据为非结构化数据,同时更关注排名和需要智能分词模糊匹配的特性,则建议采用非关系型数据库如ES作为数据存储介质并使用配套搜索引擎。 ES 可以实现一些关系型数据库难以实现的功能,比如全文检索,ES 可以作为关系型数据库的补充,用来弥补关系型数据中的不足,也可能在某些情况下替代关系型数据库。
在面对大数据量简单计算的时候es的效率原高于mysql等传统数据库,对于数据量大、数据结构不固定的数据可采用全文检索方式搜索,利用全文检索技术建立索引,供用户查询;对于相对数量较少,多表join 时,mysql优势更高 。
第一,高效率:Elasticsearch对模糊搜索非常擅长
第二,查询结果排序:从Elasticsearch搜索到的数据可以根据评分过滤掉大部分的,只要返回评分高的给用户就好了
第三,模糊查询:没有那么准确的关键字也能搜出相关的结果
2、非结构化数据存储方式
非结构化数据又可称为全文数据,不定长或无固定格式,不适于由数据库二维表来表现,包括所有格式的办公文档、XML、HTML、Word 文档,邮件,各类报表、图片和咅频、视频信息等。对于非结构化数据,主要有两种方法:顺序扫描、全文检索。
顺序扫描:按照顺序扫描的方式查询特定的关键字。(这种方式无疑是耗时切低效的)
全文检索:将非结构化数据中的一部分元信息提取出来,重新组织,使其变得有一定结构,然后对此有一定结构的数据进行搜索,从而达到搜索相对较快的目的。这种方式的主要工作量在前期索引的创建,但是对于后期搜索却是快速高效的。从非结构化数据中提取出的然后重新组织的信息,我们称之索引。
索引创建:将现实世界中所有的结构化和非结构化数据提取信息,创建索引的过程。
搜索索引:就是得到用户的查询请求,搜索创建的索引,然后返回结果的过程。
文档: Elasticsearch最小的数据存储单元,JSON数据格式,类似于关系型数据库的表记录(一行数据),结构定义多样化,同一个索引下的document,结构尽可能相同。
索引: es索引,其保存具有相同结构的文档集合,类似于关系型数据库的数据库实例(6.0.0版本type废弃后,索引的概念下降到等同于数据库表的级别)。一个集群里可以定义多个索引。
类型: 类型用于区分同一个索引的不同数据类型,相当于关系型数据库中表。
分片: 因为 ES 是个分布式的搜索引擎, 所以索引通常都会分解成不同部分, 而这些分布在不同节点的数据就是分片。ES自动管理和组织分片, 并在必要的时候对分片数据进行再平衡分配, 所以用户基本上不用担心分片的处理细节。
副本(replica): ES 默认为一个索引创建 5 个主分片, 并分别为其创建一个副本分片. 也就是说每个索引都由 5 个主分片成本, 而每个主分片都相应的有一个 copy。对于分布式搜索引擎来说, 分片及副本的分配将是高可用及快速搜索响应的设计核心.主分片与副本都能处理查询请求,它们的唯一区别在于只有主分片才能处理索引请求.副本对搜索性能非常重要,同时用户也可在任何时候添加或删除副本。额外的副本能给带来更大的容量, 更高的呑吐能力及更强的故障恢复能力。
节点: 单个的ElasticSearch服务实例被称为节点(node)。一个数据节点上承载一个或多个分片。
集群: 集群是一个或多个节点(服务器)的集合, 这些节点共同保存整个数据,并在所有节点上提供联合索引和搜索功能。一个集群由一个唯一集群ID确定,并指定一个集群名(默认为“elasticsearch”)。
1、全文检索
当一个搜索请求被发送到某个节点时,这个节点就变成了协调节点。 这个节点的任务是广播查询请求到所有相关分片并将它们的响应整合成全局排序后的结果集合,这个结果集合会返回给客户端。多索引搜索恰好也是用相同的方式-只是会涉及到更多的分片。在查询的时候因为不知道要查询的数据具体在哪个分片上,所以整个过程分为 2 个步骤。
分发:请求到达协调节点后,协调节点将查询请求分发到每个分片上。
聚合: 协调节点搜集到每个分片上查询结果,在将查询的结果进行排序,之后给用户返回结果。
相关restful:
GET /_search //搜索所有的索引中所有的类型
GET /alibaba/_search //在alibaba索引中搜索所有的类型
GET /alibaba,kxtx/_search //在alibaba和kxtx索引中中搜索所有的文档
GET /m*,k*/_search //在任何以m或者k开头的索引中搜索所有的类型
GET /alibaba/employee/_search //在alibaba索引中搜索employee类型
GET /gb,us/user,tweet/_search //在gb和us索引中搜索user和tweet类型
GET /_all/user,tweet/_search //在所有的索引中搜索user和tweet 类型
2、带路由的查询(取回单个文档)
在主分片或复制分片上检索一个具体文档必要的顺序步骤:
客户端给Node 1发送get请求。协调节点默认使用文档ID参与计算(也支持通过routing),以便为路由提供合适的分片进行查找。shard = hash(document_id) % (num_of_primary_shards)
节点使用文档的_id确定文档属于分片0。分片0对应的复制分片在三个节点上都有。此时,它转发请求到Node 2。
Node 2返回文档(document)给Node 1然后返回给客户端。
对于读请求,为了平衡负载,协调节点会为每个请求选择不同的分片——它会循环所有分片副本。
相关restful:
GET twitter/_doc/0 //指定文档ID
1、插入文档
在主副分片和任何副本分片上面 成功新建,索引和删除文档所需要的步骤顺序:
客户端向 Node 1 发送新建、索引或者删除请求。coodinate(协调)节点通过hash算法可以计算出是在哪个主分片上,然后路由到对应的节点shard = hash(document_id) % (num_of_primary_shards)
节点使用文档的 _id 确定文档属于分片 0 。请求会被转发到 Node 3,因为分片 0 的主分片目前被分配在 Node 3 上。
Node 3 在主分片上面执行请求。如果成功了,它将请求并行转发到 Node 1 和 Node 2 的副本分片上。一旦所有的副本分片都报告成功, Node 3 将向协调节点报告成功,协调节点向客户端报告成功。
在客户端收到成功响应时,文档变更已经在主分片和所有副本分片执行完成,变更是安全的。
相关restful:PUT /index/type/_id
和POST /index/type
PUT /province/citys/1/_create //指定ID,_create可去掉
POST /province/citys/ //由elasticsearch自动生成ID
2、更新文档
客户端向node1 发送一个请求,node1作为协调节点。coodinate(协调)节点通过hash算法可以计算出是在哪个主分片上,然后路由到对应的节点shard = hash(document_id) % (num_of_primary_shards)
.
它将请求转发到主分片这个文档所在的Node 3.
node 3从主分片检索文档,修改_Source json ,并且尝试重新索引主分片的文档。如果文档被另一个进程修改,他会重复步骤3 ,直到超过retry_on_conflict 次后放弃。
node 3 成功更新文档,它将新版本的文档并行转发到node 1 和node 2 的副本分片,重新建立索引。所有副本分片都返回成功,node 3 向协调节点也返回成功,协调节点向客户端返回成功
update 操作也支持 新建索引的时的那些参数 routing 、 replication 、 consistency 和 timeout
相关restful: PUT /index/type/_id
和POST /index/type/_id
PUT /province/citys/1 //替换,PUT只会将json数据都进行替换
POST /province/citys/1/_update //更新,POST只会更新相同字段的值, _update可去掉
3、删除文档
该过程可以分为四个阶段来描述:
Elasticsearch是建立在Apache Lucene 基础上的实时分布式搜索引擎,Lucene为了提高搜索的实时性,采用不可再修改(immutable)方式将文档存储在一个个segment中。也就是说,一个segment在写入到存储系统之后,将不可以再修改。那么Lucene是如何从一个segment中删除一个被索引的文档呢?简单的讲,当用户发出命令删除一个被索引的文档#ABC时,该文档并不会被马上从相应的存储它的segment中删除掉,而是通过一个特殊的文件来标记该文档已被删除。当用户再次搜索到#ABC时,Elasticsearch在segment中仍能找到#ABC,但由于#ABC文档已经被标记为删除,所以Lucene会从发回给用户的搜索结果中剔除#ABC,所以给用户感觉的是#ABC已经被删除了。 Elasticseach会有后台线程根据Lucene的合并规则定期进行segment merging合并操作,一般不需要用户担心或者采取任何行动。被删除的文档在segment合并时,才会被真正删除掉。
相关restful:
DELETE /province/citys/1
4、es post和put的区别
PUT
可以新增也可以修改。PUT 必须指定 id;由于 PUT 需要指定 id,我们一般都用来做修改;5、写一致性保障
首先需要说明的一点,增删改其实都是一个写操作,所以这里的写指的是增删改三个操作。这里我们所说的写一致性指的是primary shard和replica shard上数据的一致性。es API为我们提供了一个可自定的参数consistency。该参数可以让我们自定义处理一次增删改请求,是不是必须要求所有分片都是active的才会执行。
该参数可选的值有三个:one,all,quorum(default,默认)。
1 one:要求我们这个写操作,只要有一个primary shard是active活跃可用的,就可以执行。
2 all:要求我们这个写操作,必须所有的primary shard和replica shard都是活跃的,才可以执行这个写操作
3 quorum:默认的值,要求所有的shard中,必须是大部分的shard都是活跃的,可用的,才可以执行这个写操作
写同步机制:
es是一个接近实时的搜索平台,这就意味着,从索引一个文档直到文档能够被搜索到有一个轻微的延迟。在 Elasticsearch 中,写入和打开一个新段的轻量的过程叫做 Refresh (即内存刷新到文件缓存系统)。默认情况下每个分片会每秒自动刷新一次。这就是为什么我们说 Elasticsearch 是近实时搜索,因为文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。
refresh机制:内存缓冲区的documents每隔一秒会被refresh(刷新)到filesystem cache中的一个新的segment中,segment就是索引的最小单位,此时segment将会被打开供检索。也就是说一旦文档被刷新到文件系统缓存中,其就能被检索使用了。这也是es近实时性(NRT)的关键。refresh的开销比较大, 在10W条记录的场景下refresh一次大概要14ms, 因此在批量构建索引时可以把refresh间隔设置成-1来临时关闭refresh,等到索引都提交完成之后再打开refresh默认情况下,es每隔一秒钟执行一次refresh,可以通过参数index.refresh_interval
来修改这个刷新间隔,执行refresh操作具体做了哪些事情呢?
相关restful: POST /student/_refresh
translog机制: 每个shard都对应一个translog文件,elastic使用translog来记录所有的操作,我们称之为write-ahead-log,我们新增了一条记录时,es会把数据写到translog和in-memory buffer(内存缓存区)。假如由于某种原因,ES的进程突然挂了,那些在内存中的数据就会丢失。而实际上,用户调用api, 返回结果确认用户数据已经添加到索引中。这种数据丢失是无法被接受的。怎么解决这个问题呢?
ES实现了Translog, 即数据索引前,会先写入到日志文件中。假如节点挂了,重启节点时就会重放日志,这样相当于把用户的操作模拟了一遍。保证了数据的不丢失。Translog
类是一个索引分片层级的组件,即每个index shard
一个Translog
类。它的作用是: 将没有提交的索引操作以持久化的方式记录起来(其实就是写到文件中)。t
translog 的目的是保证操作不会丢失。这引出了这个问题: translog 有多安全?在文件被 fsync 到磁盘前,被写入的文件在重启之后就会丢失。默认 translog 是每 5 秒被 fsync 刷新到硬盘,也就是说系统掉电的情况下es最多会丢失5秒钟的数据, 如果你对数据安全比较敏感,可以把这个间隔减小或者改为每次请求之后都把translog fsync到磁盘,但是会占用更多资源。这个过程在主分片和复制分片都会发生。在每次请求后都执行一个 fsync 会带来一些性能损失,尽管实践表明这种损失相对较小(特别是bulk导入,它在一次请求中平摊了大量文档的开销)。但是对于一些大容量的偶尔丢失几秒数据问题也并不严重的集群,使用异步的 fsync 还是比较有益的。比如,写入的数据被缓存到内存中,再每5秒执行一次 fsync 。
translog 可以是实时 fsync 的,也既写入 es 的数据,其对应的 translog 内容是实时写入磁盘的,并且是以顺序 append 文件的方式,所以写磁盘的性能很高。只要数据写入 translog 了,就能保证其原始信息已经落盘,进一步就保证了数据的可靠性。内存缓存区和translog就是近实时near-realtime的关键所在,前面我们讲过新增的索引必须写入到segment后才能被搜索到,因此我们把数据写入到内存缓冲区之后并不能被搜索到,如果希望该文档能立刻被搜索,需要手动调用refresh操作。
Flush机制: 随着translog文件越来越大时要考虑把内存中的数据刷新到磁盘中,这个过程称为flush,flush过程主要做了如下操作:
在Elasticsearch中,分词器是用于将文本数据划分为一系列的单词(或称之为词项term)的组件。这个过程是全文搜索中的关键步骤。分词器 接受一个字符串作为输入,将这个字符串拆分成独立的词或 语汇单元(token) (可能会丢弃一些标点符号等字符),然后输出一个 语汇单元流(token stream) 。分词器是Elasticsearch中很重要的一个组件,用来将一段文本分析成一个一个的词,Elasticsearch再根据这些词去做倒排索引。
一个分词器通常包含以下三个部分:
analyzed
(
被分析)的 string fields(字符串字段)的值通过 analyzer
(分析器)来传递,将字符串转换为一串 tokens
(标记)标记或者 terms
(词条)。例如,基于某种分析器,字符串 “The quick Brown Foxes” 被解析为 : quick,brown
,fox。
这些是索引该字段的实际 terms
(词条),可以用来有效地搜索大块文本内的单个单词。这样的分析过程不仅发生在索引的时候,而且在查询时也需要 。查询字符串需要通过相同(或类似的)analyzer
分析器传递,以便尝试查找那些存在于索引的相同格式的 terms
(词条)。可以在字段层级指定分析器, 但是如果该层级没有指定任何的分析器,那么我们如何能确定这个字段使用的是哪个分析器呢?分析器可以从三个层面进行定义:按字段(per-field)、按索引(per-index)或全局缺省(global default)。Elasticsearch 会按照以下顺序依次处理,直到它找到能够使用的分析器。索引时的顺序如下:
在搜索时,顺序有些许不同:
full-text query
(全文查找)中定义的 analyzer
(分析器)。search_analyzer
(搜索分析器)。analyzer
(分析器)。default_search
(默认搜索的)analyzer
(分析器)。default
(默认)的 analyzer
(分析器)。analyzer
(分析器)。写入时分词:在写入时,内置的 english analyzer 将首先句子转换成做个单词标记。然后将这些单词标记转换成小写,然后删除过滤词,并将单词转换成词干(foxes → fox,jumped → jump,lazy → lazi),最后将term存储在倒排索引中。mapping中的每个 text 类型字段都可以指定自己的 analyzer。在写入索引时,如果没有指定 analyzer
,它会在索引设置中查找名为 default
的分析器。 否则,它默认使用 standard
分析器。
搜索时分词:在 full text query 中,在搜索时将相同的分析过程应用于查询的字符串,例如 match
query 将查询字符串中的文本转换的terms形式为存储在倒排索引中的存储的terms相同。
分词就是将文档通过Analyzer分成一个一个的Term(关键词查询),每一个Term都指向包含这个Term的文档
。 注意: 在ES中默认使用标准分词器: StandardAnalyzer 特点: 中文单字分词 单词分词
我是中国人 this is good man----> analyzer----> 我 是 中 国 人 this is good man
分析器(analyzer)都由三种构件组成的:character filters
, tokenizers
, token filters
character filter
字符过滤器
tokenizers
分词器
Token filters
Token过滤器
ES的默认分词设置是standard,这个在中文分词时就比较尴尬了,会单字拆分,比如我搜索关键词“清华大学”,这时候会按“清”,“华”,“大”,“学”去分词,然后搜出来的都是些“清清的河水”,“中华儿女”,“地大物博”,“学而不思则罔”之类的莫名其妙的结果,这里我们就想把这个分词方式修改一下,于是呢,就想到了ik分词器,有两种ik_smart和ik_max_word。ik_smart会将“清华大学”整个分为一个词,而ik_max_word会将“清华大学”分为“清华大学”,“清华”和“大学”,按需选其中之一就可以了。修改默认分词方法(这里修改school_index索引的默认分词为:ik_max_word)。
通常情况下,我们在搜索和创建索引时使用的是同一分析器,以确保我们搜索是的词根与倒排索引中的词根拥有相同的格式,不过可以设置search_analyzer来覆盖搜索时的分析器,。 我们可能要想为同义词建索引(例如,所有 quick出现的地方,同时也为 fast 、 rapid 和 speedy 创建索引)。但在搜索时,我们不需要搜索所有的同义词,取而代之的是寻找用户输入的单词是否是 quick 、 fast 、 rapid 或 speedy 。为了区分,Elasticsearch 也支持一个可选的 search_analyzer 映射,它仅会应用于搜索时( analyzer 还用于索引时)。还有一个等价的 default_search 映射,用以指定索引层的默认配置。通常情况下,我们在搜索和创建索引时使用的是同一分析器,以确保我们搜索是的词根与倒排索引中的词根拥有相同的格式。但是有时我们又会有意识的在搜索时使用不同的分析器,例如使用edge_ngram解析器自动解析。默认情况下,查询将会使用字段映射时定义的分析器,但也能通过search_analyzer设置来进行修改:如果考虑到这些额外参数,一个搜索时的 完整 顺序会是下面这样:
search_quote_analyzer(搜索引用分析器)参数指定一个短语分析器,在处理短语查询(phrases query)禁用停止词时特别有用,当search_quote_analyzer参数设置时,analyzer参数和search_analyzer参数也必须设置。
该search_quote_analyzer
设置允许你为短语指定 analyzer
(分析器),这在处理禁用短语的 stop words
(停用词)时特别有用。要使用三个 analyzer
(分析器)设置来禁用短语的停用词 :
analyzer
(分析器)设置成索引所有的 terms
(词条)包括 stop words
(停用词)。search_analyzer
设置成将移除 stop words
(停用词)的非短语查询。search_quote_analyzer
设置不会移除 stop words
(停用词)的短语查询。停用词:有些词在文本中出现的频率非常高,但是对文本所携带的信息基本不产生影响。文本经过分词之后,停用词通常被过滤掉,不会被进行索引。在检索的时候,用户的查询中如果含有停用词,检索系统也会将其过滤掉(因为用户输入的查询字符串也要进行分词处理)。排除停用词可以加快建立索引的速度,减小索引库文件的大小,并且还可以提高查询的准确度。 如果不去除停用词,可能会存在这个情况:假设有一批文章数据,基本上每篇文章里面都有 的 这个词,那我在检索的时候只要输入了的这个词,那么所有文章都认为是满足条件的数据,但是这样是没有意义的
短语搜索:ES引擎首先分析查询字符串,从分析后的文本中构建短语查询,这意味着必须匹配短语中的所有分词,并且保证各个分词的相对位置不变。根据一组关键字进行精确匹配,返回包含所有关键字的文档。适用于需要精确匹配多个关键字的场景。match_phrase 查询首先将查询字符串解析成一个词项列表,然后对这些词项进行搜索,但只保留那些包含 全部 搜索词项,且 位置 与搜索词项相同的文档,且中间不许夹杂其他词流程:
slop
参数来设置,默认为0。即查询条件中的词组相隔的的位置。分词器参数的区别:
analyzer
参数定义text
字段索引和查询所使用的分析器,默认使用es自带的Standard
标准分析器。Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。