Elasticsearch 实战教程

你是否曾为 SQL LIKE 查询的缓慢而头疼?是否需要快速分析海量非结构化数据?Elasticsearch 正是解决这些问题的利器——它是基于 Apache Lucene 构建的分布式 RESTful 搜索与分析引擎,适用于全文检索、日志分析、实时数据洞察等场景。


1. 快速上手:安装与启动

我们使用 Docker 进行部署,这是本地开发环境最快的启动方式,无需处理系统依赖。

1.1 Docker 单节点部署

首先拉取官方稳定版镜像(本文使用 8.12.0):

# 拉取 Elasticsearch 8.12.0 镜像
docker pull docker.elastic.co/elasticsearch/elasticsearch:8.12.0

然后运行容器(注意:本地开发禁用了安全功能,生产环境必须开启):

# 启动单节点 Elasticsearch 容器
docker run -d --name elasticsearch \
  -p 9200:9200 -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=false" \
  -e "ES_JAVA_OPTS=-Xms512m -Xmx512m" \
  docker.elastic.co/elasticsearch/elasticsearch:8.12.0

等待 30 秒左右,检查是否启动成功:

# 检查集群状态
curl -X GET "localhost:9200/"

看到包含 cluster_nameversion 的 JSON 响应即说明成功。

1.2 Docker Compose 部署

为了方便后续管理,使用 docker-compose.yml 文件:

# docker-compose.yml
version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.12.0
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
    ports:
      - "9200:9200"
      - "9300:9300"
    volumes:
      - es_data:/usr/share/elasticsearch/data

volumes:
  es_data:

启动命令:

docker-compose up -d

2. 核心概念扫盲

用relational-database做类比,快速理解 Elasticsearch 的核心概念:

Elasticsearch 概念说明类比 MySQL
Index文档的集合Database
Document搜索的基本单位(JSON 格式)Row
Field文档的属性Column
Shard分片(水平分割索引,用于扩展)水平分表
Replica副本(分片的备份,用于高可用)备份表
Note

Type 概念在 Elasticsearch 7.x 后已废弃,无需关注。


3. 索引管理:定义数据结构

索引是文档的容器,创建索引前需要先定义 Mapping(类似数据库的表结构)。

3.1 创建博客文章索引

我们创建一个用于存储博客文章的索引,包含常用字段:

PUT /blog_posts
{
  "settings": {
    "number_of_shards": 1,    // 单节点环境用 1 个分片
    "number_of_replicas": 0   // 单节点副本设为 0(否则集群状态为 yellow)
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",        // 全文搜索用 text(会分词)
        "fields": {
          "keyword": { "type": "keyword" }  // 精确匹配/排序用 keyword
        }
      },
      "content": { "type": "text" },
      "author": { "type": "keyword" },
      "publish_date": { "type": "date" },
      "tags": { "type": "keyword" },
      "views": { "type": "integer" }
    }
  }
}
常用字段类型
  • text:用于全文检索,会被分词器拆分为词条;
  • keyword:用于精确匹配、排序、聚合,不会分词;
  • date/integer:时间、数值类型,用于范围查询和聚合。 :::

检查索引是否创建成功:

GET /_cat/indices?v

4. 文档操作:CRUD 基础

现在我们在 blog_posts 索引中进行文档的增删改查操作。

4.1 新增文档

可以指定 ID,也可以让 Elasticsearch 自动生成:

# 指定 ID 新增文档
PUT /blog_posts/_doc/1
{
  "title": "Elasticsearch 入门指南",
  "content": "Elasticsearch 是一个基于 Lucene 的分布式搜索引擎,支持全文搜索、实时分析等功能。",
  "author": "张三",
  "publish_date": "2026-04-10",
  "tags": ["elasticsearch", "search", "tutorial"],
  "views": 100
}

# 自动生成 ID 新增文档
POST /blog_posts/_doc
{
  "title": "Python 与 Elasticsearch 集成",
  "content": "如何在 Python 项目中使用 Elasticsearch 客户端进行搜索开发。",
  "author": "李四",
  "publish_date": "2026-04-09",
  "tags": ["python", "elasticsearch"],
  "views": 200
}

4.2 查询文档

根据 ID 获取单个文档:

GET /blog_posts/_doc/1

4.3 更新文档

部分更新文档(无需重写整个文档):

POST /blog_posts/_update/1
{
  "doc": {
    "views": 120,  // 增加浏览量
    "last_updated": "2026-04-10T12:00:00"  // 新增字段
  }
}

4.4 删除文档

根据 ID 删除文档:

DELETE /blog_posts/_doc/1

5. 搜索 DSL:核心功能

