ElasticSearch学习笔记

一、ElasticSearch简介

1、ES是什么?

ElasticSearch是个基于Lucene实现的、(准)实时的、分布式的全文搜索和分析引擎。

准实时,意味着有轻微的延迟,通常为1秒,就可以从入库建索引文件到能够进行关键字搜索。

2、ES能干什么?

ES主要提供全文搜索、结构化搜索,以及分析的功能,并能将这三者混用。

3、ES的特性

  • 支持Restful风格的http接口
  • 输入输出支持json风格
  • 分布式索引、搜索
  • 索引自动分片、负载均衡
  • 自动发现机器、组建集群
  • 高性能
  • 高可扩展性
  • 高可用、提供复制机制
  • 使用简单

二、ES的基本概念

1、索引词(term)

一个能够被索引的精确值,区分大小写:即可以通过term查询进行准确的搜索。

2、文本(text)

一段普通的非结构化文字,文本会被分析成一个个索引词,存储在ES的索引库中,这样才能进行搜索。

3、分析(analysis)

将文本转换成索引词的过程,分析的结果依赖于分词器。
分词器的分析机制用于对全文文本进行分词,分词后用于建立可供搜索的反向索引。

4、索引(index)

index类似于关系数据库中的数据库,每个索引有不同的字段,可以对应不同的类型;
每个索引可以有一个或多个主索引片,同时每个索引还可以有零个或多个副本索引片。

5、类型(type)

type类似于关系数据库中的表,每种type都可以指定不同的列,映射定义文档中的每个字段的类型,并可以指定如何分析

6、文档(document)

document类似于关系数据库表中的行记录,每个存储在index中的一个document都有一个原始的json文档,被存储在一个叫_source的字段中。当搜索document时默认返回的就是_source字段。

一个document不只有数据,还包含了元数据(metadata)-- 关于文档的信息。三个必须的元数据节点是:

  • _index:文档存储的地方,名字必须全部小写,不能以下划线开头,不能包含逗号;
  • _type:名字可以大写或小写,不能包含下划线和逗号;
  • _id:是一个字符串,是一个文件的唯一标识。_id和_type, _index组合时,在ES就可以唯一标识一个document。在创建新文档时,_id可以自定义,也可以让ES自动生成,自动生成的_id有22个字符长。

7、映射(mapping)

mapping类似于关系数据库中的表结构,每一个index都有一个mapping,他定义了index中每一个字段的类型,以及一个index范围内的设置。一个mapping可以被事先定义,或者在第一次存储文档的时候自动识别。

mapping机制用于进行字段类型的确认,将每个字段匹配为一直确定的数据类型(string, number, boolean, data等)

8、字段(field)

field类似于关系数据库中表的列,每个字段都对应一个字段类型,如整型、字符串、对象等。
在ES中,每个document里面的字段都默认会被索引并被查询,也就是说,每个字段都专门有一个反向索引用于快速检索。与其他数据库不同的是,他可以在一次查询中,利用所有的这些反向索引,以惊人的速度返回结果。

ES与关系数据库对比:

ES关系数据库
index数据库
type数据库表
document表中的行
mapping表结构定义
field表中的列

9、来源字段(source field)

默认情况下,原始文档将被存储在_source这个字段中,查询的时候也是返回这个字段。这样可以从搜索结果中获取原始的对象,这个对象显示为一个精确的json字符串。

10、集群(cluster)

集群是指,有一个或多个ES节点组成的组,他们具有相同的cluster.name,这些节点协同工作,共享数据和负载。

ES是一个分布式的document存储引擎,他可以实时存储并检索复杂的数据结构,序列化的json文档。
换言之,一旦document被存储到ES中,他就可以在任意节点中被搜索到。

11、节点(node)

节点是指集群中的一个ES服务器,一个节点是一个逻辑上独立的服务,他是集群的一部分,可以存储数据,并参与集群的索引和搜索功能。在节点启动时,节点将使用广播来发现具有相同集群名称的集群,并尝试加入该集群。

主节点(master node)

每个集群都有一个主节点,这是由程序自动选择的,如果当前主节点失败,程序会自动选举其他节点作为主节点。

主节点将临时管理集群级别的一些变更,例如新建或删除索引,增加或移除节点等。主节点不参与文档级别的变更或搜索,这意味着在流量增长的时候,主节点不会成为集群的瓶颈。

12、路由(routing)

路由指:在操作文档时,选择文档所在分片的过程。一个文档会存储在一个唯一的主分片中,具体存储在哪个分片,是通过散列值来进行选择的。默认情况下,这个值由文档的id生成。如果文档有一个指定的父文档,从父文档ID中生成,该值可以在存储文档的时候进行修改。

13、分片(shard)

分片指:一个单一的Lucene实例,用来真正存储索引,并提供搜索功能。这个是由ES管理的比较底层的功能,ES的索引是指向主分片和副本分片的逻辑空间。

对于使用,只需要指定分片的数量,其他不需要做过多的事情。在开发使用过程中,我们对应的对象都是索引,ES会自动管理集群中所有的分片,当发生故障的时候,ES会把分片移动到不同的节点或添加新的节点。

注意:可以在一个单一的Lucene索引中存储的最大值为2147483519 (=integer.max_value - 128)个文档。

主分片(primary shard)

每个文档都存储在一个分片中,当你存储一个文档的时候,系统会首先存储在主分片中,然后会复制到不同的副本中。默认情况下,一个索引有5个主分片。可以在事先指定分片的数量,当分片一旦建立,分片的数量则不能修改。

副本分片(replica shard)

副本是主分片的复制,每一个主分片有零个或多个副本,这样做有两个目的:
1)增加高可用性:当主分片失败的时候,可以从副本分片中选择一个作为主分片
2)提高性能:当查询的时候,可以到主分片或副本分片中进行查询。

