elasticsearch-query-builder, 一款能夠基於配置化以及參數綁定的ES語句構造神器

前言

在這裏,我想向你們推薦一個我本身開發的項目,也就是elasticsearch-query-builder,這個項目目前在github上已經開源,有興趣的朋友能夠去fork或者star,你的star就是對我最大的鼓勵。同時,本項目長期維護和更新,我也接受而且很高興有小夥伴向本項目pull request,或者協同開發,有興趣的同窗能夠給我發郵件。git

elasticsearch-query-builder是一個很是方便構造elasticsearch(後面簡稱ES) DSL 查詢語句的工具包,在elasticsearch-query-builder中,我嘗試基於配置化的操做去構建ES的查詢語句,而且接受外界傳入參數,這極大的減小了在Java代碼中構建ES查詢語句的工做,並同時減小了代碼量,使代碼更加直觀和清晰。基於使ES中DSL構造語句和Java代碼分離的思想,elasticsearch-query-builder誕生了。去GithubFork!github

構建

elasticsearch-query-builder工程通常做爲jar包爲別的工程提供使用,固然,若是須要基於本項目作二次開發,這都須要將Github上克隆本項目到本地數據庫

1
git clone https://github.com/xiaowei1118/elasticsearch-query-builder.git

 

在將本項目克隆到本地後,執行mvn package 將本項目打成jar包,或者直接將本項目做爲大家本身maven項目的module項目。json

elasticsearch-query-builder使用詳細說明

elastcisearch-query-builder接受配置文件(特定json格式)或者json格式的字符串配置,配置格式以下:數組

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
{
"index": "user_portrait",
"type": "docs",
"from": "${from}",
"size": "10",
"include_source": ["name","age"], //須要哪些字段
"exclude_source": ["sex"], //排除哪些字段
"query_type": "terms_level_query",
"terms_level_query": {
"terms_level_type": "term_query",
"term_query": {
"value": "${value}",
"key": "key",
"boost": 2
}
},
"aggregations": [
{
"aggregation_type": "terms",
"name": "",
"field": "field",
"sub_aggregations": {
"aggregation_type": "terms",
"name": "sub",
"field": "field",
"size": "${size.value}",
"sort": "asc",
"sort_by": "_count"
}
}
],
"highlight":{
"fields": [
{
"field": "content",
"number_of_fragment": 2,
"no_match_size": 150
}
],
"pre_tags":["<em>"],
"post_tags":["</em>"]
},
"sort": [
"_score",
{
"field": "age",
"order": "asc"
}
]
}

 

參數說明

# index

index表示elasticSearch中的索引或者別名。數據結構

# type

type表示elasticSearch索引或者別名下的type。app

# from

from表示檢索文檔時的偏移量,至關於關係型數據庫裏的offset。elasticsearch

# include_source

include_source 搜索結果中包含某些字段,格式爲json數組,"include_source": ["name","age"]maven

# exclude_source

exclude_source 搜索結果中排除某些字段,格式爲json數組,"exclude_source":["sex"]工具

# query_type

query_type表示查詢類型,支持三種類型terms_level_query,text_level_query,bool_level_query,而且這三種類型
不能夠一塊兒使用。

  • terms_level_query 操做的精確字段是存儲在反轉索引中的。這些查詢一般用於結構化數據, 如數字、日期和枚舉, 而不是全文字段,包含term_query,terms_query,range_query,exists_query 等類型。

  • text_level_query 查詢一般用於在完整文本字段 (如電子郵件正文) 上運行全文查詢。他們瞭解如何分析被查詢的字段, 並在執行以前將每一個字段的分析器 (或 search_analyzer) 應用到查詢字符串。

    包含 match_query,multi_match_query,query_string,simple_query_string 等類型。

  • bool_query 與其餘查詢的布爾組合匹配的文檔匹配的查詢。bool 查詢映射到 Lucene BooleanQuery。它是使用一個或多個布爾子句生成的, 每一個子句都有一個類型化的實例。 布爾查詢的查詢值包括: must,filter,should,must_not. 想要了解這幾個類型的差別,能夠查閱elasticSearch的相關文檔 在每一個布爾查詢的查詢類型值中, 能夠包含terms_level_query 和 text_level_query中任意的查詢類型,如此即可以構造很是複雜的查詢狀況。

