es如今几乎已是开源搜索引擎的事实标准了,搭建简易,使用方便。不过在不少公司里(包括我司的部分部门),并非把它当搜索引擎来用,而是当db来用。由于自己查询/搜索原理的区别,使es在千万或者亿级的数据中进行逻辑筛选相对高效。例如一些wms、工单查询系统,单表几十个甚至上百个字段,若是在数据库里为每种类型的查询都创建合适的索引,成本比较高,更不用说索引建多了还会影响到插入速度,后期的索引优化也是比较麻烦的问题。
不过若是把es当db来使的话,始终会有一个绕不过去的坎。就是es的DSL。让全部业务开发去学习dsl的话也不是不能够,但DSL真的有点反人类(不要打我)。简单的a and b或者a or b还比较容易写,若是我要的是a and (b and (c or d) and e)的查询逻辑,那我以为谁写都会晕。即便是用官方或者第三方提供的client,若是需求多种多样的话,想要灵活地实现`需求=>DSL`的过程仍是比较痛苦。
对于业务开发来讲,固然是sql更平易近人(毕竟写了这么多年CRUD)。因此还有一种歪门邪道的流派,直接把sql转成DSL。要作sql和DSL转换的工做,须要进行sql的解析,先不要怵,这个年代找一个靠谱的sql parser仍是比较容易的。好比阿里开源的druid链接池里的sql模块:
https://github.com/alibaba/dru ... d/sql
由于笔者的实现是用的下面这个golang版的parser:
https://github.com/xwb1989/sqlparser
因此用这个来举例吧~
这个是其做者从youtube/vitness里提取并进行改进的一个parser,咱们能用到的是一部分子集功能,只须要解析select类的sql。
先举个简单的sql的例子:git
sql的select语句在被解析以后生成一个Select的结构体,若是咱们不关心使用者须要的字段的话,能够先把SelectExprs/Distinct/Comments/Lock里的内容忽略掉。若是不是分组统计类的需求,也能够先把GroupBy/Having忽略掉。这里咱们关心的就剩下From、Where、OrderBy和Limit。
From对应的TableExprs实际上能够认为是简单的字符串,这里的值其实就是`x_order`。
OrderBy其实是一个元素为github
的数组。
Limit也很简单,golang
其实就是俩数字。
那么剩下的就是这个Where结构了。where会被解析为AST(`https://en.wikipedia.org/wiki/Abstract_syntax_tree`),中文是抽象语法树。在不说子查询之类的状况下,这个AST也不会太复杂,毕竟where后面的状况比起编译原理里的程序语言来讲状况仍是要少得多的。以上述的sql为例,这里解析出来的Where结构是这样的:sql
只有一个节点,一个ComparisonExpr表达式,这个ComparisonExpr,中文比较表达式,指代的就是咱们sql里的`user_id = 1`。实际上咱们能够认为这个"比较表达式"便是全部复杂AST的叶子节点。叶子结点在AST遍历的时候通常也就是递归的终点。由于这里的查询比较简单,整棵AST只有一个节点,即根节点和叶子节点都是这个ComparisonExpr。
再来一个复杂点的例子。数据库
稍微有一些二叉树的样子了吧。把这棵简单的树画出来:
数组
回到文章开头的那个复杂的例子:微信
看着真够麻烦的,咱们把这棵树画出来:
学习
这样看着就直观多了。咱们有了AST的结构,那要怎么对应到es的查询DSL呢?少安毋躁。
咱们知道es的bool query是能够进行嵌套的,因此实际上咱们能够一样能够构造出树形结构的bool query。这里把bool嵌套must和bool嵌套should简化一下,写成boolmust和boolshould:
例如a and (b and c)优化
咱们把query内部的第一个boolmust看成根节点,内部嵌套的a和另外一个boolmust看成它的两个子节点,而后b和c又是这个boolmust的子节点。能够看出来,实际上这棵树和AST的节点能够一一对应。
再回到文章开头的例子,a and (b and (c or d) and e):ui
和前文中ast来作个简单的结构对比~
和前文中sql的where解析后的AST树也是彻底匹配的。思路来了,只要对sql解析生成的AST进行递归,便可获得这棵树。固然了,这里还能够进行一些优化,若是子节点的类型和父
节点的类型一致,例如都是and表达式或者都是or表达式,咱们能够在生成dsl的时候将其做为并列的节点进行合并,这里再也不赘述。
在递归中有这么几种状况:
这样问题就变成了如何处理AST的叶子节点。前面提到了叶子节点实际上就是Comparison Expression。只要简单进行一些对应便可,下面是咱们的项目里的一些对应关系,仅供参考:
最后再附上demo
https://github.com/cch123/elasticsql
本文分享自微信公众号 - Elastic中文社区(elastic-cn)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。