默认情况下,一个主分片有一个副本,但副本的数量可以在后面动态的配置增加。副本必须部署在不同的节点上,不能部署在和主分片相同的节点上。

三、ES的基本使用

3.1、请求格式

curl -X<VERB> '<PROTOCOL>://<HOST>:<PORT>?<QUERY_STRING>' -d'<BODY>'

1)VERB:HTTP方法:get, post, put, head, delete
2)PROTOCOL: http或者https协议
3)HOST:ES集群中的任何一个节点的主机名
4)PORT:ES HTTP服务所在的端口,默认为9200
5)PATH:指定要访问的路径和要做的操作,比如:/索引名/类型名/具体要操作的文档ID
6)QUERY_STRING:一些可选的查询请求参数,例如 ?pretty 参数将使请求返回格式化过的json数据
7)BODY:一个JSON格式的请求主体

返回

ES返回一个类似200的HTTP状态码和JSON格式的响应主体(除了HEAD请求),如果要显示HTTP头,在curl命令后跟-i参数

3.2、创建索引

curl -XPUT http://localhost:9200/mytest?pretty

也可以按照json格式来写,例如:

curl -XPUT 'http://localhost:9200/mytest2/' -d '{
	"settings" : {
		"index" : {
			"number_of_shards" : 5,
			"number_of_replicas" : 2
		}
	}
}'

查看索引,列出所有的索引

curl -XGET http://localhost:9200/_cat/indices

跟 ?v 能看到结果的表头

3.3、插入数据

curl -XPUT http://localhost:9200/mytest/product/p1 -d '{
	"name":"Mac Book 笔记本",
	"price":12345,
	"description":"这是一款笔记本",
	"cats":["3c", "computer"]
}'

1、请记住 _index, _type, _id三者唯一确定了一个document,所以想要保证document是新加入的,最简单的方式是使用post方法让ES自动生成唯一 _id

2、如果想使用自定义的_id,必须告诉ES应该在 _index, _type, _id三者都不同时,才接受请求。为了做到这点,有两种方法:
1)第一种方法,使用op_type查询参数:

PUT /website/blog/123?op_type=create {...}

2)第二种方法是在URL后加 /_create 作为端点:

PUT /website/blog/123/_create {...}

3、如果请求成功的创建了一个新document, ES将返回正常的元数据,且响应状态码是201 Created。另一方面,如果包含相同的 _index, _type和 _id的文档已经存在,ES将返回409 Conflict 响应状态码。

4、当创建文档的时候,如果索引不存在,则会自动创建该索引。自动创建的索引会自动映射每个字段的类型。

禁用“自动创建索引”功能,可以通过配置文件设置 action.auto_create_index为false。禁用自动映射的字段类型,可以通过配置文件设置 index.mapper.dynamic 为false。

自动创建索引可以通过模板设置索引名称,例如:可以设置
action.auto_create_index为 +aaa*, -bbb*, +ccc*, -* (+表示准许,-表示禁止)

3.4、查询数据

curl -XGET http://localhost:9200/mytest/product/p1?pretty

1、通常,GET请求将返回文档的全部,存储在 _source 参数中。但是你感兴趣的字段只是title, 请求个别字段可以使用 _source参数。多个字段可以用逗号分隔:

curl -XGET http://localhost:9200/mytest/product/p1?_source=name,price

2、如果你想做的只是检测文档是否存在,对内容完全不敢兴起,使用HEAD方法来代替GET,HEAD请求不会返回响应体,只有HTTP头

3、你也可以禁掉source,只有设置_source=false即可

4、如果不写type,可以用_all来代替,表示在所有的type中获取

5、如果你只想获取source中的一部分内容,还可以用_source_include或者_source_exclude来包含或者过滤其中的某些字段,如:

curl -GET http://localhost:9200/mytest/product/p1?_source_exclude=name,price

6、也可以用fields来选择source中的字段,如:

curl -XGET http://localhost:9200/mytest/product/p1?fields=name,price

注意:从返回值可以看出,返回的字段是数组类型,因此只有基本类型的字段可以从fields中进行查询,对象数据是不行的。

7、如果只想获取文档的内容,可以直接指定_source,例如:

curl -XPOST http://localhost:9200/mytest/product/p1/_source?pretty

3.5、修改数据

curl -XPOST http://localhost:9200/mytest/product/p1/_update?pretty -d ’{
	"doc":{"name":"新款Mac Book 笔记本","price":54321}
}'

1、document在ES中是不可变的,如果需要更新已存在的document, 可以替换掉它

2、在内部,ES已经标记旧document为删除,并添加了一个完整的新document。旧版本的document不会立即消失,但你也不能去访问他。ES会再你继续索引更多数据时清理被删除的文档。

3、ES可以在操作中指定version参数,如:

curl -XPOST http://localhost:9200/mytest/product/p1/_update?version=1 -d '{
	"doc":{"name":"新款Mac Book笔记本","price":54321},
}'

4、检查是否需要更新索引, 如果设置detect_noop为false, 那么不管这个字段是否发生了改变,都会更新索引, 设置为:

"doc":{"name":"new_name"},
"detect_noop":false

5、upsert:如果要修改的文档不存在,就执行upsert,如:

curl -XPOST http://localhost:9200/mytest/product/p11/_update?pretty -d '{
	"doc":{"name":"新款mac book笔记本", "price":54321},
	"upsert":{"name":"upsert haha"}
}'

还可以设置”doc_as_upsert":true, 直接把doc部门当做新的文档插入

3.6、删除数据

curl -XDELETE http://localhost:9200/mytest/product/p1?pretty

删除一个文档,也不会立即从磁盘上删除,它只是被标记成已删除。ES将会再你之后添加更多索引的时候才会在后头进行删除内容的清理。

删除索引

