前段时间公司开发新项目,其中我负责搜索功能,使用的搜索软件是elasticsearch,语言python,框架flask,使用了gevent协程,flask-restplus生成swagger文档及测试界面。
使用python的elasticsearch-dsl完成flask对elasticsearch的访问,详见我的另一篇博客:使用elasticsearch_dsl完成对ElasticSearch的复杂搜索.
0、es基础回顾
1、项目架构
2、elasticsearch数据存储设计
当时有这么几种方案:
方案一:所有的数据库表格,全部存在一个index里面,使用一个Field进行区分不同的表;
方案二:每个数据库表格,都创建一个index;
方案三:按照项目实际情况,根据各个数据库表的关系,分层,同一层的放在一个index里面,例如,不管是“老师”这个表,还是“医生”这个表,都放在一个index里面;不管是“老师的学生”还是“医生的助手”,都放在一个index里面;不管是“老师的学生的家长”还是“医生的助手的毕业院校”,都放在一个index里面。总之就是一个,分级的思想吧。
我提出的方案一,同事提出的方案二,领导提出的方案三,最后当然采用的方案三。
我的思路是尽可能的简单吧,即使数据多,还有es的分片什么的方案进行解决。
领导是担心查询速度会受数据量的影响,我也觉得有一定的道理,都是第一次用,也不清楚es速度怎么样。
3、数据导入、同步
使用的python脚本实现的,
使用python的elasticsearch-dsl完成对elasticsearch的访问,
sqlalchemy作为orm,
marshmallow数据格式化,
Python用sqlacodegen将存在的数据库表转化成model.py,
使用队列进行数据的同步rabbitmq,而用的语言主要是python,所以也就经常会用到python中的pika模块,
脚本功能:
a、创建、展示、删除mapping
b、创建索引:批量查询数据库表,比如每次获取1000条数据这样,传进rabbitmq;
c、同步数据:数据库有update_time字段,按这个查询最近10分钟更新的数据,传进rabbitmq;每天夜晚会查询全天的,传进rabbitmq,覆盖一下,防止错漏。
d、rabbitmq接到数据就写入elasticsearch
4、访问实现
Flask接到前端的一个请求:
a、先解析用户的身份,会先发起一次es查询,确认这个人的可查询范围,一般是一个id的列表,咱们叫他“权限约束”
b、关键字和权限约束作为查询条件,使用gevent同时发起多个对es的请求
c、最后一个es请求回来了,返回给前端,封装、整理好的数据
d、实际实现的时候,已经redis缓存了用户的权限,而且有时候还会缓存查询结果,第一次请求给他一个钥匙,让他二次访问拿上钥匙,才能拿到结果,防止前端一直转圈等待。
5、其他项目复用,可能存在的问题
同步更新时,如果没有类似update_time的字段,或者即使有这种字段,但是好多旧代码更新的时候,没有写入这个字段,那就不太好查询了。之前我们也考虑过使用mysql的二进制日志文件,但是没有找到好用的库或者工具,正好同事的update_time字段使用的很彻底,所以就使用上面的方案实现的。