Elasticsearch (ES) 教程:初学者入门指南
Elasticsearch (ES) 教程:初学者入门指南 (超详细版)
摘要
Elasticsearch (简称 ES) 是一个基于 Apache Lucene 构建的开源、分布式、RESTful 风格的搜索和数据分析引擎。它以其强大的全文搜索能力、近乎实时的搜索和分析性能、高可用性和可扩展性而闻名。本指南旨在为初学者提供一个全面而详细的入门教程,涵盖 ES 的核心概念、安装部署、基本操作、查询技巧以及一些进阶概念,帮助您快速上手并理解 Elasticsearch 的强大之处。
目录
- Elasticsearch 是什么?
- 定义与核心优势
- 常见应用场景
- 核心概念解析
- 近实时 (Near Real-Time, NRT)
- 集群 (Cluster)
- 节点 (Node)
- 索引 (Index)
- 类型 (Type) - (历史概念,需注意)
- 文档 (Document)
- 字段 (Field)
- 映射 (Mapping)
- 分片 (Shard)
- 副本 (Replica)
- 安装与配置
- 环境准备 (Java 环境)
- 下载与安装 Elasticsearch
- 运行 Elasticsearch
- 安装 Kibana (可视化工具)
- 使用 Docker 快速部署 (推荐)
- 基本操作 (CRUD & Bulk API)
- 与 ES 交互:RESTful API
- 创建索引 (Index)
- 添加/更新文档 (Indexing Documents)
PUT /index/_doc/id
POST /index/_doc
(自动生成 ID)
- 获取文档 (Retrieving Documents)
- 删除文档 (Deleting Documents)
- 更新文档 (Updating Documents) - 部分更新
- 批量操作 (Bulk API)
- 核心功能:搜索 (Searching)
- 搜索基础:
_search
API - URI 搜索 vs 请求体搜索
- 查询 DSL (Query DSL) 入门
match_all
查询:匹配所有文档match
查询:标准全文搜索term
查询:精确匹配 (未分词)terms
查询:匹配多个精确值- 组合查询 (
bool
query)must
: 必须匹配 (AND)should
: 应该匹配 (OR)must_not
: 必须不匹配 (NOT)filter
: 过滤子句 (不计算得分,性能更优)
- 范围查询 (
range
query)
- 排序 (
sort
) - 分页 (
from
,size
) - 高亮 (
highlighting
)
- 搜索基础:
- 映射 (Mapping) 详解
- 什么是映射?
- 动态映射 (Dynamic Mapping)
- 显式映射 (Explicit Mapping)
- 核心数据类型 (
text
,keyword
,integer
,long
,float
,double
,boolean
,date
等) text
vskeyword
的区别- 定义和更新映射
- 文本分析 (Analysis) 简介
- 分析器 (Analyzer) 的作用
- 分析过程:字符过滤器 -> 分词器 -> Token 过滤器
- 内置分析器 (
standard
,simple
,whitespace
,keyword
等) - 自定义分析器 (概述)
- 聚合 (Aggregations) 入门
- 聚合的概念 (类似 SQL 的
GROUP BY
+ 聚合函数) - 指标聚合 (Metrics Aggregations):
sum
,avg
,min
,max
,stats
,value_count
等 - 桶聚合 (Bucket Aggregations):
terms
,range
,date_histogram
,histogram
等 - 聚合的基本使用示例
- 聚合的概念 (类似 SQL 的
- 进阶话题与后续学习
- 分布式特性深入:分片路由、故障转移
- 性能调优:索引优化、查询优化、硬件选择
- 安全配置:用户认证、授权、TLS/SSL 加密
- 插件生态
- 与其他大数据工具集成 (Logstash, Beats, Spark等)
- 总结
1. Elasticsearch 是什么?
定义与核心优势
Elasticsearch 是一个基于 Apache Lucene 库构建的开源、分布式、RESTful 风格的搜索和数据分析引擎。你可以把它想象成一个功能极其强大的 NoSQL 数据库,但它的核心优势在于搜索和分析。
核心优势:
- 速度快: 基于 Lucene 构建,对全文索引和搜索进行了深度优化,查询通常能在毫秒级别返回结果。
- 分布式: 天生支持分布式架构,可以轻松横向扩展到数百甚至数千台服务器,处理 PB 级别的数据。
- 易用性 (RESTful API): 通过标准的 HTTP 方法 (GET, POST, PUT, DELETE) 和 JSON 进行交互,学习曲线相对平缓,与各种编程语言都能轻松集成。
- 高可用: 通过副本机制,确保部分节点宕机时数据不丢失,服务不中断。
- 功能丰富: 不仅仅是全文搜索,还提供强大的结构化搜索、地理空间搜索、聚合分析、度量计算等功能。
- 近实时: 数据写入后,通常在秒级内即可被搜索到 (NRT)。
常见应用场景
Elasticsearch 的应用场景非常广泛,包括但不限于:
- 站内搜索: 为网站或应用程序提供强大的内容搜索功能 (如电商网站的商品搜索、博客的文章搜索)。
- 日志分析 (ELK/Elastic Stack): 作为 Elastic Stack (Elasticsearch, Logstash, Kibana, Beats) 的核心,用于收集、存储、搜索和分析大量的日志数据,进行监控和故障排查。
- 应用性能监控 (APM): 收集和分析应用程序的性能指标、追踪请求链路。
- 商业智能 (BI): 对业务数据进行复杂的聚合分析和可视化,发现商业洞察。
- 安全信息和事件管理 (SIEM): 实时分析安全日志,检测威胁。
- 地理空间数据分析: 存储和查询地理位置信息,实现基于位置的服务 (LBS)。
2. 核心概念解析
理解以下核心概念是掌握 Elasticsearch 的基础:
- 近实时 (Near Real-Time, NRT): 数据从索引操作完成到能够被搜索到,存在一个短暂的延迟(通常是 1 秒,可配置),而不是严格意义上的实时。这是因为 ES 需要执行一个轻量级的
refresh
操作,使新数据对搜索可见。 - 集群 (Cluster): 一个或多个节点(服务器)的集合,它们共同持有你的完整数据,并提供跨节点的联合索引和搜索能力。一个集群有一个唯一的名称(默认为 "elasticsearch"),节点通过集群名称加入。
- 节点 (Node): 集群中的一个服务器实例。节点负责存储数据、参与集群的索引和搜索操作。每个节点默认也会有一个唯一的名称。节点有不同的角色(Master 节点、Data 节点、Ingest 节点、Coordinating 节点等),可以根据需求配置。
- 索引 (Index): 类似于关系数据库中的“数据库” (Database)。它是具有相似特征的文档的集合。例如,可以有一个
products
索引存储所有商品信息,一个logs
索引存储所有日志数据。索引名称必须小写。 - 类型 (Type): (重要提示: 在 ES 6.x 及以后版本中,一个索引只允许包含一个类型
_doc
。在 ES 7.x 中类型被完全弃用,在 8.x 中已移除)。在早期版本中,类型类似于关系数据库中的“表” (Table),用于在一个索引内对文档进行逻辑分类。现在,推荐将不同“类型”的数据存储在不同的索引中。 - 文档 (Document): 类似于关系数据库中的“行” (Row)。它是可以被索引的基本信息单元,以 JSON (JavaScript Object Notation) 格式表示。每个文档都存储在一个索引中,并拥有一个唯一的 ID。
- 字段 (Field): 类似于关系数据库中的“列” (Column)。文档由字段组成,每个字段都有其数据类型(如文本、数字、日期、布尔值等)。
- 映射 (Mapping): 定义索引中文档及其字段如何存储和索引的过程。类似于关系数据库中的“模式” (Schema)。映射定义了每个字段的数据类型以及它们应如何被 Lucene 索引(例如,是否需要分词、使用哪种分词器等)。
- 分片 (Shard): 由于单个节点存储能力和处理能力的限制,ES 允许将一个索引水平分割成多个部分,称为分片。每个分片都是一个功能齐全且独立的“索引”,可以托管在集群中的任何节点上。分片使得:
- 水平扩展: 允许存储超过单节点容量的数据。
- 并行处理: 查询可以在多个分片上并行执行,提高性能。
- 创建索引时需要指定主分片 (Primary Shard) 的数量,此数量一旦设定后不能更改。
- 副本 (Replica): 每个主分片可以有一个或多个副本分片 (Replica Shard)。副本是主分片的一个精确拷贝。副本提供:
- 高可用性: 如果主分片所在的节点宕机,副本分片可以提升为新的主分片,保证数据不丢失。
- 读性能扩展: 搜索请求可以同时在主分片和副本分片上处理,提高查询吞吐量。
- 副本分片的数量可以在索引创建后动态调整。副本分片不会与其主分片分配在同一个节点上。
关系类比 (不完全精确,仅供理解):
- Elasticsearch Cluster ≈ RDBMS Instance
- Index ≈ Database
- ~~Type (Deprecated) ≈ Table~~ (现在推荐一个 Index ≈ 一个 Table 的概念)
- Document ≈ Row
- Field ≈ Column
- Mapping ≈ Schema
- Shard ≈ Table Partition (水平分区)
- Replica ≈ Table Partition Replica (分区副本)
3. 安装与配置
环境准备
Elasticsearch 是用 Java 编写的,需要 Java 运行环境 (JRE)。请确保安装了 ES 版本兼容的 JDK 或 JRE。可以从 Oracle官网 或 OpenJDK 社区下载。安装后,检查 Java 版本:
bash
java -version
下载与安装 Elasticsearch
访问 Elastic 官网 (https://www.elastic.co/downloads/elasticsearch) 下载适合你操作系统的 ES 安装包(如 .tar.gz
, .zip
, .deb
, .rpm
)。
以 Linux/macOS 下使用 .tar.gz
包为例:
```bash
下载 (请替换为最新版本链接)
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.x.y-linux-x86_64.tar.gz
wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-8.x.y-linux-x86_64.tar.gz.sha512
校验下载文件 (可选但推荐)
shasum -a 512 -c elasticsearch-8.x.y-linux-x86_64.tar.gz.sha512
解压
tar -xzf elasticsearch-8.x.y-linux-x86_64.tar.gz
进入目录
cd elasticsearch-8.x.y/
```
运行 Elasticsearch
进入解压后的目录,执行启动脚本:
bash
./bin/elasticsearch
首次启动时,ES 会进行一些初始化设置,并可能在控制台打印出重要的信息,例如集群名称、节点名称、默认密码 (如果启用了安全特性) 以及 Kibana 的注册 Token。请务必留意这些信息。
默认情况下,ES 监听 localhost:9200
。你可以通过 curl
或浏览器访问 http://localhost:9200
来检查 ES 是否成功运行。如果启用了安全特性,访问时需要提供用户名和密码(通常是 elastic
和启动时生成的密码)。
```bash
检查 ES 是否运行 (如果需要认证,添加 -u elastic:PASSWORD)
curl http://localhost:9200
或者 (带认证)
curl -u elastic:YOUR_GENERATED_PASSWORD -k https://localhost:9200 # 注意:新版本默认启用 HTTPS 和安全特性,-k 忽略证书验证
成功会返回类似以下的 JSON 信息:
json
{
"name" : "your_node_name",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "...",
"version" : { ... },
"tagline" : "You Know, for Search"
}
```
注意: ES 8.x 版本默认启用了安全特性 (HTTPS、用户认证)。初学者如果想简化体验,可以在 config/elasticsearch.yml
文件中禁用安全特性(不推荐在生产环境这样做!):
yaml
xpack.security.enabled: false
xpack.security.http.ssl.enabled: false
xpack.security.transport.ssl.enabled: false
修改配置后需要重启 ES。
安装 Kibana (可视化工具)
Kibana 是 Elasticsearch 的官方可视化工具,提供了强大的数据探索、可视化和仪表盘功能,以及方便的开发工具 (Dev Tools) 来与 ES API 交互。
下载并安装 Kibana (确保版本与 ES 兼容):
```bash
下载 (请替换为最新版本链接)
wget https://artifacts.elastic.co/downloads/kibana/kibana-8.x.y-linux-x86_64.tar.gz
wget https://artifacts.elastic.co/downloads/kibana/kibana-8.x.y-linux-x86_64.tar.gz.sha512
shasum -a 512 -c kibana-8.x.y-linux-x86_64.tar.gz.sha512
tar -xzf kibana-8.x.y-linux-x86_64.tar.gz
cd kibana-8.x.y/
修改 Kibana 配置文件 `config/kibana.yml`,指定 Elasticsearch 的地址:
yaml
如果 ES 在本机且端口为 9200 (且禁用了安全特性)
elasticsearch.hosts: ["http://localhost:9200"]
如果 ES 启用了安全特性 (默认)
elasticsearch.hosts: ["https://localhost:9200"]
需要配置用户名密码或 Token 等进行连接,参考官方文档
运行 Kibana:
bash
./bin/kibana
``
http://localhost:5601`。打开浏览器访问该地址。首次访问可能需要配置连接 ES 的信息(如使用 ES 启动时生成的 Kibana Token)。
Kibana 默认运行在
使用 Docker 快速部署 (推荐)
对于学习和开发,使用 Docker 是最快捷方便的方式。
单节点 ES + Kibana (无安全特性,仅供学习):
bash
docker network create elastic
docker run -d --name es01 --net elastic -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "xpack.security.enabled=false" docker.elastic.co/elasticsearch/elasticsearch:8.x.y
docker run -d --name kib01 --net elastic -p 5601:5601 -e "ELASTICSEARCH_HOSTS=http://es01:9200" docker.elastic.co/kibana/kibana:8.x.y
将 8.x.y
替换为你想要使用的具体版本号。等待容器启动后,即可通过 http://localhost:9200
访问 ES,http://localhost:5601
访问 Kibana。
单节点 ES + Kibana (带安全特性,推荐接近生产的方式):
```bash
docker network create elastic
docker run -d --name es01 --net elastic -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "ELASTIC_PASSWORD=YourStrongPassword" docker.elastic.co/elasticsearch/elasticsearch:8.x.y
启动后查看容器日志获取 Kibana Token: docker logs es01
或者使用设置的密码 elastic / YourStrongPassword
docker run -d --name kib01 --net elastic -p 5601:5601 -e "ELASTICSEARCH_HOSTS=https://es01:9200" -e "ELASTICSEARCH_USERNAME=elastic" -e "ELASTICSEARCH_PASSWORD=YourStrongPassword" -e "ELASTICSEARCH_SSL_VERIFICATIONMODE=none" docker.elastic.co/kibana/kibana:8.x.y
访问 https://localhost:9200 和 http://localhost:5601
浏览器访问 https://localhost:9200 可能需要接受自签名证书
登录 Kibana 使用 elastic / YourStrongPassword
```
4. 基本操作 (CRUD & Bulk API)
与 ES 交互:RESTful API
Elasticsearch 主要通过 HTTP RESTful API 进行交互。常用的 HTTP 方法包括:
GET
: 获取信息(如获取文档、搜索、获取集群状态)。POST
: 创建资源(如创建文档时自动生成 ID)或执行操作(如搜索、批量操作)。PUT
: 创建或更新资源(如创建索引、创建/更新指定 ID 的文档)。DELETE
: 删除资源(如删除文档、删除索引)。
请求和响应体通常使用 JSON 格式。推荐使用 Kibana Dev Tools 或 curl
工具,或者各种编程语言的 ES 客户端库来与 ES 交互。以下示例主要使用 curl
格式,你可以在 Kibana Dev Tools 中直接运行这些命令(去掉 curl -X...
部分,保留方法和路径,以及 JSON 体)。
(假设 ES 运行在 localhost:9200 且禁用了安全特性,或已正确配置认证)
创建索引 (Index)
创建一个名为 my_first_index
的索引:
bash
curl -X PUT "localhost:9200/my_first_index"
如果成功,ES 会返回:
json
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "my_first_index"
}
也可以在创建时指定分片和副本数量(默认为 1 个主分片,1 个副本分片):
bash
curl -X PUT "localhost:9200/my_custom_index" -H 'Content-Type: application/json' -d'
{
"settings": {
"index": {
"number_of_shards": 3,
"number_of_replicas": 1
}
}
}
'
添加/更新文档 (Indexing Documents)
向索引中添加数据称为“索引文档”。
方法一:PUT /index/_doc/id
(指定文档 ID)
如果 ID 已存在,则会更新文档(替换整个文档);如果 ID 不存在,则会创建新文档。
bash
curl -X PUT "localhost:9200/my_first_index/_doc/1" -H 'Content-Type: application/json' -d'
{
"user": "Alice",
"message": "Hello Elasticsearch!",
"post_date": "2024-01-01T10:00:00"
}
'
响应会包含索引、ID、版本号等信息:
json
{
"_index" : "my_first_index",
"_id" : "1",
"_version" : 1,
"result" : "created", // 或 "updated"
"_shards" : { ... },
"_seq_no" : 0,
"_primary_term" : 1
}
方法二:POST /index/_doc
(让 ES 自动生成 ID)
每次执行都会创建新文档。
bash
curl -X POST "localhost:9200/my_first_index/_doc" -H 'Content-Type: application/json' -d'
{
"user": "Bob",
"message": "Learning ES is fun",
"post_date": "2024-01-02T11:30:00"
}
'
响应中 _id
会是一个 ES 自动生成的唯一字符串。
获取文档 (Retrieving Documents)
通过 GET /index/_doc/id
获取指定 ID 的文档:
bash
curl -X GET "localhost:9200/my_first_index/_doc/1"
响应中 _source
字段包含原始 JSON 文档:
json
{
"_index" : "my_first_index",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"user" : "Alice",
"message" : "Hello Elasticsearch!",
"post_date" : "2024-01-01T10:00:00"
}
}
如果文档不存在,found
会是 false
。
删除文档 (Deleting Documents)
通过 DELETE /index/_doc/id
删除指定 ID 的文档:
bash
curl -X DELETE "localhost:9200/my_first_index/_doc/1"
响应会告知操作结果。
更新文档 (Updating Documents) - 部分更新
使用 POST /index/_update/id
API 可以只更新文档的部分字段,而不是替换整个文档。
bash
curl -X POST "localhost:9200/my_first_index/_update/1" -H 'Content-Type: application/json' -d'
{
"doc": {
"message": "Updated message!",
"tags": ["elasticsearch", "tutorial"]
}
}
'
这会将 ID 为 1 的文档的 message
字段更新,并添加 tags
字段。如果文档不存在,会报错。也可以使用 upsert
参数实现在文档不存在时插入新文档。
批量操作 (Bulk API)
当需要执行大量索引、更新或删除操作时,逐条发送请求效率很低。_bulk
API 允许在一个请求中执行多个操作。
Bulk 请求体格式比较特殊,每两行为一个操作单元:
第一行:描述操作类型(index
, create
, update
, delete
)和元数据(如 _index
, _id
)。
第二行:对于 index
, create
, update
操作,是文档数据或更新脚本(delete
操作没有第二行)。
注意:请求体最后必须有一个换行符!
```bash
curl -X POST "localhost:9200/_bulk" -H 'Content-Type: application/x-ndjson' -d'
{ "index" : { "_index" : "my_first_index", "_id" : "3" } }
{ "user" : "Charlie", "message" : "Bulk indexing example 1" }
{ "index" : { "_index" : "my_first_index", "_id" : "4" } }
{ "user" : "David", "message" : "Bulk indexing example 2" }
{ "update" : {"_id" : "1", "_index" : "my_first_index"} }
{ "doc" : {"views" : 100} }
{ "delete" : { "_index" : "my_first_index", "_id" : "2" } }
'
注意最后有一个换行符
```
响应会包含每个操作的结果。使用 Bulk API 可以显著提高写入性能。
5. 核心功能:搜索 (Searching)
搜索是 Elasticsearch 的核心能力。
搜索基础:_search
API
所有搜索请求都通过 _search
端点进行。可以针对特定索引 (/index_name/_search
)、多个索引 (/index1,index2/_search
) 或所有索引 (/_search
) 进行搜索。
URI 搜索 vs 请求体搜索
- URI 搜索: 将查询参数直接放在 URL 中。简单方便,但功能有限。
bash
# 查找 message 字段包含 "elasticsearch" 的文档
curl -X GET "localhost:9200/my_first_index/_search?q=message:elasticsearch" - 请求体搜索 (Request Body Search): 将查询逻辑放在请求体 (JSON) 中,使用 Query DSL。功能极其强大和灵活,是推荐的方式。
bash
curl -X GET "localhost:9200/my_first_index/_search" -H 'Content-Type: application/json' -d'
{
"query": {
// 查询语句放在这里
}
// 其他选项如排序、分页、高亮等也放在这里
}
'
查询 DSL (Query DSL) 入门
Query DSL (Domain Specific Language) 是一种基于 JSON 定义查询的灵活方式。主要包含两种类型的子句:
- 叶子查询子句 (Leaf Query Clauses): 用于在特定字段中查找特定值,如
match
,term
,range
。 - 复合查询子句 (Compound Query Clauses): 用于组合其他叶子或复合查询,以实现更复杂的逻辑,如
bool
查询。
一些常用的查询类型:
-
match_all
查询:匹配所有文档
json
{
"query": {
"match_all": {}
}
} -
match
查询:标准全文搜索
这是进行全文搜索的标准查询。它会先对查询字符串进行分词,然后查找包含这些词项的文档。
json
{
"query": {
"match": {
"message": "learning elasticsearch fun" // 会被分词为 "learning", "elasticsearch", "fun"
}
}
}
默认情况下,match
查询是 OR 逻辑(包含任何一个词项即可),可以通过operator
参数改为and
。 -
term
查询:精确匹配 (未分词)
用于查找未经分词的精确值。通常用于keyword
类型的字段、数字、日期或布尔值。
json
{
"query": {
"term": {
"user": "Alice" // 假设 user 字段是 keyword 类型或未分词的 text
}
}
}
重要: 如果对一个标准分词的text
字段使用term
查询,通常需要查询具体的词项(小写,去除标点等),而不是原始短语。例如,对于 "Hello Elasticsearch!",term
查询message: "Hello Elasticsearch!"
不会匹配,但term
查询message: "hello"
或message: "elasticsearch"
可能会匹配(取决于分词结果)。 -
terms
查询:匹配多个精确值
允许指定一个值的列表,匹配字段值是列表中任何一个的文档。
json
{
"query": {
"terms": {
"user": ["Alice", "Bob"] // 匹配 user 是 "Alice" 或 "Bob" 的文档
}
}
} -
组合查询 (
bool
query)
用于组合多个查询子句,是最常用的复合查询。有四种布尔逻辑:must
: 子句必须匹配。贡献得分。相当于逻辑 AND。should
: 子句应该匹配。匹配的越多,得分越高。相当于逻辑 OR。如果bool
查询中没有must
子句,则至少需要匹配一个should
子句。must_not
: 子句必须不匹配。在filter
上下文中执行,不贡献得分。相当于逻辑 NOT。filter
: 子句必须匹配,但在过滤上下文中执行。不计算得分,速度更快,且结果可被缓存。非常适合用于精确匹配、范围查询等只需要判断“是/否”的场景。
json
{
"query": {
"bool": {
"must": [
{ "match": { "message": "elasticsearch" } }
],
"filter": [
{ "term": { "status": "published" } },
{ "range": { "post_date": { "gte": "2024-01-01" } } }
],
"should": [
{ "match": { "tags": "tutorial" } }
],
"must_not": [
{ "match": { "author": "spam_user" } }
]
}
}
}
这个查询要求message
必须包含 "elasticsearch",并且status
必须是 "published",post_date
必须大于等于 2024-01-01,同时不能是spam_user
写的,如果tags
包含 "tutorial" 会获得更高的相关性得分。 -
范围查询 (
range
query)
查找字段值落在指定范围内的文档。适用于数字、日期等类型。
json
{
"query": {
"range": {
"views": {
"gte": 100, // Greater than or equal to
"lt": 1000 // Less than
}
}
}
}
常用操作符:gte
(>=),gt
(>),lte
(<=),lt
(<)。
排序 (sort
)
默认情况下,搜索结果按相关性得分 (_score
) 降序排列。可以使用 sort
参数按一个或多个字段排序。
json
{
"query": { "match_all": {} },
"sort": [
{ "post_date": { "order": "desc" } }, // 按 post_date 降序
{ "_score": { "order": "desc" } } // 日期相同则按得分降序
]
}
分页 (from
, size
)
size
: 指定每页返回多少条结果(默认为 10)。from
: 指定从第几条结果开始返回(默认为 0)。相当于偏移量。
json
{
"query": { "match": { "message": "elasticsearch" } },
"from": 10, // 跳过前 10 条
"size": 5 // 返回第 11 到 15 条
}
注意: 使用 from
和 size
进行深度分页(from
值很大时)会消耗大量资源。对于深度分页,推荐使用 search_after
参数或滚动查询 (Scroll API)。
高亮 (highlighting
)
在搜索结果中高亮显示匹配的查询词。
json
{
"query": {
"match": { "message": "elasticsearch fun" }
},
"highlight": {
"fields": {
"message": {} // 对 message 字段进行高亮
},
"pre_tags": ["<em>"], // 高亮起始标签
"post_tags": ["</em>"] // 高亮结束标签
}
}
高亮结果会出现在每个 hit
的 highlight
字段中。
6. 映射 (Mapping) 详解
什么是映射?
映射 (Mapping) 定义了 Elasticsearch 如何处理索引中的文档及其包含的字段。它规定了:
- 哪些字段被视为全文 (
text
)?哪些是精确值 (keyword
, 数字, 日期等)? - 字段的数据类型 (如
string
,integer
,date
,boolean
,object
,nested
等)。 - 字段值在索引前应如何处理(例如,使用哪个分析器 (Analyzer) 对文本进行分词)。
- 其他高级选项(是否索引、是否存储
_source
、格式化等)。
动态映射 (Dynamic Mapping)
当你索引一个文档到一个新索引(或向现有索引添加一个新字段)而没有预先定义映射时,Elasticsearch 会自动猜测字段类型并创建映射,这就是动态映射。
优点: 上手简单,无需预先定义结构。
缺点:
* 类型猜测可能不准确(例如,字符串可能被错误地映射为 text
而不是 keyword
,或者数字可能被错误地映射为 long
而不是 float
)。
* 可能导致不期望的分词行为。
* 可能导致 "映射爆炸" (mapping explosion),即过多唯一字段名导致集群元数据过大。
动态映射规则可以通过动态模板 (Dynamic Templates) 进行定制。
显式映射 (Explicit Mapping)
在生产环境中,强烈建议使用显式映射,即在索引第一个文档之前手动定义索引的映射。
优点:
* 对数据结构有完全的控制。
* 确保字段被正确地索引和分析。
* 优化存储和搜索性能。
定义映射: 在创建索引时通过 mappings
参数指定。
bash
curl -X PUT "localhost:9200/my_products" -H 'Content-Type: application/json' -d'
{
"settings": {
"number_of_shards": 1,
"number_of_replicas": 0
},
"mappings": {
"properties": {
"product_id": { "type": "keyword" },
"name": {
"type": "text",
"analyzer": "standard",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"description": { "type": "text", "analyzer": "english" },
"price": { "type": "float" },
"stock_count": { "type": "integer" },
"on_sale": { "type": "boolean" },
"tags": { "type": "keyword" },
"created_at": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss||epoch_millis" }
}
}
}
'
这个例子定义了 my_products
索引的映射:
* product_id
和 tags
是 keyword
类型,用于精确匹配、聚合和排序。
* name
是 text
类型,用于全文搜索(使用标准分词器)。同时,通过 fields
定义了一个名为 keyword
的多字段 (multi-field),允许对 name
字段也进行精确匹配和聚合(使用 name.keyword
)。
* description
是 text
类型,使用英文分词器。
* price
, stock_count
, on_sale
, created_at
分别定义为浮点数、整数、布尔值和日期类型。created_at
指定了接受的日期格式。
核心数据类型
text
: 用于索引全文(如文章内容、邮件正文)。这些字段会被分析(分词),以便进行全文搜索。不直接用于排序或聚合。keyword
: 用于索引结构化内容(如邮箱地址、主机名、状态码、标签、商品 ID)。这些字段不被分析(作为一个整体索引),适用于精确匹配、范围查询(如果值有序)、排序和聚合。- 数字类型:
long
,integer
,short
,byte
,double
,float
,half_float
,scaled_float
. date
: 用于日期和时间。可以指定多种格式。内部以毫秒时间戳存储。boolean
: 接受true
或false
。binary
: Base64 编码的二进制值。range
: 范围类型 (integer_range
,float_range
,long_range
,double_range
,date_range
).- 地理类型:
geo_point
(经纬度点),geo_shape
(复杂形状如多边形)。 - 复合类型:
object
(默认的 JSON 对象),nested
(用于索引对象数组,保持对象内字段关联性)。
text
vs keyword
的区别
这是初学者最容易混淆的地方:
-
text
字段:- 主要用途:全文搜索。
- 处理方式:内容会被分析器 (Analyzer) 处理(如分词、转小写、去除停用词等),生成多个词项 (term)。
- 存储:存储的是分析后的词项列表(倒排索引)。
- 查询:通常使用
match
查询。 - 排序/聚合:默认不开启 (
fielddata
默认禁用,因为它消耗大量内存)。如果需要,需要显式开启fielddata=true
(不推荐) 或使用多字段 (fields
) 定义一个keyword
子字段。 - 示例:"Quick brown fox" ->
quick
,brown
,fox
-
keyword
字段:- 主要用途:精确匹配、过滤、排序、聚合。
- 处理方式:内容不被分析,整个字符串作为一个单一的词项被索引。
- 存储:存储的是原始的完整字符串。
- 查询:通常使用
term
,terms
,prefix
,wildcard
,regexp
查询。 - 排序/聚合:天然支持。
- 示例:"Quick brown fox" ->
Quick brown fox
选择建议:
* 如果字段需要进行全文搜索(像搜索文章内容),用 text
。
* 如果字段用于精确匹配(如用户 ID、状态码)、排序或聚合,用 keyword
。
* 如果一个字段既需要全文搜索,又需要精确匹配/排序/聚合,使用 text
类型,并通过 fields
定义一个 keyword
子字段。
定义和更新映射
- 定义: 在创建索引时通过
mappings
指定。 - 更新: 只能向现有映射中添加新字段。不能修改现有字段的类型或其索引方式。如果需要修改现有字段,必须创建一个新索引(使用正确的映射),然后将数据从旧索引迁移到新索引(使用 Reindex API)。
bash
# 向现有索引 my_products 添加一个新字段 last_updated
curl -X PUT "localhost:9200/my_products/_mapping" -H 'Content-Type: application/json' -d'
{
"properties": {
"last_updated": {
"type": "date"
}
}
}
'
7. 文本分析 (Analysis) 简介
文本分析是将文本(如一句话或一篇文章)转换为可供搜索的词项 (term) 的过程。这是 text
字段实现全文搜索的核心机制。
分析器 (Analyzer) 的作用
分析器是执行文本分析任务的组件。一个分析器通常由三部分按顺序组成:
- 字符过滤器 (Character Filters): 在文本被分词之前对其进行预处理。例如,去除 HTML 标签、替换字符等。(0 个或多个)
- 分词器 (Tokenizer): 将文本流分割成独立的词项 (token)。例如,按空格或标点符号分割。(必须有 1 个)
- Token 过滤器 (Token Filters): 对分词器输出的词项进行处理。例如,转换为小写、删除停用词(如 "a", "the", "is")、添加同义词、词干提取(将词语还原为词根,如 "running" -> "run")等。(0 个或多个)
内置分析器
Elasticsearch 提供了许多内置的分析器,可以直接使用:
standard
Analyzer: 默认分析器。基于 Unicode 文本分割算法,按词分割,转小写。对大多数西方语言效果不错。simple
Analyzer: 按非字母字符分割,然后转小写。whitespace
Analyzer: 仅按空白字符分割。不转小写。keyword
Analyzer: “无操作”分析器,将整个输入字符串作为一个单独的词项输出。english
,french
,german
等语言分析器: 针对特定语言优化,包含该语言的停用词和词干提取规则。
可以使用 _analyze
API 测试分析器的效果:
```bash
curl -X POST "localhost:9200/_analyze" -H 'Content-Type: application/json' -d'
{
"analyzer": "standard",
"text": "Elasticsearch is FUN!"
}
'
响应会显示生成的 tokens: "elasticsearch", "is", "fun"
curl -X POST "localhost:9200/_analyze" -H 'Content-Type: application/json' -d'
{
"analyzer": "english",
"text": "Elasticsearch is FUN!"
}
'
响应会显示生成的 tokens: "elasticsearch", "fun" ("is" 被作为停用词移除)
```
自定义分析器 (概述)
当内置分析器无法满足需求时(例如,需要特定的分词逻辑、同义词处理、或组合使用不同的过滤器),可以在索引设置中定义自定义分析器。这涉及到组合选择字符过滤器、分词器和 Token 过滤器。
8. 聚合 (Aggregations) 入门
聚合是 Elasticsearch 的另一个强大功能,允许你对数据进行分组和统计分析,类似于 SQL 中的 GROUP BY
和聚合函数 (SUM, COUNT, AVG 等)。聚合是实时计算的,速度非常快。
聚合的概念
聚合框架可以让你从数据中获得分析性的信息。聚合操作在查询匹配的文档集上执行。
聚合主要分为两大类:
- 指标聚合 (Metrics Aggregations): 对字段值进行统计计算,如求和 (
sum
)、平均值 (avg
)、最大值 (max
)、最小值 (min
)、统计信息 (stats
- 同时返回 count, min, max, avg, sum)、计数值 (value_count
)、基数统计 (cardinality
- 统计唯一值数量) 等。这些聚合输出一个数值结果。 - 桶聚合 (Bucket Aggregations): 将满足特定条件的文档划分到不同的“桶” (Bucket) 中。每个桶关联一个键和一个文档集合。类似于 SQL 的
GROUP BY
。常见的桶聚合有:terms
:按字段的唯一值分组。range
:按数值或日期的范围分组。date_histogram
/histogram
:按固定的日期或数值间隔分组。filters
:按多个过滤条件分组。nested
/reverse_nested
:用于处理嵌套文档的聚合。
聚合可以嵌套,即在一个桶聚合的结果内部再进行指标聚合或其他桶聚合,实现复杂的多维度分析。
聚合的基本使用示例
聚合请求与查询一起放在 _search
API 的请求体中。size: 0
通常用于只关心聚合结果,不关心具体的文档 hits
。
示例 1:计算所有产品的平均价格 (指标聚合)
json
{
"size": 0, // 不需要返回具体的文档
"aggs": { // "aggs" 或 "aggregations" 都可以
"average_price": { // 给这个聚合起个名字
"avg": { // 聚合类型:平均值
"field": "price" // 在哪个字段上计算
}
}
}
}
响应中的 aggregations
部分会包含名为 average_price
的结果。
示例 2:按标签分组,统计每个标签下的产品数量 (桶聚合)
json
{
"size": 0,
"aggs": {
"products_per_tag": { // 聚合名称
"terms": { // 聚合类型:按词项分组
"field": "tags" // 分组依据字段 (通常是 keyword 类型)
}
}
}
}
响应会列出每个标签(桶的 key
)以及该标签下的文档数量(doc_count
)。
示例 3:按标签分组,并计算每个标签下产品的平均价格 (桶聚合 + 嵌套指标聚合)
json
{
"size": 0,
"aggs": {
"tags_agg": { // 外层桶聚合名称
"terms": { "field": "tags" },
"aggs": { // 在每个桶内进行嵌套聚合
"avg_price_per_tag": { // 内层指标聚合名称
"avg": { "field": "price" }
}
}
}
}
}
响应会显示每个标签及其对应的文档数,以及该标签下所有产品的平均价格。
聚合功能非常强大,是 Elasticsearch 进行数据分析和构建仪表盘的基础。
9. 进阶话题与后续学习
本指南涵盖了 Elasticsearch 的入门基础。要深入掌握 ES,可以继续学习以下方面:
- 分布式特性深入: 理解分片如何路由请求、集群如何发现节点、故障检测和恢复机制。
- 性能调优:
- 索引优化: 合理设置分片数、选择合适的硬件、调整 refresh interval、使用 Bulk API、优化映射。
- 查询优化: 理解查询如何执行、使用
filter
上下文、避免脚本查询、优化聚合、使用profile
API 分析查询性能。 - JVM 调优: 合理配置堆内存大小。
- 安全配置: 学习配置用户认证 (密码、证书、SAML、OIDC)、基于角色的访问控制 (RBAC)、字段级和文档级安全、启用 TLS/SSL 加密通信。
- 插件生态: 了解常用的插件,如 ICU Analysis (增强分词)、Mapper Attachments (已废弃,替代方案是 Ingest Attachment Processor) 等。
- Elastic Stack (ELK): 学习如何结合 Logstash (数据收集和转换)、Beats (轻量级数据收集器) 和 Kibana (可视化) 构建完整的日志分析、监控或其他解决方案。
- 客户端库: 学习使用官方或社区提供的各种编程语言客户端库(Java, Python, JavaScript, Go, Ruby, PHP 等)与 ES 交互。
- 索引生命周期管理 (ILM): 自动管理索引(如基于时间创建新索引、将旧索引转为只读、迁移到冷节点、最终删除),常用于日志和时序数据。
- 跨集群复制 (CCR) 和跨集群搜索 (CCS): 实现多数据中心部署或数据共享。
10. 总结
Elasticsearch 是一个功能极其强大且灵活的搜索和分析引擎。通过本指南,您应该已经了解了它的核心概念(集群、节点、索引、文档、分片、副本、映射),掌握了基本的安装、配置和 CRUD 操作,并初步接触了核心的搜索 (Query DSL)、文本分析和聚合功能。
要真正精通 Elasticsearch,关键在于实践。尝试搭建环境,索引自己的数据,不断试验各种查询和聚合,并深入理解映射和分析对搜索结果的影响。利用 Kibana Dev Tools 可以方便地进行实验。
Elasticsearch 的学习曲线可能有些陡峭,但其带来的强大功能和性能回报是巨大的。希望本指南能为您开启探索 Elasticsearch 世界的大门!祝您学习愉快!