前言
在這里,我想向大家推薦一個我自己開發的項目,也就是elasticsearch-query-builder
,這個項目目前在github上已經開源,有興趣的朋友可以去fork或者star,你的star就是對我最大的鼓勵。同時,本項目長期維護和更新,我也接受並且很高興有小伙伴向本項目pull request,或者協同開發,有興趣的同學可以給我發郵件。
elasticsearch-query-builder
是一個非常方便構造elasticsearch
(后面簡稱ES) DSL 查詢語句的工具包,在elasticsearch-query-builder
中,我嘗試基於配置化的操作去構建ES的查詢語句,並且接受外界傳入參數,這極大的減少了在Java代碼中構建ES查詢語句的工作,並同時減少了代碼量,使代碼更加直觀和清晰。基於使ES中DSL構造語句和Java代碼分離的思想,elasticsearch-query-builder
誕生了。去GithubFork!
構建
elasticsearch-query-builder
工程一般作為jar包為別的工程提供使用,當然,如果需要基於本項目做二次開發,這都需要將Github上克隆本項目到本地
1 |
git clone https://github.com/xiaowei1118/elasticsearch-query-builder.git |
在將本項目克隆到本地后,執行mvn package
將本項目打成jar包,或者直接將本項目作為你們自己maven項目的module項目。
elasticsearch-query-builder使用詳細說明
elastcisearch-query-builder接受配置文件(特定json格式)或者json格式的字符串配置,配置格式如下:
1 |
{ |
參數說明
# index
index表示elasticSearch中的索引或者別名。
# type
type表示elasticSearch索引或者別名下的type。
# from
from表示檢索文檔時的偏移量,相當於關系型數據庫里的offset。
# include_source
include_source 搜索結果中包含某些字段,格式為json數組,"include_source": ["name","age"]
。
# 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": ""
},
- key,value,boost解釋同
-
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": ""
}
- key elasticSearch字段。
# 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 |
"term_query": { |
通過以上查詢就可以查出性別為女性的文檔。那如果我們的value值需要從外面傳進來呢,比如我們的參數在一個json字符串中(非常適合application/json的傳值:)),如:{ "sex": "female",type: 1}
,我們的配置文件應該怎么寫?
在elasticsearch-query-builder
中,我們約定需要外界綁定的參數用${}
將字段包括進來,如:${sex}
這里的sex
同json數據里面的key一致。那么在配置文件中就轉換成了:
1 |
"term_query": { |
如果json中的字段不在第一層呢?比方說:{ "a.sex": "female",type: 1}
, 那么我們用.
號來表示層級結構,${a.sex}
, 不管層級多深都沒有問題。
# 范圍參數綁定
對於范圍類型的參數綁定,比如:type 從 1->6
或者 date 從 2017-06-10 -> 2017-12-12
, 我們應該怎么從外界進行參數綁定呢?在range查詢中,我們已經定義了range的傳參方式,如下:
1 |
"range_query":{ |
其實,其實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 |
{ |
使用elasticsearch-query-builder
生成ES的查詢語句。
1 |
import com.alibaba.fastjson.JSON; |
生成的ES的DSL查詢語句:
1 |
{ |
不足和待改進
本項目並沒有涵蓋ES的所有查詢功能,同時,也沒有包含ES的最新版本的功能,這些都是我后續需要逐漸完善的地方,我希望可以通過自己的努力,使本項目越來越完善。
致謝
本項目使用了阿里的fastjson
jar包,elasticsearch公司的elasticsearch
jar包,以及io.searchbox
的jest
jar包,這里表示由衷的感謝。