Elasticsearch 2024 最新入门教程
Elasticsearch 2024 最新入门教程:从零开始掌握分布式搜索引擎
前言
在数据爆炸式增长的今天,如何快速、准确地从海量数据中检索信息、分析洞察,成为了企业和开发者面临的核心挑战。Elasticsearch(简称 ES)作为一款基于 Apache Lucene 构建的开源、分布式、RESTful 风格的搜索和数据分析引擎,凭借其强大的全文搜索能力、近乎实时的索引和分析、高可用性和可扩展性,已成为该领域的事实标准之一。无论你是希望构建一个强大的站内搜索引擎、集中式日志管理平台、业务数据分析系统,还是探索新兴的向量搜索领域,Elasticsearch 都是一个值得深入学习和掌握的工具。
2024 年,Elasticsearch 持续演进,不断优化性能、增强功能并简化用户体验。本教程旨在为初学者提供一份全面、详细且与时俱进的入门指南,帮助你从零开始,逐步理解 Elasticsearch 的核心概念、掌握基本操作,并为后续的深入学习打下坚实的基础。本文预计篇幅较长,涵盖从概念、安装、核心操作到基本原理的方方面面,力求详尽。
第一章:初识 Elasticsearch——它是什么?为何选择它?
-
什么是 Elasticsearch?
- 核心:搜索引擎: ES 的根基是 Lucene 库,它提供了强大的全文检索引擎能力。你可以将各种结构化、半结构化、非结构化数据(如日志、商品信息、文章、指标数据、甚至向量嵌入)喂给 ES,然后通过丰富的查询语言快速检索相关信息。
- 分布式系统: ES 天生就是分布式的。数据可以分散存储在多个节点上(分片),并且可以有多个副本(副本分片)以保证高可用性和提高读取吞吐量。集群可以轻松地水平扩展,以应对数据量和查询负载的增长。
- 近实时 (NRT - Near Real-Time): 从数据被索引到可以被搜索到,通常只有秒级的延迟(默认 1 秒刷新间隔),这使得 ES 非常适用于需要快速反映数据变化的场景。
- RESTful API: ES 的所有操作都通过 HTTP RESTful API 进行。这意味着你可以使用任何你喜欢的编程语言或工具(如 cURL、Postman、Kibana Dev Tools 或各种语言的官方/社区客户端库)与 ES 集群进行交互。数据交换格式主要是 JSON。
- 数据存储与分析: 虽然核心是搜索,但 ES 也常被用作 NoSQL 数据存储,特别是对于文档型数据。其强大的聚合(Aggregations)功能使其在数据分析、指标监控和商业智能领域也大放异彩。
- 可观察性平台核心: ES 是 Elastic Stack(ELK/ECK Stack - Elasticsearch, Logstash, Kibana, Beats)的核心组件,广泛应用于日志管理、指标监控和应用性能管理(APM)。
- 向量数据库能力: 近年来,随着 AI 的发展,ES 增加了对向量数据(Embeddings)的存储和相似性搜索支持,使其成为构建语义搜索、推荐系统等 AI 应用的重要基础设施。
-
为何选择 Elasticsearch (核心优势)?
- 速度与性能: 基于倒排索引(Inverted Index)等高效数据结构,ES 能够实现毫秒级的搜索响应。分布式架构进一步分散了负载。
- 强大的全文搜索: 支持复杂查询、相关性评分、高亮显示、拼写检查、自动补全等高级搜索功能。对多种语言的分词和分析有良好支持。
- 可扩展性: 水平扩展能力强,可以通过增加节点来轻松扩展存储容量和处理能力。
- 高可用性: 通过数据分片和副本机制,即使部分节点发生故障,也能保证数据的安全和服务的可用性。
- 易用性: RESTful API 和 JSON 格式使得与其他系统集成相对简单。Kibana 提供了强大的可视化和管理界面。
- 丰富的功能: 除了搜索,还提供强大的聚合分析、地理空间查询、安全功能、机器学习特性(需订阅)等。
- 活跃的社区与生态: 拥有庞大的用户社区和完善的生态系统(Elastic Stack),文档丰富,问题容易找到解决方案。
第二章:核心概念解析——理解 ES 的基石
在开始实践之前,理解 Elasticsearch 的核心术语至关重要:
-
文档 (Document):
- ES 中存储的基本信息单元,类似于关系数据库中的一行记录。
- 文档以 JSON 格式表示。每个文档都有一个唯一的 ID(可以自动生成或手动指定)和一个类型(在现代版本中类型被简化,通常使用
_doc
)。 - 例如,一个代表用户的文档可能是:
{ "name": "Alice", "age": 30, "email": "[email protected]", "interests": ["reading", "hiking"] }
-
索引 (Index):
- 索引是具有相似特征的文档集合,类似于关系数据库中的一个表。
- 索引名称必须是小写,不能包含特殊字符。
- 例如,你可以创建一个名为
products
的索引来存储所有商品文档,创建一个名为logs-2024-07
的索引来存储特定日期的日志文档。 - 索引也是 ES 中数据管理和查询的基本单位。
-
映射 (Mapping):
- 映射定义了索引中文档及其字段的存储方式和索引方式,类似于关系数据库中的表结构(Schema)。
- 它规定了每个字段的数据类型(如
text
,keyword
,integer
,date
,boolean
,object
,nested
,geo_point
,dense_vector
等)以及该字段如何被分析(Analyze)。 text
vskeyword
是一个关键区别:text
类型用于全文搜索,其内容会被分析器 (Analyzer) 处理(如分词、转小写、去除停用词),适合描述性文本。keyword
类型用于精确匹配、排序和聚合,其内容不会被分析,作为一个整体存储。适合存储 ID、标签、状态、邮箱地址等。
- ES 支持动态映射 (Dynamic Mapping):如果插入文档时索引不存在或字段未定义,ES 会根据字段值自动推断类型并创建映射。虽然方便,但在生产环境中强烈建议使用显式映射 (Explicit Mapping) 来精确控制数据结构和索引行为。
-
节点 (Node):
- 一个运行中的 Elasticsearch 实例就是一个节点。
- 节点负责存储数据、参与集群的索引和搜索功能。
- 每个节点都有一个唯一的名称和一个传输地址,用于节点间的通信。
- 节点可以扮演不同角色(Master-eligible, Data, Ingest, Machine Learning 等),大型集群通常会配置专门角色的节点。
-
集群 (Cluster):
- 一个或多个节点的集合,它们共同持有所有数据,并提供跨所有节点的联合索引和搜索功能。
- 集群由一个唯一的名称标识(默认为
elasticsearch
)。 - 集群通过选举产生一个主节点 (Master Node),负责管理集群状态(如创建/删除索引、添加/删除节点等),但不参与文档级别的搜索或索引请求处理。
-
分片 (Shard):
- 由于单个节点存储能力和处理能力有限,ES 将索引分割成多个部分,称为分片。每个分片都是一个功能齐全且独立的“子索引”。
- 分片是 ES 实现数据水平扩展的关键。数据分布在不同的分片上,查询可以并行在多个分片上执行。
- 创建索引时需要指定主分片 (Primary Shard) 的数量,这个数量一旦设定后通常不能修改(除非进行 reindex 操作)。合理规划分片数量非常重要。
-
副本分片 (Replica Shard):
- 副本分片是主分片的完整拷贝。
- 主要作用:
- 高可用性: 如果持有主分片的节点宕机,对应的副本分片可以被提升为新的主分片,保证数据不丢失,服务不中断。
- 提高读取性能: 搜索请求可以在主分片或其任意副本分片上执行,增加了查询吞吐量。
- 副本分片的数量可以在索引创建后动态调整。
- 副本分片永远不会和它的主分片分配在同一个节点上。
-
REST API & JSON:
- 如前所述,所有与 ES 的交互都通过 RESTful API 进行,使用标准的 HTTP 方法(GET, POST, PUT, DELETE)。
- 请求体和响应体通常使用 JSON 格式。
-
倒排索引 (Inverted Index):
- 这是 ES(以及 Lucene)实现快速全文搜索的核心数据结构。
- 它不像传统数据库那样存储“文档ID -> 内容”,而是存储“词项 (Term) -> 包含该词项的文档列表”。
- 例如,对于文档:
- Doc 1: "Elasticsearch is fast"
- Doc 2: "Elasticsearch is powerful and fast"
- 简化版的倒排索引可能如下:
- "elasticsearch": [Doc 1, Doc 2]
- "is": [Doc 1, Doc 2]
- "fast": [Doc 1, Doc 2]
- "powerful": [Doc 2]
- "and": [Doc 2]
- 当搜索 "fast" 时,ES 只需查找 "fast" 这个词项,就能立即定位到包含它的所有文档(Doc 1, Doc 2),速度极快。
第三章:环境搭建——启动你的第一个 ES 集群
对于初学者,推荐使用 Docker 来快速搭建 Elasticsearch 和 Kibana 环境。这是目前最便捷、跨平台且环境隔离的方式。
-
安装 Docker:
- 请根据你的操作系统(Windows, macOS, Linux)访问 Docker 官网 (https://www.docker.com/) 下载并安装 Docker Desktop 或 Docker Engine。
-
创建 Docker 网络(推荐):
- 为了让 Elasticsearch 和 Kibana 容器能够方便地互相通信,创建一个自定义 Docker 网络是个好习惯。
bash
docker network create elastic-net
- 为了让 Elasticsearch 和 Kibana 容器能够方便地互相通信,创建一个自定义 Docker 网络是个好习惯。
-
运行 Elasticsearch 容器:
- 我们将运行一个单节点的 Elasticsearch 集群。注意:从 ES 8.x 开始,安全特性默认开启,需要设置密码或禁用安全特性。为了入门简单,我们先生成密码。
```bash
拉取最新镜像 (根据需要可指定版本,如 elasticsearch:8.13.4)
docker pull docker.elastic.co/elasticsearch/elasticsearch:8.14.0
运行容器
docker run -d --name es01 --net elastic-net -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "ELASTIC_PASSWORD=YourStrongPassword123" -e "xpack.security.enabled=true" -v es_data:/usr/share/elasticsearch/data docker.elastic.co/elasticsearch/elasticsearch:8.14.0
``
-d
* **参数解释:**
*: 后台运行容器。
--name es01
*: 给容器命名为
es01。
--net elastic-net
*: 将容器连接到我们创建的网络。
-p 9200:9200
*: 将宿主机的 9200 端口映射到容器的 9200 端口(HTTP REST API)。
-p 9300:9300
*: 将宿主机的 9300 端口映射到容器的 9300 端口(节点间通信,单节点模式下非必需,但保留)。
-e "discovery.type=single-node"
*: 设置为单节点模式,简化启动。
-e "ELASTIC_PASSWORD=YourStrongPassword123"
*: **重要!** 设置
elastic超级用户的密码。请替换为你自己的强密码。
-e "xpack.security.enabled=true"
*: 明确启用安全特性(8.x 默认)。
-v es_data:/usr/share/elasticsearch/data
*: 将 Elasticsearch 的数据目录挂载到 Docker 的命名卷
es_data,实现数据持久化。首次运行会自动创建该卷。
docker.elastic.co/elasticsearch/elasticsearch:8.14.0`: 使用的镜像。请使用官方最新稳定版。
*- 验证 Elasticsearch 是否运行:
- 等待一两分钟让 ES 启动。
- 打开浏览器或使用 cURL 访问
https://localhost:9200
(注意是https
)。 - 由于使用了自签名证书,浏览器会提示不安全,选择接受风险继续。
- 会弹出认证窗口,用户名是
elastic
,密码是你上面设置的YourStrongPassword123
。 - 如果看到类似以下的 JSON 响应,说明 ES 运行成功:
json
{
"name" : "es01", // 节点名称,可能不同
"cluster_name" : "elasticsearch",
"cluster_uuid" : "...",
"version" : {
"number" : "8.14.0",
// ... 其他信息
},
"tagline" : "You Know, for Search"
} - 或者使用 cURL (需要
-k
忽略证书验证,-u
提供用户名密码):
bash
curl -k -u elastic:YourStrongPassword123 https://localhost:9200
- 我们将运行一个单节点的 Elasticsearch 集群。注意:从 ES 8.x 开始,安全特性默认开启,需要设置密码或禁用安全特性。为了入门简单,我们先生成密码。
-
运行 Kibana 容器:
- Kibana 是 Elastic Stack 的可视化和管理界面,强烈推荐安装。
```bash
拉取 Kibana 镜像
docker pull docker.elastic.co/kibana/kibana:8.14.0
运行 Kibana 容器
docker run -d --name kibana --net elastic-net -p 5601:5601 -e "ELASTICSEARCH_HOSTS=https://es01:9200" -e "ELASTICSEARCH_USERNAME=elastic" -e "ELASTICSEARCH_PASSWORD=YourStrongPassword123" -e "ELASTICSEARCH_SSL_VERIFICATIONMODE=none" docker.elastic.co/kibana/kibana:8.14.0
``
--name kibana
* **参数解释:**
*: 容器命名。
--net elastic-net
*: 连接到同一网络。
-p 5601:5601
*: 映射 Kibana 的 Web 界面端口。
-e "ELASTICSEARCH_HOSTS=https://es01:9200"
*: **重要!** 告诉 Kibana 连接哪个 Elasticsearch 实例。使用容器名
es01和
https。
-e "ELASTICSEARCH_USERNAME=elastic"
*和
-e "ELASTICSEARCH_PASSWORD=YourStrongPassword123": 提供访问 ES 的凭证。
-e "ELASTICSEARCH_SSL_VERIFICATIONMODE=none"
*: **重要!** 由于 ES 使用自签名证书,需要告知 Kibana 跳过 SSL 证书验证。在生产环境中应配置正确的证书。
docker.elastic.co/kibana/kibana:8.14.0`: Kibana 镜像。
*- 访问 Kibana:
- 等待 Kibana 启动(可能需要一两分钟)。
- 打开浏览器访问
http://localhost:5601
。 - 首次访问可能需要输入一个验证码(会显示在 Kibana 容器的日志中,使用
docker logs kibana
查看)或者直接使用elastic
用户和密码登录。 - 登录成功后,你将看到 Kibana 的主界面。
- Kibana 是 Elastic Stack 的可视化和管理界面,强烈推荐安装。
-
使用 Kibana Dev Tools:
- 在 Kibana 的左侧导航栏中,找到 "Management" -> "Dev Tools"。这是一个交互式控制台,可以方便地发送 REST API 请求给 Elasticsearch。本教程后续的示例都将使用 Dev Tools 来执行。
- Dev Tools 界面左边是请求编辑区,右边是响应显示区。点击绿色的三角按钮发送请求。它会自动处理认证和
https
。
第四章:核心 API 操作——与 ES 互动
现在我们已经搭建好环境,可以开始通过 Kibana Dev Tools 与 Elasticsearch 进行交互了。
-
检查集群健康状态:
- 这是检查集群是否正常运行的常用命令。
http request
GET /_cat/health?v ?v
参数表示显示表头。你会看到类似epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
的输出。status
字段很重要:green
: 所有主分片和副本分片都正常分配。集群健康。yellow
: 所有主分片都正常,但至少有一个副本分片未能分配(比如单节点集群,副本无法分配到不同节点)。数据仍然可用,但高可用性受影响。我们的单节点集群通常是 yellow 状态,这是正常的。red
: 至少有一个主分片未能分配。部分数据不可用,集群功能不完整。需要紧急处理。
- 这是检查集群是否正常运行的常用命令。
-
索引管理 (Index Management):
- 创建索引 (Create Index):
- 创建一个名为
my_first_index
的索引。
http request
PUT /my_first_index - 响应会告诉你操作是否成功 (
"acknowledged": true
)。 - 默认情况下,ES 会为这个索引分配一定数量的主分片(ES 7.x 及之后默认为 1 个)和副本分片(默认为 1 个)。
- 创建一个名为
- 创建带设置和映射的索引:
- 更常见的是在创建索引时指定设置(如分片数、副本数)和映射。
http request
PUT /products
{
"settings": {
"index": {
"number_of_shards": 2, // 指定 2 个主分片
"number_of_replicas": 1 // 指定 1 个副本分片(在单节点上不会完全生效)
}
},
"mappings": {
"properties": {
"name": { "type": "text" }, // 商品名称,用于全文搜索
"description": { "type": "text" }, // 商品描述,全文搜索
"price": { "type": "double" }, // 价格,数值类型
"stock_quantity": { "type": "integer" }, // 库存,整数
"category": { "type": "keyword" }, // 分类,精确匹配/聚合
"tags": { "type": "keyword" }, // 标签,数组,精确匹配/聚合
"available": { "type": "boolean" }, // 是否可用,布尔值
"created_at": { "type": "date" } // 创建时间,日期类型
}
}
}
- 更常见的是在创建索引时指定设置(如分片数、副本数)和映射。
- 查看索引列表:
http request
GET /_cat/indices?v - 查看特定索引的映射:
http request
GET /products/_mapping - 删除索引:
- 警告: 删除索引会永久删除其中的所有数据!请谨慎操作。
http request
DELETE /my_first_index
- 警告: 删除索引会永久删除其中的所有数据!请谨慎操作。
- 创建索引 (Create Index):
-
文档 CRUD 操作 (Create, Read, Update, Delete):
-
索引文档 (Indexing Documents - Create/Update):
- 向
products
索引添加一个文档,让 ES 自动生成 ID。
http request
POST /products/_doc // 使用 POST 到 /_doc 端点自动生成 ID
{
"name": "Laptop Pro X",
"description": "High-performance laptop for professionals.",
"price": 1499.99,
"stock_quantity": 50,
"category": "Electronics",
"tags": ["laptop", "pro", "workstation"],
"available": true,
"created_at": "2024-07-15T10:00:00Z"
} - 响应会包含生成的文档 ID (
"_id": "some_auto_generated_id"
)。 - 指定文档 ID 为
1
。如果 ID1
不存在,则创建;如果存在,则覆盖整个文档(更新)。
http request
PUT /products/_doc/1 // 使用 PUT 和指定 ID
{
"name": "Wireless Mouse",
"description": "Ergonomic wireless mouse with long battery life.",
"price": 25.50,
"stock_quantity": 200,
"category": "Accessories",
"tags": ["mouse", "wireless", "ergonomic"],
"available": true,
"created_at": "2024-07-15T11:30:00Z"
} - 再添加几个文档用于后续查询:
```http request
POST /products/_doc
{
"name": "Mechanical Keyboard",
"description": "RGB mechanical keyboard with blue switches.",
"price": 89.90,
"stock_quantity": 100,
"category": "Accessories",
"tags": ["keyboard", "mechanical", "rgb"],
"available": true,
"created_at": "2024-07-14T15:00:00Z"
}
POST /products/_doc
{
"name": "4K Monitor",
"description": "27-inch 4K Ultra HD Monitor.",
"price": 349.00,
"stock_quantity": 30,
"category": "Electronics",
"tags": ["monitor", "4k", "display"],
"available": false, // 注意这个是 false
"created_at": "2024-07-13T09:00:00Z"
}
``` - 向
-
获取文档 (Read Document):
- 根据 ID 获取文档。
http request
GET /products/_doc/1 - 响应中的
_source
字段包含了文档的原始 JSON 内容。found: true
表示找到了文档。
- 根据 ID 获取文档。
-
检查文档是否存在 (HEAD Request):
- 不返回文档内容,只检查是否存在,效率更高。
http request
HEAD /products/_doc/1 - 如果存在,返回
200 OK
;如果不存在,返回404 Not Found
。
- 不返回文档内容,只检查是否存在,效率更高。
-
更新文档 (Update Document):
- 部分更新 (Partial Update): 只更新指定字段,不影响其他字段。推荐使用
_update
API。 - 例如,将 ID 为
1
的无线鼠标价格改为29.99
,并添加一个新标签 "office"。
http request
POST /products/_update/1
{
"doc": {
"price": 29.99,
"tags": ["mouse", "wireless", "ergonomic", "office"] // 注意:会替换整个 tags 数组
}
} - 使用脚本更新 (Scripted Update): 可以执行更复杂的更新逻辑,例如增加库存。
- 将 ID 为
1
的鼠标库存增加 10。
http request
POST /products/_update/1
{
"script": {
"source": "ctx._source.stock_quantity += params.amount", // ctx._source 引用当前文档
"lang": "painless", // Painless 是 ES 的默认脚本语言
"params": {
"amount": 10 // 参数传递给脚本
}
}
} - 再次
GET /products/_doc/1
查看更新后的结果。
- 部分更新 (Partial Update): 只更新指定字段,不影响其他字段。推荐使用
-
删除文档 (Delete Document):
- 根据 ID 删除文档。
http request
DELETE /products/_doc/1 - 响应会显示
result: "deleted"
。
- 根据 ID 删除文档。
-
-
搜索文档 (Searching Documents):
-
这是 Elasticsearch 的核心功能。ES 提供了强大的基于 JSON 的查询领域特定语言 (Query DSL)。
-
匹配所有文档 (Match All):
- 获取索引中的所有文档(默认最多返回 10 条)。
http request
GET /products/_search
{
"query": {
"match_all": {}
}
} - 响应结构:
took
(耗时毫秒),timed_out
,_shards
(分片信息),hits
(命中的结果)。hits.total
是匹配的总文档数,hits.max_score
是最高相关性得分,hits.hits
是一个包含实际文档的数组(每个文档包含_index
,_id
,_score
,_source
)。
- 获取索引中的所有文档(默认最多返回 10 条)。
-
分页 (Pagination):
- 使用
from
和size
参数进行分页。from
是起始文档的偏移量(从 0 开始),size
是每页返回的文档数量。
http request
GET /products/_search
{
"from": 0, // 从第 0 个开始
"size": 2, // 返回 2 个
"query": {
"match_all": {}
}
}
- 使用
-
全文搜索 (
match
query):- 在分析过的字段(通常是
text
类型)上进行搜索。查询字符串也会被分析。 - 搜索名称或描述中包含 "laptop" 的产品。
http request
GET /products/_search
{
"query": {
"match": {
"description": "high performance laptop" // 查询词会被分析 ("high", "performance", "laptop")
}
}
} match
查询会计算相关性得分 (_score
),得分越高的文档排在前面。
- 在分析过的字段(通常是
-
短语搜索 (
match_phrase
query):- 要求查询词语按顺序出现在字段中。
- 搜索描述中精确包含短语 "mechanical keyboard" 的产品。
http request
GET /products/_search
{
"query": {
"match_phrase": {
"description": "mechanical keyboard"
}
}
}
-
精确匹配 (
term
query):- 在未分析过的字段(通常是
keyword
类型)上进行精确匹配。查询词不会被分析。 - 查找分类 (category) 精确为 "Electronics" 的产品。
http request
GET /products/_search
{
"query": {
"term": {
"category": "Electronics" // category 是 keyword 类型,精确匹配
// 如果用 "electronics" (小写) 就匹配不到,因为 keyword 不区分大小写除非特殊配置
}
}
} - 查找标签 (tags) 包含 "rgb" 的产品 (tags 是
keyword
数组)。
http request
GET /products/_search
{
"query": {
"term": {
"tags": "rgb"
}
}
}
- 在未分析过的字段(通常是
-
多条件组合 (
bool
query):-
用于组合多个查询子句,是最常用的复合查询。包含四种子句:
must
: 子句必须匹配,并且计算得分。相当于逻辑 AND。filter
: 子句必须匹配,但不计算得分(会缓存,性能更好)。用于过滤数据,相当于不计分的 AND。推荐用于精确匹配、范围查询等过滤场景。should
: 子句可以选择性匹配,匹配越多得分越高。相当于逻辑 OR。如果bool
查询内没有must
或filter
子句,则should
子句中至少要匹配一个。must_not
: 子句必须不匹配。相当于逻辑 NOT。
-
示例: 查找分类为 "Accessories",并且价格低于 100,并且标签包含 "keyboard" 或 "mouse" 的产品。
http request
GET /products/_search
{
"query": {
"bool": {
"filter": [ // 使用 filter 进行精确匹配和范围过滤,效率高
{ "term": { "category": "Accessories" } },
{ "range": { "price": { "lt": 100 } } } // lt = less than
],
"should": [ // 使用 should 实现 OR 逻辑
{ "term": { "tags": "keyboard" } },
{ "term": { "tags": "mouse" } }
],
"minimum_should_match": 1 // 要求至少匹配一个 should 子句
}
}
} - 示例: 查找所有可用的 (
available: true
) 电子产品 (category: Electronics
)。
http request
GET /products/_search
{
"query": {
"bool": {
"filter": [
{ "term": { "available": true } },
{ "term": { "category": "Electronics" } }
]
}
}
}
-
-
排序 (Sorting):
- 默认按相关性得分 (
_score
) 降序排列。可以指定按一个或多个字段排序。 - 按价格升序排列。
http request
GET /products/_search
{
"query": { "match_all": {} },
"sort": [
{ "price": { "order": "asc" } } // asc = ascending (升序), desc = descending (降序)
]
} - 先按分类升序,再按价格降序。
http request
GET /products/_search
{
"query": { "match_all": {} },
"sort": [
{ "category": { "order": "asc" } },
{ "price": { "order": "desc" } }
]
} - 注意: 对
text
字段排序通常没有意义且效率低下。排序应主要在keyword
,numeric
,date
,boolean
等类型的字段上进行。如果需要在text
字段上排序,通常需要为其启用fielddata
(内存消耗大)或使用多字段映射(为其添加一个keyword
子字段)。
- 默认按相关性得分 (
-
-
聚合 (Aggregations):
- 聚合允许你对数据进行统计分析,类似于 SQL 中的
GROUP BY
和聚合函数(COUNT, SUM, AVG, MIN, MAX 等)。 -
基本概念: 聚合可以嵌套,形成复杂的分析结果。通常与查询结合使用,对查询结果进行聚合。如果你只想获取聚合结果而不需要命中的文档,可以设置
"size": 0
。 -
指标聚合 (Metrics Aggregations): 计算数值指标。
- 计算所有产品的平均价格。
http request
GET /products/_search
{
"size": 0, // 不需要返回文档本身
"aggs": { // "aggs" 或 "aggregations" 都可以
"average_price": { // 给这个聚合起个名字
"avg": { // 使用 avg 聚合类型
"field": "price" // 指定要计算平均值的字段
}
}
}
} - 同时计算最低、最高、总库存量。
http request
GET /products/_search
{
"size": 0,
"aggs": {
"min_stock": { "min": { "field": "stock_quantity" } },
"max_stock": { "max": { "field": "stock_quantity" } },
"total_stock": { "sum": { "field": "stock_quantity" } }
}
}
- 计算所有产品的平均价格。
-
桶聚合 (Bucket Aggregations): 将文档划分到不同的“桶”中,类似于
GROUP BY
。- 按产品分类 (category) 统计各类产品的数量。
http request
GET /products/_search
{
"size": 0,
"aggs": {
"products_by_category": { // 聚合名称
"terms": { // 使用 terms 聚合类型,按字段值分组
"field": "category" // 指定分组依据的字段 (必须是 keyword, numeric, boolean 等精确值类型)
}
}
}
} - 响应会包含一个
aggregations
块,里面有products_by_category
,其buckets
数组列出了每个分类(桶的 key)及其对应的文档数量 (doc_count
)。
- 按产品分类 (category) 统计各类产品的数量。
-
嵌套聚合 (Nested Aggregations): 在桶内进行进一步聚合。
- 按分类统计产品数量,并计算每个分类下产品的平均价格。
http request
GET /products/_search
{
"size": 0,
"aggs": {
"products_by_category": {
"terms": { "field": "category" },
"aggs": { // 在 terms 聚合内部嵌套新的 aggs
"average_price_in_category": {
"avg": { "field": "price" } // 计算每个桶内的平均价格
}
}
}
}
}
- 按分类统计产品数量,并计算每个分类下产品的平均价格。
- 聚合允许你对数据进行统计分析,类似于 SQL 中的
聚合是 ES 强大的数据分析能力的体现,值得花更多时间深入学习各种聚合类型(如 histogram
, date_histogram
, range
, filter
, nested
等)。
第五章:深入理解分析与映射
-
分析 (Analysis):
- 分析是将文本(
text
类型字段)转换为词项(terms)以创建倒排索引的过程。 - 一个分析器 (Analyzer) 通常由三部分组成:
- 字符过滤器 (Character Filters): 在分词前对原始文本进行处理(如去除 HTML 标签)。0 个或多个。
- 分词器 (Tokenizer): 将文本流分割成单个词项(如按空格、标点分词)。必须有 1 个。
- 词项过滤器 (Token Filters): 对分词器产生的词项进行处理(如转小写、去除停用词、词干提取)。0 个或多个。
- ES 内置了多种分析器(如
standard
,simple
,whitespace
,keyword
,english
,chinese
等),也可以自定义分析器。 - 使用 Analyze API 测试分析过程:
http request
GET /_analyze
{
"analyzer": "standard", // 使用标准分析器
"text": "Elasticsearch is FUN!"
}- 响应会显示分析后的词项 (
tokens
),如elasticsearch
,is
,fun
。
http request
GET /_analyze
{
"analyzer": "whitespace", // 使用空格分词器
"text": "Elasticsearch is FUN!"
} - 响应词项可能是
Elasticsearch
,is
,FUN!
(大小写和标点保留)。
- 响应会显示分析后的词项 (
- 在映射中为
text
字段指定分析器:
http request
PUT /my_index_with_analyzer
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "english" // 为 title 字段指定 english 分析器
},
"content": {
"type": "text",
"analyzer": "standard" // content 字段使用 standard 分析器
}
}
}
}
- 分析是将文本(
-
显式映射的重要性:
- 虽然动态映射很方便,但它可能做出不符合预期的类型推断(例如,将数字 ID 推断为
long
而不是keyword
,导致无法精确匹配)。 - 显式定义映射可以:
- 确保字段类型正确,避免后续问题。
- 精确控制字段是否被索引 (
index: true/false
)。 - 为
text
字段选择合适的分析器。 - 启用特定功能,如
fielddata
(用于 text 字段排序/聚合,慎用)或doc_values
(用于排序/聚合的列式存储,默认开启)。 - 使用多字段 (Multi-fields) 为同一个源字段提供不同的索引方式。例如,一个
city
字段,既需要全文搜索(text
类型),又需要精确匹配和聚合(keyword
类型)。
json
"mappings": {
"properties": {
"city": {
"type": "text", // 主要用于全文搜索
"fields": { // 添加一个 keyword 子字段
"keyword": {
"type": "keyword", // 用于精确匹配、排序、聚合
"ignore_above": 256 // 超过长度则不索引 (keyword 限制)
}
}
}
}
} - 查询时,可以用
city
进行全文搜索,用city.keyword
进行精确匹配或聚合。
- 虽然动态映射很方便,但它可能做出不符合预期的类型推断(例如,将数字 ID 推断为
第六章:Elastic Stack 生态简介与 2024 年关注点
-
Elastic Stack (ELK/ECK):
- Kibana: (已介绍) 数据可视化、探索和管理界面。提供仪表盘、图表、地图、画布、Lens 等工具。
- Logstash: 服务器端数据处理管道,用于从多种来源(文件、数据库、消息队列等)收集数据,进行转换、过滤和丰富,然后发送到 Elasticsearch 或其他目的地。灵活但资源消耗相对较高。
- Beats: 轻量级数据采集器(Shippers),安装在源服务器上,用于收集特定类型的数据并直接发送到 Elasticsearch 或 Logstash。
Filebeat
: 收集日志文件。Metricbeat
: 收集系统和服务的指标。Packetbeat
: 监控网络流量。Winlogbeat
: 收集 Windows 事件日志。Auditbeat
: 收集审计数据。Heartbeat
: 监控服务可用性(Uptime)。
- 通常的工作流是:Beats (采集) -> Logstash (可选,复杂处理) -> Elasticsearch (存储和索引) -> Kibana (可视化和查询)。对于简单场景,也可以 Beats -> Elasticsearch -> Kibana。
-
2024 年及未来的关注点:
- 向量搜索 (Vector Search) / AI: ES 正在大力投入向量数据库能力,支持存储和搜索高维向量(Embeddings),用于实现语义搜索、图像搜索、推荐系统等 AI 应用。
dense_vector
字段类型和knn
(k-Nearest Neighbors) 搜索是核心。这是当前非常热门的方向。 - Serverless / Elastic Cloud: Elastic 提供的云服务 (Elastic Cloud) 持续发展,推出了 Serverless 产品,进一步简化了运维管理和成本优化,按需付费。对于不想自己管理集群的用户是很好的选择。
- ES|QL (Elasticsearch Query Language): 推出了一种新的基于管道 (pipe) 的查询语言 ES|QL,旨在简化数据探索和分析流程,语法类似 SQL 和其他流行的数据查询语言。
- 安全默认开启: 自 8.x 版本起,安全特性(认证、TLS 加密)默认开启,提升了开箱即用的安全性。初学者需要注意配置密码和处理 HTTPS。
- 性能和效率: 每个版本都在持续优化索引速度、查询性能、存储效率和资源利用率。
- 向量搜索 (Vector Search) / AI: ES 正在大力投入向量数据库能力,支持存储和搜索高维向量(Embeddings),用于实现语义搜索、图像搜索、推荐系统等 AI 应用。
结语与后续学习
恭喜你!通过本教程,你已经对 Elasticsearch 的核心概念、安装部署、基本 CRUD 操作、搜索查询、聚合分析以及映射有了初步的了解。你现在已经具备了使用 Elasticsearch 解决实际问题的基础能力。
然而,Elasticsearch 的世界远不止于此。要成为一名熟练的 ES 开发者或管理员,你还需要继续探索:
- 更复杂的查询 DSL: 深入学习
bool
查询的各种组合、范围查询 (range
)、存在查询 (exists
)、模糊查询 (fuzzy
)、通配符查询 (wildcard
)、正则表达式查询 (regexp
)、地理空间查询 (geo_shape
,geo_point
) 等。 - 高级聚合: 掌握更多聚合类型,如
histogram
,date_histogram
,nested
,reverse_nested
,significant_terms
等,以及管道聚合 (Pipeline Aggregations)。 - 索引管理进阶: 索引模板 (Index Templates)、索引生命周期管理 (ILM - Index Lifecycle Management)、别名 (Aliases)、Reindex API、Shrink/Split API。
- 集群管理与调优: 节点角色、分片分配策略、集群监控、性能优化(查询优化、索引优化、JVM 调优)、备份与恢复 (Snapshot/Restore)。
- 数据建模: 如何根据业务需求设计高效的索引映射,处理父子关系 (
join
字段) 或嵌套文档 (nested
类型)。 - Elastic Stack 整合: 深入学习 Kibana 的可视化能力,以及如何使用 Logstash 和 Beats 构建完整的数据管道。
- 向量搜索实践: 了解 Embeddings 的生成,使用
dense_vector
和knn
实现语义搜索。 - 安全配置: 用户角色管理、字段级/文档级安全、配置 TLS/SSL 证书。
最好的学习方式是实践! 尝试在你自己的项目中使用 Elasticsearch,或者找一些公开数据集导入 ES 进行探索。阅读官方文档 (https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html) 是最权威的学习途径。
Elasticsearch 是一个功能强大且不断发展的工具。希望这篇 2024 年的入门教程能为你打开探索 Elasticsearch 世界的大门,祝你在数据搜索与分析的旅程中一帆风顺!