es-索引详解

发布于:2025-03-10 ⋅ 阅读:(14) ⋅ 点赞:(0)

在 Elasticsearch 中,**索引(Index)**是核心概念之一,类似于关系型数据库中的“表”。索引用于存储、组织和检索文档(Document)。以下是关于 Elasticsearch 索引的详细解析:


1. 索引的基本概念

  • 索引:一个索引是一个逻辑命名空间,用于存储具有相似结构的文档。例如,可以创建一个名为 products 的索引来存储所有产品信息。
  • 文档:文档是索引中的基本数据单元,以 JSON 格式存储。例如,一个产品文档可能包含 namepricedescription 等字段。
  • 类型(Type):在 Elasticsearch 6.x 及之前版本中,索引可以包含多个类型(类似于表)。但从 7.x 开始,类型已被弃用,每个索引只能包含一种类型(默认是 _doc)。
  • 分片(Shard):索引被划分为多个分片,分片是数据的物理存储单元。分片可以分布在不同的节点上,从而实现分布式存储和并行处理。
  • 副本(Replica):每个分片可以有多个副本,用于提高数据的可用性和容错性。

2. 索引的创建

es 支持动态映射(自动推断字段类型)和显式映射(手动定义字段类型)。

显式创建

PUT /products   
{
   "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 2
   },
   "mappings": {
    "properties": {
      "name": { "type": "text" },
      "price": { "type": "float" },
      "description": { "type": "text", "analyzer": "english" },
      "extra": {
        "type": "text",
        "index": false
      },
      "number" : {
        "type" : "keyword",
        "null_value": "NULL"
      }
    }
   }   
}
  • 该索引名为 products,包含 3 个分片和 2 个副本。
  • 定义了5个字段:name(文本类型)、price(浮点类型)、description(文本类型,使用英文分词器)、extra(文本类型,不创建倒排索引)、number(keyword类型,通过NULL可筛选出没有手机号的文档)

筛选出number为空的文档

GET products/_search
{
  "query": {
    "match": {
      "number":"NULL"
    }
  }
}

动态创建(不建议)

POST /products/_doc/1   
{
   "name": "Laptop",
   "price": 999.99,
   "description": "A powerful laptop for professionals."
}
  • Elasticsearch 会自动推断字段类型:name 和 description 为文本类型,price 为浮点类型。

动态创建的类型,与实际需要的类型可能不一致,不建议使用


3. 索引维护

查看索引

GET /products

删除索引

DELETE /products

4.索引的性能优化

  • 合理设置分片数量:分片数量过多会增加集群负担,过少会影响查询性能。
  • 使用副本提高可用性:副本可以提高数据的可用性和查询性能。
  • 优化映射:避免使用不必要的字段类型(如 keyword 用于大文本)。
  • 定期清理旧数据:使用索引生命周期管理(ILM)自动删除或归档旧数据

避免排序

将term、match转换成filter

使用score计算分数

GET /my_index/_search   
{
   "query": {
    "bool": {
      "must": [
        { "term": { "status": "active" } },
        { "match": { "description": "powerful laptop" } }
      ]
    }
   }   
}

转换成不需要score计算分数

GET /my_index/_search   
{
   "query": {
    "bool": {
      "filter": [
        { "term": { "status": "active" } },
        { "match": { "description": "powerful laptop" } }
      ]
      }
      }      
}      

优化排序与聚合

eager_global_ordinals 可以加速 排序、聚合

原理:global_ordinals全局序数是一种将字段值映射为连续整数的机制。例如,字段值 ["apple", "banana", "cherry"] 可能被映射为 [0, 1, 2]

默认情况下,全局序数是在查询时动态生成的。这意味着每次执行聚合或排序操作时,Elasticsearch 都需要遍历字段值并生成全局序数。

对于高基数字段(字段值种类多),生成全局序数可能会消耗大量时间和资源。

启用 eager_global_ordinals 时,Elasticsearch 会在索引刷新(Refresh)或段合并(Segment Merge)时预先生成全局序数

适用场景

  • 高基数字段
  • 频繁聚合或排序
  • 实时性要求高

缺点

  • 增加索引开销:在索引刷新或段合并时生成全局序数会增加 CPU 和内存开销。
  • 占用更多内存:全局序数需要存储在内存中,可能会增加内存使用量

启用eager_global_ordinals 

PUT /my_index   
{
   "mappings": {
    "properties": {
      "my_field": {
        "type": "keyword",
        "eager_global_ordinals": true
      }
    }
   }   
}

避免不必要的字段类型

字段不创建索引

PUT /my_index   
{
   "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "metadata": {
        "type": "object",
        "enabled": false
      },
      "description": {
        "type": "text",
        "index": false
      }
    }
   }   
}

name 字段:正常索引,可以用于搜索。

metadata 字段:禁用整个对象的索引功能。

description 字段:禁用索引,无法用于搜索。

禁用索引后的字段特性

无法搜索:禁用索引的字段无法用于查询(如 matchterm 等)。

可以存储:字段的值仍然会存储在 _source 中,可以通过 _source 获取。

可以用于聚合:禁用索引的字段仍然可以用于聚合操作(如 termssum 等),性能会降低。

可以用于脚本:字段的值可以在脚本中使用。

禁用索引的适用场景

日志数据:某些字段(如原始日志)可能不需要搜索,但需要存储。

大文本字段:某些大文本字段(如文章内容)可能不需要搜索,但需要存储。

敏感数据:某些敏感数据(如密码、密钥)不需要索引,但需要存储。

注意事项

无法恢复索引:如果需要重新启用索引,必须重新创建索引或使用 reindex 

存储开销:禁用索引的字段仍然会占用存储空间,因为其值存储在 _source 中。

聚合性能:禁用索引的字段在聚合时可能会影响性能,因为需要从 _source 中提取数据。

不使用fielddata

索引的生命周期管理(ILM)

创建策略

PUT _ilm/policy/my_custom_policy   
{
   "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_size": "50GB",
            "max_age": "30d"
          }
        }
      },
      "delete": {
        "min_age": "90d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

该策略定义了索引的生命周期:在 hot 阶段,当索引大小超过 50GB 或创建时间超过 30 天时,滚动到新索引;在 delete 阶段,当索引创建时间超过 90 天时,删除索引。

(场景:删除3年之前的数据)

 将策略绑定到索引

PUT /my_index   
{
   "settings": {
    "index.lifecycle.name": "my_custom_policy"
  }
}

验证是否生效

GET /my_index/_ilm/explain

其他

添加字段禁止自动创建倒排索引

dynamic的取值类型如下:

取值 是否添加字段到映射 是否存储字段数据 是否抛出异常 适用场景
true 数据结构不固定,需要动态添加字段。
false 数据结构固定,但需要存储未知字段。
strict - - 数据结构严格固定,不允许未知字段。

true: 默认,添加倒排索引、储存字段

false:只会存储字段

strict:不支持自动添加字段,需要手动维护

(建议:如果字段是动态的,需要自动映射,则使用true;否则使用strict。避免出现创建多余的映射现象。。原因:索引不容易修改,建议手动创建映射

 手动添加字段:

PUT /my_index/_mapping   
{
   "properties": {
    "age": { "type": "integer" }
  }
}

 

索引模板