curl -XDELETE http://localhost:9200/mytest?pretty

3.7、简单查询

ES搜索有两种方式:
1)通过URL参数进行搜索
2)通过POST请求参数进行搜索,如:

curl _XGET http://localhost:9200/mytest/product/_search?q=price:12345

默认搜索出前10条,可以跟的参数有:
1)q:查询字符串
2)df:当查询中没有定义前缀的时候,默认使用的字段
3)analyzer:当分析查询字符串的时候使用的分词器
4)lowercase_expanded_terms:搜索的时候忽略大小写标志,默认为true
5)analyze_wildcard:通配符或者前缀查询是否被分析,默认为false
6)default_operator:默认多个条件的关系,AND或者OR,默认OR
7)Ienient:如果设置为true,字段类型转换失败的时候将被忽略,默认为false
8)explain:在每个返回结果中,将包含评分机制的解释
9)_source:是否包含元数据,同时支持_source_include和_source_exclude
10)fields:只返回索引中指定的列,多个列中间用逗号分开
11)sort:排序,例如fieldName:acs或者fieldName:desc
12)track_scores:评分轨迹,当排序的时候,设置为true的时候返回评分的信息
13)timeout:超时的时间设置
14)terminate_after:在每个分片中查询的最大条数,如果设置返回结果中会有一个terminated_early字段
15)from:开始的记录数
16)size:搜索结果的条数
17)search_type:搜索的类型,可以是dfs_query_then_fetch, query_then_fetch, 默认query_then_fetch

3.7.1、关于timeout

一般情况下,搜索请求不会超时。通常,协调节点会等待接收所有分片的回答。如果有一个节点遇到问题,他会拖慢整个搜索请求。

Timeout参数告诉协调节点,最多等待多久,就可以放弃等待,而将已有结果返回。返回部分结果总比什么都没有好。搜索请求的返回将会指出这个搜索是否超时,以及有多少分片成功答复了。

你可以定义timeout参数为10或者10ms,或者1s,例如:

GET /_search?timeout=10ms

ES将返回再请求前收集到的结果。

注意:超时不是一个断路器,也就是说timeout不会停止执行查询,它仅仅告诉你目前顺利返回结果的节点,然后关闭连接。在后台,其他分片可能依旧执行查询,尽管结果已经被发送。

3.7.2、查询多index多type

通过限制搜索的不同index或type,可以在集群中跨所有document搜索。ES转发搜索请求到集群中的主分片或每个分片的复制分片上,收集结果后,选择顶部的10个返回。

可以通过定义URL中的索引或类型类限定搜索的范围,例如:
1)/_search:在所有index的所有type中搜索
2)/mytest/_search:在索引mytest的所有type中搜索。
3)/mytest, test2/_search:在索引mytest和test2的所有type中搜索
4)/my*, t*/_search:在以my或t开头的索引的所有类型中搜索
5)/mytest/product/_search:在索引mytest的类型product中搜索
6)/mytest, test2/product, user/_search:在索引mytest和test2的类型为product和user中搜索
7)/_all/product, user/_search:AI所有索引的product和user中搜索

当你搜索包含单一index时,ES转发搜索请求到这个index的主分片或每个分片的复制分片上,然后汇总每个分片的结果。搜索包含多个索引也是同样的方式,只不过或有更多的分配被关联。

注意:搜索一个索引有5个主分片和5个索引各有一个分片,事实上是一样的。

3.7.3、分页

ES接受from和size参数:

  • size:结果数,默认为10
  • from:跳过开始的结果数,默认为0
    如果你想每页显示5个结果,页面从1到2,请求如下:
GET /_search?size=5
GET /_search?size=5&from=5

在集群系统中深度分页

为什么深度分页有问题?假设在一个有5个主分片的索引中搜索,当请求结果的第一页(结果1到10)时,每个分片产生自己最顶端10个结果,然后返回他们给请求节点,他们再拍下这所有的50个结果,以选出顶端的10个结果。

现在假设请求第1000页,结果10001到10010, 工作方式都相同,不同的是每个分片都必须产生顶端的10010个结果,然后请求节点排序这50050个结果,并丢弃50040个!

可以看到在分布式系统中,排序结果的花费随着分页的深入而成倍增长,这也是为什么网络搜索引擎中,任何预计不能返回多余1000个结果的原因。

3.7.4、关于routing

可以在操作文档的时候,指定用来计算路由的routing值,从而限定操作会落在哪些分片上,如果在新增文档的时候指定了routing,那么后续对这个文档的所有操作,都应该使用同样的routing值,这个技术在设计非常大的搜索系统时非常有用,例如:
1、新增Document,指定routing:

curl -XPUT http://localhost:9200/mytest/product/p12?routing=myrouting -d '{
	"name":"Mac Book 笔记本1212“,
	”price":12,
	"description":"这是一款笔记本“,
	”cats":["3c","computer"]
}'

2、查询的时候,也带上相同的routing值:

curl -XGET http://localhost:9200/mytest/product/p12?pretty=true\&routing=myrouting

3.7.5、关于加减符号

搜索中,还可以使用加减号,"+"前缀表示语句匹配条件必须被满足。类似的”-“前缀表示条件必须不被满足。所有条件如果没有+或-表示是可选的:匹配越多,相关的document就越多,例如:

curl -XGET http://localhost:9200/mytest/product/_search?q=+price:12345\&pretty

四、索引

4.1、索引基本流程

4.1.1、准备知识

1、在ES中构建索引,相当于创建库和标
2、指定mapping, 相当于指定表结构

4.1.2、构建索引数据

1、要把要搜索的原始数据加入到ES中,可通过客户端开发、运行导入。
2、ES会对这些数据进行分析,依赖于分词器、分析器等,分析的结果就是索引的数据。
3、把这些数据添加到索引中,其实就是放到底层的Lucene中。

