Skip to content
ES
核心概念

核心概念

Elasticsearch 是一款基于 Apache Lucene 构建的实时分布式搜索与分析引擎。理解 Lucene 的基本原理和 ES 的核心概念是高效使用 ES 的前提。


架构全景

img


Lucene 基础

ES 的底层是 Lucene,了解 Lucene 有助于理解 ES 的行为。

倒排索引(Inverted Index)

倒排索引是搜索引擎的核心数据结构。它将文档 → 词条的正向关系反转为词条 → 文档的映射。

文档1: "Elasticsearch is fast"
文档2: "Elasticsearch is powerful"

倒排索引:
"elasticsearch" → [文档1, 文档2]
"is"           → [文档1, 文档2]
"fast"         → [文档1]
"powerful"     → [文档2]

🔬 深入原理:倒排索引不仅记录了词条出现在哪些文档中,还记录了位置(position)和偏移量(offset),这正是短语匹配(match_phrase)和高亮功能的基础。

段(Segment)

  • Lucene 将索引数据写入不可变的段(Segment)
  • 新文档写入新段,已存在的段不会修改
  • 文档更新 = 标记旧文档删除 + 写入新段
  • 段的数量过多会影响搜索性能,Lucene 后台自动合并(Merge)

🔬 深入原理:这种"不可变段"设计带来两个核心优势:(1)写操作不需要加锁,天然支持高并发写入;(2)段可以在多个查询间共享文件系统缓存。代价是删除/更新操作不会立即释放磁盘空间——需要通过段合并进行物理清理。

关键写入流程

文档写入 → 内存 Buffer(不可搜索)
         → refresh(每 1s)→ 生成新 Segment → 可搜索
         → translog 持久化 → 防止宕机丢失
         → flush → 提交到磁盘
操作 触发条件 效果
refresh 每 1s 自动 文档变为可搜索
flush 每 30min 或 translog 满 文档持久化到磁盘
merge 后台自动 合并小段,释放磁盘空间

💡 最佳实践:大批量写入时,可临时调高 refresh_interval(如 -1 关闭),写完再恢复,减少段碎片。


核心名词

Near Realtime(NRT)— 近实时

数据写入后,经过 refresh 即可被搜索(默认 1s 延迟)。ES 不是即时性的 OLTP 数据库,但在搜索场景下这一延迟通常可接受。

Cluster — 集群

  • 由一个唯一的集群名称标识,默认 "elasticsearch"
  • 相同集群名的节点自动组网(通过 discovery.seed_hosts 发现)
  • 集群名在 elasticsearch.yml 中配置

Node — 节点

  • 集群中的一台服务器实例,存储数据和/或参与查询
  • 默认启动时以随机 UUID 前 7 位作为节点名,可通过 node.name 自定义
  • 通过集群名称在网络中自动发现同伴并组成集群

Index — 索引

  • 一个逻辑命名空间,包含一组具有相同结构的文档
  • 类比关系数据库的 Database(ES 6.x 之前:Index ≈ Database + Table)
  • 一个集群可以有任意多个索引
  • 索引命名:小写字母 + 连字符,如 order-logs-2025

Type — 类型(已废弃)

  • ES 6.0 起 Deprecated,ES 7.0 起完全移除
  • 一个索引只能存一类数据的 Mapping
  • 如果你的旧项目使用了 _type,迁移方案:每种类型拆成独立索引

Document — 文档

  • ES 中的最小数据单元,以 JSON 格式表示
  • 每个文档有唯一的 _id(手动指定或自动生成)
  • 写入后会被序列化为 JSON 存入 _source 字段

Shard — 分片

  • 索引在创建时可以指定切分为多个分片
  • 每个分片本身是一个独立完整的 Lucene 索引
  • 分片可以分布在集群的任意节点上

两种分片:

类型 说明 数量
Primary Shard(主分片) 数据的第一存放位置 创建索引时指定,不可修改
Replica Shard(副本分片) 主分片的复制品 可动态修改

Replica — 副本

作用 说明
高可用 主分片宕机时,副本可以提升为主分片
提升读吞吐 副本可以提供读服务,分担查询负载
不提升写吞吐 写入必须先写主分片,再同步到副本

💡 最佳实践:ES 自动确保主分片和其副本不会分配到同一节点。生产环境至少设置 number_of_replicas: 1

数据库类比

ES 关系数据库
Index Database
Type(废弃) Table
Document Row
Mapping Schema(DDL)
Field Column
Shard 水平分表
Replica 读副本 / Standby

Mapping 映射

Mapping 定义索引中文档的字段结构和行为。ES 支持两种 Mapping 方式:

方式 说明 适用场景
Dynamic Mapping 自动推断字段类型 快速上手、日志类数据
Explicit Mapping 手动定义每个字段 生产环境、需要精确控制分词和索引行为

