MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

ElasticSearch文档读写操作入门

2024-05-255.4k 阅读

ElasticSearch 基础概念

在深入探讨 ElasticSearch 的文档读写操作之前,我们先来理解一些关键的基础概念。

索引(Index)

索引是 ElasticSearch 存储数据的逻辑容器,类似于关系型数据库中的数据库概念。一个索引可以包含多个类型(在 ElasticSearch 7.0 之后,类型的概念逐渐被弱化,单个索引建议只存储一种类型的数据),并且每个索引都有自己的配置,例如分片数量、副本数量等。可以将索引看作是一个存放相似文档的地方,比如可以创建一个名为 “products” 的索引来存放所有产品相关的文档。

文档(Document)

文档是 ElasticSearch 中最基本的数据单元,它是一个 JSON 格式的对象,包含了各种字段及其对应的值。每个文档都存在于一个索引中,并且可以通过唯一的标识符(ID)来进行区分。例如,一个产品文档可能包含产品名称、价格、描述等字段,如下所示:

{
    "product_name": "示例手机",
    "price": 2999,
    "description": "一款高性能的智能手机"
}

分片(Shard)

为了处理大规模的数据,ElasticSearch 将索引划分成多个分片。每个分片本身就是一个完整的搜索引擎,它可以独立地进行数据的存储和检索。ElasticSearch 会自动管理这些分片,在节点之间进行负载均衡。例如,一个大的 “products” 索引可以被分成多个分片,分布在不同的服务器节点上,这样可以提高数据处理的并行性和整体性能。

副本(Replica)

副本是分片的拷贝,主要用于提高数据的可用性和查询性能。当某个分片所在的节点出现故障时,副本可以替代它继续提供服务。同时,副本也可以用于分担读请求,提高查询的响应速度。每个分片可以有多个副本,ElasticSearch 会自动维护副本与主分片之间的数据一致性。

安装与环境准备

在开始进行 ElasticSearch 的文档读写操作之前,需要先安装 ElasticSearch 并确保环境配置正确。