4.1.3、查询阶段

1、ES对查询词进行处理
2、ES查找和匹配document, 各种查询会有完全不一样的过程
3、ES对查询结果进行处理,如:评分、排序、高亮等。

在这里插入图片描述

4.2、API约定

ES对外提供的API是以http协议的方式,通过json格式以REST方式。

4.2.1、多索引查询支持以下参数:

1)ignore_unavailable:当索引不存在或者关闭的时候,是否忽略这些索引,值为true或false
2)allow_no_indices:当使用通配符查询时,当有索引不存在的时候,是否返回查询失效。
3)expand_wildcards:控制什么类型的索引被支持,值为open, close, none, all。open表示只支持open类型的索引,close表示只支持关闭状态的索引,none表示不可用,all表示同时支持open和close索引。
注意:文档操作API和索引别名API不支持多索引参数。

4.2.2、通用参数

1、pretty参数:返回经过格式化的json。系统还提供了 “?format=yaml"的yaml格式。
2、human参数:”?human=true" (默认为false) 提供适合人类阅读的数据,如:“size_in_bytes”:1024 变成 “size”:“1kb”
3、响应过滤(filter_path):所有返回值可以通过filter_path来减少返回值的内容,多个值可以通过逗号分开。即指定过滤掉的field, 例如:

curl -XGET http://localhost:9200/website/blog/_search?pretty\&filter_path=took,hits.hits._id -d '{
	"query":{
		"match":{
			"operator":"or",
			"query":"value 笔记本",
			"type":"boolean"
		|
	}
}'

它也支持通配符*匹配任何部分的字段的名称,如:

curl -XGET http://localhost:9200/website/blog/_search?pretty\&filter_path=took,hits.h*._id -d '{
	"query":{
		"match":{
			"operator":"or",
			"query":"value 笔记本",
			"type":"boolean"
		|
	}
}'

我们可以用两个通配符 ** 来匹配不确定名称的字段,例如我们可以返回lucene版本的段信息:

curl -XGET http://localhost:9200/_segments?pretty\&filter_path=indices.**.version

注意:有事直接返回ES的某个字段的原始值,如_source字段。如果你想过滤_source字段,可以结合_source字段和filter_path参数,如:

curl -XGET http://localhost:9200/_search?pretty\&filter_path=hits.hits._source\&_source=source_node

4.3、索引操作

4.3.1、创建索引

手动创建索引,可以在请求中加入所有设置和类型映射:

curl -XPOST http://localhost:9200/mytest3 -d '{
	"settings":{
		"number_of_shards":3,
		"number_of_replicas":2
	},
	"mapptings":{
		"type1":{
			"properties":{
				"field1":{"type":"string","index":"not_analyzed"}
			}
		}
	}
}'

可以在config/elasticsearch.yml中添加下面的配置来防止自动创建索引:

action.auto_create_index:false

4.3.2、获取索引

curl -XGET http://localhost:9200/mytest3?pretty

还可以加入过滤,支持:_settings, _mapptings, _warmers, _aliases, 如:

curl -XGET http://localhost:9200/mytest3/_settings,mappings?pretty

检查索引是否存在

curl -XHEAD -i http://localhost:9200/mytest3

根据返回值来判断

打开/关闭索引

curl -XPOST http://localhost:9200/mytest/_close
curl -XPOST http://localhost:9200/mytest/_open

4.3.3、Put mapping API

该API允许你创建索引,并设定mapping, 或者给存在的索引增加新的类型,或者在已有的类型中增加新的字段。一般不能修改已有的字段。

例1、创建索引并设定Mapping:

PUT twitter{
	"mapping":{
		"tweet":{
			"properties":{
				"message":{"type":"string"}
			}
		}
	}
}

例2、给存在的索引增加新的user类型

PUT twitter/_mapping/user{
	"properties":{
		"name":{"type":"string"}
	}
}

例3、在已有类型tweet中增加新的字段user_name

PUT twitter/_mapping/tweet{
	"properties":{
		"user_name":{"type":"string"}
	}
}

这个API的index部分,可以接受多个Index的名字,或者使用通配符。

4.3.4、获取mapping API

可以指定index和type, 也可以都不指定,例如:

curl -XGET http://localhost:9200/_mapping/twitter,kimchy
curl -XGET http://localhost:9200/_all/_mapping/tweet,book
curl -XGET http://localhost:9200/_all/_mapping
curl -XGET http://localhost:9200/_mapping

获取字段的mapping API

curl -XGET http://localhost:9200/twitter/_mapping/tweet/field/text
curl -XGET http://localhost:9200/twitter,kimchy/_mapping/tweet/field/message
curl -XGET http://localhost:9200/_all/_mapping/tweet,book/field/message,user.id
curl -XGET http://localhost:9200/_all/_mapping/tw*/field/*.id
curl -XGET http://localhost:9200/_all/_mapping/*/field/*?pretty

检查类型是否存在

curl -XHEAD -i http://localhost:9200/mytest/product?pretty

4.3.5、更新索引的设置

ES提供了优化好的默认配置,除非你明白这些配置的行为和为什么要这么做,否则请不要修改这些配置。下面是两个最重要的设置:
1、number_of_shards:定义一个索引的主分片个数,默认值是5。这个配置在索引创建后不能修改。
2、number_of_replicas:每个主分片的复制分片个数,默认是1。

curl -XPUT http://localhost:9200/mytest/_settings -d '{
	"index":{"number_of_replicas":4}
}'

更新索引分析器

需要先关闭索引,然后再更新分析器,然后再打开索引:

curl -XPOST http://lcoalhost:9200/mytest/_close
curl -XPUT http://localhost:9200/mytest/_settings -d '{
	"analysis":{
		"analyzer":{
			"content":{
				"type":"custom","tokenizer":"whitespace"
			}
		}
	}
}'

