Elasticsearch基础介绍

6 阅读12分钟

一、什么是 Elasticsearch (ES)

Elasticsearch 是一款基于 Lucene 构建的开源、分布式、RESTful 风格的搜索引擎,核心定位是解决“快速查找数据”的问题,尤其擅长非结构化文本检索,比数据库的 LIKE 语句快数十倍。

其核心特点如下:

  • 分布式:自动分片存储数据,支持水平扩展,轻松应对海量数据

  • 实时性:近实时(NRT)索引和搜索,数据写入后秒级可查

  • 全文检索:支持复杂的文本检索、模糊匹配、高亮等功能

  • 易扩展:与 Kibana、Logstash 组成 ELK 栈(现 Elastic Stack),适用于日志分析、监控、全文检索等场景

  • REST API:通过 HTTP 请求即可完成所有操作,支持多种编程语言客户端(Java/Python/Go 等)

二、ES 安装步骤(Linux 环境)

2.1 前置条件

  • 安装 JDK 11+(ES 7.x+ 推荐 JDK 11,8.x+ 支持 JDK 17)

  • 禁用系统 Swap 分区(避免性能损耗)

  • 调整系统文件描述符限制(建议至少 65535)

2.2 具体步骤

1. 下载并解压 ES 安装包

下载(以 8.14.0 为例)

wget artifacts.elastic.co/downloads/e…

解压

tar -zxvf elasticsearch-8.14.0-linux-x86_64.tar.gz cd elasticsearch-8.14.0

2. 修改系统配置(解决权限/性能问题)

1. 修改系统限制(临时生效,永久生效需修改 /etc/security/limits.conf)

ulimit -n 65535 ulimit -u 4096

2. 禁止 ES 使用 root 用户运行(创建专用用户)

useradd esuser chown -R esuser:esuser elasticsearch-8.14.0

3. 配置 ES 核心参数(config/elasticsearch.yml)

基本配置

cluster.name: my-es-cluster # 集群名称(同一集群需一致) node.name: node-1 # 节点名称(每个节点唯一) path.data: /data/es/data # 数据存储路径 path.logs: /data/es/logs # 日志存储路径 network.host: 0.0.0.0 # 监听地址(0.0.0.0 允许外部访问) http.port: 9200 # HTTP 端口 discovery.seed_hosts: ["127.0.0.1"] # 集群节点列表 cluster.initial_master_nodes: ["node-1"] # 初始主节点

关闭安全功能(测试用,生产环境必须开启)

xpack.security.enabled: false xpack.security.enrollment.enabled: false

4. 启动 ES

切换到 esuser 用户

su esuser

启动(前台运行,测试用)

./bin/elasticsearch

后台启动(生产环境)

./bin/elasticsearch -d

验证启动成功(返回 JSON 表示正常)

curl http://localhost:9200