# terms_level_query查詢類型
terms_level_type

terms_level查詢類型,支持term_query,terms_query,range_query,exists_query查詢。

  • term_query

    • key 表示elasticSearch中須要查詢的字段
    • value 表示要查詢的值
    • boost 佔搜索中的權重
      1
      2
      3
      4
      5
      "term_query": {
      "value": "",
      "key": "",
      "boost": 2
      }
  • terms_query

    • key,value,boost解釋同term_query
    • value 能夠傳入多個,以逗號隔開,如」[1,2]」。
      1
      2
      3
      4
      "terms_query": {
      "value": "[1,2]", //數組
      "key": ""
      },
  • range_query,給定的查詢條件使一個範圍

    • key 表示elasticSearch中須要查詢的字段
    • range 表示要搜索的值範圍,格式如」[a,b]」,表示範圍在a、b之間,a、b能夠缺省,a缺省則表示沒有下限,
      b缺省則表示沒有上限,但ab不能夠同時爲空。a,b能夠爲時間或者數值。
    • boost 佔搜索中的權重
    • format 若是範圍使時間的化,format定義時間格式。
    • include_lower 布爾值,是否包含下限。
    • include_upper 布爾值,是否包含上限。
      1
      2
      3
      4
      5
      6
      7
      8
      "range_query": {
      "key": "",
      "range": "", //[,]
      "boost": "",
      "format": "",
      "include_lower": true,
      "include_upper": false
      }
  • exists_query,存在查詢,查找字段不存在的文檔。

    • key elasticSearch字段。
      1
      2
      3
      "exists_query": {
      "key": ""
      }
# text_level_query查詢類型
text_query_type

text_level_query查詢類型,支持match_query,multi_match_query,query_string,simple_query_string等。

  • match_query,普通的文本匹配查詢。

    • key 供文本匹配的ES字段
    • value 須要搜索的文本關鍵字,會分詞。
    • zero_terms_query 決定是否使用停詞。all表示不使用停詞,默認使none。
      1
      2
      3
      4
      5
      "match_query": {
      "key": "",
      "value": "this is a test",
      "zero_terms_query": "none"
      }
  • multi_match_query 在多個字段中進行文本匹配

    • value 須要搜索的文本關鍵字,會分詞。
    • fields ES中的字段,能夠多個,用逗號隔開,在字段旁邊使用^表示該字段的權重,如」a^3,b」。
    • type 匹配類型,支持best_fields(默認),most_fields,cross_fields,phrase,phrase_prefix。
      1
      2
      3
      4
      5
      "multi_match_query": {
      "value": "",
      "fields": "a^3,b",
      "type": "best_fields" //most_fields,cross_fields,phrase,phrase_prefix
      }
  • query_string 字符串文本匹配。

    • value 須要搜索的文本關鍵字,會分詞。
    • fields ES中的字段,格式爲數組,如」[a,b]」
      1
      2
      3
      4
      "query_string": {
      "value": "",
      "fields": ""//數組
      }
  • simple_query_string 簡單字符串匹配
    • value fields 同 query_string
    • default_operate 匹配邏輯,值爲and 或者 or
      1
      2
      3
      4
      5
      "simple_query_string": {
      "value": "",
      "fields": "", //數組
      "default_operate": "and"
      }
  • match_all_query 匹配全部文檔
# bool_query 布爾查詢

bool_query是其餘查詢的布爾組合,通常用於構建複雜的查詢,而這正是elasticsearch-query-builder最拿手的地方。

bool_type
  • must查詢
    must查詢全部的查詢條件都會用於作文檔匹配(至關於and),而且用於計算相關度score的值。
  • filter查詢
    filter查詢全部的查詢條件都會用於作文檔匹配(至關於and),可是和must不一樣的是,filter查詢裏面的查詢條件並不用於計算相關度。
  • should查詢
    should查詢條件只須要知足其中一個便可(至關於or)。
  • must_not
    must_not查詢表示全部的查詢條件同時不知足(至關於not)。
    如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    "query_type": "bool_query",
    "bool_query": [
    {
    "bool_type": "must",
    "items": [
    {
    "value": "",
    "key": "province_code",
    "terms_method": "term" //term,terms,range,match
    },
    {
    "value": "",
    "key": "city_code",
    "terms_method": "term" //term,terms,range,match
    }
    ]
    },
    {
    "bool_type":"filter",
    "items":[
    "value": "",
    "key": "sex",
    "terms_method":"term"
    ]
    }
    ]
