Skip to content

Elasticsearch

欢迎来到 Elasticsearch 知识库!

🔍 Elasticsearch 简介

Elasticsearch (ES) 是一个基于 Lucene 的分布式搜索和分析引擎,能够实现近实时的搜索、分析大规模数据。广泛应用于全文搜索、日志分析、数据可视化等场景。

🎯 核心特性

✅ 主要优势

  • 分布式 - 天然支持集群,自动分片和复制
  • 近实时 - 数据写入后约 1 秒可搜索
  • 全文搜索 - 强大的文本分析和搜索能力
  • RESTful API - 简单易用的 HTTP 接口
  • 多租户 - 支持多索引查询
  • 文档导向 - 以 JSON 文档存储数据

📊 ES vs 传统数据库

概念ElasticsearchMySQL
数据库Index (索引)Database
Type (类型, 7.x 已废弃)Table
Document (文档)Row
Field (字段)Column
SchemaMapping (映射)Schema

🎯 适用场景

✅ 特别适合

  • 全文搜索 - 电商搜索、站内搜索
  • 日志分析 - ELK 日志收集分析
  • 数据分析 - 实时统计、聚合分析
  • APM - 应用性能监控
  • 安全分析 - 日志审计、威胁检测

⚠️ 不太适合

  • 主数据库(不支持事务)
  • 频繁更新的数据
  • 复杂的关联查询

🚀 快速开始

1. 基本概念

集群 (Cluster)
  └─ 节点 (Node)
      └─ 索引 (Index)
          └─ 分片 (Shard)
              ├─ 主分片 (Primary Shard)
              └─ 副本分片 (Replica Shard)

2. 索引操作

bash
# 创建索引
PUT /users
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1
  },
  "mappings": {
    "properties": {
      "username": { "type": "keyword" },
      "email": { "type": "keyword" },
      "age": { "type": "integer" },
      "bio": { "type": "text" },
      "createdAt": { "type": "date" }
    }
  }
}

# 查看索引
GET /users

# 删除索引
DELETE /users

3. 文档操作 (CRUD)

bash
# 创建文档 (指定 ID)
PUT /users/_doc/1
{
  "username": "zhangsan",
  "email": "zhang@example.com",
  "age": 25,
  "bio": "热爱技术的程序员",
  "createdAt": "2024-01-01T12:00:00Z"
}

# 创建文档 (自动生成 ID)
POST /users/_doc
{
  "username": "lisi",
  "email": "li@example.com",
  "age": 30
}

# 查询文档
GET /users/_doc/1

# 更新文档 (部分更新)
POST /users/_update/1
{
  "doc": {
    "age": 26
  }
}

# 删除文档
DELETE /users/_doc/1

🔍 搜索查询

1. 简单查询

bash
# 查询所有文档
GET /users/_search
{
  "query": {
    "match_all": {}
  }
}

# 精确匹配
GET /users/_search
{
  "query": {
    "term": {
      "username": "zhangsan"
    }
  }
}

# 全文搜索
GET /users/_search
{
  "query": {
    "match": {
      "bio": "程序员"
    }
  }
}

# 多字段搜索
GET /users/_search
{
  "query": {
    "multi_match": {
      "query": "张三",
      "fields": ["username", "bio"]
    }
  }
}

2. 复合查询

bash
# bool 查询
GET /users/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "bio": "程序员" } }
      ],
      "filter": [
        { "range": { "age": { "gte": 20, "lte": 30 } } }
      ],
      "should": [
        { "term": { "username": "zhangsan" } }
      ],
      "must_not": [
        { "term": { "status": "deleted" } }
      ]
    }
  }
}

bool 查询子句:

  • must - 必须匹配,影响相关性得分
  • filter - 必须匹配,不影响得分(可缓存)
  • should - 应该匹配,影响得分
  • must_not - 必须不匹配,不影响得分

3. 范围查询

bash
GET /users/_search
{
  "query": {
    "range": {
      "age": {
        "gte": 20,
        "lte": 30
      }
    }
  }
}

# 日期范围
GET /users/_search
{
  "query": {
    "range": {
      "createdAt": {
        "gte": "2024-01-01",
        "lt": "2024-12-31"
      }
    }
  }
}

4. 模糊查询

bash
# 前缀查询
GET /users/_search
{
  "query": {
    "prefix": {
      "username": "zhan"
    }
  }
}

# 通配符查询
GET /users/_search
{
  "query": {
    "wildcard": {
      "username": "zhan*"
    }
  }
}

# 模糊查询
GET /users/_search
{
  "query": {
    "fuzzy": {
      "username": {
        "value": "zhangsan",
        "fuzziness": 2
      }
    }
  }
}

📊 聚合分析

1. Metrics 聚合(指标)

bash
# 平均值
GET /users/_search
{
  "size": 0,
  "aggs": {
    "avg_age": {
      "avg": { "field": "age" }
    }
  }
}

# 多个统计
GET /users/_search
{
  "size": 0,
  "aggs": {
    "stats_age": {
      "stats": { "field": "age" }
    }
  }
}

2. Bucket 聚合(分组)

