Elasticsearch查询以返回所有记录

616

我在 Elasticsearch 中有一个小型数据库,为了测试目的,我想要拉回所有记录。我尝试使用以下形式的 URL...

http://localhost:9200/foo/_search?pretty=true&q={'matchAll':{''}}

请问有人可以给我实现这个功能所需的URL吗?


1
...其中“foo”是您想显示所有记录的索引名称。 - jonatan
1
所有仅使用“size”查询参数的答案都是不正确的。无论查询中的“size”值如何,ES在响应中最多返回“index.max_result_window”个文档(默认为10k)。请参考“scroll”和“search_after”。 - narendra-choudhary
我只需要这一行代码就能够返回所有记录:http://curl -XGET 'localhost:9200/foo/_search' - Mr. N
30个回答

907
我认为lucene语法是被支持的,因此:

http://localhost:9200/foo/_search?pretty=true&q=*:*

大小默认为10,所以您可能还需要&size=BIGNUMBER来获取超过10个项目。(其中BIGNUMBER等于您认为比数据集更大的数字)

但是,Elasticsearch文档建议对于大量结果集使用扫描搜索类型。

例如:

curl -XGET 'localhost:9200/foo/_search?search_type=scan&scroll=10m&size=50' -d '
{
    "query" : {
        "match_all" : {}
    }
}'

请按照文档链接所建议的方式继续请求。
编辑:2.1.0中scan已被弃用。 scan与按_doc排序的常规scroll请求相比没有任何优势。指向elastic文档的链接(由@christophe-roussy发现)

6
谢谢。这是我想到的最终结果,可以返回我现在需要的内容...http://localhost:9200/foo/_search?size=50&pretty=true&q=*:*(请注意,此为代码,非自然语言文本) - John Livermore
2
除了@Steve的回答之外,您可以在此链接中找到elasticsearch理解的参数列表http://www.elasticsearch.org/guide/reference/api/search/uri-request/。 - Karthick
1
感谢@Steve的回答。我认为这并不足以成为一个新问题。因为没有明确说明,所以我想在这里问一下以确认。 - Churro
9
你应该真正使用扫描+滚动请求。如果你使用size=BIGNUMBER,请注意Lucene为该数字分配得分的内存,因此不要使其过大。 :) - Alex Brasetvik
4
Scan在2.1.0版本中已经被弃用:https://www.elastic.co/guide/en/elasticsearch/reference/current/search-request-search-type.html#scan - Christophe Roussy
显示剩余10条评论

183

12
需要记住的一件事(来自Elasticsearch文档):请注意,from + size不能超过index.max_result_window索引设置,该设置默认为10,000。 - user3078523
3
这将返回1000,而不是所有的结果,user3078523是正确的,这个方法有一个名为max_result_window的限制。 - stelios
1
它有一个最大值,而且(如果你有很多记录要获取)这是一种相当笨重的方法去接近那个最大值。相反,你应该使用“滚动”查询。 - Harry Wood
你应该将 pretty 参数设置为布尔类型:curl -XGET 'localhost:9200/logs/_search/?size=1000&pretty=true' - Yar
这就是我要找的答案。不需要传递请求参数 q。谢谢! - asgs

48

elasticsearch(ES)支持使用GET或POST请求从ES集群索引中获取数据。

当我们使用GET时:

http://localhost:9200/[your index name]/_search?size=[no of records you want]&q=*:*

当我们进行POST请求时:

http://localhost:9200/[your_index_name]/_search
{
  "size": [your value] //default 10
  "from": [your start index] //default 0
  "query":
   {
    "match_all": {}
   }
}   

我建议使用一个带有 Elasticsearch 的用户界面插件 http://mobz.github.io/elasticsearch-head/,这将帮助您更好地了解您创建的索引,并测试您的索引。


5
正如另一位用户所提到的:from + size 不能超过默认为10,000的 index.max_result_window 索引设置。 - stelios
这种方法有一个最大值,而且(如果你要获取许多千条记录),这是一种相当笨重的方法来接近这个最大值。相反,你应该使用“滚动”查询。 - Harry Wood
很奇怪,官方文档展示了 curl -XGET ... -d '{...}' 这种非正式的混合请求方式。感谢您展示了正确的 GET 和 POST 格式。 - Jesse Chisholm

35

注意: 此答案相关的是较旧版本的Elasticsearch 0.90。自那时以来发布的版本具有更新的语法。请参考其他答案,可能会提供更准确的最新答案。

下面的查询将返回您想要返回的NO_OF_RESULTS数量..

curl -XGET 'localhost:9200/foo/_search?size=NO_OF_RESULTS' -d '
{
"query" : {
    "match_all" : {}
  }
}'

现在的问题是你希望全部记录都被返回。因此,在编写查询之前,你自然不知道NO_OF_RESULTS的值。

我们如何知道文档中存在多少记录?只需键入以下查询即可。

curl -XGET 'localhost:9200/foo/_search' -d '

