今天在使用ES查询20000条数据时报错:

   ERRO[0005] Search dga rules failed elastic: Error 500 (Internal Server Error): all shards failed [type=search_phase_execution_exception]
 
随手附个代码吧,或许对有缘人有用~

searchResult,err := es.ESClient.Search().
Index(a).Type(b).
Query(elastic.NewMatchAllQuery()).
SortBy(elastic.NewFiledSort("num").Asc()).
Size(20000).
Do(context.TODO())

(由于这里用的es6,所以还有type)
 

原因:

    ES为了避免用户的过大分页请求造成ES服务所在机器内存溢出,默认对深度分页的条数进行了限制,默认的最大条数是10000条
 

解决办法:

修改es的默认窗口大小 — index.max_result_window
 

办法一:修改es的配置文件(elasticsearch 5.x 以下版本可用,所以基本是行不通的)

    想必很多人都试了这种方式,但基本都启动失败了吧~
 
    在es安装路径/config/elasticsearch.yml文件中的最后加上index.max_result_window: 999999,999999前面有一个空格,这是yml的语法规范

index.max_result_window: 999999

在5.x以上版本使用启动es的时候会报错并且给出了提示:

es超过10000查询 es只能查询10000条_elastic


意思是由于elasticsearch 5.x 以后,这个参数需要和索引绑定,而索引级别设置无法在节点上设置,所以不支持在配置文件中直接修改窗口大小参数

 

方法二:通过API接口修改对应索引的默认窗口大小

xxx_index为要修改的索引名,如果是修改所有索引,则索引名为_all

curl -XPUT 127.0.0.1:9200/xxx_index/_settings -d ‘{ “index.max_result_window” :“1000000”}’ -H ‘Content-Type: application/json’

至于怎么查看是否修改成功,在上面的截图中也给了提示:

curl -XGET 127.0.0.1:9200/xxx_index/_settings

之后新加的索引,窗口大小还是默认的10000
 

方法三:在创建索引时就指定窗口的大小
“settings”:{
 “index”:{
 “max_result_window”:100000
   }
 }

 
附个go的使用吧 (注意mapping里不是单引号而是反引号)

const mapping = `
{
"settings":{
"index"{
"max_result_windows":"1000000"
}}}
`

_,err := es.ESClient.CreateIndex("test").BodyString(mapping).Do(context.Background())
if err != nil {
	log.Fatal("ES create index failed",err.Error())
}

 
如果需要指定各字段属性的话,可以一起写在mapping中,然后CreateIndex

const mapping = `
{
	"settings":{
		"index"{
			"max_result_windows":"1000000"
}},
	"mappings":{
		"text":{
			"properties:"{
				"name":{"type":"text","fields":{"keyword","ignore_above":256}}},
				"age":{"type":"long"},
				"id":{"type":"keyword"}
}}}}
`

 
(这是es6的写法text为type,es7中不建议使用type了,只需要像下面这样写,原因可以瞧瞧这一篇:https://blog.miuyun.work/archives/16677312

"mappings":{
	"properties": {
		"name":{"type":"text","fields":{"keyword","ignore_above":256}}},
		"age":{"type":"long"},
		"id":{"type":"keyword"}
	}
}

 

方法四:通过游标Scroll控制

附个go写法

func getScroll(size int){              //size为要查询的条数
	var scrollId string
	var count = 0
	serchResult,err := es.ESClient.Scroll().
		Index("People").Type("student").
		Query(elastic.NewMatchAllQuery()).            //查询所有
		SortBy(elastic.NewFieldSort("age").Asc()).    //按照年龄升序
		Scroll("2m").                                 //查询时间2分钟以内
		Size(5000).                                   //一次查询5000条,不能超过10000
		Do(context.TODO())
	if err != nil{
		log.Fatal("ES query failed",err.Error())
	}
	//在这里可以处理serchResult查询返回的数据或者存到list中
	count = len(serchResult.Hits.Hits)          //记录已经查询到的条数
	if count < size {    //第一次没查完
		scrollId = searchResult.ScrollId
		for{
			if count >size {                    //查询条数够了不再查询
				break
			}
			//根据scrollId继续往下查询
			serchResult,err = es.ESClient.Scroll("2m")ScrollId(scrollId).Do(context.TODO())
			if err != nil{
				log.Fatal("ES query failed",err.Error())
			}
			//在这里可以处理本次serchResult查询返回的数据或者存到list中
			count = count + len(serchResult.Hits.Hits)
		}
	}
}

 

方法五:通过自己写代码进行分页,FROM()+SIZE()

嘻 go的还没时间写出来 有空了补坑
 
参考链接:
https://blog.miuyun.work/archives/17705553  
鉴于本人太菜,有不对的地方麻烦路过的大佬们指正一下,十分感谢!