遇到的问题
elasticsearch.exceptions.ConflictError: ConflictError(409, '{“took”:5287,“timed_out”:false,“total”:2962,“updated”:214,“deleted”:0,“batches”:1,“version_conflicts”:786,“noops”:0,“retries”:{“bulk”:0,“search”:0},“throttled_millis”:0,“requests_per_second”:-1.0,“throttled_until_millis”:0,“failures”:[{“index”:“lily_202312_v1”,“type”:“_doc”,“id”:“0_c48ff990037f728980c7985791fdcf90”,“cause”:{“type”:“version_conflict_engine_exception”,“reason”:“[0_c48ff990037f728980c7985791fdcf90]: version conflict, required seqNo [47901788], primary term [1]. current document has seqNo [56256979] and primary term [1]”,“index_uuid”:“mPxSdiGBTOm0wUDlIo2Ceg”,“shard”:“1”,“index”:“]lily_202312_v1”},“status”:409}
原因
错误是由于update_by_query请求不会等任务处理完成后才返回结果,而是先返回结果,之后会在es后台自动执行。在这个过程中,如果执行下次查询,更新操作,会导致同一个Item同时被两个更新进程更新,进而出现同一个item的版本冲突。
两个更新操作的语句间隔太短了.
解决方案
在使用update_by_query更新时,加上参数wait_for_completion=false。加上这个参数后,更新请求会返回一个这个更新请求对应的任务的 task id。之后在进行下一次查询前,可以根据该id,查询任务是否完成,在完成后再进行后续操作。
task_id = self.es_client.update_by_query(index=index_name, body=body, wait_for_completion=False)
stop = True
while stop:
time.sleep(5)
status = es_client.tasks.get(task_id["task"])
if status["completed"]:
stop = False
updated_prefix_num = status["task"]["status"]["updated"]