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源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。