ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

使用requests发请求操作Elasticsearch【二】

2026/9/21 10:15:39 拓冰建站 浏览量
使用requests发请求操作Elasticsearch【二】

本文为博主原创,未经授权,严禁转载及使用。
本文链接:https://blog.csdn.net/zyooooxie/article/details/118367832

前面刚刚分享 使用requests发请求操作Elasticsearch【一】 ,继续分享下。

【实际这篇博客推迟发布N个月】

个人博客:https://blog.csdn.net/zyooooxie

【以下所有内容仅为个人项目经历,如有不同,纯属正常】

Document APIs

https://www.elastic.co/guide/en/elasticsearch/reference/7.17/docs.html

"""
@blog: https://blog.csdn.net/zyooooxie
@qq: 153132336
@email: zyooooxie@gmail.com
"""import json
import random
import time
import string
import copy
import requestsfrom requests_toolbelt.utils import dump
from requests import api
from XXX.common_es import gl_es_auth, gl_es_host_new
from XXX.common_functions import one_choice_true_falsefrom user_log import Log# 一个文档不仅仅包含它的数据 ,也包含 元数据(有关 文档的信息)。 三个必须的元数据元素如下:
# _index    文档在哪存放
# _type 文档表示的对象类别
# _id   文档唯一标识gl_index = 'ABC-data'
gl_type = '_doc'gl_int = random.randint(1, 999)
gl_id = 'test' + str(time.time())# https://www.elastic.co/guide/en/elasticsearch/reference/7.17/docs.htmldef es_send_request(request_method: str, request_url: str, data_dict: dict,auth: tuple = gl_es_auth, **kwargs) -> requests.Response:""":param request_method::param request_url::param data_dict::param auth::param kwargs::return:"""assert hasattr(api, request_method) is Trueres = requests.request(method=request_method, url=request_url, json=data_dict, auth=auth, **kwargs)Log.info(dump.dump_all(res).decode('utf-8'))res.close()Log.info('********')return resdef test_index_doc(document_id):""":param document_id::return:"""Log.info(document_id)# 提供自定义的 _id 值# PUT /{index}/{type}/{id}url = '/'.join([gl_es_host_new, gl_index, gl_type, document_id])data_dict = {'test': gl_int * 1, 'text': {'content': document_id + '是id'}}res = es_send_request('put', url, data_dict, gl_es_auth)assert res.json().get('_id') == document_idtest_get_doc(document_id)# 在 Elasticsearch 中每个文档都有一个版本号。当每次对文档进行修改时(包括删除), _version 的值会递增。Log.info(res.json().get('_version'))Log.info('********')# 让 index API 自动生成# POST /{index}/{type}/url = '/'.join([gl_es_host_new, gl_index, gl_type])data_ = {'test': gl_int * 10000, 'text': {'content': 'id是es自动生成的'}}res = es_send_request('post', url, data_)assert res.json().get('result') == 'created'# _id 是 Elasticsearch 自动生成的id_ = res.json().get('_id')Log.info(res.json().get('_id'))test_get_doc(id_)def test_create_doc(document_id):""":param document_id::return:"""# 当我们索引一个文档,怎么确认我们正在创建一个完全新的文档,而不是覆盖现有的呢?# 如果已经有自己的 _id ,那么我们必须告诉 Elasticsearch ,只有在相同的 _index 、 _type 和 _id 不存在时,才接受我们的索引请求# 1.使用 op_type# PUT  /{index}/{type}/{id}?op_type=createurl = '/'.join([gl_es_host_new, gl_index, gl_type, document_id + '?op_type=create'])data_dict = {'test': str(gl_int)}res = es_send_request('put', url, data_dict)Log.info(res.status_code)Log.info('********')new_id_ = document_id if one_choice_true_false else document_id + gl_idLog.info(new_id_)# 2.在 URL 末端使用 /_create# PUT /{index}/{type}/{id}/_create# POST /{index}/{type}/{id}/_createurl = '/'.join([gl_es_host_new, gl_index, gl_type, new_id_, '_create'])res = es_send_request('put', url, data_dict)Log.info(res.status_code)res = es_send_request('post', url, data_dict)Log.info(res.status_code)# 如果具有相同的 _index 、 _type 和 _id 的文档已经存在,Elasticsearch 将会返回 409 Conflict 响应码# 如果创建新文档的请求成功执行,Elasticsearch 会返回  201 Created 的 HTTP 响应码。def test_get_doc(document_id: str):""":param document_id::return:"""# 执行 一个 HTTP GET 请求并指定文档的地址——索引库、类型和ID# GET /{index}/{type}/{id}url = '/'.join([gl_es_host_new, gl_index, gl_type, document_id])res = es_send_request('get', url, {})Log.info('********')# 加上 pretty 参数,这将会调用 Elasticsearch 的 pretty-print 功能,该功能 使得 JSON 响应体更加可读    【调试使用】# GET /{index}/{type}/{id}?prettyurl = '/'.join([gl_es_host_new, gl_index, gl_type, document_id + '?pretty'])# res = es_send_request('get', url, {})Log.info(res.json())found_ = res.json().get('found')assert res.status_code == (404 if found_ is False else 200)# GET 请求的响应体包括 {"found": true} ,这证实了文档已经被找到。# 如果我们请求一个不存在的文档,我们仍旧会得到一个 JSON 响应体,但是 found 将会是 false 。# 此外, HTTP 响应码将会是 404 Not Found ,而不是 200 OK 。return resdef test_get_doc2(document_id: str):""":param document_id: :return: """# 默认情况下, GET 请求会返回整个文档,这个文档正如存储在 _source 字段中的一样。但是也许你只对其中的 title 字段感兴趣。# 单个字段能用 _source 参数请求得到,多个字段也能使用逗号分隔的列表来指定。# GET /{index}/{type}/{id}?_source=title,texturl = '/'.join([gl_es_host_new, gl_index, gl_type, document_id + '?_source={}'.format('seq')])es_send_request('get', url, {})url = '/'.join([gl_es_host_new, gl_index, gl_type, document_id + '?_source={}'.format('seq,text')])es_send_request('get', url, {})# _source_includesurl = '/'.join([gl_es_host_new, gl_index, gl_type, document_id + '?_source_includes={}'.format('seq')])es_send_request('get', url, {})url = '/'.join([gl_es_host_new, gl_index, gl_type, document_id + '?_source_includes={}'.format('seq,text')])es_send_request('get', url, {})Log.info('********')# _source_excludesurl = '/'.join([gl_es_host_new, gl_index, gl_type, document_id + '?_source_excludes={}'.format('seq')])es_send_request('get', url, {})url = '/'.join([gl_es_host_new, gl_index, gl_type, document_id + '?_source_excludes={}'.format('seq,text')])es_send_request('get', url, {})Log.info('********')# 只想得到 _source 字段,不需要任何元数据,你能使用 _source# GET /{index}/{type}/{id}/_sourceurl = '/'.join([gl_es_host_new, gl_index, gl_type, document_id, '_source'])es_send_request('get', url, {})def test_doc_exists(document_id: str):""":param document_id: :return: """# 如果只想检查一个文档是否存在--根本不想关心内容,那么用 HEAD 方法来代替 GET 方法。# HEAD 请求没有返回体,只返回一个 HTTP 请求报头url = '/'.join([gl_es_host_new, gl_index, gl_type, document_id])res = es_send_request('head', url, {})Log.info(res.status_code)# 如果文档存在, Elasticsearch 将返回一个 200 ok 的状态码# 若文档不存在, Elasticsearch 将返回一个 404 Not Found 的状态码def test_update_doc(document_id: str):"""更新整个文档:param document_id::return:"""res = test_get_doc(document_id)_version = res.json().get('_version')Log.info(_version)# 更新整个文档# PUT /{index}/{type}/{id}url = '/'.join([gl_es_host_new, gl_index, gl_type, document_id])data_dict = {'abc': gl_int}res = es_send_request('put', url, data_dict, auth=gl_es_auth)Log.info(res.status_code)# 【若此id存在】    status_code是200# 【若此id不存在】  创建  status_code是201assert res.status_code == 200 if _version is not None else 201assert res.json().get('_version') == (_version if _version is not None else 0) + 1# 在内部,Elasticsearch 已将旧文档标记为已删除,并增加一个全新的文档。 尽管你不能再对旧版本的文档进行访问,但它并不会立即消失。当继续索引更多的数据,Elasticsearch 会在后台清理这些已删除文档。test_get_doc(document_id)def test_partial_updates(document_id):"""文档的部分更新:param document_id::return:"""res = test_get_doc(document_id)_version = res.json().get('_version')Log.info(_version)# 文档的部分更新# 作为 doc 的参数, 它只是与现有的文档进行合并。对象被合并到一起,覆盖现有的字段,增加新的字段# POST /{index}/{type}/{id}/_updateurl = '/'.join([gl_es_host_new, gl_index, gl_type, document_id, '_update'])data = {"doc": {random.choice(string.ascii_letters): 1, "test": str(gl_int)}}  # 已有字段要保证 字段值类型一致res = es_send_request('post', url, data)Log.info(res.status_code)assert res.status_code == 200 if _version is not None else 404Log.info('********')# POST /{index}/_update/{id}        没有 {type}url = '/'.join([gl_es_host_new, gl_index, '_update', document_id])data = {"doc": {random.choice(string.ascii_letters): 1, "test": str(gl_int)}}  # 已有字段要保证 字段值类型一致res = es_send_request('post', url, data)Log.info(res.status_code)assert res.status_code == 200 if _version is not None else 404# 【若此id存在】   status_code是200# 【若此id不存在】 不做更新 + 不创建  status_code是404test_get_doc(document_id)def test_delete_doc(document_id: str):""":param document_id::return:"""# DELETE /{index}/{type}/{id}url = '/'.join([gl_es_host_new, gl_index, gl_type, document_id])res = es_send_request('delete', url, {})# 如果找到该文档,Elasticsearch 将要返回一个 200 ok 的 HTTP 响应码# 如果文档没有找到,我们将得到 404 Not Found 的响应码Log.info(res.status_code)def create_source(docs_list: list):""":param docs_list::return:"""Log.info(docs_list)# 如果你想检索一个或者多个特定的字段,那么你可以通过 _source 参数来指定这些字段的名字:# By default, the _source field is returned for every document (if stored). Use the _source and _source_include or source_exclude attributes to filter what fields are returned for a particular document.# You can include the _source, _source_includes, and _source_excludes query parameters in the request URI to specify the defaults to use when there are no per-document instructions.dl_copy = copy.deepcopy(docs_list)for dl in dl_copy:# dl.update(_source=random.sample(['abc', 'test', 'text'], k=2)) if random.getrandbits(1) else dl.update(#     _source='abc')abc = random.getrandbits(2)if not abc:dl.update(_source=random.sample(['abc0', 'msgType', 'text'], k=2))elif abc == 1:dl.update(_source='seq')elif abc == 2:dl.update(_source={'include': ['abc2', 'text', 'msgTime']})else:dl.update(_source={'include': ['abc3', 'text', 'msgId'], 'exclude': ['text.content']})Log.info(dl_copy)return dl_copydef test_multi_get(document_id_list: list):"""取回多个文档:param document_id_list::return:"""# mget API 要求有一个 docs 数组作为参数,每个元素包含需要检索文档的元数据, 包括 _index 、 _type 和 _id 。# GET /_mgeturl1 = '/'.join([gl_es_host_new, '_mget'])docs_1 = [{'_index': gl_index, '_type': gl_type, '_id': di} for di in document_id_list]data1 = {'docs': docs_1}data1_ = {'docs': create_source(docs_1)}Log.info('********')# 如果想检索的数据都在相同的 _index 中(甚至相同的 _type 中),则可以在 URL 中指定默认的 /_index 或者默认的 /_index/_type# GET /{index}/_mgeturl2 = '/'.join([gl_es_host_new, gl_index, '_mget'])docs_2 = [{'_id': di, '_type': gl_type} for di in document_id_list]data2 = {'docs': docs_2}data2_ = {'docs': create_source(docs_2)}# GET /{index}/{type}/_mgeturl3 = '/'.join([gl_es_host_new, gl_index, gl_type, '_mget'])docs_3 = [{'_id': di} for di in document_id_list]data3 = {'docs': docs_3}data3_ = {'docs': create_source(docs_3)}Log.info('********')# 所有文档的 _index 和 _type 都是相同的,你可以只传一个 ids 数组,而不是整个 docs 数组data3_new = {'ids': document_id_list}Log.info('********')for u, d in zip((url1, url1, url2, url2, url3, url3, url3),(data1, data1_, data2, data2_, data3, data3_, data3_new)):# 对于每一个在请求中指定的文档,这个数组中都包含有一个对应的响应,且顺序与请求中的顺序相同。# 其中的每一个响应都和使用单个 get request 请求所得到的响应体相同es_send_request('get', u, d)time.sleep(1)def test_count():""":return: """# POST /{index}/{type}/_counturl = '/'.join([gl_es_host_new, gl_index, gl_type, '_count'])es_send_request('post', url, {})def test_mapping():""":return: """# 通过 /_mapping ,我们可以查看 Elasticsearch 在一个或多个索引中的一个或多个类型的映射# GET /{index}/_mappingurl = '/'.join([gl_es_host_new, gl_index, '_mapping'])es_send_request('get', url, {})# GET /{index}/_mapping/{type}url = '/'.join([gl_es_host_new, gl_index, '_mapping', gl_type])es_send_request('get', url, {}, params={'include_type_name': 'true'})if __name__ == '__main__':# 映射(Mapping)   描述数据在每个字段内如何存储# 分析(Analysis)  全文是如何处理使之可以被搜索的# 领域特定查询语言(Query DSL)   Elasticsearch 中强大灵活的查询语言Log.info(gl_int)Log.info(gl_id)

本文链接:https://blog.csdn.net/zyooooxie/article/details/118367832

个人博客 https://blog.csdn.net/zyooooxie