【问题标题】:How do I retrieve more than 10000 results/events in Elasticsearch?如何在 Elastic-search 中检索超过 10000 个结果/事件
【发布时间】:2017-05-30 01:59:24
【问题描述】:

查询示例:

GET hostname:port /myIndex/_search { 
    "size": 10000,
    "query": {
        "term": { "field": "myField" }
    }
}

我一直在使用 size 选项,知道:

index.max_result_window = 100000

但是,例如,如果我的查询有 650,000 个文档甚至更多,我怎样才能在一个 GET 中检索所有结果?

我一直在阅读有关 SCROLL、FROM-TO 和 PAGINATION API 的信息,但它们都不会提供超过 10K 的内容。

这是我一直在使用的来自 Elasticsearch 论坛的示例:

GET /_search?scroll=1m

谁能提供一个示例,您可以在其中检索 GET 搜索查询的所有文档?

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    如果您想检索大量文档,滚动是一种方法,因为它超过了可以提高的 10000 个默认限制。

    第一个请求需要指定您要进行的查询以及持续时间为before the search context times outscroll 参数(在下面的示例中为1 分钟)

    POST /index/type/_search?scroll=1m
    {
        "size": 1000,
        "query": {
            "match" : {
                "title" : "elasticsearch"
            }
        }
    }
    

    在对第一个呼叫的响应中,您会收到一个 _scroll_id,您需要使用它来拨打第二个呼叫:

    POST /_search/scroll 
    {
        "scroll" : "1m", 
        "scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAAD4WYm9laVYtZndUQlNsdDcwakFMNjU1QQ==" 
    }
    

    在每个后续响应中,您都会收到一个新的_scroll_id,您需要在下次调用时使用它,直到您检索到所需的文档数量。

    所以在伪代码中它看起来有点像这样:

    # first request
    response = request('POST /index/type/_search?scroll=1m')
    docs = [ response.hits ]
    scroll_id = response._scroll_id
    
    # subsequent requests
    while (true) {
       response = request('POST /_search/scroll', scroll_id)
       docs.push(response.hits)
       scroll_id = response._scroll_id
    }
    

    更新:

    关于深度分页的最佳解决方案,请参考以下更准确的答案:Elastic Search - Scroll behavior

    【讨论】:

    • 谢谢 val。我不确定我是否可以在 php 中使用 curl。除非我可以参数化获取滚动 ID 并提前知道我必须检索多少个文档。你看我没有使用感觉或kibana。我必须使用谷歌图表进行高级聚合,并且我必须查询弹性来获取两组大数据。对它们进行正则表达式并将结果存储在数组中。 Elastic api 可能非常奇特。你认为有一种更简单的方法来检索所有数据吗?可以增加索引最大值吗?或者有没有更简单的方法来使用 scroll Id s?
    • 您绝对可以increase the index.max_result_window value,但如果您想一次性获得 650000 个文档,您将面临关闭集群的风险。
    • 另一种可能性是从 Google 脚本中查询 ES,以便更轻松地将结果与 Google Charts 集成
    • 否则您可以继续使用 curl 并使用 existing solutions 滚动您的索引。
    • 嘿@Val;我会尽快测试这个并给你反馈。我为延迟道歉。我保证我会在接下来的 3-4 天内做到这一点。
    【解决方案2】:

    另一个选项是search_after 标签。加入排序机制,您可以将最后一个元素保存在第一次返回中,然后在最后一个元素之后询问结果。

    GET twitter/_search
    {
        "size": 10,
        "query": {
            "match" : {
                "title" : "elasticsearch"
            }
        },
        "search_after": [1463538857, "654323"],
        "sort": [
            {"date": "asc"},
            {"_id": "desc"}
        ]
    }
    

    为我工作。但是直到现在,获得超过 10.000 个文档确实不容易。

    【讨论】:

    • 什么是 1463538857 和 "654323"
    • same here: ' "search_after": [1463538857, "654323"]' 如何获取这些数组值?任何 java 示例都会有很大帮助。谢谢
    • 这是唯一可以让您不受限制地滚动的正确答案。您可以增加滚动窗口,但除了 ES 不建议这样做(并且滚动需要成本)之外,它总是受到滚动窗口大小的限制。 search_after 没有该限制,但它的一个缺点是您没有位置数据(因此您无法“计算”您所在的页面)
    • 对象 []lastSortValues; for (SearchHit documentFields : response.getHits()) { lastSortValues = documentFields.getSortValues(); }
    【解决方案3】:

    我可以建议一个更好的方法来做到这一点。我猜你正试图获得超过 10,000 条记录。试试下面的方法,你也会得到数百万条记录。

    1. 定义你的客户。

      client = Elasticsearch(['http://localhost:9200'])
      
    2. search = Search(using=client)

    3. 检查点击总数。

      results = search.execute()
      results.hits.total
      
    4. s = Search(using=client)

    5. 写下您的查询。

      s = s.query(..write your query here...)
      
    6. 使用扫描将数据转储到数据框中。扫描会将所有数据转储到您的数据框中,即使它是数十亿,所以要小心。

      results_df = pd.DataFrame((d.to_dict() for d in s.scan()))
      
    7. 看看你的数据框。

      results_df
      
    8. 如果搜索功能出错,请执行以下操作:

      from elasticsearch_dsl import Search
      

    【讨论】:

    • @mairan 它对我来说工作正常。不要试图获取所有数据,我想这就是它崩溃的原因。您必须获得大量数据。首先,检查您获得了多少点击量。浏览我的中型博客以获得更好的理解:-medium.com/@abhimanyusingh_16119/…。如果有效,请接受答案。
    【解决方案4】:

    使用elascticsearch的nodeJS滚动示例:

    const elasticsearch = require('elasticsearch');
    const elasticSearchClient = new elasticsearch.Client({ host: 'esURL' });
    
    async function getAllData(query) {
      const result = await elasticSearchClient.search({
        index: '*',
        scroll: '10m',
        size: 10000,
        body: query,
      });
    
      const retriever = async ({
        data,
        total,
        scrollId,
      }) => {
        if (data.length >= total) {
          return data;
        }
    
        const result = await elasticSearchClient.scroll({
          scroll: '10m',
          scroll_id: scrollId,
        });
    
        data = [...data, ...result.hits.hits];
    
        return retriever({
          total,
          scrollId: result._scroll_id,
          data,
        });
      };
    
      return retriever({
        total: result.hits.total,
        scrollId: result._scroll_id,
        data: result.hits.hits,
      });
    }
    

    【讨论】:

    • 有一个使用生成器函数的更新示例here
    【解决方案5】:

    search_after documentation

    Ruby 中的哈希查询示例:

    query = {
      size: query_size,
      query: {
        multi_match: {
          query: "black",
          fields: [ "description", "title", "information", "params" ]
        }
      },
      search_after: [after],
      sort: [ {id: "asc"} ]
    

    }

    【讨论】:

    • 是否有任何 java 实现作为 search-after 的示例?另外,在search_after 字段中,这里的值应该是什么?如何获得?
    【解决方案6】:

    当有超过 10000 个结果时,获得其余结果的唯一方法是将您的查询拆分为具有更严格过滤器的多个更精细的查询,以便每个查询返回少于 10000 个结果。然后结合查询结果得到你完整的目标结果集。

    这一对 10000 个结果的限制适用于由 ElasticSearch 索引支持的 Web 服务,并且无法绕过它,必须在不使用 ElasticSearch 的情况下重新实现 Web 服务。

    【讨论】:

    • 嗨@Tenusha。我正在尝试使用搜索查询通过RestClient从弹性搜索中获取10万条记录。我现在正在发送一个查询。你能告诉我如何将查询拆分为多个并获取记录吗它也提高了性能
    • @SachinHR 有一种方法可以检索超过 10000 条记录。但要注意后果(即记忆)。参考这个(discuss.elastic.co/t/…)也参考quora.com/…
    【解决方案7】:

    给你:

    GET /_search
    {
      "size": "10000",
        "query": {
            "match_all": {"boost" : "1.0" }
        }
    }
    

    但我们应该避免这种一次性检索大量文档的方法,因为它会增加数据使用量和开销。

    【讨论】:

      【解决方案8】:

      您可以使用scroll 检索超过 10000 条记录。下面是实现滚动的Python函数示例。

      self._elkUrl = "http://Hostname:9200/logstash-*/_search?scroll=1m"
      self._scrollUrl="http://Hostname:9200/_search/scroll"
      
      """
      Function to get the data from ELK through scrolling mechanism
      """
      import logging
      import pandas as pd
      import requests
      import sys
      
      
      def GetDataFromELK(self):
          # implementing scroll and retrieving data from elk to get more than 100000 records at one search
          # ref :https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-scroll.html
          try:
              dataFrame = pd.DataFrame()
              if self._elkUrl is None:
                  raise ValueError("_elkUrl is missing")
              if self._username is None:
                  raise ValueError("_userNmae for elk is missing")
              if self._password is None:
                  raise ValueError("_password for elk is missing")
              response = requests.post(self._elkUrl, json=self.body,
                                       auth=(self._username, self._password))
              response = response.json()
              if response is None:
                  raise ValueError("response is missing")
              sid = response['_scroll_id']
              hits = response['hits']
              total = hits["total"]
              if total is None:
                  raise ValueError("total hits from ELK is none")
              total_val = int(total['value'])
              url = self._scrollUrl
              if url is None:
                  raise ValueError("scroll url is missing")
              # start scrolling 
              while (total_val > 0):
                  # keep search context alive for 2m
                  scroll = '2m'
                  scroll_query = {"scroll": scroll, "scroll_id": sid}
                  response1 = requests.post(url, json=scroll_query,
                                            auth=(self._username, self._password))
                  response1 = response1.json()
                  # The result from the above request includes a scroll_id, which should be passed to the scroll API in order to retrieve the next batch of results
                  sid = response1['_scroll_id']
                  hits = response1['hits']
                  data = response1['hits']['hits']
                  if len(data) > 0:
                      cleanDataFrame = self.DataClean(data)
                      dataFrame = dataFrame.append(cleanDataFrame)
                  total_val = len(response1['hits']['hits'])
                  num = len(dataFrame)
              print('Total records recieved from ELK=', num)
              return dataFrame
          except Exception as e:
              logging.error('Error while getting the data from elk', exc_info=e)
              sys.exit()
      
      

      【讨论】:

      • 这个答案对我有用并且非常有用。谢谢!
      【解决方案9】:

      对于 Node.js,从 ElasticSeach v7.7.0 开始,现在有一个滚动助手!

      此处的文档:https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/7.x/client-helpers.html#_scroll_documents_helper

      否则,Scroll API 的主要文档有一个很好的示例可以使用:https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/scroll_examples.html

      【讨论】:

        【解决方案10】:

        注意 from + size 不能超过 index.max_result_window 索引设置,默认为 10,000。

        https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-from-size.html

        所以这里有两种方法:

        1.将您的查询添加到“track_total_hits”:true变量。

        GET index/_search
        {
            "size":1,
            "track_total_hits": true
        }

        2.使用Scroll API,但是你不能用普通的方式做from,size,你必须使用Scroll API。

        https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-scroll.html

        例如:

         POST /twitter/_search?scroll=1m
        {
        "size": 100,
        "query": {
            "match" : {
                "title" : "elasticsearch"
            }
        }
        }

        【讨论】:

        • 虽然此代码可以解决 OP 的问题,但最好包含关于您的代码如何解决 OP 问题的说明。这样,未来的访问者可以从您的帖子中学习,并将其应用到他们自己的代码中。 SO 不是编码服务,而是知识资源。此外,高质量、完整的答案更有可能得到支持。这些功能,以及所有帖子都是独立的要求,是 SO 作为一个平台的一些优势,使其与论坛区分开来。您可以编辑以添加其他信息和/或使用源文档补充您的解释。
        • track_total_hits 是我的票。我不想得到一个大的结果窗口,但我确实想知道有多少点击。
        • "track_total_hits" 为我工作。谢谢!
        • 我不明白“track_total_hits”是如何工作的,或者那里有什么意义?在与此方法链接的文档中,它指出“请注意,from + size 不能超过默认为 10,000 的 index.max_result_window 索引设置”。这意味着,第一种方法不能用于显示超过 10k 的条目?
        【解决方案11】:

        升级10000限制

        PUT _settings
        {
          "index.max_result_window": 500000
        }
        

        【讨论】:

          【解决方案12】:

          Scroll API 有其自身的局限性。最近 elastic 引入了一个新功能(Point in Time)。

          Point in time

          基本上它会拍摄当时的索引快照,然后您可以使用search_after检索超过10000的结果。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-11-30
            • 1970-01-01
            • 2021-06-12
            • 1970-01-01
            • 1970-01-01
            • 2013-07-20
            • 1970-01-01
            • 2014-03-23
            相关资源
            最近更新 更多