# aggregation 聚合

ES的聚合操做一般用於聚合查詢結果數據,一般用於數據的分類和統計工做。同時ES自己支持多種聚合操做,爲咱們的數據分析和統計提供了便利,相應的,本項目也支持聚合操做的配置化和參數綁定。

Avg Aggregation 計算平均數
  • name 聚合名稱。
  • aggregation_type 聚合類型。
  • field 查詢結果中用於聚合的字段。
  • missing_value 若是文檔中該字段爲空時,設置的默認值。
    1
    2
    3
    4
    5
    6
    7
    8
    "aggregations": [
    {
    "aggregation_type": "avg", // 聚合類型
    "name": "", //聚合的名稱
    "field": "",
    "missing_value": 10
    }
    ]
Terms Aggregation 根據字段的值進行聚合
  • name 聚合名稱。
  • aggregation_type 聚合類型。
  • field 查詢結果中用於聚合的字段。
  • size 默認爲10,設置爲0即統計全部的字段值分類的文檔個數。
  • sort asc || desc,肯定是升序仍是降序,default: asc。
  • min_doc_count 最小的匹配文檔數,count低於該值的字段值不顯示。
  • sort_by 設置聚合結果的排序,默認是根據聚合字段的值排序,能夠設置成以聚合分類下的個數排序即_count。
  • sub_aggregations 子聚合,對聚合結果進行再聚合,子聚合能夠是別的任意聚合類型。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    {
    "aggregation_type": "terms",
    "name": "",
    "field": "",
    "size": "${size.value}",
    "sort": "asc",
    "sort_by": "_count",
    "sub_aggregations":{ //子聚合
    "aggregation_type": "terms",
    "name": "",
    "field": "",
    "size": "${size.value}",
    "sort": "asc",
    "sort_by": "_count"
    }
    }

由於aggregation聚合的類型比較多,另外還有,min, max, cardinality,extended_stats, stats,sum,top_hits,value_count,range,missing,date_range,ipv4_range,date_histogram等,這裏就再也不贅述,須要查看聚合類型怎麼用的,能夠查看配置文件樣例

# highlight 文檔高亮

ES能夠設置對查詢結果中包含搜索關鍵字的字段部分進行高亮。

  • fields 設置須要高亮的字段
    • field 字段名
    • fragment_size 字段高亮顯示的片斷的字符長度大小,default: 100
    • number_of_fragment 最多返回片斷數,default: 5
  • pre_tags 匹配出來的文檔的標籤前綴, default: <em>
  • post_tags 匹配出來的文檔的標籤後綴, default: </em>
  • tags_schema
  • order 高亮片斷的排序方式
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    "highlight":{
    "fields": [
    {
    "field": "content",
    "number_of_fragment": 2,
    "fragment_size": 150
    }
    ],
    "pre_tags":[],
    "post_tags":[],
    "tags_schema":"", //styled
    "order":"score"
    }

參數綁定

# 單值參數綁定

單值綁定,這裏咱們以sex字段爲例,咱們須要查詢出index中性別爲女性的記錄,咱們能夠用terms查詢,如:

1
2
3
4
"term_query": {
"value": "female",
"key": "sex",
}

 

經過以上查詢就能夠查出性別爲女性的文檔。那若是咱們的value值須要從外面傳進來呢,好比咱們的參數在一個json字符串中(很是適合application/json的傳值:)),如:{ "sex": "female",type: 1},咱們的配置文件應該怎麼寫?

elasticsearch-query-builder中,咱們約定須要外界綁定的參數用${}將字段包括進來,如:${sex}這裏的sex同json數據裏面的key一致。那麼在配置文件中就轉換成了:

