本文为博主原创,未经授权,严禁转载及使用。
本文链接:https://blog.csdn.net/zyooooxie/article/details/118367832
前面刚刚分享 使用requests发请求操作Elasticsearch【一】 ,继续分享下。
【实际这篇博客推迟发布N个月】
个人博客:https://blog.csdn.net/zyooooxie
【以下所有内容仅为个人项目经历,如有不同,纯属正常】
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/docs.html
"""
@blog: https://blog.csdn.net/zyooooxie
@qq: 153132336
@email: [email protected]
"""
import json
import random
import time
import string
import copy
import requests
from 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_false
from 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.html
def 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 True
res = 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 res
def 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_id
test_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=create
url = '/'.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_id
Log.info(new_id_)
# 2.在 URL 末端使用 /_create
# PUT /{index}/{type}/{id}/_create
# POST /{index}/{type}/{id}/_create
url = '/'.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}?pretty
url = '/'.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 res
def test_get_doc2(document_id: str):
"""
:param document_id:
:return:
"""
# 默认情况下, GET 请求会返回整个文档,这个文档正如存储在 _source 字段中的一样。但是也许你只对其中的 title 字段感兴趣。
# 单个字段能用 _source 参数请求得到,多个字段也能使用逗号分隔的列表来指定。
# GET /{index}/{type}/{id}?_source=title,text
url = '/'.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_includes
url = '/'.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_excludes
url = '/'.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}/_source
url = '/'.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是201
assert res.status_code == 200 if _version is not None else 201
assert 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}/_update
url = '/'.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 404
Log.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是404
test_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_copy
def test_multi_get(document_id_list: list):
"""
取回多个文档
:param document_id_list:
:return:
"""
# mget API 要求有一个 docs 数组作为参数,每个元素包含需要检索文档的元数据, 包括 _index 、 _type 和 _id 。
# GET /_mget
url1 = '/'.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}/_mget
url2 = '/'.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}/_mget
url3 = '/'.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}/_count
url = '/'.join([gl_es_host_new, gl_index, gl_type, '_count'])
es_send_request('post', url, {})
def test_mapping():
"""
:return:
"""
# 通过 /_mapping ,我们可以查看 Elasticsearch 在一个或多个索引中的一个或多个类型的映射
# GET /{index}/_mapping
url = '/'.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