Elasticsearch 的 Query DSL 是其最强大的功能,使用 JSON 构建复杂的搜索请求。

5.1 基础搜索

1. 搜索所有文档

GET /blog_posts/_search
{
  "query": { "match_all": {} },
  "size": 10  // 默认返回 10 条结果
}

2. 全文搜索(match)

content 字段中搜索包含 "elasticsearch" 的文档:

GET /blog_posts/_search
{
  "query": {
    "match": { "content": "elasticsearch" }
  }
}

3. 多字段搜索(multi_match)

titlecontenttags 三个字段中搜索,其中 title 权重最高(^3):

GET /blog_posts/_search
{
  "query": {
    "multi_match": {
      "query": "elasticsearch",
      "fields": ["title^3", "content", "tags^2"]
    }
  }
}

4. 精确匹配(term)

查找作者为 "张三" 的文档(必须使用 keyword 字段):

GET /blog_posts/_search
{
  "query": {
    "term": { "author.keyword": "张三" }
  }
}

5.2 布尔查询(bool)

结合多个条件,使用 must(AND)、filter(过滤,不影响评分)、should(OR):

GET /blog_posts/_search
{
  "query": {
    "bool": {
      "must": [  // 必须满足的条件
        { "match": { "content": "elasticsearch" } }
      ],
      "filter": [  // 过滤条件(不计算相关性,更快且缓存)
        { "term": { "author.keyword": "张三" } },
        { "range": { "views": { "gte": 100 } } }  // 浏览量 >= 100
      ]
    }
  }
}

:::tip 优先使用 filter Filter 上下文不会计算相关性评分,且结果会被缓存,性能远高于 must

5.3 结果排序

按发布时间倒序,再按相关性评分倒序:

GET /blog_posts/_search
{
  "query": { "match_all": {} },
  "sort": [
    { "publish_date": { "order": "desc" } },
    { "_score": { "order": "desc" } }
  ]
}

6. Python 集成:实战开发

使用官方 elasticsearch Python 客户端与集群交互。

6.1 安装客户端

pip install elasticsearch

6.2 基础连接与操作

首先连接到本地集群:

from elasticsearch import Elasticsearch
import json

# 连接本地 Elasticsearch
es = Elasticsearch(hosts=["http://localhost:9200"])

# 检查连接
if es.ping():
    print("✅ 成功连接到 Elasticsearch")
else:
    print("❌ 连接失败")

然后编写几个常用的辅助函数:

def index_post(post_id: str, post: dict) -> dict:
    """新增或更新博客文章"""
    return es.index(index="blog_posts", id=post_id, document=post)

def get_post(post_id: str) -> dict | None:
    """根据 ID 获取文章"""
    try:
        res = es.get(index="blog_posts", id=post_id)
        return res["_source"]
    except Exception as e:
        print(f"获取文章失败: {e}")
        return None

def search_posts(query: str, size: int = 10) -> dict:
    """搜索文章,支持高亮"""
    query_body = {
        "query": {
            "multi_match": {
                "query": query,
                "fields": ["title^3", "content", "tags^2"]
            }
        },
        "highlight": {
            "fields": {"title": {}, "content": {}}
        },
        "size": size
    }
    return es.search(index="blog_posts", body=query_body)

6.3 测试代码

添加一篇文章并执行搜索:

# 新增示例文章
sample_post = {
    "title": "Elasticsearch Python 客户端实战",
    "content": "本文介绍如何使用 Python 客户端操作 Elasticsearch,包括索引、搜索、聚合等功能。",
    "author": "王五",
    "publish_date": "2026-04-11",
    "tags": ["python", "elasticsearch", "client"],
    "views": 150
}
index_post("3", sample_post)

# 执行搜索
res = search_posts("Python Elasticsearch")
print(json.dumps(res, indent=2, ensure_ascii=False))

7. 快速优化与最佳实践

这里列出几个新手必知的优化建议:

  1. 批量索引:使用 bulk API 一次添加多个文档,减少网络开销;
  2. 限制返回字段:使用 _source 只获取需要的字段;
  3. 使用索引别名:通过别名访问索引,避免重索引时的 downtime;
  4. 避免过度分片:小索引用 1-3 个分片即可;
  5. 监控集群状态:使用 GET /_cluster/health 检查状态(green=正常,yellow=无副本,red=异常)。

总结

本文涵盖了 Elasticsearch 的核心内容:快速安装、核心概念、索引与文档管理、Query DSL 搜索以及 Python 集成。掌握这些内容后,你已经可以为项目添加基础的搜索功能了。

后续我们会继续更新聚合分析、集群部署、安全配置等进阶内容,敬请关注!