获取settings信息

curl -XGET http://localhost:9200/twitter/_settings
curl -XGET http://localhost:9200/twitter,kimchy/_settings
curl -XGET http://localhost:9200/_all/_settings
curl -XGET http://localhost:9200/2016.*/_settings

4.3.6、Analyze API

这个API执行对文本的分析,然后返回token结果,例如:

curl -XGET http://localhost:9200/_analyze?pretty -d '{
	"analyzer":"standard",
	"text":"this is a notebook"
}'

1、可以把analyzer设置成ik看看效果
2、text部分,支持使用数组,里面放多个字符串
3、还可以设置更细致的 tokenizers, token filters, char filters,例如:

"analyzer":"standard",
"tokenizer":"keyword",
"token_filter":["lowercase"],
"char_filter":["html_strip"],

4.4、索引管理

4.4.1、索引统计信息

curl http://localhost:9200/_stats?pretty
curl http://localhost:9200/mytest/_stats?pretty

多个索引之间用逗号分隔

4.4.2、Indices Segments API

提供低级别的lucene中索引段的信息,例如:

curl -XGET http://localhost:9200/mytest/_segments?pretty
curl -XGET http://localhost:9200/mytest,mytest2/_segments
curl -XGET http://localhost:9200/_segments

如果想要查看更详细的信息,可以在url上添加?verbose=true

Indices Recovery API

提供查看索引分片的恢复信息,会报告recovery的状态,例如:

curl -XGET http://localhost:9200/mytest,mytest2/_recovery?pretty
curl -XGET http://localhost:9200/_recovery?pretty&human

可以添加detailed=true的参数,来查看更详细的信息

Indices Shard Store API

提供查看索引分片的存储信息,例如:

curl -XGET http://localhost:9200/mytest/_shard_stores?pretty
curl -XGET http://localhost:9200/mytest,test2/_shard_stores
curl -XGET http://localhost:9200/_shard_stores

Clear Cache API

用来清除1到多个索引相关的缓存,例如:

curl -XPOST http://localhost:9200/mytest/_cache/clear?pretty
curl -XPOST http://localhost:9200/mytest,mytest2/_cache/clear
curl -XPOST http://localhost:9200/_cache/clear

Flush API

Flush API的功能是把索引在内存里面的数据,存储到具体的存储器上,并删除相应的内部事务日志。
例如:

curl -XPOST http://lcoalhost:9200/mytest/_flush?pretty
curl -XPOST http://localhost:9200/mytest,mytest2/_flush

Refresh API

刷新索引,使得上次refresh的操作引起的变化,都能反映到查询上。

curl -XPOST http://localhost:9200/mytest/_refresh?pretty
curl -XPOST http://localhost:9200/mytest,mytest2/_refresh
curl -XPOST http://localhost:9200/_refresh

Force merge API

提供枪支让索引里面的lucene段进行合并的功能

curl -XPOST http://localhost:9200/mytest/_forcemerge?pretty
curl -XPOST http://localhost:9200/mytest,mytest2/_forcemerge

4.5、索引配置

4.5.1、内存控制器

在ES中有很多控制器可以峰值内存溢出,每个控制器可以指定内存使用的最大值。除此之外,还有一个总的控制器在确定整个系统使用的最大内存值。这些配置都是可以动态更新的。

总的内存控制:indices.breaker.total.limit:总的内存使用大写,默认为JVM对内存的70%

4.5.2、缓存

1、节点查询缓存:是负责缓存查询的结果。每个节点都有一个查询缓存,这个缓存为这个节点下的所有分片服务。这个缓存采用LRU算法;当缓存满时,把最少使用的数据优先删掉。查询缓存只有使用过滤的时候才会起作用。

2、索引缓冲区:用于存储新的索引文档,当缓冲区满后,缓冲区中的文件被写入磁盘上的一个段,他会在节点的所有分片上分离。它的设置是静态的,并且必须在集群中的每个数据节点上配置。

3、分片请求缓存:当一个搜索请求是对一个索引或者多个索引的时候,每一个分片都是进行它自己内容的搜索,然后把结果返回到协调节点上,然后把这些结果合并到一起,统一对外提供。分片缓存模块缓存了这个分片的搜索结果。这使得搜索频率高的请求会立即返回。
注意:请求缓存只荤菜查询条件size=0的搜索,缓存的内容有hits.total, aggregation,suggestions, 不缓存原始的hits。通过now查询的结果将不缓存。

4、缓存失效:只有在分片的数据,实际上发生了变化的时候,刷新分片缓存才会失效。刷新的时间间隔越长,缓存的数据越多,当缓存不够的时候,最少使用的数据将被删除。缓存过期可以手工设置。

五、Mapping

5.1、Mapping概述

Mapping是用来定义一个ducument和他所包含的fields,如何被存储和索引的过程。例如,使用mapping来定义:
1、字符串字段是否作为全文本搜索字段。
2、哪些字段包含数据,日期或地理信息
3、document中所有field的值是否应该被索引到_all字段
4、日期值的格式
5、自定义规则来控制动态添加的字段的映射。

5.2、Mapping类型概述

每个index有一个或多个mapping type, type是对ducment划分的逻辑组,index中每个document都有一个type,每个type拥有自己的mapping或模式定义(schema definition)。每个Mapping type包括:
1、关联到类型上的元数据,如:_index, _type, _id, _source
2、字段或属性的定义,如:字段类型,每个字段的数据类型,以及字段被ES处理的方式。

数据类型概述

数据类型有如下几类:
1、基本类型:string, date, long, double, boolean, ip等
2、嵌套类型
3、特殊类型:geo_point, geo_shape, completion等

5.3、动态Mapping概述

