提交带有“_bulk”端点的 POST 请求时来自 elasticsearch 的 400

400 from elasticsearch when submitting POST request with "_bulk" end point

我已经使用 elasticsearch 模块成功提交了批量 POST 请求。

但是我想做所有不使用这个模块的事情,只使用 requests 模块。

当我尝试用 _bulk 结束点执行 POST 时遇到问题。这是代码,其中 post_object 是用于填充索引的单个文档的连接 json.dumps(...) + '\n' 的字符串。注意 url 只是 'http://localhost:9200/docs'.

print(f'post_object:\n{json.dumps(post_object, indent=2, default=str)}')
headers = {'Content-type': 'application/json'}        
params = {'grant_type' : 'client_credentials'}                
response = requests.post(f'{url}/_bulk', data=json.dumps(post_object, default=str) + '\n', headers=headers, params=params)        
print(f'response.json() {response.json()}')

这给出:

response.json() {'error': {'root_cause': [{'type': 'illegal_argument_exception', 'reason': 'Malformed action/metadata line [1], 
expected START_OBJECT but found [VALUE_STRING]'}], 'type': 'illegal_argument_exception', 'reason': 'Malformed action/metadata line [1], expected START_OBJECT but found [VALUE_STRING]'}, 'status': 400}

我之前曾尝试制作 post_object 个人 JSON dict 的列表...但这给出了 400 的另一个原因:

response.json() {'error': {'root_cause': [{'type': 'illegal_argument_exception', 'reason': 'Malformed action/metadata line [1], 
expected START_OBJECT but found [START_ARRAY]'}], 'type': 'illegal_argument_exception', 'reason': 'Malformed action/metadata line [1], expected START_OBJECT but found [START_ARRAY]'}, 'status': 400}

...有谁知道什么样的“START_OBJECT”requests 想用这个 _bulk 终点找到什么?

注意有很多页面专门介绍这个,例如here or here。我似乎必须提交一个字符串作为 data 参数,显然带有一些元数据元素,并在正确的位置换行。我显然还必须将 header“Content-type”设置为“x-ndjson”,我现在已经完成了……但我只是想要一个简单的例子,理想情况下!

知道了。 ES的NB版本是7.12,Python3.9.4.

只是想我会把它留在这里以节省其他人半小时的浪费时间。

是的,事实证明“Content-type”“x-ndjson”的使用是必不可少的。确实有必要提交一个字符串作为data参数。因此:

post_object_str = ''
for num, obj in enumerate(  ... 
    # iteration loop creating the dicts to prepare the ES documents

    dict_doc = {}
    # fill this with your fields, e.g.:
    dict_doc['interesting_data'] = 'something'
    dict_doc['timestamp'] = datetime.datetime.now()
    # NB you get a complaint if you try to include the "_id" field not as "metadata"
    post_object_str += f'{{"index": {{"_id": "{str(num)}"}}}}\n'
    post_object_str += json.dumps(dict_doc, default=str) + '\n'

# see what it looks like    
print(f'post_object_str:\n{post_object_str[:400]}')
        
headers = {'Content-type': 'application/x-ndjson'}        
response = requests.post(f'{url}/_bulk', data=post_object_str, headers=headers)
# examine the response...
print(f'post response.json():\n{json.dumps(response.json(), indent=2)}')

200: 索引瞬间填充。漂亮。