🏆 简介
本教程将带你从0到1掌握Elasticsearch的核心操作,通过知识点解析+代码示例的形式,让你轻松理解并应用Elasticsearch。教程基于Elasticsearch 6.x版本,内容涵盖从基础连接到高级查询的完整知识体系。
📚 目录
-
- 安装依赖
- 连接Elasticsearch
- 测试连接状态
-
- 索引概念
- 创建索引
- 修改索引设置
- 索引别名管理
-
- 单个文档操作
- 批量操作
- 数据查询
-
- 迁移原理
- 实现步骤
- 原子切换
-
- 分页查询
- 排序查询
- 复合查询
- 全文搜索
1. 环境准备与基础连接
1.1 安装依赖
知识点: Elasticsearch提供了官方的Python客户端库,通过pip安装后可以方便地与Elasticsearch服务器交互。
安装命令:
bash
pip install elasticsearch
1.2 连接Elasticsearch
知识点: 使用Elasticsearch类创建连接客户端,需要指定Elasticsearch服务器的主机地址和端口。支持多个节点的连接配置,以提高系统的可用性。
代码示例:
python
from elasticsearch import Elasticsearch
# 连接到单节点Elasticsearch
es = Elasticsearch([{"host": "localhost", "port": 9200}])
# 连接到多节点Elasticsearch(生产环境推荐)
es = Elasticsearch([
{"host": "es-node1", "port": 9200},
{"host": "es-node2", "port": 9200},
{"host": "es-node3", "port": 9200}
])
1.3 测试连接状态
知识点: 连接Elasticsearch后,应测试连接是否成功。可以通过info()
方法获取Elasticsearch服务器信息,或使用ping()
方法快速检查连接状态。
代码示例:
python
# 获取Elasticsearch服务器信息
info = es.info()
print(f"Elasticsearch版本: {info['version']['number']}")
print(f"集群名称: {info['cluster_name']}")
# 快速测试连接是否可用
if es.ping():
print("✅ 连接成功!")
else:
print("❌ 连接失败!")
2. 索引管理
2.1 索引概念
知识点: 索引(Index)是Elasticsearch中存储数据的基本单位,类似于关系数据库中的数据库。每个索引都有自己的映射(Mapping)和设置(Settings):
- Mapping: 定义文档的结构和字段类型
- Settings: 配置索引的性能参数(如分片数、副本数等)
2.2 创建索引
知识点: 创建索引时需要定义映射结构和索引设置。映射定义了文档中每个字段的数据类型,设置定义了索引的性能参数。
代码示例:
python
# 定义索引名称
index_name = "my_index"
# 定义索引结构
index_body = {
"settings": {
"index": {
"number_of_shards": 3, # 分片数
"number_of_replicas": 1 # 副本数
}
},
"mappings": {
"_doc": { # ES 6.x版本需要指定type为_doc
"properties": {
"title": {"type": "text"}, # 全文本字段
"author": {"type": "keyword"}, # 关键词字段(精确匹配)
"publish_date": {"type": "date"}, # 日期字段
"views": {"type": "integer"}, # 整数字段
"price": {"type": "float"} # 浮点数字段
}
}
}
}
# 创建索引
es.indices.create(index=index_name, body=index_body)
print(f"✅ 索引 '{index_name}' 创建成功!")
2.3 检查与删除索引
知识点: 在创建索引前,通常需要检查索引是否已存在;当不再需要索引时,可以删除索引以释放资源。
代码示例:
python
# 检查索引是否存在
if es.indices.exists(index=index_name):
print(f"索引 '{index_name}' 已存在")
# 删除索引
es.indices.delete(index=index_name)
print(f"索引 '{index_name}' 已删除")
2.4 修改索引设置
知识点: 创建索引后,可以修改部分索引设置,如副本数。但分片数等核心设置在创建后无法修改。
代码示例:
python
# 修改索引的副本数
es.indices.put_settings(
index=index_name,
body={"settings": {"index": {"number_of_replicas": 2}}}
)
print(f"✅ 索引 '{index_name}' 的副本数已修改为2")
2.5 修改映射结构
知识点: 索引创建后,可以向映射中添加新字段,但不能修改现有字段的数据类型(除非重建索引)。
代码示例:
python
# 向映射中添加新字段
es.indices.put_mapping(
index=index_name,
doc_type="_doc",
body={"properties": {"tags": {"type": "keyword"}}}
)
print(f"✅ 索引 '{index_name}' 的映射已添加新字段'tags'")
2.6 索引别名管理
知识点: 索引别名是指向一个或多个索引的引用,可以随时更改别名指向的索引,从而实现零停机维护。
代码示例:
python
# 添加索引别名
alias_name = "my_index_alias"
es.indices.put_alias(index=index_name, name=alias_name)
print(f"✅ 已为索引 '{index_name}' 添加别名 '{alias_name}'")
# 获取索引的所有别名
aliases = es.indices.get_alias(index=index_name)
print(f"索引 '{index_name}' 的别名:{list(aliases[index_name]['aliases'].keys())}")
# 删除索引别名
es.indices.delete_alias(index=index_name, name=alias_name)
print(f"✅ 已删除索引 '{index_name}' 的别名 '{alias_name}'")
3. 文档CRUD操作
3.1 单个文档操作
3.1.1 创建文档
知识点: 可以通过指定ID创建文档,也可以让Elasticsearch自动生成ID。创建文档时,如果ID已存在,则会覆盖现有文档。
代码示例:
python
# 指定ID创建文档
doc_id = "1"
doc = {
"title": "Elasticsearch实战教程",
"author": "张三",
"publish_date": "2024-01-15",
"views": 1000,
"price": 99.9
}
# 使用index方法创建文档
es.index(index=index_name, doc_type="_doc", id=doc_id, body=doc)
print(f"✅ 文档已创建,ID: {doc_id}")
3.1.2 查询文档
知识点: 可以通过ID查询单个文档,也可以使用搜索API查询多个文档。
代码示例:
python
# 根据ID查询文档
res = es.get(index=index_name, doc_type="_doc", id=doc_id)
print(f"📄 查询结果:{res['_source']}")
# 查询所有文档
res = es.search(index=index_name, body={"query": {"match_all": {}}})
print(f"📊 共找到 {res['hits']['total']} 条文档")
3.1.3 更新文档
知识点: 更新文档时,可以更新整个文档,也可以只更新部分字段。Elasticsearch会先检索文档,然后更新它,最后重新索引。
代码示例:
python
# 部分更新文档
es.update(
index=index_name,
doc_type="_doc",
id=doc_id,
body={"doc": {"views": 1500, "price": 89.9}}
)
print(f"✅ 文档 '{doc_id}' 已更新")
3.1.4 删除文档
知识点: 可以通过ID删除单个文档,也可以使用删除查询API删除符合条件的多个文档。
代码示例:
python
# 根据ID删除文档
es.delete(index=index_name, doc_type="_doc", id=doc_id)
print(f"✅ 文档 '{doc_id}' 已删除")
3.2 批量操作
知识点: 批量操作可以提高处理大量文档时的性能,减少网络往返次数。Elasticsearch提供了helpers.bulk()
方法来简化批量操作。
代码示例:
python
from elasticsearch import helpers
# 准备批量操作数据
actions = [
{
"_index": index_name,
"_type": "_doc",
"_id": str(i+1),
"_source": {
"title": f"文档 {i+1}",
"author": "作者",
"views": (i+1)*100
}
}
for i in range(5)
]
# 执行批量索引操作
helpers.bulk(es, actions)
print(f"✅ 已批量索引 {len(actions)} 条文档")
3.3 数据查询
3.3.1 基本查询
知识点: Elasticsearch提供了丰富的查询功能,包括精确查询、范围查询、模糊查询等。查询条件通过JSON格式的查询体定义。
代码示例:
python
# 精确匹配查询
res = es.search(
index=index_name,
body={
"query": {
"term": {"author": "张三"}
}
}
)
print(f"🔍 找到 {res['hits']['total']} 条匹配文档")
# 范围查询
res = es.search(
index=index_name,
body={
"query": {
"range": {
"views": {"gte": 500, "lte": 2000}
}
}
}
)
print(f"🔍 找到 {res['hits']['total']} 条浏览量在500-2000之间的文档")
3.3.2 复合查询
知识点: 复合查询允许组合多个查询条件,使用布尔逻辑(must、should、must_not)来构建复杂查询。
代码示例:
python
# 布尔复合查询
res = es.search(
index=index_name,
body={
"query": {
"bool": {
"must": [ # 必须满足的条件
{"term": {"author": "张三"}},
{"range": {"views": {"gt": 1000}}}
],
"filter": [ # 过滤条件(不影响评分)
{"range": {"price": {"lt": 100}}}
]
}
}
}
)
print(f"🔍 找到 {res['hits']['total']} 条符合所有条件的文档")
4. 零停机索引迁移
4.1 迁移原理
知识点: 零停机索引迁移是指在不中断服务的情况下,将数据从一个索引迁移到另一个索引。这在需要修改索引结构(如字段类型)时非常有用。主要通过索引别名和原子切换实现。
4.2 实现步骤
知识点: 零停机迁移的核心步骤包括:创建新索引、数据迁移、原子切换别名。
代码示例:
python
# 定义旧索引、新索引和别名
old_index = "products_v1"
new_index = "products_v2"
write_alias = "products_write"
read_alias = "products_read"
# 1. 创建新索引(修改映射结构)
es.indices.create(
index=new_index,
body={
"settings": {"index": {"number_of_shards": 3, "number_of_replicas": 1}},
"mappings": {
"_doc": {
"properties": {
# 新的映射结构,可以修改字段类型等
"name": {"type": "text"},
"price": {"type": "scaled_float", "scaling_factor": 100} # 修复精度问题
}
}
}
}
)
# 2. 数据迁移:从旧索引复制数据到新索引
es.reindex(
body={"source": {"index": old_index}, "dest": {"index": new_index}},
wait_for_completion=True # 同步执行
)
print(f"🚚 数据已从 '{old_index}' 迁移到 '{new_index}'")
4.3 原子切换
知识点: 原子切换是零停机迁移的关键步骤,通过update_aliases
API在一个原子操作中完成别名的移除和添加,确保服务不中断。
代码示例:
python
# 3. 原子性切换别名
es.indices.update_aliases(
body={
"actions": [
{"remove": {"index": old_index, "alias": write_alias}},
{"add": {"index": new_index, "alias": write_alias}},
{"remove": {"index": old_index, "alias": read_alias}},
{"add": {"index": new_index, "alias": read_alias}}
]
}
)
print(f"✅ 已原子性切换别名到新索引 '{new_index}'")
# 4. 验证:通过别名查询数据
res = es.search(index=read_alias, body={"query": {"match_all": {}}})
print(f"📊 通过别名查询到 {res['hits']['total']} 条记录")
5. 高级查询技巧
5.1 分页查询
知识点: 当查询结果较多时,需要使用分页功能。Elasticsearch通过from
和size
参数实现分页,from
指定起始位置,size
指定每页记录数。
代码示例:
python
# 分页查询:第1页,每页10条
page = 1
page_size = 10
from_pos = (page - 1) * page_size
res = es.search(
index=index_name,
body={
"query": {"match_all": {}},
"from": from_pos,
"size": page_size
}
)
print(f"📄 第{page}页,共找到 {res['hits']['total']} 条记录,本页有 {len(res['hits']['hits'])} 条")
5.2 排序查询
知识点: Elasticsearch支持对查询结果进行排序,可以按单个字段排序,也可以按多个字段排序。
代码示例:
python
# 按单个字段排序(价格升序)
res = es.search(
index=index_name,
body={
"query": {"match_all": {}},
"sort": [{"price": {"order": "asc"}}]
}
)
print("🔀 按价格升序排序结果:")
for hit in res['hits']['hits']:
print(f" - {hit['_source']['title']}: {hit['_source']['price']}元")
# 按多个字段排序(先按分类,再按价格降序)
res = es.search(
index=index_name,
body={
"query": {"match_all": {}},
"sort": [
{"category": {"order": "asc"}},
{"price": {"order": "desc"}}
]
}
)
5.3 聚合查询
知识点: 聚合查询用于对数据进行统计分析,可以实现分组、求和、平均值等统计功能。
代码示例:
python
# 按分类分组并统计数量
res = es.search(
index=index_name,
body={
"size": 0, # 不返回原始文档
"aggs": {
"category_count": {
"terms": {"field": "category.keyword"}
}
}
}
)
print("📊 按分类统计:")
for bucket in res['aggregations']['category_count']['buckets']:
print(f" - {bucket['key']}: {bucket['doc_count']} 件")
# 计算平均价格
res = es.search(
index=index_name,
body={
"size": 0,
"aggs": {
"avg_price": {
"avg": {"field": "price"}
}
}
}
)
print(f"💰 平均价格: {res['aggregations']['avg_price']['value']:.2f} 元")
5.4 全文搜索
知识点: 全文搜索是Elasticsearch的核心功能,可以对文本字段进行分词搜索,并根据相关性评分返回结果。
代码示例:
python
# 基本全文搜索
res = es.search(
index=index_name,
body={
"query": {
"match": {
"title": "Elasticsearch教程"
}
}
}
)
print(f"🔍 找到 {res['hits']['total']} 条匹配'Elasticsearch教程'的记录")
# 多字段全文搜索
res = es.search(
index=index_name,
body={
"query": {
"multi_match": {
"query": "入门指南",
"fields": ["title", "description"]
}
}
}
)
print(f"🔍 在多个字段中找到 {res['hits']['total']} 条匹配'入门指南'的记录")
🎯 总结与建议
通过本教程,你已经学习了Elasticsearch的核心操作,包括:
- 基础连接 - 如何连接Elasticsearch并测试连接状态
- 索引管理 - 如何创建、修改和管理索引
- 文档操作 - 如何进行文档的增删改查和批量操作
- 零停机迁移 - 如何在不中断服务的情况下更新索引结构
- 高级查询 - 如何使用分页、排序、聚合和全文搜索功能
希望本教程能帮助你快速掌握Elasticsearch的使用技巧,祝你在搜索的世界里探索愉快!
🌟 如果你觉得本教程对你有帮助,请给我一个赞!如有任何问题或建议,欢迎留言讨论。