安装 ElasticSearch

  1. 下载:从 ElasticSearch 的官方网站(https://www.elastic.co/downloads/elasticsearch)下载适合你操作系统的安装包。
  2. 解压:对于压缩包形式的安装包,解压到你希望安装的目录。例如,在 Linux 系统下,可以使用以下命令解压:
tar -zxvf elasticsearch-<version>.tar.gz
  1. 启动:进入解压后的目录,在 bin 目录下执行启动脚本。在 Linux 或 macOS 系统下:
cd elasticsearch-<version>/bin
./elasticsearch

在 Windows 系统下,打开命令提示符,进入 bin 目录,执行 elasticsearch.bat

安装 Elasticsearch 客户端

为了方便与 ElasticSearch 进行交互,我们可以安装 Elasticsearch 客户端。这里以 Python 的 Elasticsearch 客户端为例,使用 pip 进行安装:

pip install elasticsearch

文档写入操作

创建文档

在 ElasticSearch 中创建文档,需要指定索引、文档类型(在新版中可不指定)和文档内容。下面以 Python 的 Elasticsearch 客户端为例,展示如何创建一个文档。

首先,导入 Elasticsearch 客户端库并建立连接:

from elasticsearch import Elasticsearch

es = Elasticsearch([{'host': 'localhost', 'port': 9200}])

然后,创建一个文档,例如创建一个名为 “test_index” 的索引下的产品文档:

doc = {
    "product_name": "示例笔记本电脑",
    "price": 5999,
    "description": "轻薄便携的高性能笔记本"
}

response = es.index(index='test_index', body=doc)
print(response)

在上述代码中,es.index 方法用于创建文档。index 参数指定索引名称,body 参数为文档的具体内容。执行代码后,ElasticSearch 会返回一个响应,包含文档的创建结果,例如创建的文档 ID、版本等信息。

更新文档

如果文档已经存在,我们可以对其进行更新。ElasticSearch 提供了多种更新文档的方式。

  1. 全量更新:可以直接使用 index 方法再次写入文档,ElasticSearch 会根据文档 ID 进行判断,如果文档存在则更新,不存在则创建。例如:
updated_doc = {
    "product_name": "更新后的示例笔记本电脑",
    "price": 6299,
    "description": "升级配置后的轻薄高性能笔记本"
}

response = es.index(index='test_index', id=response['_id'], body=updated_doc)
print(response)

这里通过 id 参数指定要更新的文档 ID,将新的文档内容传递给 body 参数。

  1. 部分更新:使用 update 方法可以对文档的部分字段进行更新。例如,只更新价格字段:
update_body = {
    "doc": {
        "price": 6499
    }
}

response = es.update(index='test_index', id=response['_id'], body=update_body)
print(response)

update_body 中,doc 字段包含了要更新的具体内容。

批量写入文档

当需要写入大量文档时,逐个写入效率较低,此时可以使用批量写入操作。ElasticSearch 提供了 bulk 方法来实现批量操作。

假设我们有一个包含多个产品文档的列表:

products = [
    {
        "product_name": "示例平板电脑",
        "price": 1999,
        "description": "小巧便携的平板电脑"
    },
    {
        "product_name": "示例耳机",
        "price": 299,
        "description": "高音质无线耳机"
    }
]

actions = []
for product in products:
    action = {
        "index": {
            "_index": "test_index"
        }
    }
    actions.append(action)
    actions.append(product)

response = es.bulk(body=actions)
print(response)

在上述代码中,我们构建了一个包含多个操作的列表 actions,每个操作由一个索引动作和对应的文档组成。然后使用 es.bulk 方法执行批量操作。

文档读取操作

根据 ID 获取文档

通过文档的唯一 ID 可以快速获取文档内容。以 Python 客户端为例:

response = es.get(index='test_index', id=response['_id'])
print(response['_source'])

这里 es.get 方法的 index 参数指定索引,id 参数指定文档 ID。响应中的 _source 字段包含了文档的原始内容。

搜索文档

ElasticSearch 强大的搜索功能允许我们根据各种条件搜索文档。

  1. 简单搜索:例如搜索价格大于 3000 的产品文档:
query = {
    "query": {
        "range": {
            "price": {
                "gt": 3000
            }
        }
    }
}

response = es.search(index='test_index', body=query)
for hit in response['hits']['hits']:
    print(hit['_source'])

在上述代码中,query 定义了搜索条件,range 表示范围查询,gt 表示大于。es.search 方法执行搜索,hits 字段包含了搜索结果,通过遍历 hits['hits'] 可以获取每个匹配的文档。

  1. 全文搜索:ElasticSearch 对文本字段的全文搜索非常强大。例如搜索描述中包含 “高性能” 的产品文档:
query = {
    "query": {
        "match": {
            "description": "高性能"
        }
    }
}

response = es.search(index='test_index', body=query)
for hit in response['hits']['hits']:
    print(hit['_source'])

match 查询用于对文本字段进行全文搜索,ElasticSearch 会对文本进行分词处理,然后查找匹配的文档。

  1. 组合查询:可以将多个查询条件组合起来,实现更复杂的搜索。例如搜索价格大于 3000 且描述中包含 “高性能” 的产品文档:
query = {
    "query": {
        "bool": {
            "must": [
                {
                    "range": {
                        "price": {
                            "gt": 3000
                        }
                    }
                },
                {
                    "match": {
                        "description": "高性能"
                    }
                }
            ]
        }
    }
}

response = es.search(index='test_index', body=query)
for hit in response['hits']['hits']:
    print(hit['_source'])

bool 查询可以组合多个查询条件,must 表示所有条件都必须满足。

分页查询

当搜索结果较多时,需要进行分页显示。ElasticSearch 通过 fromsize 参数来实现分页。例如,每页显示 10 条记录,获取第二页的结果:

query = {
    "query": {
        "match_all": {}
    }
}

from_value = 10
size_value = 10
response = es.search(index='test_index', body=query, from_=from_value, size=size_value)
for hit in response['hits']['hits']:
    print(hit['_source'])

from_ 参数指定从结果集的第几条记录开始返回(从 0 开始计数),size 参数指定每页返回的记录数。

文档删除操作

根据 ID 删除文档

通过文档 ID 可以删除指定的文档。以 Python 客户端为例:

response = es.delete(index='test_index', id=response['_id'])
print(response)

es.delete 方法的 index 参数指定索引,id 参数指定要删除的文档 ID。执行后 ElasticSearch 会返回删除操作的结果。

条件删除文档

ElasticSearch 本身并没有直接提供条件删除的 API,但可以通过先搜索出符合条件的文档 ID,然后逐个删除来实现类似功能。例如,删除价格小于 1000 的产品文档:

query = {
    "query": {
        "range": {
            "price": {
                "lt": 1000
            }
        }
    }
}

response = es.search(index='test_index', body=query)
for hit in response['hits']['hits']:
    es.delete(index='test_index', id=hit['_id'])

首先通过搜索获取符合条件的文档,然后遍历结果集,使用 es.delete 方法逐个删除文档。

深入理解文档读写原理

写入原理

  1. 索引与分片:当我们写入一个文档时,ElasticSearch 首先根据文档的 ID(如果没有指定,ElasticSearch 会自动生成一个)通过哈希算法计算出该文档应该存储在哪个分片上。然后,主分片会接收这个文档并进行写入操作。
  2. 副本同步:主分片写入成功后,会将数据同步到它的副本分片上。只有当所有副本分片都成功同步数据后,写入操作才会被认为是成功的(这可以通过 consistency 参数进行调整,例如 one 表示只要有一个副本成功同步即可,all 表示所有副本都要成功同步)。

读取原理

  1. 搜索请求分发:当发起一个搜索请求时,ElasticSearch 会将请求发送到索引的所有分片(包括主分片和副本分片)上。每个分片独立执行搜索操作,并返回部分结果。
  2. 结果合并:ElasticSearch 协调节点会收集所有分片返回的结果,并根据相关性得分等因素进行合并和排序,最终返回给客户端完整的搜索结果。

性能优化与注意事项

性能优化

  1. 合理设置分片和副本数量:分片数量过多会增加管理开销,过少则可能导致数据存储和查询性能瓶颈。副本数量过多会占用更多的存储空间和网络带宽,应根据实际的读/写负载进行合理设置。
  2. 使用批量操作:如前面提到的批量写入和批量读取操作,可以减少网络交互次数,提高整体性能。
  3. 优化查询语句:避免使用过于复杂或低效的查询,例如尽量避免使用通配符查询(wildcard),因为它的性能开销较大。

注意事项

  1. 版本控制:ElasticSearch 对文档进行更新操作时,会增加文档的版本号。在并发操作时,需要注意版本冲突问题,可以通过在更新请求中指定版本号来避免覆盖最新的数据。
  2. 数据一致性:由于副本同步存在一定的延迟,在某些对数据一致性要求极高的场景下,可能需要等待副本同步完成后再进行读取操作,可以通过设置 refresh 参数来实现。

通过以上内容,我们全面地了解了 ElasticSearch 的文档读写操作,包括基础概念、安装配置、具体的读写操作、原理以及性能优化等方面。希望这些知识能帮助你在实际项目中更好地使用 ElasticSearch 进行数据的管理和检索。