在添加数据的时候,ES会使用动态mapping类猜测字段类型,从而自动进行映射。在运行期需要的时候,动态的添加映射,加入新的type或者字段,效果跟预先做好映射是一样的。
看个官方文档的sample:

PUT my_index {
	"mappings":{
		"user":{
			"_all":{"enabled":false}
			"properties":{
				"title":{"type":"string"},
				"body":{"type":"string"},
				"user_id":{
					"type":"string","index":"not_analyzed"
				}
			},
			"created":{
				"type":"string","format":"strict_date_optional_time||epoch_millis"
			}
		}
	}
}

查看type的mapping

curl -XGET http://localhost:9200/mytest/_mapping/product?pretty

根对象

mapping最高一层被称为根对象,他包含下面几项:
1)一个properties节点,列出了文档中可能包含的每个字段的mapping
2)多个元数据字段,每个都以下划线开头,例如_type, _id, _source
3)设置项,控制如何动态处理新的字段,如analyzer, dynamic_date_formats,dynamic_templates
4)其他属性,可以同时应用在根对象和其他obejct类型的字段上,如enabled, dynamic等属性。

属性

属性就是properties节点下的属性的设置,可以设置很多东西,比如:
1、type

{
	"字段1":{"type":"integer"}
}

2、index:index参数控制字符串以何种方式被索引,它包含下面三个之一:
1)analyzed:首先分析这个字符串,然后索引。换言之,以全文形式索引此字段。
2)not_analyzed:索引这个字段,使之可以被搜索。但索引内容和指定值一样。不分析此字段。
3)no:不索引这个字段,这个字段不能被搜索到。
string类型字段默认是analyzed。如果我们想映射字段为确切值,需要设置他为not_analyzed:

"字段1":{
	"type":"string","index":"not_analyzed"
}

注意:除了string外的其他简单类型(long, double, date等)也接受index参数,但相应的值只能是no或not_analyzed,他们的值不能被分析。

3、analyzer:确定在索引和搜索时全文字段使用的分析器。
对于analyzed类型的字符串字段,使用analyzer参数来指定哪一种分析器,将在搜索和索引的时候使用。默认的,ES使用standard分析器,但是你可以通过指定一个内奸的分析器来更改他,如:whitespace, simple, english

{
	"字段1":{
		"type":"string","analyzed":"english"
	}
}

5.4、动态模板

使用dynamic_templates, 你可以完全控制新字段的mapping,你设置可以通过字段名或数据类型应用一个完全不同的mapping。

每个模板都有一个名字,用于描述这个模板的用途,一个mapping字段用于指明这个mapping怎么使用,和至少一个参数(如match)来定义这个模板适用于哪个字段。

模板安装顺序来检查,第一个匹配的模板会被启用。例如给string类型字段定义两个模板:
es:字段名以 _es 结尾需要使用spanish分析器
en:所有其他字段使用 english 分析器
我们讲es模板放在第一位,因为它比匹配所有字符串的 en 模板更特殊一点:

PUT /my_index {
	"mapping":{
		"my_type":{
			"dynamic_templates":[
				"es":{
					"match":"*_es",
					"match_mapping_type":"string",
					"mapping":{
						"type":"string","analyzer":"spanish"
					}
				},
				"en":{
					"match":"*",
					"match_mapping_type":"string",
					"mapping":{
						"type":"string","analyzer":"english"
					}
				}
			]
		}
	}
}

六、倒排索引

6.1、Lucene如何处理文档

在Lucene中,一个文档由一组简单的key/value对组成,一个字段至少需要有一个value,但是任何字段都可以有多个value。类似的,一个单独的字符串可能在分析过程中被转换成多个值。Lucene不关心这些值是字符串、数字还是日期,所有的值都被当成不透明字节。

当我们在Lucene中索引一个文档时,每个字段的值都被加到相关字段的倒排索引中。你也可以选择将原始数据存起来以备今后取回。

ES中类型是怎么实现的

ES中一个index可能包含多个type,每个type有各自的mapping和document。因为Lucene没有document type的概念,每个document的type名被存储在一个叫 _type的元数据字段中。当我们搜索一种特殊类型的document时,ES简单的通过 _type字段来过滤出这些document。

Lucene同样没有mapping的概念,mapping是ES将复杂的json文档映射成Lucene需要的扁平化数据的方式。

预防type陷阱

事实上,不同type的document可以被加到同一个index里,这带来了一些预想不到的困难。为了保证你不会遇到这些冲突,建议在同一个index的每一个type中,确保用统一的方式映射同名的字段。

6.2、倒排索引概述

ES使用一种叫做倒排索引(inverted index) 的结构来做快速的全文搜索。倒排索引由”在文档中出现的唯一的单词列表,以及对每个单词在文档中的位置“组成。

现代搜索引擎的关键步骤就是建立倒排索引,倒排索引一般表示为一个关键词,然后是他的频度(出现的次数),位置(出现在哪一篇文章或网页中,及有关的日期,作者等信息)等构成。例如,我们有两个文档,每个文档content字段包含:
Doc1:This is a dog
Doc2:That is a dog too
为了创建倒排索引,我们首先切分每个文档的content字段为单独的单次(叫做terms或tokens),然后把所有的唯一词放入列表并排序,结果是这个样子:
在这里插入图片描述
现在想要搜索” is a dog too", 就只需要找到每个词在文档中存在即可。
很明显,Doc1包含了3个,而Doc2包含了4个词,如果此时我们来个简单的相似度算法,只计算匹配单次的数目,这样我们就可以说第二个文档比第一个匹配度更高,也即是第二个文档对于我们的查询具有更多的相关性。

这样简单的方式存在一些问题,比如:
1)This和this会任务是不同的词
2)dog和dogs很相似,毕竟他们是同根词
3)dog和puppy意思相近,他们是同义词
如果按照简单的匹配的话,上面这些情况就得不到我们预期的结果了。

