迁移到 8.0
编辑迁移到 8.0编辑
客户端有重大更改,需要更改您使用客户端的方式。以下概述了从 7.x 升级到 8.0 时需要考虑的所有更改。
启用兼容模式并升级 Elasticsearch编辑
将您的 Elasticsearch 客户端升级到 7.16
$ python -m pip install --upgrade 'elasticsearch>=7.16,<8'
如果您有现有的应用程序,请通过设置 ELASTIC_CLIENT_APIVERSIONING=1
环境变量来启用兼容模式。这将指示 Elasticsearch 服务器接受并使用与 7.x 兼容的请求和响应。
完成此操作后,您可以 将 Elasticsearch 服务器升级到 8.0.0。
升级客户端编辑
在您使用 7.16 客户端部署应用程序并使用 8.0.0 Elasticsearch 服务器后,您可以将客户端升级到 8.0。
$ python -m pip install --upgrade 'elasticsearch>=8,<9'
移除弃用警告编辑
将客户端升级到 8.0 后,您可能会注意到您的代码要么引发错误,要么引发 DeprecationWarning
,以指示在使用 8.0 客户端之前需要更改代码的位置。
严格的客户端配置编辑
以前,客户端在指定要连接的节点时会使用 scheme="http"
、host="localhost"
和 port=9200
默认值。从 8.0 开始,这些默认值已被移除,需要显式配置方案、主机和端口,或者使用 cloud_id
进行配置,以避免混淆连接的是哪个 Elasticsearch 实例。
做出此选择是因为从 8.0.0 开始,Elasticsearch 默认启用 HTTPS,因此 https://127.0.0.1:9200
是本地运行的集群不再是一个合理的假设。
请参阅有关 连接到 Elasticsearch 和 配置 HTTPS 的文档。
对于快速示例,使用以下两种配置之一效果最佳
from elasticsearch import Elasticsearch # If you're connecting to an instance on Elastic Cloud: client = Elasticsearch( cloud_id="cluster-1:dXMa5Fx...", # Include your authentication like 'api_key' # 'basic_auth', or 'bearer_auth' here. basic_auth=("elastic", "<password>") ) # If you're connecting to an instance hosted elsewhere: client = Elasticsearch( # Notice that the scheme (https://) host (localhost), # and port (9200) are explicit here: "https://127.0.0.1:9200", # Include your authentication like 'api_key' # 'basic_auth', or 'bearer_auth' here: api_key="api_key" )
API 的仅限关键字参数编辑
API 过去支持位置参数和关键字参数,但是文档中 始终建议使用仅限关键字参数。从 7.14 开始,使用位置参数会引发 DeprecationWarning
,但仍然可以正常工作。
现在,从 8.0 开始,API 需要仅限关键字参数,以便更好地向前兼容新的 API 选项。尝试使用位置参数时,将引发 TypeError
。
# 8.0+ SUPPORTED USAGE: client.indices.get(index="*") # 7.x UNSUPPORTED USAGE (Don't do this!): client.indices.get("*")
开始使用 .options() 设置传输参数编辑
以前,客户端 API 方法中允许使用一些每个请求的选项,例如 api_key
和 ignore
。从 8.0 开始,所有 API 都已弃用此功能,并且对于少数 API,如果不更改,可能会以意外的方式中断。
参数 headers
、api_key
、http_auth
、opaque_id
、request_timeout
和 ignore
会受到影响
from elasticsearch import Elasticsearch client = Elasticsearch("https://127.0.0.1:9200") # 8.0+ SUPPORTED USAGE: client.options(api_key="api_key").search(index="blogs") # 7.x DEPRECATED USAGE (Don't do this!): client.search(index="blogs", api_key=("id", "api_key"))
其中一些参数已重命名,以提高可读性和适应其他 API。 ignore
应为 ignore_status
,http_auth
应为 basic_auth
# 8.0+ SUPPORTED USAGES: client.options(basic_auth=("username", "password")).search(...) client.options(ignore_status=404).indices.delete(index=...) # 7.x DEPRECATED USAGES (Don't do this!): client.search(http_auth=("username", "password"), ...) client.indices.delete(index=..., ignore=404)
此更改会导致中断并且由于客户端 API 和 Elasticsearch 的 API 之间的冲突而没有弃用期的 API
-
使用
request_timeout
的sql.query
-
使用
api_key
的security.grant_api_key
-
使用
params
的render_search_template
-
使用
params
的search_template
您应该立即评估这些参数的使用情况,并开始使用 .options(...)
以避免意外行为。以下是从 security.grant_api_key
API 中移除每个请求的 api_key
的示例
# 8.0+ SUPPORTED USAGE: resp = ( client.options( # This is the API key being used for the request api_key="request-api-key" ).security.grant_api_key( # This is the API key being granted api_key={ "name": "granted-api-key" }, grant_type="password", username="elastic", password="changeme" ) ) # 7.x DEPRECATED USAGE (Don't do this!): resp = ( # This is the API key being used for the request client.security.grant_api_key( api_key=("request-id", "request-api-key"), body={ # This is the API key being granted "api_key": { "name": "granted-api-key" }, "grant_type": "password", "username": "elastic", "password": "changeme" } ) )
从 8.12 客户端开始,完全支持使用 body 参数,这意味着您也可以像这样使用 grant_api_key
# 8.12+ SUPPORTED USAGE: resp = ( client.options( # This is the API key being used for the request api_key="request-api-key" ).security.grant_api_key( body={ # This is the API key being granted "api_key": { "name": "granted-api-key" }, "grant_type": "password", "username": "elastic", "password": "changeme" } ) )
API 响应的更改编辑
在 7.x 及更早版本中,API 方法的返回类型是原始的反序列化响应正文。这意味着无法从传输层访问 HTTP 状态代码、标头或其他信息。
在 8.0.0 中,响应不再是原始的反序列化响应正文,而是一个具有两个属性的对象:meta
和 body
。有关响应的传输层元数据(例如 HTTP 状态、标头、版本以及处理请求的节点)可在此处找到
>>> resp = client.search(...) # Response is not longer a 'dict' >>> resp ObjectApiResponse({'took': 1, 'timed_out': False, ...}) # But can still be used like one: >>> resp["hits"]["total"] {'value': 5500, 'relation': 'eq'} >>> resp.keys() dict_keys(['took', 'timed_out', '_shards', 'hits']) # HTTP status >>> resp.meta.status 200 # HTTP headers >>> resp.meta.headers['content-type'] 'application/json' # HTTP version >>> resp.meta.http_version '1.1'
由于响应不再是字典、列表、str
或 bytes
实例,因此对响应对象调用 isintance()
将返回 False
。如果您需要直接访问底层反序列化响应正文,可以使用 body
属性
>>> resp.body {'took': 1, 'timed_out': False, ...} # The response isn't a dict, but resp.body is. >>> isinstance(resp, dict) False >>> isinstance(resp.body, dict) True
使用 HEAD
HTTP 方法的请求仍然可以在 if
条件中使用,但不能与 is
一起使用。
>>> resp = client.indices.exists(index=...) >>> resp.body True >>> resp is True False >>> resp.body is True True >>> isinstance(resp, bool) False >>> isinstance(resp.body, bool) True
错误类的更改编辑
以前,elasticsearch.TransportError
是传输层错误(如超时、连接错误)和 API 层错误(如访问索引时出现“404 未找到”)的基类。当您想捕获 API 错误以检查其响应正文而不捕获来自传输层的错误时,这非常令人困惑。
现在,在 8.0 中,elasticsearch.TransportError
是 elastic_transport.TransportError
的重新定义,并且将仅作为真正的传输层错误的基类。如果您想捕获 API 层错误,可以使用新的 elasticsearch.ApiError
基类。
from elasticsearch import TransportError, Elasticsearch try: client.indices.get(index="index-that-does-not-exist") # In elasticsearch-py v7.x this would capture the resulting # 'NotFoundError' that would be raised above. But in 8.0.0 this # 'except TransportError' won't capture 'NotFoundError'. except TransportError as err: print(f"TransportError: {err}")
elasticsearch.ElasticsearchException
基类也已被移除。如果您想捕获可以从库中引发的所有错误,可以捕获 elasticsearch.ApiError
和 elasticsearch.TransportError
from elasticsearch import TransportError, ApiError, Elasticsearch try: client.search(...) # This is the 'except' clause you should use if you *actually* want to # capture both Transport errors and API errors in one clause: except (ApiError, TransportError) as err: ... # However I recommend you instead split each error into their own 'except' # clause so you can have different behavior for TransportErrors. This # construction wasn't possible in 7.x and earlier. try: client.search(...) except ApiError as err: ... # API errors handled here except TransportError as err: ... # Transport errors handled here
elasticsearch.helpers.errors.BulkIndexError
和 elasticsearch.helpers.errors.ScanError
现在使用 Exception
作为基类,而不是 ElasticsearchException
。
7.x 和 8.0 错误之间的另一个区别是它们的属性。以前有 status_code
、info
和 error
属性,它们不是很有用,因为它们将是不同值类型的混合,具体取决于错误是什么以及它从哪个层(传输层还是 API 层)引发。您可以通过 meta
检查错误并从 ApiError
实例获取响应元数据,并通过 body
获取响应
from elasticsearch import ApiError, Elasticsearch try: client.indices.get(index="index-that-does-not-exist") except ApiError as err: print(err.meta.status) # 404 print(err.meta.headers) # {'content-length': '200', ...} print(err.body) # { # 'error': { # 'type': 'index_not_found_exception', # 'reason': 'no such index', # 'resource.type': 'index_or_alias', # ... # }, # 'status': 404 # }