1. 索引的定义
索引是具有相同结构的文档的集合,类似于关系型数据库中的表,由唯一索引名称标定,索引名不能用大写字母。
# 创建索引
PUT index_001
{
"settings": {
"number_of_shards": 2, # 两个主分片
"number_if_repicas": 1 # 一个副本分片
},
"mappings": { # 映射
"properties": {
"column1":{ # 字段1
"type": "text",
"analyzer": "ik_smart"
},
"column2":{
"type": "keyword", # keyword类型用于聚合、排序和精准匹配
"index": "false"
},
"column3":{
"properties": {
"子字段1": {
"type": "keyword"
},
"子字段2": {
"type": "keyword"
}
}
}
}
}
}
2. 索引设置
- 静态设置: 只允许在创建索引时或者针对已关闭的索引进行设置。
- 动态设置: 可以借助更新设置的方式进行动态更新,更新后立即生效。
设置主分片大小的参数index.number_of_shards不支持动态修改。默认主分片大小为1,每个索引的分片数量上限默认为1024。此限制是一个安全限制,可防止索引分片数过多导致集群不稳定。
在业务层面扩充节点后确实需要扩展主分片数,该怎么办?在非业务核心时间通过reindex操作迁移实现。
动态设置的实战场景举例如下。
PUT index_001/_settings
{
"number_of_replicas": 3, # 设置副本数参数为index.number_of_replicas
"refresh_interval": "1s" # 设置刷新频率参数
"max_result_window": 50000 # 搜索结果的最大窗口大小,如果每页显示50条数据,则最多可以翻到1000页
}
默认刷新频率参数值为1s,即每秒刷新一次。这1s决定了es是近实时的搜索引擎,而非准实时搜索引擎。如果业务对实时性的要求不高,可以考虑将该值调大。因为如果采用1s,则每秒都会生成一个新的分段,会影响写入性能。
增大窗口大小可能对es集群的性能产生影响。需要权衡性能和查询范围间的关系。
3. 索引映射和别名
可以将索引映射理解成MySQL中的表结构Schema,包括如下主要内容。
- 字段名称。
- 字段类型。
- 分词器选择。
- 其他精准设置,如coerce、fielddata、doc_values等。
索引别名的作用类似于快捷方式
- 一个索引可以创建多个别名。
- 一个别名也可以指向多个索引
4. 索引操作
新增索引
#方式一:详细定义索引设置、映射、别名。
#方式二:只定义索引名,而settings、mappings取默认值
PUT myindex
删除索引
#方式一:删除索引。
DELETE myindex
#方式二:清空数据,保留索引
POST myindex/delete_by_query
{
"query":{
"match_all":{}
}
}
- 使用DELETE可以从索引层面删除索引及数据,为物理删除,效率更高、更快,能立马释放磁盘空间。
- 用delete_by_query命令是通过查询来删除数据,为逻辑删除,不会立即释放磁盘空间,而是形成新的数据分段,待段合并时才能被物理删除。
查询索引
# 获取索引的基础信息。
GET myindex
# 若加上_search,则获取的是在该索引下的数据的信息
GET myindex/_search
修改索引
#如果创建索引时没有指定别名,那么可以通过如下方式添加别名。
POST /_aliases
{
"actions": [
{
"add": {
"index": "myindex", #索引名
"alias":"myIndex_alias" # 别名
}
}
]
}
索引别名
在很多业务场景下,单一索引可能无法满足要求:
- 面对PB级别的增量数据,对外提供服务的是基于日期切分的n个不同索引,每次检索都要指定数十个甚至数百个索引,非常麻烦。
- 线上提供服务的某个索引设计不合理,比如某字段分词定义不准确,那么如何保证对外提供服务不停止,也就是在不更改业务代码的前提下更换索引?
这两个问题都可以借助索引别名来解决。使用别名会很方便、灵活、快捷,且使业务代码松耦合。
# 创建索引时起别名
PUT myindex
{
"aliases": {
"myindex_alias": {}
}
}
多索引检索
POST index_0921,index_0922/_search # 用逗号分隔索引名
POST index_*/_search # 用通配符
使用别名能透明的更换别名使用的索引
PUT index1
PUT index2
POST /_aliases
{
"actions":[
{
"add":{
"index":"index1",
"alias":"index_alias"
}
},
{
"add":{
"index":"index2",
"alias":"index_alias"
}
},
]
}
# 使用别名进行检索,自动把搜索操作应用到两个索引上
POST index_alais/_search
别名常见问题
# 批量插入可以使用别名吗
POST myindex/_bulk
{
"index":{},
{"title": "001"}
}
# 如果非要指定别名来插入数据,则需要提前设置is_write_index。
POST /_aliases
{
"actions":[
{
"add":{
"index":"myindex",
"alias":"myindex_alias",
"is_write_index":true
}
}
]
}
# 如何通过索引别名查找实际索引名称。
GET _cat/aliases?v
对相同索引别名的物理索引建议有一致的映射,以提升检索效率。
充分发挥别名在检索方面的优势,但在写入和更新时还得使用物理索引。
5. 索引模版
问题1:数据量非常大,需要按日期划分索引,且要求多个索引的Mapping一致,每次手动创建或者脚本创建都很麻烦,怎么办?
问题2:业务中应用了多个索引,想让这些索引中相同名字的字段类型完全一致,以便实现跨索引检索,怎么办?
传统方式不能解决多索引的快速定义和高效管理等问题。因此,索引模板应运而生。
模版定义
- 普通模版
PUT _index_template/template_1 # 生成一个叫template_1的模版
{
"index_patterns": [ # 要匹配的索引集合,te开头的和bar开头的
"te*",
"bar*"
],
"template": {
"aliases": {
"alias1": {}
},
"settings": {
"number_of_shards": 1
},
"mappings": {
"_source": {
"enabled": false
},
"properties": {
"host_name": {
"type": "keyword"
}
}
}
}
}
- 组件模版:将原有普通模板定义的mappings、settings等以组件的方式分隔,以便最小化更新模板。
PUT _component_template/my_mapping_template
{
"template":{
"mappings":{
"properties":{
"host_name":{
"type":"keyword"
}
}
}
}
}
PUT _component_template/my_settings_template
{
"settings":{
"number_of_shards":3
},
"aliases":{
"mydata":{}
}
}
PUT _index_template/mydata_template
{
"index_patterns":[
"mydata*"
],
"priority":500,
"composed_of":[
"my_mapping_template",
"my_settings_template"
],
"version":1,
"_meta":{
"description":"my custom template"
}
}
由上可知,模板名称为mydata_template,包含两个核心组件——my_mapping_template、my_settings_template。
当业务层面需要更新映射时,只需要更新my_mapping_template组件模板即可,改动范围更小、操作更精细化
索引模版基础操作
# 新增模版
PUT _index_template/my_template
# 删除模版
DELETE _index_template/my_template
# 查询模版
GET _index_template/my_template
# 修改模版
按创建模版的方式去修改模版,生成具有相同名称的新模版,覆盖原模版。新模版只对新创建的索引生效。
动态模版
需求: 1.如果默认不显示指定映射,则数值类型的值会被映射为long,但实际业务数值都比较小,会存储浪费,将默认值改成integer。 2.date_*开头的字符将统一匹配为date日期类型。
PUT _index_template/sample_dynamic_template
{
"index_patterns":[
"sample*" # sample开头的索引都要匹配该模版
],
"template":{
"mappings":{
"dynamic_templates":[
{
"hadle_integers":{ # 动态模版名,可自定义
"match_mapping_type":"long",
"mapping":{
"type":"integer"
}
}
},
{
"handle_date":{
"match": "date_*",
"mapping":{
"type":"date"
}
}
}
]
}
}
}
# 看看效果
PUT sampleindex/_doc/1
{
"ivalue":123,
"date_currenttime":"1574494620000"
}
GET sampleindex/_mapping
如果想更新映射,那么可以通过更新模板来实现吗?
一旦创建了映射,除几个特定的类型以外,其他类型都不支持更新,除非进行reindex操作。
所以创建索引后,对索引模板的更新将不会影响该索引,更新模板仅适用于新创建的索引。更新为动态模板仅会影响索引中的新字段。索引模板是一个很高效的工具,可全局设置多个索引且批量生效,避免不必要的重复工作。
映射和别名的优势如下。
- 映射有助于保持数据库结构的一致性,并提供了丰富的es数据类型以及更复杂的自定义类型。
- 别名对于在无须中断服务的情况下尽可能完成索引切换起到重要作用。
因此,当新系统准备选择es存储核心数据时,需要优先注意数据建模,并且在数据建模的过程中要综合考虑模板、别名、映射、设置的优势,才能保证模型的健壮性。