零基础 Elasticsearch 详细教程
欢迎来到 Elasticsearch 的世界!如果你对搜索引擎、数据分析、日志管理感兴趣,或者只是想了解这项强大的技术,那么你来对地方了。本教程将从零开始,带你一步步认识 Elasticsearch,理解其核心概念,并掌握一些基础操作。无论你之前有没有数据库或搜索技术的经验,都可以通过本教程迈出第一步。
本文旨在详细、全面地讲解,内容较多,建议分阶段阅读和实践。
第一章:初识 Elasticsearch – 它是做什么的?为什么选择它?
1.1 Elasticsearch 是什么?
简单来说,Elasticsearch 是一个分布式、RESTful 风格的搜索和分析引擎。它基于 Apache Lucene 构建,并提供了简单易用的 RESTful API,使得复杂的搜索、分析和存储操作变得容易。
想象一下,你有一个巨大的图书馆,藏书成千上万。如果只是按书名、作者进行简单的查找,传统数据库或许可以胜任。但如果你想快速找到包含特定关键词的所有书籍(比如“人工智能”),并且按相关度排序;或者你想统计某个年代出版的书籍数量;甚至你想分析不同主题书籍的受欢迎程度——这些复杂的全文搜索和聚合分析需求,传统数据库往往力不从心。
Elasticsearch 正是为了解决这类问题而生。它能快速地存储、搜索和分析海量数据,特别擅长处理非结构化或半结构化的文本数据。
1.2 为什么选择 Elasticsearch?
Elasticsearch 之所以如此流行,主要得益于它的以下特点:
- 速度快: 基于 Lucene 的倒排索引机制,Elasticsearch 能够实现近乎实时的搜索。一旦数据被索引,几乎立刻就可以被搜索到。
- 全文搜索能力强: 提供丰富的查询类型(如
match
、query_string
等),支持模糊搜索、短语搜索、高亮显示等功能。 - 分布式和可扩展: 它可以轻松地在多台服务器上构建集群,水平扩展以处理不断增长的数据量和查询负载。节点的增删几乎不会影响服务可用性。
- 高可用: 支持数据副本(Replica),当集群中的某个节点发生故障时,系统仍然可以继续提供服务,不会丢失数据。
- 强大的分析能力: 提供了 Aggregations(聚合)功能,可以轻松地进行数据统计、分组、计算平均值、最大值、最小值等,实现丰富的商业智能和数据洞察。
- RESTful API: 所有操作都通过标准的 RESTful API 进行,可以使用各种编程语言(Java, Python, Node.js, Go 等)方便地与之交互。
- 生态系统完善: 作为 Elastic Stack (ELK/ECK) 的核心,它与 Logstash (数据收集和处理)、Kibana (数据可视化和管理界面) 以及 Beats (轻量级数据采集器) 无缝集成,形成了一套强大的数据处理和分析解决方案。常见的应用场景包括日志分析、指标监控、APM(应用性能管理)、安全分析等。
1.3 Elasticsearch 的应用场景
- 站内搜索: 为网站或应用程序提供快速、准确的站内搜索功能(如电商网站的产品搜索)。
- 日志和指标分析: 收集、存储和分析大量的日志数据和系统指标,用于故障排查、性能监控和安全审计(ELK Stack 的经典应用)。
- 数据分析平台: 作为数据仓库的一部分,进行实时的数据分析和商业智能。
- 地理位置搜索: 存储和搜索地理位置数据,实现基于位置的服务。
- 安全信息和事件管理 (SIEM): 收集和分析安全相关的日志和事件,检测威胁。
第二章:环境准备与安装
在开始学习 Elasticsearch 的操作之前,你需要先将它安装并运行起来。
2.1 前置条件:Java 环境
Elasticsearch 是用 Java 语言开发的,因此运行 Elasticsearch 需要 Java 运行时环境(JRE)或 Java 开发工具包(JDK)。
- 版本要求: 不同版本的 Elasticsearch 需要对应版本的 Java。通常,Elasticsearch 的文档中会明确指出支持的 Java 版本范围。建议安装 OpenJDK,并选择 Elasticsearch 官方推荐或支持的 LTS (长期支持) 版本,例如 Java 11 或 Java 17。
- 检查 Java: 打开终端或命令行窗口,输入
java -version
。如果 Java 已经安装并配置好环境变量,会显示版本信息。
bash
java -version
如果未安装或版本不符,请根据你的操作系统(Windows, macOS, Linux)安装合适的 OpenJDK 版本,并确保 JAVA_HOME
环境变量已设置。
2.2 下载 Elasticsearch
访问 Elasticsearch 官方下载页面:https://www.elastic.co/cn/downloads/elasticsearch
选择适合你操作系统的版本进行下载(通常是 .zip
或 .tar.gz
文件)。对于初学者和本地学习,下载最新的稳定版即可。
2.3 安装与启动
以下以下载 .zip
(Windows) 或 .tar.gz
(macOS/Linux) 文件为例:
步骤 1:解压文件
将下载的文件解压到一个合适的目录,例如 C:\elasticsearch
(Windows) 或 /usr/local/elasticsearch
(macOS/Linux)。
“`bash
macOS/Linux
tar -zxvf elasticsearch-
cd /usr/local/elasticsearch-
Windows (使用解压工具)
“`
步骤 2:启动 Elasticsearch
打开终端或命令行窗口,进入 Elasticsearch 的解压目录。
-
macOS/Linux:
bash
cd elasticsearch-<version> # 进入解压后的目录
./bin/elasticsearch -
Windows:
powershell
cd elasticsearch-<version> # 进入解压后的目录
.\bin\elasticsearch.bat
执行启动命令后,会看到大量的日志输出。等待片刻,直到日志中出现类似 publish_address {127.0.0.1:9200, _local_}, bound_addresses {127.0.0.1:9200}
的信息,这表示 Elasticsearch 已经在本地启动,并监听在 9200 端口。
注意: 直接运行 ./bin/elasticsearch
会在前台运行,关闭终端窗口会停止 Elasticsearch。在生产环境中,通常会将其配置为服务在后台运行。但在学习阶段,前台运行方便观察日志。
2.4 验证安装
打开浏览器或使用 curl
命令,访问 http://localhost:9200
。如果一切正常,你应该会看到一个 JSON 响应,其中包含 Elasticsearch 集群的信息,例如版本号、集群名称等。
bash
curl http://localhost:9200
预期的输出类似于:
json
{
"name" : "your-node-name",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "...",
"version" : {
"number" : "8.x.x",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "...",
"build_date" : "...",
"build_snapshot" : false,
"lucene_version" : "...",
"minimum_wire_compatibility_version" : "...",
"minimum_index_compatibility_version" : "..."
},
"tagline" : "You Know, for Search"
}
如果能看到这个响应,恭喜你!Elasticsearch 已经成功运行起来了。
第三章:核心概念解析
在深入操作之前,理解 Elasticsearch 的一些核心概念至关重要。它们是构建 Elasticsearch 索引、存储数据和执行搜索的基础。
3.1 索引 (Index)
- 类比: 在传统关系型数据库中,一个 Index 可以类比为一个数据库 (Database)。
- 定义: Index 是一个逻辑上的命名空间,用于存储具有相似特征的文档。它由一个或多个物理分片 (Shard) 组成。
- 作用: Index 是你对数据进行索引、搜索、更新和删除的入口点。例如,你可以创建一个
products
索引来存储商品信息,一个users
索引来存储用户信息,或者一个logs-2023-10-26
索引来存储某一天的日志。 - 命名规则: 索引名称必须是小写字母,不能包含特殊字符(
\
,/
,*
,?
,"
,<
,>
,|
,,
,
,#
),不能以下划线_
开头或包含..
。
3.2 文档 (Document)
- 类比: 在传统关系型数据库中,一个 Document 可以类比为一行数据 (Row)。
- 定义: Document 是 Elasticsearch 中最小的数据单元。它是一个包含字段 (Field) 的 JSON 对象。每个 Document 都有一个唯一的 ID,在一个 Index 内是唯一的。
- 特点: 文档是无模式 (schema-less) 的,意味着你可以在同一个 Index 中存储结构略有不同的文档(尽管在实际应用中通常会尽量保持结构一致或通过 Mapping 管理)。Elasticsearch 在索引文档时会动态地猜测字段的类型,但更严谨的做法是显式定义 Mapping。
例如,一个表示用户的文档可以是:
json
{
"name": "张三",
"age": 30,
"city": "北京",
"interests": ["阅读", "旅行"]
}
或者一个表示商品的文档:
json
{
"product_id": "A123",
"name": "高性能笔记本电脑",
"price": 8999.00,
"description": "轻薄、高性能,适合开发者。",
"tags": ["电子产品", "笔记本", "电脑"]
}
3.3 字段 (Field)
- 类比: 在传统关系型数据库中,一个 Field 可以类比为一列数据 (Column)。
- 定义: Field 是 Document 中的一个键值对,键是字段名,值是字段的值。字段可以是字符串、数字、布尔值、日期、数组等类型。
- 重要性: Elasticsearch 根据字段的类型和 Mapping 来决定如何索引和搜索该字段。例如,文本字段 (
text
) 会被分词和分析,而关键字字段 (keyword
) 则会被当作一个整体进行精确匹配。
3.4 映射 (Mapping)
- 类比: 在传统关系型数据库中,Mapping 可以类比为表结构定义 (Schema)。
- 定义: Mapping 定义了 Index 中文档及其字段如何存储和索引。它指定了每个字段的数据类型(
text
,keyword
,long
,double
,boolean
,date
,geo_point
等),以及如何对字段进行分词、标准化等处理。 - 作用: 映射是 Elasticsearch 搜索引擎工作的基础。正确的映射能够确保数据被正确索引,从而实现高效且准确的搜索和聚合。虽然 Elasticsearch 可以动态猜测映射,但在生产环境中强烈建议手动或通过模板定义明确的映射。
3.5 分片 (Shard)
- 定义: 分片是 Index 的物理切片。一个 Index 可以被分成多个 Shard,每个 Shard 都是一个功能完整的、独立的 Lucene 索引。
- 作用: Shard 是 Elasticsearch 实现水平扩展的关键。通过将 Index 分成多个 Shard,数据可以分布到集群中的不同节点上,从而能够处理超出单个节点存储或处理能力的数据量。同时,搜索请求也可以并行地在多个 Shard 上执行,提高搜索速度。
- 设置: 创建 Index 时可以指定主分片 (Primary Shard) 的数量。一旦 Index 创建,主分片的数量就不能更改。
3.6 副本 (Replica)
- 定义: 副本是主分片的一个拷贝。
- 作用: 副本有两个主要目的:
- 高可用 (High Availability): 当主分片所在的节点发生故障时,副本可以晋升为新的主分片,保证数据不丢失和服务不中断。
- 提高读取性能: 搜索请求可以在主分片和副本分片上并行执行,增加集群的处理能力。
- 设置: 创建 Index 时可以指定副本分片 (Replica Shard) 的数量。副本分片可以在 Index 创建后动态地增加或减少。副本的数量是针对每个主分片而言的。例如,一个有 5 个主分片和 1 个副本的 Index,总共会有 5 个主分片和 5 个副本分片,共计 10 个分片。
3.7 节点 (Node) 与集群 (Cluster)
- 节点 (Node): 运行一个 Elasticsearch 实例的服务器。
- 集群 (Cluster): 由一个或多个 Node 组成的集合,它们共同存储数据并提供索引和搜索功能。一个集群由一个唯一的名称标识。节点通过网络发现彼此并加入同一集群。一个集群通常有一个主节点 (Master Node),负责集群的管理和协调。
第四章:基础操作 – CRUD
了解了核心概念后,我们来学习如何通过 RESTful API 与 Elasticsearch 进行交互,执行数据的创建 (Create)、读取 (Read)、更新 (Update) 和删除 (Delete) 操作。
我们将使用 curl
命令行工具来演示这些操作。在实际开发中,你会使用各种编程语言提供的 Elasticsearch 客户端库,或者使用 Kibana 的 Dev Tools 控制台(强烈推荐在学习阶段使用 Kibana Dev Tools,它提供了一个更友好的界面来发送 API 请求和查看响应)。
所有 API 请求都发送到 Elasticsearch 的 HTTP 端口,默认是 9200。
4.1 创建/索引文档 (Index a Document)
将一个 JSON 文档添加到指定的 Index 中。有两种方式:自动生成文档 ID 或指定文档 ID。
方式一:自动生成 ID
使用 POST
方法,发送到 /<index_name>/_doc/
端点。
“`bash
创建一个名为 ‘users’ 的索引,并添加一个文档,ID 由 Elasticsearch 自动生成
curl -X POST “localhost:9200/users/_doc/” -H “Content-Type: application/json” -d’
{
“name”: “李四”,
“age”: 25,
“city”: “上海”
}
‘
“`
响应会返回文档的 Index (_index
)、自动生成的 ID (_id
)、版本号 (_version
) 以及结果 (result
: “created”)。
json
{
"_index" : "users",
"_id" : "...", # 自动生成的 ID
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
方式二:指定 ID
使用 PUT
方法,发送到 /<index_name>/_doc/<document_id>
端点。如果该 ID 不存在,则创建文档;如果存在,则完全替换现有文档(包括所有字段)。
“`bash
在 ‘products’ 索引中添加/替换一个 ID 为 ‘A001’ 的文档
curl -X PUT “localhost:9200/products/_doc/A001” -H “Content-Type: application/json” -d’
{
“product_id”: “A001”,
“name”: “入门级机械键盘”,
“price”: 399.50,
“tags”: [“外设”, “键盘”]
}
‘
“`
响应同样会返回相关信息,result
可能是 “created” 或 “updated”。
json
{
"_index" : "products",
"_id" : "A001",
"_version" : 1, # 或更高版本如果替换了现有文档
"result" : "created", # 或 updated
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
4.2 获取文档 (Get a Document)
使用 GET
方法,发送到 /<index_name>/_doc/<document_id>
端点,可以根据 ID 获取指定的文档。
“`bash
获取 ‘products’ 索引中 ID 为 ‘A001’ 的文档
curl -X GET “localhost:9200/products/_doc/A001”
“`
响应会返回文档的元信息 (_index
, _id
, _version
等),以及文档的源数据 (_source
字段)。
json
{
"_index" : "products",
"_id" : "A001",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true, # 表示找到了文档
"_source" : { # 文档的原始数据
"product_id": "A001",
"name": "入门级机械键盘",
"price": 399.50,
"tags": ["外设", "键盘"]
}
}
如果文档不存在,found
字段将为 false
,且没有 _source
字段。
4.3 更新文档 (Update a Document)
使用 POST
方法,发送到 /<index_name>/_update/<document_id>
端点。这允许你部分更新文档,而不是完全替换。
在请求体中,使用 doc
字段包含要更新的字段及其新值。Elasticsearch 会合并现有文档和 doc
字段的内容。
“`bash
更新 ‘products’ 索引中 ID 为 ‘A001’ 的文档,修改价格并添加新标签
curl -X POST “localhost:9200/products/_update/A001” -H “Content-Type: application/json” -d’
{
“doc”: {
“price”: 380.00,
“tags”: [“外设”, “键盘”, “静音”] # tags 字段会被替换为新值
}
}
‘
“`
响应会显示更新后的版本号 (_version
) 和结果 (result
: “updated”)。
json
{
"_index" : "products",
"_id" : "A001",
"_version" : 2, # 版本号增加
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
注意: _update
操作实际上是先获取文档,修改后再重新索引,因此效率低于直接使用 PUT
替换。但它避免了并发问题。
4.4 删除文档 (Delete a Document)
使用 DELETE
方法,发送到 /<index_name>/_doc/<document_id>
端点。
“`bash
删除 ‘products’ 索引中 ID 为 ‘A001’ 的文档
curl -X DELETE “localhost:9200/products/_doc/A001”
“`
响应会显示结果为 “deleted”。
json
{
"_index" : "products",
"_id" : "A001",
"_version" : 3, # 版本号增加
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}
4.5 删除索引 (Delete an Index)
使用 DELETE
方法,发送到 /<index_name>
端点。这个操作会永久删除整个索引及其包含的所有文档,请谨慎使用!
“`bash
删除整个 ‘products’ 索引
curl -X DELETE “localhost:9200/products”
“`
响应会显示 acknowledged
为 true
表示删除成功。
json
{
"acknowledged" : true
}
第五章:基础搜索操作
CRUD 操作让你学会了如何管理单个文档,但 Elasticsearch 的真正威力在于搜索。搜索操作主要通过 _search
端点进行。
搜索请求主要有两种方式:
- URI Search: 将查询参数直接放在 URL 中,简单快捷,适合快速测试。
- Request Body Search: 将查询条件写在请求体(POST 请求)的 JSON 中,功能强大,支持复杂的查询和过滤,是生产环境中最常用的方式。
我们主要关注 Request Body Search。
5.1 简单的 Request Body Search
使用 GET
或 POST
方法发送请求到 /<index_name>/_search
端点,并在请求体中包含一个 JSON 对象,该对象定义了搜索条件。
最基本的搜索是 match_all
查询,它返回 Index 中的所有文档。
“`bash
搜索 ‘users’ 索引中的所有文档
curl -X GET “localhost:9200/users/_search” -H “Content-Type: application/json” -d’
{
“query”: {
“match_all”: {}
}
}
‘
“`
搜索结果响应是一个 JSON 对象,其中最重要的部分是 hits
字段:
json
{
"took" : 10, # 搜索花费的时间(毫秒)
"timed_out" : false,
"_shards" : { # 参与搜索的分片信息
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : { # 匹配到的总文档数
"value" : 2,
"relation" : "eq" # eq 表示 value 是精确值,gte 表示大于等于
},
"max_score" : 1.0, # 最高相关度得分
"hits" : [ # 匹配到的文档列表
{
"_index" : "users",
"_id" : "...",
"_score" : 1.0, # 文档相关度得分
"_source" : { # 文档原始数据
"name": "李四",
"age": 25,
"city": "上海"
}
},
{
"_index" : "users",
"_id" : "...",
"_score" : 1.0,
"_source" : {
"name": "张三",
"age": 30,
"city": "北京",
"interests": ["阅读", "旅行"]
}
}
# ... 更多文档
]
}
}
5.2 常用查询类型 (Query Types)
query
对象内部可以包含各种查询类型。以下介绍几种最常用的:
-
match
查询:
进行全文搜索。它会对输入的查询文本进行分词和分析,然后查找在指定字段中包含这些分词的文档。通常用于text
类型的字段。“`bash
搜索 name 或 city 字段包含 “上海” 的文档
curl -X GET “localhost:9200/users/_search” -H “Content-Type: application/json” -d’
{
“query”: {
“match”: {
“city”: “上海”
}
}
}
‘
“`如果查询文本是多个词,
match
查询默认使用 OR 逻辑(匹配任一词即可)。你可以通过operator
参数改为 AND 逻辑(匹配所有词)。“`bash
搜索 description 字段同时包含 “高性能” 和 “开发者” 的文档
curl -X GET “localhost:9200/products/_search” -H “Content-Type: application/json” -d’
{
“query”: {
“match”: {
“description”: {
“query”: “高性能 开发者”,
“operator”: “and”
}
}
}
}
‘
“` -
term
查询:
进行精确匹配。它不会对输入的查询文本进行分析,而是直接查找在指定字段中包含完全相同词条的文档。通常用于keyword
、数字、布尔值或日期等不进行分词的字段。重要提示: 如果你对一个
text
类型的字段使用term
查询,通常不会得到预期的结果,因为term
查询不会匹配经过分词后的词条。例如,如果name
字段是text
类型,值为 “高性能笔记本”,term
查询 “高性能笔记本” 将找不到,但term
查询 “高性能” (如果 “高性能” 是分词结果之一) 可能找到。因此,通常对需要精确匹配的文本字段使用keyword
类型并在其上执行term
查询。“`bash
搜索 age 字段精确等于 30 的文档
curl -X GET “localhost:9200/users/_search” -H “Content-Type: application/json” -d’
{
“query”: {
“term”: {
“age”: 30
}
}
}
‘
“`“`bash
搜索 tags 字段中包含精确词条 “外设” 的文档(假设 tags 是 keyword 类型)
curl -X GET “localhost:9200/products/_search” -H “Content-Type: application/json” -d’
{
“query”: {
“term”: {
“tags”: “外设”
}
}
}
‘
“` -
range
查询:
查找在指定字段中值落在某个范围内的文档。常用于数字和日期字段。支持的范围操作符有:gt
: Greater Than (大于)gte
: Greater Than or Equal to (大于等于)lt
: Less Than (小于)lte
: Less Than or Equal to (小于等于)
“`bash
搜索 price 字段值在 300 到 500 之间的产品 (包含边界)
curl -X GET “localhost:9200/products/_search” -H “Content-Type: application/json” -d’
{
“query”: {
“range”: {
“price”: {
“gte”: 300,
“lte”: 500
}
}
}
}
‘
“`
5.3 组合查询 – bool
查询
在实际应用中,经常需要组合多个查询条件(例如,既要包含某个词,又要满足某个范围)。bool
查询是实现这一目的的核心。
bool
查询包含以下子句:
must
: 子句中的所有查询都必须匹配。类似于 SQL 中的 AND。影响相关度得分 (_score
)。filter
: 子句中的所有查询都必须匹配。类似于 SQL 中的 AND。与must
不同的是,filter
不计算相关度得分,只判断是否匹配,因此性能通常更好,适合用于过滤数据。should
: 子句中的查询可以匹配。类似于 SQL 中的 OR。匹配的子句越多,相关度得分越高。如果没有must
或filter
子句,should
至少需要匹配一个子句。must_not
: 子句中的所有查询都不能匹配。类似于 SQL 中的 NOT。不计算相关度得分。
“`bash
搜索 city 为 “上海”,并且 age 大于 20 且小于 30 的用户
curl -X GET “localhost:9200/users/_search” -H “Content-Type: application/json” -d’
{
“query”: {
“bool”: {
“filter”: [ # 使用 filter 提高性能,因为不需要计算相关度
{ “term”: { “city”: “上海” }},
{ “range”: { “age”: { “gt”: 20, “lt”: 30 }}}
]
}
}
}
‘
“`
“`bash
搜索 description 包含 “高性能” 或 “轻薄”,但 price 不在 10000 以上的产品
curl -X GET “localhost:9200/products/_search” -H “Content-Type: application/json” -d’
{
“query”: {
“bool”: {
“should”: [
{ “match”: { “description”: “高性能” }},
{ “match”: { “description”: “轻薄” }}
],
“must_not”: [
{ “range”: { “price”: { “gte”: 10000 }}}
],
“minimum_should_match”: 1 # 可选:如果should子句匹配数量少于等于这个值,整个bool查询就不算匹配。默认是1,表示至少匹配一个。
}
}
}
‘
“`
5.4 控制搜索结果
你可以通过在搜索请求体中添加参数来控制返回结果:
size
: 返回匹配文档的数量 (默认 10)。from
: 跳过匹配结果的前多少个文档,用于分页 (默认 0)。from
和size
组合实现分页。但深分页 (>10000 条) 效率低下,建议使用search_after
或 Scroll API。_source
: 控制是否返回文档的原始数据,或者只返回部分字段。"_source": false
不返回_source
。"_source": ["field1", "field2"]
只返回指定的字段。
“`bash
搜索所有用户,只返回前 5 个文档,并且只包含 name 和 city 字段
curl -X GET “localhost:9200/users/_search” -H “Content-Type: application/json” -d’
{
“size”: 5,
“from”: 0,
“_source”: [“name”, “city”],
“query”: {
“match_all”: {}
}
}
‘
“`
第六章:理解和管理映射 (Mapping)
前面提到,Mapping 决定了字段如何索引和搜索。虽然 Elasticsearch 可以动态映射,但显式定义 Mapping 尤其重要,特别是对于文本字段。
6.1 查看现有映射
使用 GET
方法到 /<index_name>/_mapping
端点。
“`bash
查看 users 索引的映射
curl -X GET “localhost:9200/users/_mapping”
“`
如果你之前只是简单地索引了文档,Elasticsearch 会自动为你创建动态映射。例如,一个简单的用户索引映射可能看起来像这样:
json
{
"users" : {
"mappings" : {
"properties" : {
"age" : {
"type" : "long" # 数字字段通常被映射为 long 或 double
},
"city" : {
"type" : "text", # 字符串字段默认可能被映射为 text 和 keyword (multi-fields)
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"interests" : { # 数组字段的映射与其中元素的映射相同
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
注意 city
, interests
, name
字段被映射为了 text
类型,并且自动创建了一个 keyword
子字段 (city.keyword
, interests.keyword
, name.keyword
)。这意味着你可以在 city
字段上进行全文搜索 (match
),也可以在 city.keyword
字段上进行精确匹配 (term
)。
6.2 显式创建带有映射的索引
建议在索引文档之前就创建索引并定义好映射,特别是对于需要精确匹配的文本字段,确保其类型是 keyword
或具有 keyword
子字段。
使用 PUT
方法到 /<index_name>
端点,并在请求体中包含 mappings
定义。
“`bash
创建一个名为 ‘books’ 的索引,并定义映射
curl -X PUT “localhost:9200/books” -H “Content-Type: application/json” -d’
{
“mappings”: {
“properties”: {
“title”: {
“type”: “text”, # 书名用于全文搜索
“analyzer”: “ik_smart” # 假设你安装了中文分词器
},
“author”: {
“type”: “keyword” # 作者名用于精确过滤和聚合
},
“publish_date”: {
“type”: “date” # 日期类型
},
“price”: {
“type”: “double” # 价格使用 double 类型
},
“tags”: {
“type”: “keyword” # 标签用于精确过滤和聚合
},
“description”: {
“type”: “text”, # 描述用于全文搜索
“analyzer”: “ik_smart”
}
}
},
“settings”: { # 可选:设置主分片和副本分片数量
“index”: {
“number_of_shards”: 3,
“number_of_replicas”: 1
}
}
}
‘
“`
这个例子定义了 title
和 description
为 text
类型,并指定了中文分词器 (ik_smart
)。author
和 tags
被定义为 keyword
类型,适合精确查找和聚合。publish_date
和 price
分别定义为 date
和 double
类型。
创建索引后,你就可以向 books
索引中索引文档了。例如:
bash
curl -X POST "localhost:9200/books/_doc" -H "Content-Type: application/json" -d'
{
"title": "三体",
"author": "刘慈欣",
"publish_date": "2008-01-01",
"price": 68.00,
"tags": ["科幻", "小说"],
"description": "刘慈欣创作的长篇科幻小说,中国科幻文学的里程碑之作。"
}
'
现在,你可以使用 match
查询在 title
或 description
字段上进行全文搜索(例如搜索 “里程碑”),使用 term
查询在 author
或 tags
字段上进行精确搜索(例如搜索 “刘慈欣” 或 “科幻”),或者使用 range
查询搜索特定价格范围或出版日期的书籍。
第七章:初探聚合 (Aggregations)
聚合是 Elasticsearch 的另一个强大功能,它允许你对搜索结果进行分组、统计和分析,类似 SQL 中的 GROUP BY
、COUNT
、SUM
、AVG
等操作。
聚合请求通常放在搜索请求体中的 aggregations
(或 aggs
) 字段下。每个聚合都有一个用户定义的名称和一个聚合类型。
7.1 terms
聚合
terms
聚合是最常用的聚合类型之一,它根据字段的不同词条(通常是 keyword
字段)进行分组,并统计每组文档的数量,类似于 SQL 的 GROUP BY
和 COUNT
。
“`bash
统计不同作者的书籍数量(在 books 索引上执行,假设 author 是 keyword 类型)
curl -X GET “localhost:9200/books/_search” -H “Content-Type: application/json” -d’
{
“size”: 0, # 我们只需要聚合结果,不需要搜索匹配的文档,所以设置 size 为 0
“aggs”: {
“books_by_author”: { # 用户定义的聚合名称
“terms”: { # 聚合类型
“field”: “author” # 根据 author 字段进行分组
}
}
}
}
‘
“`
响应中会包含 aggregations
字段:
json
{
...
"hits" : { ... }, # hits 部分是空的,因为 size=0
"aggregations" : {
"books_by_author" : { # 聚合名称
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [ # 分组结果列表
{
"key" : "刘慈欣", # 组的键(作者名)
"doc_count" : 5 # 该作者名下文档的数量
},
{
"key" : "金庸",
"doc_count" : 3
}
# ... 其他作者
]
}
}
}
7.2 avg
、sum
、min
、max
、stats
聚合
这些聚合用于对数值字段进行统计计算。
“`bash
计算所有书籍的平均价格、总价格、最高价、最低价和统计信息
curl -X GET “localhost:9200/books/_search” -H “Content-Type: application/json” -d’
{
“size”: 0,
“aggs”: {
“average_price”: { # 计算平均价格
“avg”: {
“field”: “price”
}
},
“total_price”: { # 计算总价格
“sum”: {
“field”: “price”
}
},
“price_stats”: { # 计算统计信息 (包括 min, max, avg, sum, count)
“stats”: {
“field”: “price”
}
}
}
}
‘
“`
响应中会包含相应的计算结果。
你还可以将聚合嵌套使用,例如先按作者分组,再统计每个作者书籍的平均价格。
聚合是 Elasticsearch 数据分析的强大工具,这里只是冰山一角,还有很多其他类型的聚合(如 range
, date_histogram
, geo_distance
等)可以用于更复杂的数据分析。
第八章:Kibana – 你的可视化和管理界面
虽然我们可以使用 curl
或其他工具与 Elasticsearch 的 REST API 交互,但在学习和管理阶段,使用 Kibana 会大大提高效率。
8.1 Kibana 是什么?
Kibana 是 Elastic Stack 的可视化和管理工具。它提供了一个友好的 Web 界面,可以用来:
- 探索数据: 在 Discover 页面搜索、过滤和查看 Elasticsearch 中的文档。
- 数据可视化: 创建各种图表、图形和仪表盘来展示数据(如直方图、饼图、地图等)。
- 开发工具: 使用 Dev Tools 控制台直接发送 REST API 请求给 Elasticsearch,并查看格式化的响应。这是学习 API 的绝佳工具。
- 管理 Elasticsearch: 查看集群健康状况、管理索引、用户、快照等。
8.2 安装与启动 Kibana
- 下载 Kibana: 访问 Kibana 官方下载页面 https://www.elastic.co/cn/downloads/kibana,下载与你 Elasticsearch 版本相匹配的版本。版本必须兼容!
- 解压文件: 将下载的文件解压到任意目录。
- 配置 Kibana: 打开 Kibana 解压目录下的
config/kibana.yml
文件。通常,你只需要检查并确保elasticsearch.hosts
配置指向你的 Elasticsearch 实例。如果 Elasticsearch 运行在localhost:9200
,默认配置通常是正确的。 - 启动 Kibana: 打开终端或命令行窗口,进入 Kibana 的解压目录。
- macOS/Linux:
./bin/kibana
- Windows:
.\bin\kibana.bat
- macOS/Linux:
等待 Kibana 启动完成。
8.3 访问 Kibana
打开浏览器,访问 http://localhost:5601
(Kibana 的默认端口)。如果一切顺利,你应该能看到 Kibana 的欢迎界面。
8.4 使用 Dev Tools
在 Kibana 界面左侧导航栏找到 “Dev Tools”(开发者工具)。点击进入后,你会看到一个控制台界面,左侧是请求编辑器,右侧是响应显示区。
现在,你可以像使用 curl
一样,直接在左侧输入 Elasticsearch 的 API 请求,然后点击绿色的播放按钮执行。Kibana Dev Tools 支持多行输入,自动格式化,并且有语法高亮和自动完成功能,非常方便!
例如,尝试在 Dev Tools 中输入:
json
GET /
然后点击执行,右侧会显示 Elasticsearch 的版本信息,和你之前用 curl http://localhost:9200
看到的一样。
再试试我们之前的搜索请求:
json
GET /users/_search
{
"query": {
"match_all": {}
}
}
在学习和实践 Elasticsearch API 时,强烈推荐使用 Kibana Dev Tools。
第九章:总结与进阶方向
恭喜你!走到这里,你已经掌握了 Elasticsearch 的核心概念、安装方法,以及最基础的 CRUD 和搜索操作,甚至了解了如何使用 Kibana 这个得力助手。这为你深入学习打下了坚实的基础。
本教程覆盖的内容是 Elasticsearch 世界的入门级知识。要成为熟练的 Elasticsearch 用户,还有很多内容值得探索:
- 更丰富的查询类型: 除了
match
,term
,range
,bool
,还有fuzzy
,wildcard
,regexp
,query_string
,simple_query_string
等。 - 文本分析器 (Analyzers): 深入理解 Elasticsearch 如何处理文本,包括分词器 (Tokenizer)、词条过滤器 (Token Filter) 和字符过滤器 (Character Filter),以及如何使用和配置它们(特别是中文分词器,如 IK Analyzer)。
- 相关度得分 (Relevance Scoring): 了解 Elasticsearch 如何计算文档与查询的相关度 (
_score
),以及如何影响和自定义评分过程。 - 高级聚合: 学习更多聚合类型,进行更复杂的数据分析。
- 排序 (Sorting): 按字段值对搜索结果进行排序,而不是按相关度排序。
- 高亮显示 (Highlighting): 在搜索结果中高亮显示匹配的关键词。
- 索引模板 (Index Templates): 定义索引创建时的默认设置和映射,方便批量管理。
- 别名 (Aliases): 为一个或多个索引设置别名,方便切换索引版本。
- 集群管理: 学习如何配置、监控和管理 Elasticsearch 集群,包括节点角色、分片分配、扩容缩容等。
- 数据流 (Data Streams): 对于时间序列数据(如日志、指标),数据流提供了一种更方便的管理方式。
- 安全 (Security): 学习如何保护你的 Elasticsearch 集群,包括用户认证、授权、加密等。
- Elastic Stack 其他组件: 深入学习 Logstash (数据ETL)、Beats (数据采集) 和 Kibana 的更多高级功能。
- 客户端库: 在实际项目中使用各种编程语言的 Elasticsearch 官方或第三方客户端库。
学习 Elasticsearch 最好的方式是实践。尝试在你自己的数据集上进行索引、搜索和聚合操作。结合 Kibana Dev Tools,不断试验不同的 API 请求,观察结果。
希望本教程能为你打开 Elasticsearch 的大门,祝你在数据搜索和分析的旅程中取得成功!