今天在使用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的时候会报错并且给出了提示:
意思是由于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的还没时间写出来 有空了补坑
鉴于本人太菜,有不对的地方麻烦路过的大佬们指正一下,十分感谢!