Java操作Elasticsearch6實作基本查詢
Java操作Elasticsearch6實作基本查詢
引言
業務系統接入Elasticsearch搜尋服務後,開始了寫查詢接口的任務,本篇部落格将總結Java操作Elasticsearch一些基本查詢的實作。
基礎代碼
建構查詢條件,對應Elasticsearch其實就是建構SearchRequest對象,指定索引庫Name,指定索引庫Type,建立SearchSourceBuilder對象,根據需求建立QueryBuilder對象,下面是建立和使用建構對象的基礎代碼:
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices("indexName");
searchRequest.types("indexType");
SearchSourceBuilder builder = new SearchSourceBuilder();
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
builder.query(boolQueryBuilder);
searchRequest.source(builder);
構造查詢條件代碼
1. termQuery:精确查詢(不分詞)
//termQuery 精确比對,參數(Es中對應字段的keyword,比對的值)
boolQueryBuilder.filter(QueryBuilders.termQuery("gradeName.keyword", dto.getGradeName()));
使用termQuery要注意的是,Elasticsearch5之後,取消了string類型,将原來的string類型拆分為text和keyword兩種類型,他們的差別在于text會對字段進行分詞處理,而keyword則不會。下面通過例子來看一下兩者的差別:
使用’gradeName.keyword’字段查詢,查詢條件“六年級”,查詢結果如下:
如果在Elasticsearch5之後,查詢條件年級傳入"六年級",使用’gradeName’字段查詢,是查詢不到結果的:
//termQuery 精确比對,參數(Es中的字段key,比對的值)
boolQueryBuilder.filter(QueryBuilders.termQuery("gradeName", dto.getGradeName()));
原因是在查詢中,如果使用’gradeName’查詢,是将gradeName作為text類型查詢,而使用’gradeName.keyword’,則是将其作為keyword類型查詢,前者會對查詢内容做分詞處理之後再比對,而後者則是直接精确比對。
當我們沒有對索引字段預先指定mapping,Elasticsearch會進行動态映射,如傳入價格字段的值為12,會映射為long類型;對傳入ip字段的值為’192.168.0.12’,會映射為ip類型。對于普通字元串,elasticsearch将其映射為text類型,為了保證對這些字段做精确查詢和聚合的能力,又同時做了keyword類型的映射,作為該字段的fields屬性寫到_mapping中。
Elasticsearch的termQuery做的是精确查詢而不是分詞查詢,是以對text類型的字段做term查詢則是查不到結果的(除非字段本身經過分詞器處理後不變,未被轉換或分詞)。此時,必須使用gradeName.keyword來對gradeName字段以keyword類型進行精确比對。
2. matchQuery:比對查詢(分詞)
boolQueryBuilder.filter(QueryBuilders.matchQuery("gradeName", dto.getGradeName()));
match query搜尋的時候,首先會解析查詢字元串,進行分詞,然後查詢,是以假如我搜尋的條件輸入的是"六年級",則會把各個年級(一年級至九年級)的資料都查詢出來,因為其中都包含’年級’,結果如下:
而上面提到的term query,輸入的查詢内容是什麼,就會按照什麼去查詢,并不會解析查詢内容,對它分詞。
3. queryString:精确查詢
QueryStringQueryBuilder queryStringQueryBuilder = new QueryStringQueryBuilder(dto.getGradeName()).field("gradeName").defaultOperator(Operator.AND);
boolQueryBuilder.must(queryStringQueryBuilder);
這裡使用QueryStringQueryBuilder構造查詢條件,并沒有用keyword類型字段’gradeName.keyword’,也可以查詢到結果,并且使用defaultOperator拼接操作條件AND或者OR即可。
4. wildcardQuery:模糊查詢
//wildcardQuery 模糊比對,參數(Es中的字段key,比對的值)
boolQueryBuilder.filter(QueryBuilders.wildcardQuery("phone", String.format("*%s*", dto.getPhone())));
5. rangeQuery:範圍查詢
//範圍查詢(國小階段:大于等于1,小于等于6)
boolQueryBuilder.filter(QueryBuilders.rangeQuery("gradeCode").from(1, true).to(6, true));
from和to的第二個參數表明是否包含上限值或下限值。
6. Condition 1 OR Condition 2 的實作
BoolQueryBuilder fuzzyQueryBuilder = new BoolQueryBuilder();
fuzzyQueryBuilder.should(QueryBuilders.wildcardQuery("nickName", String.format("*%s*", dto.getFuzzyCondition())))
.should(QueryBuilders.wildcardQuery("phone", String.format("*%s*", dto.getFuzzyCondition())))
這裡的should相當于OR,多個字段之間用should拼接,可實作多個字段模糊查詢。
7. (Condition 1 OR Condition 2) AND Condition3 的實作
//構造條件3使用
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
//構造條件1和條件2使用
BoolQueryBuilder fuzzyQueryBuilder = new BoolQueryBuilder();
//手機号或昵稱
if (StringUtils.isNotBlank(dto.getFuzzyCondition())) {
//must相當于and,拼接條件,should相當于or,多個字段模糊查詢條件拼接
boolQueryBuilder.must(fuzzyQueryBuilder.should(QueryBuilders.wildcardQuery("nickName", String.format("*%s*", dto.getFuzzyCondition())))
.should(QueryBuilders.wildcardQuery("phone", String.format("*%s*", dto.getFuzzyCondition()))));
}
//學員類型:付費/未付費
if (dto.getType() != null) {
boolQueryBuilder.filter(QueryBuilders.termQuery("type", dto.getType()));
}
這裡我們需要建構兩個QueryBuilder,在QueryBuilder之間,使用must進行拼接,相當于AND條件。
總結
以上總結的都屬于一些基本的查詢,能滿足目前業務系統的需求,以後遇到進階查詢再單獨進行總結。
Java操作Elasticsearch6實作基本查詢相關教程