背景及问题
说一下背景
- Doc数量约20W+
- 机器配置 4C 8G * 3
- ElasticSearch 5.6.3
- 每个Doc中的Nested字段(价格列表,不同城市价格不同)中包含约100-200个嵌套文档
查询需求:
- 每个查询均需要从嵌套文档中进行查询(根据城市Id)
- 最终只需要返回一个嵌套文档(城市Id符合需求的)
开始没有想太复杂,直接使用nested Query + inner_hits取出来文档,觉得很方便,但是后来进行测试,发现只要条件中加入了城市Id,查询就很慢(平均120+ms),而不带城市id基本在40ms+,于是开始了查询问题定位。
问题定位
- 根据条件定位问题肯定是出在了城市Id查询,观察了一下mapping,估计问题是出在了nested上,对Query DSL语句进行注意尝试,发现如果不带inner_hits,只是进行城市Id查询,速度可以稳定在45ms左右,一旦加上innder_hits速度就在120ms左右,看来问题是在这里了。
- 查了官方文档,说inner_hits是父子文档的优化版本,附带了一句nested对检索性能有较大影响,也没有其他相关资料了。
- 论坛,Google 一下也没有这方面资料,有点没有头绪。
问题解决
- 本地使用Query DSL 尝试了一下将整个整个价格列表返回,不再使用inner_hits,发现速度竟然提升了(数据返回话费了4s+,但是EsQuery仅用了50ms)那说明可以删掉inner_hits,直接返回价格列表,然后在内存中进行筛选。
- 按照这个思路改了一下项目代码,发现速度确实有提升,之前平均响应时间在130+ ms(Query+处理),现在基本不过70ms。
继续优化
- 官方的那句nested对检索性能有较大影响还是得重视起来,后来进行了一个尝试,将价格列表和Doc组合起来,不再使用嵌套文档,直接进行平铺,这样就相当于取消了nested查询,发现速度再一次提高了,查询的平均检索时间降低到40ms+,针对城市Id又加上了_routing,速度最终稳定在20ms+。好了,在测试环境的优化最终就这样了,等节后花时间测试一下,放到线上估计速度能提高不少~
总结
- 其实还是最初的索引结构设计不是很合理,尤其是城市价格这块,最开始没有加入_routing,这算是一个败笔了,每次查询都需要查询城市id,还没加上,这个确实是失误了。。。
- nested+inner_hits对检索性能确实有很大影响(最起码我这种场景影响很大了)
- 官方提示了,nested一定程度影响性能,如果可以的话,还是要注意一下,避免这种结构,现在将nested字段平铺开后虽然doc数量激增,但是检索速度大幅度提升,这样代价也值了~