Elasticsearch 实战:从索引设计到中文搜索优化的完整指南
Elasticsearch 是当下最流行的分布式搜索引擎。无论是全文检索、日志分析还是站内搜索,ES 都是首选。但"能跑起来"和"搜得好、查得快"之间,隔着索引设计与调优的门槛。本文从索引建模到查询优化,给出完整的实战路径。
一、核心概念:倒排索引与分片
ES 高效检索的基石是倒排索引:以词项(term)为键,记录包含该词项的文档列表。查询时先查词典定位词项,再取文档列表合并——无需扫描全部文档。
1.1 分片与副本
- 主分片(shard):数据切分单元,数量在创建索引时确定,之后不可修改;
- 副本(replica):主分片的拷贝,提供读扩展与高可用,可动态调整。
PUT /articles
{
"settings": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}
容量规划:单个分片建议 20~50GB,总数据量 ÷ 单分片容量即可估算分片数;小索引(<10GB)用 1 个分片反而更高效。
二、映射设计:字段类型决定一切
2.1 text 与 keyword 的区别
PUT /articles/_mapping
{
"properties": {
"title": { "type": "text", "analyzer": "ik_max_word" },
"category": { "type": "keyword" },
"tags": { "type": "keyword" },
"view_count":{ "type": "integer" },
"created_at":{ "type": "date", "format": "strict_date_optional_time" }
}
}
- text:会被分词,用于全文搜索(title、content);
- keyword:不参与分词,用于精确匹配、过滤、排序、聚合(category、tags、状态);
- 排序与聚合只能在 keyword / 数值 / 日期字段上进行。
2.2 多字段:一个字段两种用法
"title": {
"type": "text",
"analyzer": "ik_max_word",
"fields": { "keyword": { "type": "keyword", "ignore_above": 256 } }
}
这样 title 既能全文检索,又能通过 title.keyword 做精确排序与聚合。
三、中文分词:IK 插件的正确姿势
中文没有天然空格分隔,必须依赖分词器。IK 分词器是事实标准:
# 安装
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.x/elasticsearch-analysis-ik-8.x.zip
两种分词模式的取舍:
| 模式 | 行为 | 适用 | |------|------|------| | ik_max_word | 最细粒度切分(如"中华人民共和国"拆出多个词) | 建索引,召回率高 | | ik_smart | 最粗粒度切分(只保留最长匹配) | 查询,精准度高 |
推荐:索引用 ik_max_word,查询用 ik_smart(analyzer 与 search_analyzer 分离):
"content": {
"type": "text",
"analyzer": "ik_max_word",
"search_analyzer": "ik_smart"
}
IK 也支持自定义词典:在 IKAnalyzer.cfg.xml 中配置 ext_dict 指向业务词库(如产品名、人名),显著提升专业领域召回率。
四、查询 DSL:从入门到精通
4.1 全文检索:match
GET /articles/_search
{
"query": {
"match": { "title": "分布式搜索" }
}
}
4.2 精准过滤:term + filter
GET /articles/_search
{
"query": {
"bool": {
"must": { "match": { "content": "Elasticsearch 集群" } },
"filter": [
{ "term": { "category": "后端" } },
{ "range": { "view_count": { "gte": 1000 } } }
]
}
}
}
性能关键:filter 上下文会缓存结果集(bitset 缓存),命中率高的过滤条件放 filter 而非 must,查询性能大幅提升。
4.3 聚合分析
GET /articles/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category", "size": 10 },
"aggs": {
"avg_views": { "avg": { "field": "view_count" } }
}
}
}
}
4.4 高亮
{
"query": { "match": { "content": "倒排索引" } },
"highlight": {
"fields": { "content": {} },
"pre_tags": ["<em class='hl'>"],
"post_tags": ["</em>"]
}
}
五、查询性能优化八法
- 精确值查询走 term/filter,别用 match 做无谓分词;
- 避免
*通配符开头的前缀查询(正则扫描极慢); - 深分页用 search_after,不要大 size + from(每次查询开销随 from 线性增长);
- 限制返回字段:
_source只取需要的字段,减少网络与内存开销; - 聚合字段必须 keyword/数值类型,text 字段聚合会报错;
- 查询超时兜底:
"timeout": "2s"防止慢查询拖垮集群; - 热门词缓存:对高流量词用
request_cache=true或应用层缓存; - 索引生命周期:日志类数据按天滚动索引 + ILM 冷热分层,控制分片数量。
六、集群运维:从单机到三节点
# elasticsearch.yml(节点配置)
cluster.name: okgoes-es
node.name: node-1
network.host: 0.0.0.0
discovery.seed_hosts: ["node-1", "node-2", "node-3"]
cluster.initial_master_nodes: ["node-1"]
# 内存与系统调优
ES_JAVA_OPTS="-Xms4g -Xmx4g" # 堆内存设为物理内存一半,不超过 32GB
vm.max_map_count = 262144 # 需写入 sysctl
黄金法则:堆内存固定 Xms=Xmx(避免动态扩容的停顿);留一半内存给 OS 的 page cache(ES 重度依赖文件缓存)。
结语
Elasticsearch 的实战精髓可以浓缩为三点:字段类型选对(text/keyword 分清楚)、分词策略配好(ik_max_word + ik_smart 组合)、查询结构合理(filter 缓存 + 聚合优化)。把这三点融入索引建模的每一步,你的搜索就能又快又准。建议先用真实业务数据做一轮 mapping 设计评审,再上线——索引一旦创建,改 mapping 的成本远高于设计成本。
评论(0)
登录 后参与评论。