🚨 陷阱:Dynamic Mapping 会"猜"字段类型,新字段第一次写入的类型锁定后续所有文档。例如第一次写入 "count": 100,类型锁定为 long;后再写入 "count": "N/A" 会报错。

字段数据类型(完整版)

大类 具体类型 说明
字符串 text 全文搜索,会被分词
keyword 精确匹配,不参与分词(用于排序/聚合/过滤)
wildcard 适合模糊匹配的 keyword(ES 7.9+)
数值 long / integer / short / byte 有符号整数
double / float / half_float 浮点数
unsigned_long 无符号长整型
日期 date 支持多种格式(时间戳/ISO8601/自定义)
date_nanos 纳秒精度日期
布尔 boolean true / false
对象/关系 object 嵌套 JSON 对象(会被扁平化)
nested 独立索引的嵌套对象,保持关联性
join 父子关系(同一索引内的 join)
范围 integer_range / date_range / ip_range 范围查询专用
IP ip IPv4 / IPv6 地址
二进制 binary Base64 编码的二进制数据
地理位置 geo_point 经纬度坐标
geo_shape 多边形、线段等复杂地理形状
专用 completion 搜索自动补全(Completion Suggester)
dense_vector 向量存储(用于 kNN 搜索)
rank_feature 用于影响评分但不参与过滤的数字特征

常用 Mapping 参数

参数 说明 默认值
type 字段数据类型
index 是否建立倒排索引(是否可搜索) true
enabled 是否解析该对象字段(false 则整段 JSON 不索引) true
doc_values 是否启用列存储(用于排序/聚合) true(text 除外)
store 是否独立存储(不依赖 _source false
analyzer 索引时分词器 standard
search_analyzer 搜索时分词器 analyzer
ignore_above 超过此长度的字符串不索引 256(keyword)
format 日期格式(date 类型)
null_value 字段为 null 时的替代值
copy_to 将值复制到目标字段(用于多字段搜索)

Multi-Field(多字段映射)

一个字段同时拥有多种索引方式,常见模式:text(全文搜索)+ keyword(精确匹配/排序/聚合)。

{
    "mappings": {
        "properties": {
            "title": {
                "type": "text",
                "analyzer": "ik_max_word",
                "fields": {
                    "keyword": {
                        "type": "keyword",
                        "ignore_above": 256
                    }
                }
            }
        }
    }
}

使用:

  • 全文搜索:title"match": { "title": "搜索引擎" }
  • 精确匹配/聚合:title.keyword"term": { "title.keyword": "搜索引擎" }

💡 最佳实践:几乎所有 text 字段都应该配一个 .keyword 子字段,用于排序、聚合和精确过滤。

数组字段

ES 没有数组类型。字段声明为 long,写入 [1, 2, 3] 时,ES 会自动将其索引为多个值。

// Mapping
{ "tags": { "type": "keyword" } }

// 写入(两种写法等价)
{ "tags": "es" }
{ "tags": ["es", "search", "database"] }

🚨 陷阱:数组中的各元素类型必须一致。[1, "two"] 会报错(第一个元素 1 将字段类型锁定为 long)。

Dynamic Mapping 规则

当未定义 Mapping 时,ES 根据 JSON 值自动推断类型:

JSON 类型 ES 类型
null 不添加字段
true / false boolean
123 long
123.45 float
"2024-01-01" date(可配置格式)
"foo" text + keyword 子字段
{} object

Dynamic Template(动态模板)

按字段名模式自动匹配 Mapping 规则:

{
    "mappings": {
        "dynamic_templates": [
            {
                "strings_as_keywords": {
                    "match_mapping_type": "string",
                    "mapping": { "type": "keyword" }
                }
            }
        ]
    }
}

_source 字段

_source 存储文档的原始 JSON

操作 是否依赖 _source
搜索返回结果
高亮显示 ❌(单独存储位置信息)
Reindex
_update ✅(读取旧值 + 合并新值)
聚合 ❌(使用 doc_values)

💡 最佳实践:生产环境保留 _source(默认开启)。关闭可节省磁盘空间,但会失去 Reindex、_update 和 debug 能力。如需节省存储,建议使用 _source 过滤而非完全关闭。


常见陷阱

陷阱 说明
🚨 Type 已废弃 ES 6.0 起一个索引只能存一类数据;7.0 起完全移除 _type
🚨 Dynamic Mapping 猜错类型 第一个值决定字段类型,后续类型不一致会报错
🚨 index: false 不可搜索 设为 false 后字段不参与搜索,但 _source 中仍然可见
🚨 enabled: false 整对象不可搜 index: false 不同,整个嵌套 JSON 变成不索引的 blob
🚨 doc_values: false 不可排序/聚合 text 类型默认关闭 doc_values,需排序时使用 .keyword 子字段
🚨 数组元素类型不一致 [1, "two"] 报错,所有元素必须同类型
🚨 _source 关闭后无法 Reindex 没有 _source 无法索引重建