这将为您提供类似下面的结果。

 {
hits" : {
  "total" :       2357,
  "hits" : [
    {
      ..................

结果total告诉您文档中有多少条记录可用。因此,这是了解NO_OF_RESULTS的价值的好方法。

curl -XGET 'localhost:9200/_search' -d ' 

搜索所有索引中的所有类型

curl -XGET 'localhost:9200/foo/_search' -d '

搜索foo索引中的所有类型

curl -XGET 'localhost:9200/foo1,foo2/_search' -d '

在foo1和foo2索引中搜索所有类型

curl -XGET 'localhost:9200/f*/_search

搜索以f开头的所有索引中的所有类型

curl -XGET 'localhost:9200/_all/type1,type2/_search' -d '

在所有索引中搜索用户和推文类型


11
默认情况下,如果基本查询中没有包含大小参数,ES会返回10个结果。 - lfender6445
之前的回复已经三年了,现在更新为最新的回复。 - vjpandian

26

我发现使用Python客户端是最好的解决方案

  # Initialize the scroll
  page = es.search(
  index = 'yourIndex',
  doc_type = 'yourType',
  scroll = '2m',
  search_type = 'scan',
  size = 1000,
  body = {
    # Your query's 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 = '2m')
    # Update the scroll ID
    sid = page['_scroll_id']
    # Get the number of results that we returned in the last scroll
    scroll_size = len(page['hits']['hits'])
    print "scroll size: " + str(scroll_size)
    # Do something with the obtained page

https://gist.github.com/drorata/146ce50807d16fd4a6aa

使用Java客户端
import static org.elasticsearch.index.query.QueryBuilders.*;

QueryBuilder qb = termQuery("multi", "test");

SearchResponse scrollResp = client.prepareSearch(test)
        .addSort(FieldSortBuilder.DOC_FIELD_NAME, SortOrder.ASC)
        .setScroll(new TimeValue(60000))
        .setQuery(qb)
        .setSize(100).execute().actionGet(); //100 hits per shard will be returned for each scroll
//Scroll until no hits are returned
do {
    for (SearchHit hit : scrollResp.getHits().getHits()) {
        //Handle the hit...
    }

    scrollResp = client.prepareSearchScroll(scrollResp.getScrollId()).setScroll(new TimeValue(60000)).execute().actionGet();
} while(scrollResp.getHits().getHits().length != 0); // Zero hits mark the end of the scroll and the while loop.

https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-search-scrolling.html


谢谢Mark,这正是我正在寻找的!针对我的情况(ELK 6.2.1,Python 3),search_type参数无效,并且自ELK 6.0以来不再需要document_type。 - Christoph Schranz
完美的解决方案!谢谢。我正在使用 elasticsearch_dsl==5.4.0,并且它可以在不使用 search_type = 'scan' 的情况下工作。 - Usman Maqbool
ES 6.3。这个例子让我的Elasticsearch服务崩溃了,尝试使用size=10000滚动查看110k个文档,在第5-7次迭代之间出现了status=127main ERROR Null object returned for RollingFile in Appendersmain ERROR Unable to locate appender "rolling" for logger config "root"的错误。 在/var/log/elasticsearch/elasticsearch.log中没有日志。 - stelios
值得一提的是,Python客户端实现了一个名为“scan”的辅助函数,它在后台执行滚动操作(至少从5.x.x版本开始)。 - MCMZL
搜索类型search_type = 'scan'已被弃用。不使用此代码也能实现类似功能,虽然在旧文档中存在一些有趣的差异,这些差异并不明显。 https://www.elastic.co/guide/en/elasticsearch/reference/1.4/search-request-scroll.html#scroll-scan 特别是,在迁移以不使用search_type=scan时,第一个“search”查询将携带第一批要处理的结果。 - Harry Wood

23

如果数据集很小(例如1K条记录),您可以简单地指定size

curl localhost:9200/foo_index/_search?size=1000

匹配所有查询不需要,因为它是隐含的。

如果您有一个中等大小的数据集,比如1M记录,您可能没有足够的内存来加载它,所以您需要使用滚动

滚动就像数据库中的游标。在Elasticsearch中,它会记住您离开的位置,并保持索引的相同视图(即防止搜索者使用刷新,防止段合并)。

从API的角度来看,您需要在第一个请求中添加一个滚动参数:

curl 'localhost:9200/foo_index/_search?size=100&scroll=1m&pretty'

您将获得第一页和滚动ID:

{
  "_scroll_id" : "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAADEWbmJlSmxjb2hSU0tMZk12aEx2c0EzUQ==",
  "took" : 0,
...

请记住,返回的滚动ID和超时时间都适用于下一页。这里常见的错误是指定一个非常大的超时时间(scroll值),该时间将覆盖整个数据集(例如1M条记录)而不是一页(例如100条记录)。

要获取下一页,请填写上一页的滚动ID和持续到获取下一页的超时时间:

curl -XPOST -H 'Content-Type: application/json' 'localhost:9200/_search/scroll' -d '{
  "scroll": "1m",
  "scroll_id": "DXF1ZXJ5QW5kRmV0Y2gBAAAAAAAAADAWbmJlSmxjb2hSU0tMZk12aEx2c0EzUQ=="
}'

如果您需要导出大量数据(例如10亿份文档),您需要进行并行处理。可以使用sliced scroll来完成此操作。假设您想要使用10个线程进行导出。第一个线程将发出以下请求:

curl -XPOST -H 'Content-Type: application/json' 'localhost:9200/test/_search?scroll=1m&size=100' -d '{
  "slice": {
    "id": 0, 
    "max": 10 
  }
}'

您将获得第一页和一个滚动ID,就像正常的滚动请求一样。您将像普通滚动一样使用它,只是您会获得1/10的数据。

其他线程也会这样做,只不过id会变成1、2、3……


谢谢,这正是我需要理解的(大小);它帮助我解决了我的空([ ])返回问题。 - Kalnode

20

如果您想要获取数千条记录,那么使用“scroll”是正确的答案(注意:有些人建议使用“search_type=scan”。但这已经被弃用,在v5.0中已经移除。您不需要它)

从“search”查询开始,但指定一个“scroll”参数(这里我使用1分钟的超时时间):

curl -XGET 'http://ip1:9200/myindex/_search?scroll=1m' -d '
{
    "query": {
            "match_all" : {}
    }
}
'

这包括您的第一批点击。 但是我们在这里还没有完成。 上述curl命令的输出将类似于:

{"_scroll_id":"c2Nhbjs1OzUyNjE6NU4tU3BrWi1UWkNIWVNBZW43bXV3Zzs1Mzc3OkhUQ0g3VGllU2FhemJVNlM5d2t0alE7NTI2Mjo1Ti1TcGtaLVRaQ0hZU0FlbjdtdXdnOzUzNzg6SFRDSDdUaWVTYWF6YlU2Uzl3a3RqUTs1MjYzOjVOLVNwa1otVFpDSFlTQWVuN211d2c7MTt0b3RhbF9oaXRzOjIyNjAxMzU3Ow==","took":109,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":22601357,"max_score":0.0,"hits":[]}}

有_scroll_id很重要,下一步应运行以下命令:

    curl -XGET  'localhost:9200/_search/scroll'  -d'
    {
        "scroll" : "1m", 
        "scroll_id" : "c2Nhbjs2OzM0NDg1ODpzRlBLc0FXNlNyNm5JWUc1" 
    }
    '

然而,手动传递scroll_id并不是设计用于手动操作的。您最好编写代码来完成它。例如,在Java中:

    private TransportClient client = null;
    private Settings settings = ImmutableSettings.settingsBuilder()
                  .put(CLUSTER_NAME,"cluster-test").build();
    private SearchResponse scrollResp  = null;

    this.client = new TransportClient(settings);
    this.client.addTransportAddress(new InetSocketTransportAddress("ip", port));

    QueryBuilder queryBuilder = QueryBuilders.matchAllQuery();
    scrollResp = client.prepareSearch(index).setSearchType(SearchType.SCAN)
                 .setScroll(new TimeValue(60000))                            
                 .setQuery(queryBuilder)
                 .setSize(100).execute().actionGet();

    scrollResp = client.prepareSearchScroll(scrollResp.getScrollId())
                .setScroll(new TimeValue(timeVal))
                .execute()
                .actionGet();

现在使用SearchResponse循环最后一个命令以提取数据。


18

如果您只是添加了一些大数字作为大小,Elasticsearch会变得 明显 更慢,使用扫描和滚动ID的方法可以获取所有文档。

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

在Elasticsearch v7.2中,您可以像这样操作:

POST /foo/_search?scroll=1m
{
    "size": 100,
    "query": {
        "match_all": {}
    }
}

执行此操作的结果将包含一个_scroll_id,您需要查询该ID以获取下一个100个文档块。

POST /_search/scroll 
{
    "scroll" : "1m", 
    "scroll_id" : "<YOUR SCROLL ID>" 
}

1
这个答案需要更多的更新。search_type=scan现在已经被弃用了,所以你应该将其删除,但是行为有了一些变化。第一批数据从初始搜索调用中返回。你提供的链接确实展示了正确的做法。 - Harry Wood
1
我的评论实际上是想指出,你不能随意添加任何数字作为大小,因为这样会使速度变慢很多。所以我删除了代码示例,人们可以通过链接获取正确的代码。 - WoodyDRN
4
最好在您的答案中包含代码(即使它变旧了),这样当链接失效时,代码仍然可以使用。 - Trisped

12

使用server:9200/_stats可以获取有关所有别名的统计信息,例如每个别名的大小和元素数量,这非常有用并提供了有帮助的信息。


2
但是,据我记得,ES每个请求只允许获取16000条数据。因此,如果数据超过16000条,这个解决方案就不够了。 - Aminah Nuraini

8
您实际上不需要传递任何内容到 match_all,只需通过GET请求访问以下URL即可完成。这是最简单的形式。http://localhost:9200/foo/_search

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接