簡體   English   中英

Elasticsearch python API:通過查詢刪除文檔

[英]Elasticsearch python API: Delete documents by query

我看到以下 API 將在 Elasticsearch 中按查詢刪除 - http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/docs-delete-by-query.html

但我想對彈性搜索批量 API 做同樣的事情,即使我可以使用批量上傳文檔

es.bulk(body=json_batch)

我不確定如何使用用於彈性搜索的 python 批量 API 來通過查詢調用刪除。

看看elasticsearch如何通過查詢API棄用刪除。 我使用綁定創建了這個python腳本來做同樣的事情。 首先定義ES連接:

import elasticsearch
es = elasticsearch.Elasticsearch(['localhost'])

現在,您可以使用它來為要刪除的結果創建查詢。

search=es.search(
    q='The Query to ES.',
    index="*logstash-*",
    size=10,
    search_type="scan",
    scroll='5m',
)

現在,您可以循環滾動該查詢。 在我們這樣做時生成我們的請求。

 while True:
    try: 
      # Git the next page of results. 
      scroll=es.scroll( scroll_id=search['_scroll_id'], scroll='5m', )
    # Since scroll throws an error catch it and break the loop. 
    except elasticsearch.exceptions.NotFoundError: 
      break 
    # We have results initialize the bulk variable. 
    bulk = ""
    for result in scroll['hits']['hits']:
      bulk = bulk + '{ "delete" : { "_index" : "' + str(result['_index']) + '", "_type" : "' + str(result['_type']) + '", "_id" : "' + str(result['_id']) + '" } }\n'
    # Finally do the deleting. 
    es.bulk( body=bulk )

要使用批量api,您需要確保兩件事:

  1. 文檔已標識您要更新。 (索引,類型,id)
  2. 每個請求都以換行符或/ n終止。

elasticsearch-py批量API允許您通過在每條記錄中包含'_op_type': 'delete'來批量'_op_type': 'delete'記錄。 但是,如果要逐個刪除,則仍需要進行兩個查詢:一個用於獲取要刪除的記錄,另一個用於刪除它們。

批量執行此操作的最簡單方法是使用python模塊的scan()幫助程序,它包裝ElasticSearch Scroll API,因此您無需跟蹤_scroll_id 將它與bulk()幫助器一起用作已棄用的delete_by_query()的替代:

from elasticsearch.helpers import bulk, scan

bulk_deletes = []
for result in scan(es,
                   query=es_query_body,  # same as the search() body parameter
                   index=ES_INDEX,
                   doc_type=ES_DOC,
                   _source=False,
                   track_scores=False,
                   scroll='5m'):

    result['_op_type'] = 'delete'
    bulk_deletes.append(result)

bulk(elasticsearch, bulk_deletes)

由於傳遞了_source=False ,因此不會返回文檔正文,因此每個結果都非常小。 但是,如果您有內存限制,則可以非常輕松地批量處理:

BATCH_SIZE = 100000

i = 0
bulk_deletes = []
for result in scan(...):

    if i == BATCH_SIZE:
        bulk(elasticsearch, bulk_deletes)
        bulk_deletes = []
        i = 0

    result['_op_type'] = 'delete'
    bulk_deletes.append(result)

    i += 1

bulk(elasticsearch, bulk_deletes)

我目前正在使用基於@drs響應的腳本,但始終使用bulk()幫助程序。 它可以使用chunk_size參數從迭代器創建批量作業(默認為500,有關詳細信息,請參閱straming_bulk() )。

from elasticsearch import Elasticsearch
from elasticsearch.helpers import scan, bulk

BULK_SIZE = 1000

def stream_items(es, query):
    for e in scan(es, 
                  query=query, 
                  index=ES_INDEX,
                  doc_type=ES_DOCTYPE, 
                  scroll='1m',
                  _source=False):

        # There exists a parameter to avoid this del statement (`track_source`) but at my version it doesn't exists.
        del e['_score']
        e['_op_type'] = 'delete'
        yield e

es = Elasticsearch(host='localhost')
bulk(es, stream_items(es, query), chunk_size=BULK_SIZE)

謝謝,這真的很有用!

我有兩個建議:

  1. 當使用scroll獲取結果的下一頁時, es.scroll(scroll_id=search['_scroll_id'])應該是在最后一個滾動中返回的_scroll_id ,而不是搜索返回的那個。 Elasticsearch不會每次都更新滾動ID,特別是對於較小的請求(請參閱此討論 ),因此此代碼可能有效,但並非萬無一失。

  2. 清除卷軸很重要,因為長時間保持搜索上下文打開會產生成本。 Clear Scroll API - Elasticsearch API文檔它們將在超時后最終關閉,但如果您的磁盤空間不足,例如,它可以為您節省很多麻煩。

一種簡單的方法是在旅途中建立一個滾動ID列表(確保擺脫重復!),並最終清除所有內容。

es.clear_scroll(scroll_id=scroll_id_list)

雖然在操作上等同於許多其他答案,但我發現這種方式更容易理解:

import elasticsearch
from elasticsearch.helpers import bulk

es = elasticsearch.Elasticsearch(['localhost'])

ids = [1,2,3, ...]      # list of ids that will be deleted
index = "fake_name"     # index where the documents are indexed

actions = ({
    "_id": id,
    "_op_type": "delete"
} for id in ids)

bulk(client=es, actions=actions, index=index, refresh=True)
# `refresh=True` makes the result immediately available

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM