簡體   English   中英

具有多線程的 ElasticSearch Scroll API

[英]ElasticSearch Scroll API with multi threading

首先,我想讓大家知道我知道ElasticSearch Scroll API如何工作的基本工作邏輯。 要使用Scroll API,首先,我們需要使用一些滾動值(如1m )調用search方法,然后它將返回一個_scroll_id ,它將用於 Scroll 上的下一個連續調用,直到所有文檔在循環內返回。 但問題是我只想在多線程的基礎上使用相同的進程,而不是串行。 例如:

如果我有 300000 個文檔,那么我想以這種方式處理/獲取文檔

  • 第一個線程將處理初始100000 個文檔
  • 第二個線程將處理接下來的100000 個文檔
  • 第三個線程將處理剩余的100000 個文檔

所以我的問題是,我沒有找到任何方法來設置滾動 API 上的from值,如何使用線程使滾動過程更快。 不要以序列化的方式處理文檔。

我的示例 python 代碼

if index_name is not None and doc_type is not None and body is not None:
   es = init_es()
   page = es.search(index_name,doc_type, scroll = '30s',size = 10, body = body)
   sid = page['_scroll_id']
   scroll_size = page['hits']['total']

   # Start scrolling
   while (scroll_size > 0):

       print("Scrolling...")
       page = es.scroll(scroll_id=sid, scroll='30s')
       # Update the scroll ID
       sid = page['_scroll_id']

       print("scroll id: " + sid)

       # Get the number of results that we returned in the last scroll
       scroll_size = len(page['hits']['hits'])
       print("scroll size: " + str(scroll_size))

       print("scrolled data :" )
       print(page['aggregations'])

你試過切片卷軸嗎? 根據鏈接的文檔:

對於返回大量文檔的滾動查詢,可以將滾動拆分為可以獨立使用的多個切片。

每個滾動都是獨立的,可以像任何滾動請求一樣並行處理。

我自己沒有使用過這個(我需要處理的最大結果集是 ~50k 文檔),但這似乎是你正在尋找的。

您應該為此使用切片滾動,請參閱https://github.com/elastic/elasticsearch-dsl-py/issues/817#issuecomment-372271460了解如何在 python 中執行此操作。

滾動必須是同步的,這是邏輯。

您可以使用多線程,這正是 elasticsearch 適合的原因:並行性。

一個彈性搜索索引,由分片組成,這是您數據的物理存儲。 分片可以在同一個節點上,也可以不在(更好)。

另一方面,搜索 API 提供了一個非常好的選項: _preference ( https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-preference.html )

所以回到你的應用程序:

  1. 獲取索引分片(和節點)列表
  2. 通過分片創建線程
  3. 在每個線程上進行滾動搜索

等等!

此外,您可以使用 elasticsearch4hadoop 插件,它對 Spark / PIG / map-reduce / Hive 完全相同。

我遇到了和你一樣的問題,但文檔大小是 140 萬。 我不得不使用並發方法並使用 10 個線程進行數據寫入。

我用Java線程池寫了代碼,你可以在Python中找到類似的方式。

    public class ControllerRunnable implements  Runnable {
        private String i_res;
        private String i_scroll_id;
        private int i_index;
        private JSONArray i_hits;
        private JSONObject i_result;

        ControllerRunnable(int index_copy, String _scroll_id_copy) {
            i_index = index_copy;
            i_scroll_id = _scroll_id_copy;
        }

        @Override
        public void run(){
            try {
                s_logger.debug("index:{}", i_index );
                String nexturl = m_scrollUrl.replace("--", i_scroll_id);
                s_logger.debug("nexturl:{}", nexturl);
                i_res = get(nexturl);

                s_logger.debug("i_res:{}", i_res);

                i_result = JSONObject.parseObject(i_res);
                if (i_result == null) {
                    s_logger.info("controller thread parsed result object NULL, res:{}", i_res);
                    s_counter++;
                    return;
                }
                i_scroll_id = (String) i_result.get("_scroll_id");
                i_hits = i_result.getJSONObject("hits").getJSONArray("hits");
                s_logger.debug("hits content:{}\n", i_hits.toString());

                s_logger.info("hits_size:{}", i_hits.size());

                if (i_hits.size() > 0) {
                    int per_thread_data_num = i_hits.size() / s_threadnumber;
                    for (int i = 0; i < s_threadnumber; i++) {
                        Runnable worker = new DataRunnable(i * per_thread_data_num,
                                (i + 1) * per_thread_data_num);
                        m_executor.execute(worker);
                    }
                    // Wait until all threads are finish
                    m_executor.awaitTermination(1, TimeUnit.SECONDS);
                } else {
                    s_counter++;
                    return;
                }
            } catch (Exception e) {
                s_logger.error(e.getMessage(),e);
            }
        }
    }

暫無
暫無

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

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