Elasticsearch是一个基于Lucene的搜索服务器,其搜索的核心原理是倒排索引,今天谈下在日常项目中使用它遇到的一些问题及优化解决办法。
一. 搜索的深度分页问题
在日常项目中,经常会有分页搜索并支持跳页的需求,类似百度、Google搜索那样,使用ES进行这类需求的搜索时一般采用from/size的方式,from指明开始的位置,size指定获取的条数,通过这种方式获取数据称为深度分页。
通过这种分页方式当我取 from为11000,size为10时,发现无法获取:


ES报错说超过了max_result_window
初步解决方案:
我修改了索引的设置,将max_result_window设置为了10000000:
PUT ccnu_resource/_settings {   "index": {     "max_result_window": 10000000   } }这样做虽然解决了问题,并且目前在性能上也没有太大问题。一次当我用Google搜索时时,突发奇想,想试试Google的最大分页数:

我发现Google提示:Google为所有查询的结果数都不会超过1000,然后我迅速尝试了百度和微软的BING:



百度只显示76页,当修改url时,76页以外的也不会显示,这时候会跳到第一页,微软BING只会显示97页,当你继续下一页时它会回退当前页的前一页,这时候我重新查阅了ES分页遍历相关资料,这种from/to的方式采用的是深度分页机制,并且目前所有分布式搜索引擎都存在深度分页的问题。
ES深度分页:
由于数据是分散存储在各个分片上的,所以ES会从每个分片上取出当前查询的全部数据,比如from:9990,size:10,ES会在每个分片上取10000个document,然后聚合每个分片的结果再排序选取前10000个document;所以当from的值越来越大,页数越来越多时,ES处理的document就越多,同时占用的内存也越来越大,所以当数据量很大、请求数很多时,搜索的效率会大大降低;所以ES默认max_result_window为10000。
所以如果要使用from/size的方式分页遍历,最好使用ES默认的max_result_window,可以根据自己的业务需求适当增加或减少max_result_window的值,但是建议以跳页的方式分页最好控制页数在1000以内,max_result_window的值最好不要修改。
二. Mapping设置与Query查询优化问题
在ES中创建Mappings时,默认_source是enable=true,会存储整个document的值,当执行search操作的时,会返回整个document的信息。如果只想返回document的部分fields,但_source会返回原始所有的内容,当某些不需要返回的field很大时,ES查询的性能会降低,这时候可以考虑使用store结合_source的enable=false来创建mapping。
PUT article_index {   "mappings": {     "es_article_doc":{       "_source":{         "enabled":false       },       "properties":{         "title":{           "type":"
                        
                        
                    