解决方式:我们可以对存储的term进行一些变化操作,比如:
1)统一大小写,比如都小写
2)同根词都记录成 词根
3)同义词都转换成一个词来记录

6.3、Lucene概述

Lucene是一个开源的高性能的java全文搜索引擎工具包,不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询引擎和索引引擎,部分文本分析引擎。

Lucene的目的是为软件开发人员提供一个简单易用的工具包,以方便在目标系统中实现全文检索的功能,或以此为基础建立起完成的全文检索引擎。

6.4、Lucene倒排索引

Lucene采用的也是倒排索引,不过仅知道关键词在哪些文章中出现还不够,我们还需要知道关键词在文章中出现的次数和出现的位置,通常有两种位置:
1、字符位置,即记录该次是文章中第几个字符(优点是关键词高亮显示时定位快)
2、关键词位置,即记录该次是文章中第几个关键词(优点是节约空间、词组(phase)查询快),Lucene中记录的就是这种位置。

因此,Lucene记录的格式大致是:词项、词频、指针,示例如下:
在这里插入图片描述

6.5、Lucene的基本实现

实现时,Lucene将上面的三列分别作为词典文件(Term Dictionary)、词频文件(frequencies)、位置文件(positions)保存。其中词典文件不仅保存有每个关键词,还保留了指向频率文件和位置文件的指针,通过指针可以找到该关键词的频率信息和位置信息。

Lucene使用了field的概念,用于表达信息所在位置(如标题中,文章中,url中),在建索引中,该field信息也记录在词典信息中,每个关键词都有一个field信息(因为每个关键字一定属于一个或多个field)

压缩算法

为了减小索引文件的大小,Lucene对索引使用了压缩技术。首先,对词典文件中的关键词进行了压缩,关键词压缩为<前缀长度,后缀>,例如:当前词为“阿拉伯语”,上一个词为“阿拉伯”,那么“阿拉伯语”压缩为<3,语>。

其次大量用到了对数字的压缩,数字只保存与上一个值的差值(这样可以减少数字的长度,进而减少保存该数字需要的字节数)。

6.6、ES的倒排索引

1、对document构建倒排索引

2、写入磁盘,而且写入磁盘的倒排索引是不可变的。他有如下好处:
1)不需要锁:因为从来不需要更新一个索引,就不必担心多个程序同时尝试修改
2)一旦索引被读入文件系统的缓存,他就一直在那,不会改变。只要文件系统缓存有足够的空间,大部分的读会直接访问内存而不是磁盘,有助于提升性能。
3)在索引的声明周期内,所有的其他缓存都可用。他们不需要在每次数据变化了都重建,因为数据不会变。
4)写入单个大的倒排索引,可以压缩数据,减少磁盘IO和需要缓存索引的内存大小。

3、不可变的索引有如下缺点:如果想要搜索一个新document, 必须重建整个索引。这不仅严重限制了一个索引能装下的数据,还有一个索引可以被更新的频次。

动态索引

ES是如何在保持不可变的同时更新倒排索引的?
答:使用多个索引。不是重写整个倒排索引,而是增加额外的索引反映最近的变换。每个倒排索引都可以按顺序查询,从最老的开始,最后把结果聚合。

ES底层依赖的Lucene,引入了per-segment search概念,一个段(segment)是有完整功能的倒排索引,但现在Lucene中的索引指的是segment的集合,再加上提交点(commit point,包含所有segment的文件)。

动态索引的说明:
1、Lucene索引是ES中的分片,ES中的索引是分片的集合。当ES搜索索引时,他发送查询请求给该索引下的所有分片,然后过滤这些结果,聚合成全局的结果。

2、一个per-segment search这样工作:
1)新的文档首先写入内存区的索引缓存
2)然后,这些buffer被提交:

  • 一个新的segment – 额外的倒排索引 – 写入磁盘
  • 新的提交点写入磁盘,包括新segment的名称
  • 磁盘是文件同步的 – 所有写操作等待文件系统缓存同步到磁盘,确保他们可以被物理写入
    3)新segment被打开,他包含的文档可以被检索
    4)内存的缓存被清除,等待接受新的文档。

3、当一个请求被接受,所有segment一次查询。所有segment上的Term统计信息被聚合,确保每个Term和document的相关性被正确计算。通过这种方式,新的document以较小的代价加入索引。

删除和更新

segment是不可变的,所以document既不能从旧的segment中移除,旧的segment也不能更新以反映document最新的版本。相反,每一个提交点包括一个.del文件,包含了segment上已经被删除的document。

当一个document被删除,他实际上只是在.del文件中被标记为删除,新版本的document在新的segment中索引。也许该document的不同版本都会匹配一个查询,但是更老版本会从结果中删除。

理解近实时的搜索

因为per-segment search机制,索引和搜索一个document之间是有延迟的。新的document会再几分钟内可以搜索,但这依然不够快。磁盘是瓶颈,提交一个新的segment到磁盘,需要fsync操作,确保segment被物理地写入磁盘,即使电源失效也不会丢数据。但fsync是昂贵的,他不能再每个document被索引时就触发。

所以需要一种更轻量级的方式,使新的documewnt可以被搜索,这意味着移除fsync。位于ES和磁盘间的是文件系统缓存。在内存索引缓存中的document被写入新的segment,但是新的segment首先写入文件系统缓存,这代价很低;之后会被同步到磁盘,这个代价很大。但一旦一个文件被缓存,他也可以被打开和读取,就像其他文件一样。

Lucene允许新segment写入打开,好让他们包括的document可搜索,而不用执行一次全量提交。这是比提交更轻量的过程,可以经常操作,而不会影响性能。

Refresh API

在ES中,这种写入打开一个新segment的轻量级过程,叫做refresh。默认情况下,每个分片每秒自动刷新一次。这就是为什么说ES是近实时的搜索了:document的改动不会立即被搜索,但会在1秒内可见。

