ES笔记四:索引操作
一. index
1. 命名规则
_index | 命名必须小写,不能以下划线开头,不能包含逗号、 |
_type | 命名可以是大写或者小写,但是不能以下划线或者句号开头,不应该包含逗号, 并且长度限制为256个字符、 |
_id | 唯一确定的文档,要么提供自己的_id ,要么es会自动生成 |
2. 创建索引
如果你想禁止自动创建索引,在elasticsearch.yml配置action.auto_create_index: false,
number_of_shards | 分片数 |
number_of_replicas | 副本数 |
refresh_interval | 控制准实时的重要参数 |
index.write.wait_for_active_shards | 更改仅等待主分片通过索引设置 |
index.blocks.read_only | 设为true,则索引以及索引的元数据只可读 |
index.blocks.read_only_allow_delete | 设为true,只读时允许删除。 |
index.blocks.read | 设为true,则不可读。 |
index.blocks.write | 设为true,则不可写。 |
index.blocks.metadata | 设为true,则索引元数据不可读写。 |
创建index时设置
PUT /blogs
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 2
}
}修改index配置
PUT /blogs/_settings
{
"index" : {
"number_of_replicas" : 1
}
}
3. 查看索引
GET /blogs/_settings
GET /twitter,kimchy/_settings
GET /_all/_settings
GET /log_2013_*/_settings
GET /log_2013_-*/_settings/index.number_*
在上一章集群篇讲过,也可以通过监控,http://localhost:9200/_cat/indices?v
4. Exists
HEAD /blogs
HTTP status code 表示结果 404 不存在 , 200 存在
5. 删除索引
DELETE /my_index //删除单个
DELETE /index_one,index_two //删除多个
DELETE /index_* //同上
DELETE /_all //删除全部
DELETE /* //同上
如果想禁用这个命令,在elasticsearch.yml配置action.destructive_requires_name: true
6. 索引别名
索引别名就像一个快捷方式或软连接,可以指向一个或多个索引,也可以给任何一个需要索引名的API来使用。_alias用于单个操作,_aliases用于执行多个原子级操作,有了它你的应用已经在零停机的情况下从旧索引迁移到新索引了
- 在运行的集群中可以无缝的从一个索引切换到另一个索引
- 给多个索引分组
- 给索引的一个子集创建视图
PUT /my_index_v1 //创建索引my_index_v1
PUT /my_index_v1/_alias/my_index //设置别名my_index指向my_index_v1
GET /*/_alias/my_index //检测这个别名指向哪一个索引
GET /my_index_v1/_alias/ //哪些别名指向这个索引
POST /_aliases
{ "actions": [
{ "remove": { "index": "my_index_v1", "alias": "my_index" }},
{ "add": { "index": "my_index_v2", "alias": "my_index" }}
]
}
7. 数据迁移Reindex
尽管可以增加新的类型到索引中,或者增加新的字段到类型中,但是不能添加新的分析器或者对现有的字段做改动。如果你那么做的话,结果就是那些已经被索引的数据就不正确,搜索也不能正常工作。对现有数据的这类改变最简单的办法就是重新索引:用新的设置创建新的索引并把文档从旧的索引复制到新的索引。字段_source的一个优点是在Elasticsearch中已经有整个文档。你不必从源数据中重建索引,而且那样通常比较慢。为了有效的重新索引所有在旧的索引中的文档,用scroll从旧的索引检索批量文档,然后用bulk API把文档推送到新的索引中。从Elasticsearch v2.3.0开始, Reindex API被引入。它能够对文档重建索引而不需要任何插件或外部工具。
POST _reindex
{
"source" : {
"index" : "twitter"
},
"dest" : {
"index" : "new_twitter",
"version_type" : "external"
}
}
它有很多可以提高性能的参数和手段:batch_size、提高并发(slices大小=分片数)、减少复制带来重新索引的开销(副本数设置为0)、大量数据导入不要急于索引刷新(refresh_interval为-1来禁用刷新,完成后不要忘记重新启用它)
8. 打开关闭索引
开放和关闭索引API允许关闭索引,然后打开它。关闭索引几乎没有集群上的开销,并被阻止进行读/写操作。可以使用ignore_unavailable = true参数禁用此行为。
POST /my_index/_close
POST /my_index/_open
9. 收缩索引
收缩索引API允许您将现有索引缩小为具有较少主分片的新索引。目标索引中请求的主分片数必须是源索引中分片数的一个因子。例如,具有8个主分片的索引可以缩小为4个,2个或1个主分片,或者具有15个主分片的索引可以缩小为5个,3个或1个。
POST my_source_index/_shrink/my_target_index
{
"settings": {
"index.number_of_replicas": 1,
"index.number_of_shards": 1,
"index.codec": "best_compression"
},
"aliases": {
"my_search_indices": {}
}
}
10. 拆分索引
拆分索引API允许您将现有索引拆分为新索引,其中每个原始主分片在新索引中拆分为两个或更多主分片。_split API要求使用特定的number_of_routing_shards创建源索引,以便将来拆分。此要求已在Elasticsearch 7.0中删除。可以拆分索引的次数(以及每个原始分片可以拆分成的分片数)由index.number_of_routing_shards设置决定。路由分片的数量指定内部使用的散列空间,以便在具有一致散列的分片中分发文档。例如,将number_of_routing_shards设置为30(5 x 2 x 3)的5个分片索引可以按因子2或3分割。换句话说,它可以按如下方式拆分:
- 5 → 10 → 30 (split by 2, then by 3)
- 5 → 15 → 30 (split by 3, then by 2)
- 5 → 30 (split by 6)
POST my_source_index/_split/my_target_index
{
"settings": {
"index.number_of_shards": 2
}
}
11. Rollover Index
当现有索引被认为太大或太旧时,翻转索引API对于有时效性的索引数据,如日志,过一定时间后,老的索引数据就没有用了。我们可以像数据库中根据时间创建表来存放不同时段的数据一样,在ES中也可用建多个索引的方式来分开存放不同时段的数据。比数据库中更方便的是ES中可以通过别名滚动指向最新的索引的方式,让你通过别名来操作时总是操作的最新的索引。ES的rollover index API 让我们可以根据满足指定的条件(时间、文档数量、索引大小)创建新的索引,并把别名滚动指向新的索引。
12. Index templates
索引模板允许您定义在创建新索引时自动应用的模板。为每个索引写定义信息可能是一件繁琐的事情,ES提供了索引模板功能,让你可以定义一个索引模板,模板中定义好settings、mapping、以及一个模式定义来匹配创建的索引。
13. 索引状态管理
13.1 Clear Cache
Clear Cache,默认会清理所有缓存,可指定清理query, fielddata or request 缓存。
POST /_cache/clear
POST /kimchy,elasticsearch/_cache/clear
13.2 refresh
POST /kimchy,elasticsearch/_refresh
POST /_refresh
13.3 flush
Flush,将缓存在内存中的索引数据刷新到持久存储中。
问题:如果没有用fsync把数据从文件系统缓存刷(flush)到硬盘,我们不能保证数据在断电甚至是程序正常退出之后依然存在?
每秒刷新(refresh)实现了近实时搜索,es还引入了事务日志(简称translog),来解决两次提交之间发生变化的文档的丢失。translog提供所有还没有被刷到磁盘的操作的一个持久化纪录。它的用途主要有两种:
- 当ES启动的时候它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重放translog中所有在最后一次提交后发生的变更操作
- 也被用来提供实时CRUD 。当你试着通过ID查询、更新、删除一个文档,它会在尝试从相应的段中检索之前,首先检查translog任何最近的变更。这意味着它总是能够实时地获取到文档的最新版本。
它的工作流程:
- 一个文档被索引之后,就会被添加到内存缓冲区,并且追加到了translog
- 刷新(refresh)完成后, 缓存被清空但是事务日志不会,此时已经被写一个新的段中,但没有进行fsync操作
- 这个进程继续工作,更多的文档被添加到内存缓冲区和追加到事务日志
- 每隔一段时间(flush操作的频率是通过translog的大小控制的,当translog大小达到一定值的时候就执行一次flush,对应参数为index.translog.flush_threshold_size,默认值是512mb),例如translog 变得越来越大,索引被flush(文件系统缓存通过fsync被刷新),在刷新flush之后,段被全量提交,并且老的translog被删除
问题:Translog有多安全?
translog本身是文件,也需要存储到磁盘,它的存储方式通过index.translog.durability和index.translog.sync_interval(默认5秒)设定。
index.translog.durability
- request,意为每次请求都会把translog写到磁盘。这种设定可以降低数据丢失的风险,但是磁盘IO开销会较大,默认值。
- async,采用异步方式持久化translog,会采用index.translog.sync_interval间隔提交一次
默认模式每次写请求完成之后执行,是可以配置的。因此,重启节点或关闭索引之前执行flush有益于你的索引。
索引的 flush 过程通过将数据刷新到索引存储并清除内部trans log,基本上从索引中释放内存。默认情况下,ElasticSearch使用内存启发,以便根据需要自动触发刷新操作,以清除内存。
POST /blogs/_flush //手动刷新blogs索引
POST /_flush?wait_for_ongoing //手动刷新所有的索引并且并且等待所有刷新在返回前完成
13.4 Force Merge
Force Merge,强制段合并
问题:段是什么?
再回顾下,每一个段本身都是一个倒排索引。 一个Lucene索引包含一个提交点(一个列出了所有已知段的文件)和三个段(被混淆的概念是:一个Lucene索引我们在ES称作分片,一个ES索引是分片的集合)。
问题:为何要进行段合并呢?
在之前lucene的IndexWriter中讲过,由于自动刷新(refresh)流程每秒会创建一个新的段,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须逐段搜索,所以段越多,搜索也就越慢。
问题:逐段搜索流程又是什么?
当ES在索引中搜索的时候,它发送查询到每一个属于索引的分片(Lucene索引),然后所有已知的段按顺序被查询,词项统计会对所有段的结果进行聚合,以保证每个词和每个文档的关联都被准确计算。
- 新文档被收集到内存索引缓存(包含新文档的Lucene索引)
- 不时地,缓存被提交(可能是flush缓存操作)
- 新的段被开启,让它包含的文档可见以被搜索
- 内存缓存被清空,等待接收新的文档
问题: 段怎么更新或删除呢?
段是不可改变的。当一个文档被删除时,它实际上只是在.del文件中被标记删除,一个被标记删除的文档仍然可以被查询匹配到,但会在最终结果集被返回前从中移除。当一个文档被更新时,旧版本文档被标记删除,文档的新版本被索引到一个新的段中,可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就已经被移除。
问题: 怎样合并?
ES通过在后台进行段合并(参阅Lucene的MergePolicy)来解决这个问题(小的段被合并到大的段,然后这些大的段再被合并到更大的段),它并不需要你做任何事,自动完成的。 段合并的时候会将那些旧的已删除文档从文件系统中清除。被删除的文档(或被更新文档的旧版本)不会被拷贝到新的大段中。
问题: 合并要注意什么?
合并大的段需要消耗大量的I/O和CPU资源,如果任其发展会影响搜索性能。ES在默认情况下会对合并流程进行资源限制,所以搜索仍然有足够的资源很好地执行。
二. type
类型由名称和映射(像数据库中的 schema,描述了文档可能具有的字段或属性、每个字段的数据类型)组成。
文档是怎样存取的?
在Lucene中,一个文档由一组简单的键值对组成。Lucene不关心这些值是字符串、数字或日期--所有的值都被当做不透明字节。当我们在Lucene中索引一个文档时,每个字段的值都被添加到相关字段的倒排索引中。你也可以将未处理的原始数据存储起来,以便这些原始数据在之后也可以被检索到。
类型如何被实现的?
ES类型是以 Lucene处理文档的这个方式为基础来实现的,但Lucene没有文档类型的概念,每个文档的类型名被存储在一个叫_type的元数据字段上。当我们要检索某个类型的文档时, ES通过在_type字段上使用过滤器限制只返回这个类型的文档。
映射如何被实现的?
Lucene也没有映射的概念。映射是ES将复杂JSON文档映射成Lucene需要的扁平化数据的方式。
1. Indices Stats
Indices Stats,索引状态提供有关索引上发生的不同操作的统计信息。API提供有关索引级别范围的统计信息(尽管也可以使用节点级别范围检索大多数统计信息),通过GET /_stats
2. Indices Segments
Indices Segments,提供构建Lucene索引(分片级别)的低级别段信息。允许用于提供有关分片和索引状态的更多信息,可能是优化信息,删除时“wasted”的数据,等等,通过GET /test/_segments
3. Indices Recovery
Indices Recovery,索引恢复API提供对正在进行的索引碎片恢复的深入了解。可以针对特定索引或群集范围报告恢复状态。例如,以下命令将显示索引“index1”和“index2”的恢复信息:
GET index1,index2/_recovery?human
4. Indices Shard Stores
Indices Shard Stores,提供索引的分片副本的存储信息。存储有关哪些节点分片副本存在的信息报告,分片副本分配ID,每个分片副本的唯一标识符以及打开分片索引时遇到的任何异常或早期引擎故障。
通过GET /test/_shard_stores