bash
# 按字段分组
GET /users/_search
{
  "size": 0,
  "aggs": {
    "group_by_age": {
      "terms": {
        "field": "age",
        "size": 10
      }
    }
  }
}

# 范围分组
GET /users/_search
{
  "size": 0,
  "aggs": {
    "age_ranges": {
      "range": {
        "field": "age",
        "ranges": [
          { "to": 20 },
          { "from": 20, "to": 30 },
          { "from": 30 }
        ]
      }
    }
  }
}

# 日期直方图
GET /users/_search
{
  "size": 0,
  "aggs": {
    "users_over_time": {
      "date_histogram": {
        "field": "createdAt",
        "calendar_interval": "month"
      }
    }
  }
}

3. 嵌套聚合

bash
GET /users/_search
{
  "size": 0,
  "aggs": {
    "group_by_age": {
      "terms": { "field": "age" },
      "aggs": {
        "avg_score": {
          "avg": { "field": "score" }
        }
      }
    }
  }
}

🔧 Mapping 映射

数据类型

核心类型

bash
{
  "mappings": {
    "properties": {
      # 字符串
      "title": { "type": "text" },      # 全文搜索
      "status": { "type": "keyword" },  # 精确匹配
      
      # 数字
      "age": { "type": "integer" },
      "price": { "type": "float" },
      
      # 日期
      "createdAt": { "type": "date" },
      
      # 布尔
      "isActive": { "type": "boolean" },
      
      # 对象
      "user": {
        "properties": {
          "name": { "type": "keyword" },
          "age": { "type": "integer" }
        }
      },
      
      # 数组 (自动推断类型)
      "tags": { "type": "keyword" }
    }
  }
}

text vs keyword

特性textkeyword
分词✅ 分词❌ 不分词
全文搜索
精确匹配
排序
聚合

🔍 中文分词

IK 分词器

bash
# 安装
elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.10.0/elasticsearch-analysis-ik-7.10.0.zip

# 创建索引时指定分词器
PUT /articles
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",      # 索引时使用
        "search_analyzer": "ik_smart"   # 搜索时使用
      }
    }
  }
}

ik_max_word: 最细粒度拆分

"中华人民共和国" -> "中华人民共和国", "中华人民", "中华", "华人", "人民共和国", "人民", "共和国", "共和", "国"

ik_smart: 最粗粒度拆分

"中华人民共和国" -> "中华人民共和国"

📈 性能优化

1. 索引优化

bash
# 批量索引
POST /_bulk
{"index":{"_index":"users","_id":"1"}}
{"username":"user1","age":25}
{"index":{"_index":"users","_id":"2"}}
{"username":"user2","age":30}

# 调整刷新间隔
PUT /users/_settings
{
  "index": {
    "refresh_interval": "30s"  # 默认 1s
  }
}

2. 查询优化

bash
# 使用 filter 而非 query(可缓存)
GET /users/_search
{
  "query": {
    "bool": {
      "filter": [
        { "term": { "status": "active" } }
      ]
    }
  }
}

# 限制返回字段
GET /users/_search
{
  "_source": ["username", "email"],
  "query": { "match_all": {} }
}

3. 分页

bash
# from + size (浅分页)
GET /users/_search
{
  "from": 0,
  "size": 20,
  "query": { "match_all": {} }
}

# search_after (深分页)
GET /users/_search
{
  "size": 20,
  "query": { "match_all": {} },
  "search_after": [1234, "abc"],  # 上一页最后一条记录的 sort 值
  "sort": [
    { "_id": "asc" }
  ]
}

🔗 Node.js 客户端

javascript
const { Client } = require('@elastic/elasticsearch');

const client = new Client({
  node: 'http://localhost:9200'
});

// 创建文档
await client.index({
  index: 'users',
  id: '1',
  document: {
    username: 'zhangsan',
    email: 'zhang@example.com',
    age: 25
  }
});

// 搜索
const result = await client.search({
  index: 'users',
  query: {
    match: {
      username: 'zhangsan'
    }
  }
});

console.log(result.hits.hits);

// 聚合
const aggResult = await client.search({
  index: 'users',
  size: 0,
  aggs: {
    avg_age: {
      avg: { field: 'age' }
    }
  }
});

console.log(aggResult.aggregations.avg_age.value);

💡 最佳实践

  1. 合理设计 Mapping

    • 选择正确的字段类型
    • text 用于全文搜索,keyword 用于精确匹配
    • 不需要搜索的字段设置 "index": false
  2. 使用 filter 而非 query

    • filter 可以缓存,性能更好
    • 不需要评分时使用 filter
  3. 批量操作

    • 使用 Bulk API 批量索引
    • 减少网络开销
  4. 控制文档大小

    • 避免过大的文档
    • 单个文档不超过几 MB
  5. 合理设置副本和分片

    • 主分片数创建后不可修改
    • 副本数可以动态调整

📖 学习资源

官方资源

推荐书籍

  • 《Elasticsearch 权威指南》
  • 《Elasticsearch 实战》

ELK Stack

  • Elasticsearch - 搜索和分析引擎
  • Logstash - 数据收集和处理
  • Kibana - 数据可视化

准备好了吗?开始你的 Elasticsearch 学习之旅!