ElasticSearch 基础教程
ES 是一个分布式文档数据库 + 搜索引擎,擅长:
- 全文搜索(倒排索引)
- 高维数据搜索(近似向量)
- 日志检索(ELK)
- 聚合分析(近似数据分析)
核心概念:
| 概念 | 含义 |
|---|---|
| Cluster | ES 集群,由多个节点组成 |
| Node | 集群中的服务器实例 |
| Index | 类似数据库中的“库” |
| Document | 具体数据,每条数据是 JSON |
| Shard | ES 最重要概念之一,存储数据 |
| Replica | 副本,提升可用性和查询能力 |
| Mapping | 字段定义(类型、分析器) |
| Analyzer | 分词器,例如 ik_max_word、standard |
ES 对文本使用倒排索引,流程:
- 文本 -> 分词(Analyzer)
- 分词 -> token 列表
- 建立倒排表:token -> 文档 ID 列表
查询时,只需查 token -> 相关文档。
GET index/_search
{
"query": {
"match": {
"title": "fastapi 权限"
}
}
}
Filter 不参与打分,可缓存。
{
"query": {
"bool": {
"filter": [
{ "term": { "status": "active" } }
]
}
}
}
- must(必须匹配)
- should(加分项)
- filter(过滤,不评分)
- must_not(排除)
常用字段类型:
- keyword —— 精确匹配、聚合
- text —— 分词匹配(全文搜索)
- date —— 时间
- long、float —— 数字
- nested —— 嵌套对象
- object —— 普通对象
- dense_vector —— 向量检索(通常维度 ≤ 2048)
最佳实践:
| 场景 | 字段类型 |
|---|---|
| 标题、内容 | text |
| 标签、分类、状态 | keyword |
| 用户 ID | keyword |
| 价格、数量 | long/float |
| 时间 | date |
| JSON 数组 | nested |
给新索引自动使用 mapping、setting:
PUT _index_template/blog_template
{
"index_patterns": ["blog-*"],
"template": {
"settings": { "number_of_shards": 3 },
"mappings": {
"properties": {
"title": {"type": "text"},
"status": {"type": "keyword"}
}
}
}
}
- 数据量 < 50GB:1 shard
- 大型索引:每 shard 控制在 30~50GB
- 避免过多 shard(1个节点建议 < 20 shard)
- 写多读少:replica=0
- 写少读多:replica=1~3
使用 _bulk:
POST _bulk
{ "index": {"_index": "test", "_id": "1"} }
{ "title": "hello" }
写多查询少的场景(如日志)可调高:
"refresh_interval": "30s"
(默认 1s)
filter 不计算评分,性能极高。
默认开启,用于聚合和排序。
ES 8+ 支持 ANN 近似搜索,常用:
{
"query": {
"knn": {
"field": "vector",
"query_vector": [1.1, 2.3, ...],
"k": 10,
"num_candidates": 100
}
}
}
底层通常采用 HNSW。
如求 top10 热门分类:
{
"aggs": {
"top_category": {
"terms": {
"field": "category.keyword",
"size": 10
}
}
}
}
关键监控项:
- 集群状态 red/yellow/green
- 分片是否分配成功
- JVM heap 使用率(>75% 会频繁 GC)
- indexing rate
- search latency
- refresh、flush、merge 频率
常用工具:
- Kibana
- Cerebro
- ElasticHQ
ES 不适合频繁改 mapping。
生产必须关掉:
action.auto_create_index: false
nested 成本高,查询慢。
不要用:
from: 100000
改用:
- search_after
- scroll(大批量导数据用)
理由:
- 无事务
- 写入成本高(倒排index)
- 有概率丢数据