可以手动执行refresh来刷新所有的索引,如:

POST /_refresh

也可以只刷新索引blogs:

POST /blogs/_refresh

虽然刷新比提交更轻量,但他依然有消耗。人工刷新在测试写的时候有用,但不要在生产环境中每写一次就执行刷新,会影响性能。

通常我们想要的是优化索引的速度,而不是要做实时搜索,这时可以通过修改配置项refresh_interval减少刷新的频率:

PUT /my_logs {
	"settings":{"refresh_interval":"30s"
}

refresh_interval可以在存在的索引上动态更新。你在创建刷新,大索引的时候,可以关闭自动;在要使用索引的时候再打开他。如:

PUT /my_logs/_settings {
	"refresh_interval":-1
}
PUT /my_logs/_settings {
	"refresh_interval":"1s"
}

持久化变更

为了ES的可靠性,需要确保变更持久化到磁盘。ES增加了事务日志(translog),来记录每次操作。有了事务日志,过程如下:
1、当一个document被索引,他被加入到内存缓存,同时加到事务日志
2、refresh使得缓存被清除,但事务日志没有,会执行:
1)内存缓冲区的写入到segment中,但没有fsync
2)segment被打开,使得新的document可以搜索
3)缓存被清除。
3、随着更多的文档加入到缓存区,写入日志,这个过程会继续
4、当日志很大了,新的日志会被创建,会进行一次全提交:
1)内存缓存区的所有document都会写入到新segment中
2)清除缓存
3)一个提交点写入硬盘
4)文件系统缓存通过fsync操作flush到磁盘
5)事务日志被清除。
5、事务日志记录了没有flush到硬盘的所有操作。当故障重启后,ES会用最近一次提交点从硬盘恢复所有已知的segment,并且从日志里恢复所有的操作。
6、事务日志还用来提供实时的CRUD操作。当你尝试用ID进行CRUD时,它在检索相关segment内的document前会首先检查日志的最新改动,这意味着ES可以实时地获取document的最新版本。

合并Segment

通过每秒自动刷新创建新的segment,用不了多久segment的数量就爆炸了。有太多的segment是一个问题,每个segment消费文件句柄,内存,CPU资源。更重要的是,每次搜索请求都需要一次检查每个segment,segment越多,查询越慢。

ES通过后台合并segment解决这个问题,小segment被合并成大segment,再合并成更大的segment。然后删除旧的document。这个过程你不必做什么。当你在索引和搜索时,ES会自动处理。索引过程中,refresh会创建新的segment , 然后打开它。

合并过程会再后台选择一些小的segment合并成大的segment,这个过程不会中断索引和搜索。

合并后的操作大致如下:
1、新的segment flush到磁盘
2、新的提交点写入新的segment
3、新的segment打开供搜索
4、旧的segment被删除
合并大的segment会很消耗IO和CPU,如果不检查会影响到搜索性能。默认情况下,ES会限制合并过程,这样搜索就可以有足够的资源进行。

Flush API

在ES中,进行一次提交并删除旧事物日志的操作叫做flush。分片每30分钟,或事物日志过大会进行一次flush操作。flush API可用来进行一次手动flush。
flush索引blogs:

POST /blogs/_flush

flush所有索引,等操作结束再返回:

POST /_flush?wait_for_ongoing

当然,很少需要手动flush,通常自动的就够了。当你要重启或关闭一个索引,flush该索引就是很有用的。当ES尝试恢复或重新打开一个索引时,他必须重放所有的事务日志中的操作,所以日志越小,恢复速度越快。

七、分析器

7.1、分析器概述

索引的分析模块,主要实现分析器的注册、设置文档在索引阶段和搜索阶段使用的分析器,其功能映射到Lucene的Analyzer。

分析器的基本构成:
1、字符过滤器(0到多个)
字符串经过字符过滤器(character filter),在标记前处理字符串。字符过滤器能够去除HTML标记,或者转换 & 为 and

2、分词器(只有一个)
分词器(tokenizer)把数据标记化成独立的词。一个简单的分词器(tokenizer)可以根据空格或逗号将单词分开(这个在中文中不适用)

3、标记过滤(0到多个)
每个词都通过所有标记过滤(token filters), 他可以修改词(如将"Quick“转为小写),去掉词(如停用词像"a", “and”, “the"等),或者增加词(如同义词像"jump” 和 "leap”)

Analyzer由一个单一的Tokenizer和零到多个TokenFilter组成,tokenizer可以被0到对哦个CharFilter处理。Analysis模块允许你注册多个Analyzer的逻辑名字,这样在Mapping或其他API中就可以使用这些名字了。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
elasticsearch 学习笔记包括以下内容: 一、Elasticsearch概述: - Elasticsearch是一种开源的分布式搜索和分析引擎,可以用于快速搜索、分析和存储大量的结构化和非结构化数据。 - Elasticsearch与Solr相比有一些区别,包括用户、开发和贡献者社区的规模和成熟度等方面。 二、Elasticsearch安装: 1. 下载Elasticsearch,可以从官方网站或华为云镜像下载。 2. 安装Elasticsearch。 三、安装head插件: - head插件是一个可视化的管理界面,可以方便地管理和监控Elasticsearch集群。 四、安装Kibana: 1. Kibana是一个开源的数据可视化工具,用于展示和分析Elasticsearch中的数据。 2. 下载Kibana并安装。 3. 启动Kibana并进行访问测试。 4. 可选的汉化操作。 五、ES核心概念理解: - 学习ES的核心概念,包括索引、文档、映射、查询等。 以上是elasticsearch学习笔记的主要内容,希望对你有帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Elasticsearch 学习笔记(上)](https://blog.csdn.net/m0_52691962/article/details/127064350)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值