1. 程式人生 > >DSL的誕生 | 複雜sql轉成Elasticsearch DSL深入詳解

DSL的誕生 | 複雜sql轉成Elasticsearch DSL深入詳解

源自死磕ElasticsearchQQ群(626036393)中的一個問題:
問題如下:

where (position=ES or work=ES or content=ES) and academic=本科 and (city=北京 or city=深圳)

怎麼構建ES的查詢條件?

我的問題拆解與實現如下:

1、sql語句轉成DSL有哪些方法?

方案一:藉助工具 NLP團體開發的Elasticsearch-sql;
2.X安裝過,5.X沒有再安裝。
方案二:藉助工具ElasticHQ的自動轉換模組:
這裡寫圖片描述
方案一、方案二和Github上其他語言開發的sql轉DSL工具對簡單的sql生成的DSL相對準確,但對於複雜的sql生成的不一定精確。(如上所示)

方案三:徒手生成。

2、如何根據複雜的sql語句生成ES的DSL查詢語句呢?

步驟1:拆解

where (position=ES or work=ES or content=ES) and academic=本科 and (city=北京 or city=深圳)

這個sql語句由幾部分組成呢?
以and作為拆分,共分為3部分:
三個部分sql用and銜接,轉換為DSL對應最外層must;

第一部分: position=ES or work=ES or content=ES
三個子條件sql用or銜接,轉換DSL對應should;

第二部分: academic=本科
單一條件轉換為DSL對應term精確匹配;

第三部分: city=北京 or city=深圳
city的兩個or語句轉換為DSL對應terms多詞精確匹配。

上面的sql都用的=號,假定不需要分詞,我們統一採用termquery和termsquery實現。
引申:
如果需要分詞,更換為matchquery或者match_parsequery即可。
如果需要模糊匹配,更換為wildcardquery介面。

步驟2:套bool多條件檢索DSL模板

複雜bool多條件檢索DSL模板:
包含了:查詢/檢索、聚合、排序、指定欄位輸出、輸出起點、輸出多少等資訊。

{
  "query": {
  "bool
": { "must": [], "must_not": [], "should": [] } }
, "aggs": { "my_agg": { "terms": { "field": "user", "size": 10 } } }, "highlight": { "pre_tags": [ "<em>" ], "post_tags": [ "</em>" ], "fields": { "body": { "number_of_fragments": 1, "fragment_size": 20 }, "title": {} } }, "size": 20, "from": 100, "_source": [ "title", "id" ], "sort": [ { "_id": { "order": "desc" } } ] }

簡單bool多條件查詢DSL模板:
只包含查詢。

{
  "query": {
  "bool": {
  "must": [],
  "must_not": [],
  "should": []
  }
  }
}

以上根據我們的sql特點,簡單模板即能滿足要求。

步驟3:構造生成DSL

根據,步驟1、步驟2,可以構思出根據sql轉換後的DSL應該:
1)最外層bool
2)第二層:must 三個並行條件
3)第三層:各自的匹配條件。(存在bool巢狀bool的情況)

3、動動手,驗證下。

3.1 建立索引(自動生成mapping)

put test_index_01

3.2 提交資料

post test_index_01/test_type_01/1
{
  "no":"1",
  "city":"北京",
  "academic":"專科",
  "content":"ES",
  "position":"ES",
  "work":"ES"
}
post test_index_01/test_type_01/2
{
  "no":"2",
  "city":"天津",
  "academic":"本科",
  "content":"ES",
  "position":"ES",
  "work":"ES"
}
post test_index_01/test_type_01/3
{
  "no":"3",
  "city":"深圳",
  "academic":"本科",
  "content":"ES",
  "position":"ES2",
  "work":"ES3"
}
post test_index_01/test_type_01/4
{
  "no":"4",
  "city":"北京",
  "academic":"本科",
  "content":"ES1",
  "position":"ES2",
  "work":"ES"
}

插入後ES-head外掛控制檯查詢結果:
這裡寫圖片描述

3.3 完成檢索

post test_index_01/_search
{
  "query": {
  "bool": {
  "must": [
  {
  "terms": {
  "city.keyword": [
  "北京",
  "深圳"
  ]
  }
  },
  {
  "term": {
  "academic.keyword": "本科"
  }
  },
  {
  "bool": {
  "should": [
  {
  "term": {
  "content.keyword": "ES"
  }
  },
  {
  "term": {
  "position.keyword": "ES"
  }
  },
  {
  "term": {
  "work.keyword": "ES"
  }
  }
  ]
  }
  }
  ]
  }
  },
  "size": 10,
  "from": 0
}

注意:
沒有做分詞,做的精確匹配,所以加了”.keyword”。

3.4 返回結果

{
  "took": 1,
  "timed_out": false,
  "_shards": {
  "total": 5,
  "successful": 5,
  "failed": 0
  },
  "hits": {
  "total": 2,
  "max_score": 1.0577903,
  "hits": [
  {
  "_index": "test_index_01",
  "_type": "test_type_01",
  "_id": "4",
  "_score": 1.0577903,
  "_source": {
  "no": "4",
  "city": "北京",
  "academic": "本科",
  "content": "ES1",
  "position": "ES2",
  "work": "ES"
  }
  },
  {
  "_index": "test_index_01",
  "_type": "test_type_01",
  "_id": "3",
  "_score": 0.8630463,
  "_source": {
  "no": "3",
  "city": "深圳",
  "academic": "本科",
  "content": "ES",
  "position": "ES2",
  "work": "ES3"
  }
  }
  ]
  }
}

4、小結

實踐是檢驗真理的唯一標準!
如有不同意見,歡迎拍磚探討!

——————————————————————————————————
更多ES相關實戰乾貨經驗分享,請掃描下方【銘毅天下】微信公眾號二維碼關注。
(每週至少更新一篇!)

這裡寫圖片描述
和你一起,死磕Elasticsearch
——————————————————————————————————

2017.11.16 22:39 於家中床前