说起 Elasticsearch,往往大家想到的都是 ELK 的一套,但是作为 NoSQL,ES 有极快的响应速度,强大的聚合功能,支持复杂的查询条件,应对高并发的复杂查询的业务场景其实也是非常强力的。
You Know, for Search
我们团队就一直使用 ES 作为主力数据库, 从一开始做全文检索,到现在承担全部的商品列表页查询。近几个月将查询系统的 qps 从 1k 优化到了 10k+,其中 ES 的优化占了很重要一部分,准确的来说,应该是对 ES 特性的扬长避短起到了非常大的作用。
# 数组 & 嵌套结构
ES 没有 join,很多人直接就会认为 ES 无法处理一对多的情况,其实还有数组和嵌套结构可以应付常见的业务场景。
比如一个商品拥有多种属性,都存放在一个数组字段中,使用 must 和 must_not 就可以灵活地进行查询筛选。
比如同款不同色的几件T恤,使用嵌套结构保存,搜索时只需要其中一件满足筛选条件,便可以全部带出来,在页面上以多个小色块展示,而无需占用多个展示位。并且还可以拿满足筛选条件的商品中的某属性最大值/最小值等进行排序,如官网给出的示例:
|
|
# 聚合
商品列表页面能用到聚合的场景非常多,比如聚合出分类下(可能多达数万个商品)的各子分类,各属性的数量,并且需要支持复杂的筛选条件,比如库存,价格范围等等,并且这种查询速度远比 RDS 的 join + group by + count 快。
又比如需要查出最近10天内有新商品的日期列表,那就可以用到 date_histogram 聚合函数。
# 动态字段
动态字段的设计也为我们的业务提供了很大便利,由于与具体业务关联性太强,就不详细展开了。
ES能支持的动态字段数量非常的多,不过这里要留意的就是动态字段一个比较容易出问题的地方,就是瞬时写入大量的动态字段会导致集群索引的元数据大量变动,master 节点负载暴涨甚至挂掉。
# 缺陷
- 没有 join。ES 的查询速度非常的快,但是不能 join 毕竟还是有一些业务场景无法使用。当然话又说回来,在高并发量下,多表 join 能不能抗得住也是个问题。对于查询,我们一贯的原则还是:把数据离线准备成便于查询的结构,线上实时查询尽可能的简单,一步到位。
- 由于要把数据离线准备好,这便带来了数据同步更新的问题,数据的时效性、准确性都需要保证,数组与嵌套结构的数据更新也不够方便高效,这些都会增加很多的工作量。