5. 常见启动问题解决

  • 权限不足:确保数据/日志目录归 esuser 所有

  • 内存不足:修改 config/jvm.options,降低堆内存(如 Xms512m -Xmx512m

  • 端口被占用:修改 http.port 为其他端口(如 9201)

三、ES 核心关键字段说明

3.1 集群/节点相关字段

| 字段 | 说明 | 示例 |

|------|------|------|

| cluster.name | 集群名称(同一集群必须一致) | my-es-cluster |

| node.name | 节点名称(唯一标识节点) | node-1 |

| node.master | 是否允许成为主节点 | true/false |

| node.data | 是否存储数据(数据节点) | true/false |

| network.host | 监听地址 | 0.0.0.0(允许所有IP访问) |

3.2 索引(Index)核心字段

| 字段 | 说明 | 示例 |

|------|------|------|

| index.name | 索引名称(类似数据库表名) | user_info |

| index.number_of_shards | 分片数(创建后不可修改) | 3(建议等于节点数) |

| index.number_of_replicas | 副本数(可动态修改) | 1(每个分片1个副本) |

| index.refresh_interval | 刷新间隔(控制实时性) | 1s(秒级刷新)/-1(关闭自动刷新) |

3.3 映射(Mapping)核心字段

Mapping 类似数据库的「表结构」,定义字段类型和属性:

| 字段/属性 | 说明 | 常用类型 |

|-----------|------|----------|

| type | 字段类型 | text(全文检索)、keyword(精确匹配)、integer(整数)、date(日期)、object(嵌套对象) |

| analyzer | 分词器(仅 text 类型) | ik_max_word(IK中文分词)、standard(默认英文分词) |

| index | 是否创建索引(可搜索) | true(默认)/false(仅存储不检索) |

| doc_values | 是否启用列存储(排序/聚合用) | true(默认)/false |

| fielddata | text 类型是否允许排序/聚合 | false(默认,需手动开启) |

| format | 日期格式 | yyyy-MM-dd HH:mm:ss |

3.4 文档(Document)核心字段

| 字段 | 说明 | 示例 |

|------|------|------|

| _id | 文档唯一ID(类似主键) | 自动生成/手动指定(如 1001) |

| _index | 文档所属索引 | user_info |

| _type | 文档类型(7.x+ 仅支持 _doc) | _doc |

| _source | 文档原始数据(JSON格式) | {"name":"张三","age":25} |

| _score | 搜索相关性得分(越高越匹配) | 1.234 |

四、ES 基础命令示例(REST API)

4.1 集群/节点状态查询

查询集群健康状态(green/黄色/red)

curl -X GET "http://localhost:9200/_cat/health?v"

查询所有节点信息

curl -X GET "http://localhost:9200/_cat/nodes?v"

查询集群所有索引

curl -X GET "http://localhost:9200/_cat/indices?v"

4.2 索引操作

1. 创建索引(指定分片/副本)

curl -X PUT "http://localhost:9200/user_info" -H "Content-Type: application/json" -d '{ "settings": { "number_of_shards": 3, "number_of_replicas": 1, "refresh_interval": "1s" }, "mappings": { "properties": { "name": {"type": "text", "analyzer": "ik_max_word"}, # 中文分词 "age": {"type": "integer"}, "phone": {"type": "keyword"}, # 精确匹配(不分词) "create_time": {"type": "date", "format": "yyyy-MM-dd HH:mm:ss"} } } }'

2. 查询索引结构

curl -X GET "http://localhost:9200/user_info/_mapping?pretty"

3. 修改索引副本数(动态调整)

curl -X PUT "http://localhost:9200/user_info/_settings" -H "Content-Type: application/json" -d '{ "number_of_replicas": 2 }'

4. 删除索引

curl -X DELETE "http://localhost:9200/user_info"

4.3 文档操作(CRUD)

1. 添加文档(手动指定ID)

curl -X PUT "http://localhost:9200/user_info/_doc/1001" -H "Content-Type: application/json" -d '{ "name": "张三", "age": 25, "phone": "13800138000", "create_time": "2024-01-01 10:00:00" }'

2. 添加文档(自动生成ID)

curl -X POST "http://localhost:9200/user_info/_doc" -H "Content-Type: application/json" -d '{ "name": "李四", "age": 30, "phone": "13900139000", "create_time": "2024-01-02 11:00:00" }'

3. 查询文档(按ID)

curl -X GET "http://localhost:9200/user_info/_doc/1001?pretty"

4. 更新文档(全量更新)

curl -X PUT "http://localhost:9200/user_info/_doc/1001" -H "Content-Type: application/json" -d '{ "name": "张三", "age": 26, # 仅修改年龄 "phone": "13800138000", "create_time": "2024-01-01 10:00:00" }'

5. 局部更新文档(推荐)

curl -X POST "http://localhost:9200/user_info/_update/1001" -H "Content-Type: application/json" -d '{ "doc": {"age": 27} }'

6. 删除文档

curl -X DELETE "http://localhost:9200/user_info/_doc/1001"

4.4 基础搜索命令

1. 匹配所有文档(分页:from=起始位置,size=条数)

curl -X GET "http://localhost:9200/user_info/_search?pretty" -H "Content-Type: application/json" -d '{ "query": { "match_all": {} }, "from": 0, "size": 10 }'

2. 全文检索(匹配name中包含"张"的文档)

curl -X GET "http://localhost:9200/user_info/_search?pretty" -H "Content-Type: application/json" -d '{ "query": { "match": { "name": "张" } } }'

3. 精确匹配(keyword类型字段)

curl -X GET "http://localhost:9200/user_info/_search?pretty" -H "Content-Type: application/json" -d '{ "query": { "term": { "phone": "13800138000" } } }'

4. 范围查询(age大于25小于30)

curl -X GET "http://localhost:9200/user_info/_search?pretty" -H "Content-Type: application/json" -d '{ "query": { "range": { "age": { "gt": 25, "lt": 30 } } } }'

5. 组合查询(must=且,should=或,must_not=非)

curl -X GET "http://localhost:9200/user_info/_search?pretty" -H "Content-Type: application/json" -d '{ "query": { "bool": { "must": [ {"match": {"name": "张"}}, {"range": {"age": {"gte": 25}}} ], "must_not": [ {"term": {"phone": "13900139000"}} ] } } }'

4.5 批量操作(Bulk)

批量添加/更新/删除文档(格式:操作行 + 数据行)

curl -X POST "http://localhost:9200/_bulk?pretty" -H "Content-Type: application/json" -d ' {"index":{"_index":"user_info","_id":"1002"}} {"name":"王五","age":28,"phone":"13700137000","create_time":"2024-01-03 12:00:00"} {"update":{"_index":"user_info","_id":"1001"}} {"doc":{"age":28}} {"delete":{"_index":"user_info","_id":"1003"}} '

五、分词器 & 倒排索引

5.1 分词器(Analyzer)

1. 定义

分词器 = 把一段文本,切分成一个个“关键词”的工具。ES 底层是 Lucene,所有文本搜索,都依赖分词,分词的质量直接决定搜索效果。

2. 分词器组成

一个完整的分词器由 3 部分组成,按执行顺序依次是:

  • Character Filter(字符过滤):预处理文本,去掉 HTML 标签、特殊符号、表情等无关内容,比如将 `我喜欢ES

  • Tokenizer(分词器):核心步骤,按预设规则把预处理后的句子切分成独立的“词元”,比如将 我喜欢使用elasticsearch 切分成多个词。

  • Token Filter(词过滤):对词元进行优化处理,常见操作包括转小写、去除停用词(的、了、是、a、the 等无意义词汇)、同义词替换(如“ES”替换为“Elasticsearch”)。

3. ES 内置分词器

  • standard:ES 默认分词器,英文按空格、标点切分,中文按单字切分(不适合中文检索)。

  • simple:按非字母字符切分,同时将所有字母转为小写,适合简单的英文检索。

  • whitespace:仅按空格切分,不做其他处理,保留原始大小写和符号。

  • ik_smart / ik_max_word:中文分词必备(需额外安装 IK 分词器插件),专门适配中文语义。

4. 中文为什么必须用 IK 分词器?

ES 内置分词器对中文的处理的是“单字分词”,无法满足中文检索需求,对比示例如下:

  • 默认 standard 分词我喜欢使用elasticsearch 使 elasticsearch,搜索“喜欢”无法命中该文档。

  • IK 分词器我喜欢使用elasticsearch 喜欢 使用 elasticsearch,搜索“喜欢”“使用”均可精准命中。

IK 分词器的两种核心模式:

  • ik_smart:粗分模式,速度快,仅切分最核心的词汇(如 中华人民共和国中华人民共和国)。

  • ik_max_word:细粒度拆分模式,将句子拆分成所有可能的词汇(如 中华人民共和国中华人民共和国 中华人民 中华 人民 共和国),搜索更全面。

5.2 倒排索引(Inverted Index)

1. 定义

倒排索引 = 关键词 → 文档ID 的映射关系,是 ES 能实现“秒级搜索海量数据”的核心原理,也是搜索引擎的基础。

简单来说,倒排索引不存储“文档包含哪些内容”,而是存储“每个关键词出现在哪些文档中”,通过关键词快速定位文档,而非遍历所有文档。

2. 对比:正排索引 vs 倒排索引

① 正排索引(数据库 LIKE 检索方式)

核心逻辑:文档 → 内容,即存储每个文档的完整内容,检索时需遍历所有文档,逐行匹配关键词。

示例(3条文档):

文档1:我喜欢Java 文档2:我喜欢ES 文档3:ES非常快

检索“喜欢”:遍历3条文档,逐行判断是否包含“喜欢” → 效率极低,数据量越大,检索越慢。

② 倒排索引(ES 检索方式)

核心逻辑:关键词 → 文档ID,即先对所有文档的内容分词,再建立“关键词”与“包含该关键词的文档ID”的映射。

基于上面3条文档,建立的倒排索引如下:

我 → [1,2] 喜欢 → [1,2] Java → [1] ES → [2,3] 非常 → [3] 快 → [3]

检索“喜欢”:直接查询关键词“喜欢”,获取对应的文档ID [1,2],无需遍历所有文档 → 秒级出结果。

3. 倒排索引核心流程

  1. 文档写入 ES,触发分词操作(通过分词器将文档文本切分为关键词);

  2. 建立“关键词 → 文档ID”的映射关系,同时记录关键词在文档中的出现位置、频率(用于计算搜索相关性得分 _score);

  3. 用户发起搜索请求,输入的搜索词先经过分词处理;

  4. ES 查询倒排索引,根据关键词快速定位对应的文档ID;

  5. 返回文档内容,并根据相关性得分排序,呈现搜索结果。

4. 倒排索引优点

  • 检索速度极快:无需扫全表,通过关键词直接定位文档,适配海量数据检索;

  • 支持多种检索场景:模糊匹配、前缀匹配、通配符匹配、高亮显示等;

  • 天然适配全文检索:完美结合分词器,解决非结构化文本的检索难题。

六、优化建议

  1. 分词器优化:中文检索必须安装 IK 分词器(插件地址:github.com/medcl/elast…

  2. 索引规划

    • 分片数:建议等于节点数(如 3 节点设置 3 分片),避免分片过多(增加集群开销)或过少(无法充分利用节点资源);

    • 副本数:生产环境至少设置 1 个副本,保证集群高可用(某节点故障时,副本可替代主分片提供服务)。

  3. 性能优化

  • 批量写入:使用 Bulk API 代替单条写入,大幅提升数据导入效率;

    • 刷新间隔:批量导入数据时,临时设置 index.refresh_interval: -1(关闭自动刷新),导入完成后恢复为 1s,减少刷新开销;

    • 字段类型:无需检索的字段(如备注、附件路径)设置 index: false,减少索引存储和检索开销;text 类型字段尽量不用于排序/聚合,如需排序可使用 keyword 子字段。

  1. 监控与维护:通过 Kibana 监控集群状态(CPU、内存、磁盘使用率、分片健康度),定期清理过期索引,避免磁盘溢出。

七、总结

  1. ES 核心定位:分布式实时搜索引擎,基于 Lucene 构建,擅长全文检索和海量数据快速查询,提供 REST API 便于开发调用。

  2. 核心概念:索引(类似数据库表)、分片(数据拆分存储)、映射(字段结构定义)、文档(单条数据)是 ES 最基础的核心概念,需熟练掌握。

  3. 核心原理:分词器决定“能不能搜到”(中文依赖 IK 分词),倒排索引决定“搜得快不快”(关键词映射文档ID),二者是 ES 检索能力的核心。

  4. 基础操作:ES 所有操作通过 HTTP 请求完成,核心包括索引管理、文档 CRUD、各类检索(全文/精确/范围/组合),批量操作优先使用 Bulk API 提升效率。