1
2
3
4
"term_query": {
"value": "${sex}",
"key": "sex",
}

 

若是json中的字段不在第一層呢?比方說:{ "a.sex": "female",type: 1}, 那麼咱們用.號來表示層級結構,${a.sex}, 無論層級多深都沒有問題。

# 範圍參數綁定

對於範圍類型的參數綁定,好比:type 從 1->6 或者 date 從 2017-06-10 -> 2017-12-12, 咱們應該怎麼從外界進行參數綁定呢?在range查詢中,咱們已經定義了range的傳參方式,以下:

1
2
3
4
"range_query":{
"range": "[2017-06-10, 2017-12-12]"
"key": "date"
}

 

其實,其實range的參數綁定和單值的參數綁定是一致的,雖然有範圍,其實取的仍是單值${date}, 只是咱們對外界的json數據結構表示範圍的字段有限制,咱們規定json中表示範圍的字段必須是[a,b]的形式,a和b能夠單一缺省,表示無上界或者下界,可是a和b不能夠同時缺省(同時缺省,這個範圍查詢是沒有意義的)。
如json數據:{ "date": "[2017-06-10, 2017-12-12]" }即符合規範。

使用示例

這個例子也是elasticsearch-query-builder種的example。
咱們先定義配置文件test.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
"index":"event",
"query_type":"bool_query",
"size":"${pageSize}",
"from":"${offset}",
"include_source": ["age"],
"sort":[
{
"field":"date_time",
"order":"desc"
}
],
"bool_query":[
{
"bool_type":"filter",
"items":[
{
"terms_method":"term",
"value":"${is_success}",
"key":"is_success"
},
{
"terms_method":"range",
"range":"${date_time}",
"key":"date_time"
},
{
"terms_method":"term",
"value":"${id}}",
"key":"id"
}
]
},
{
"bool_type":"must",
"items":[
{
"terms_method":"match",
"value":"${name}",
"key":"name"
}
]
}
],
"type":"docs"
}

 

使用elasticsearch-query-builder生成ES的查詢語句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.coryphaei.query.FileUtil;
import org.coryphaei.query.parser.ZWSearchParser;
import org.elasticsearch.search.builder.SearchSourceBuilder;

/**
* Created by twist on 2017-08-05.
*/
public class ElasticsearchParser {
public static void main(String[] args) throws Exception {
String dataStr = "{\n" + //須要綁定的json格式參數
"\t\"pageSize\":10,\n" +
"\t\"from\": 10,\n" +
"\t\"id\": \"1\",\n" +
"\t\"date_time\":\"[2017-06-01,]\",\n" +
"\t\"is_success\":1,\n" +
"\t\"name\":\"Bob\"\n" +
"}";

JSONObject data = JSON.parseObject(dataStr);
String config = FileUtil.readResourceRemoveComments(ElasticsearchParser.class, "test.json"); //加載配置文件
SearchSourceBuilder searchSourceBuilder = ZWSearchParser.searchSourceBuilder(JSON.parseObject(config), data); //生成DSL查詢語句
System.out.println(searchSourceBuilder.toString());
}
}

 

生成的ES的DSL查詢語句:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
{
"size" : 10,
"query" : {
"bool" : {
"must" : {
"match" : {
"name" : {
"query" : "Bob",
"type" : "boolean"
}
}
},
"filter" : [ {
"term" : {
"is_success" : "1"
}
}, {
"range" : {
"date_time" : {
"from" : "2017-06-01",
"to" : null,
"include_lower" : true,
"include_upper" : true
}
}
} ]
}
},
"_source" : {
"includes" : [ "age" ],
"excludes" : [ ]
},
"sort" : [ {
"date_time" : {
"order" : "desc"
}
} ]
}

 

不足和待改進

本項目並無涵蓋ES的全部查詢功能,同時,也沒有包含ES的最新版本的功能,這些都是我後續須要逐漸完善的地方,我但願能夠經過本身的努力,使本項目愈來愈完善。

致謝

本項目使用了阿里的fastjsonjar包,elasticsearch公司的elasticsearchjar包,以及io.searchboxjestjar包,這裏表示由衷的感謝。

相關文章
相關標籤/搜索