目錄html
git地址:https://gitee.com/zxporz/ESClientRHL前端
EsClientRHL是一個可基於springboot的elasticsearch RestHighLevelClient客戶端調用封裝工具,主要提供了es索引結構工具、es索引數據增刪改工具、es查詢工具、es數據分析工具。java
基於elasticsearch6.6+版本進行開發,因爲採用RestHighLevelClient,因此版本兼容問題應該能獲得必定改善。react
更新日期 | 更新內容 |
---|---|
2019-03-19 | 修復了一個搜索建議mapping的bug,增長了按照條件刪除的api、添加了檢索時能夠檢索多個索引的api以及註解配置方式(詳見api更新) |
2019-04-16 | 優化了@EnableESTools獲取entity地址的邏輯,並添加了esclientrhl-start的支持,增長ImportBeanDefinitionRegistrar(彩蛋) |
刪除索引結構git
按照多索引查詢說明(2013-03-19新增)正則表達式
日期直方圖聚合查詢spring
存放一些註解,用於簡化組件使用sql
基於springboot的自動化的功能,包括自動配置es客戶端組件以及自動管理索引結構的功能json
基礎數據的枚舉後端
索引結構管理的功能包
CURD+聚合的功能包
內部工具包
請把組件安裝到maven倉庫
<dependency> <groupId>org.zxp</groupId> <artifactId>esclientrhl</artifactId> <version>1.0.0</version> </dependency>
也能夠直接引入starter
請下載esclientrhl-springboot-starter
<dependency> <groupId>org.zxp</groupId> <artifactId>esclientrhl-springboot-starter</artifactId> <version>1.0.0</version> </dependency>
如何集成springboot項目後出現elasticsearch底層版本問題,請在springboot工程中設定es版本號
<dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>6.6.0</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>6.6.0</version> </dependency>
在springboot啓動類上添加
@SpringBootApplication
@EnableESTools
public class EsdemoApplication {
public static void main(String[] args) {
SpringApplication.run(EsdemoApplication.class, args);
}
}
若是引入的是esclientrhl-starter,則啓動類上無需添加@EnableESTools,會自動掃描啓動類路徑下的包,除非有額外的包須要配置,不然無需配置@EnableESTools application.properties配置elasticsearch服務的uri,若是有多個(集羣狀況)請用半角逗號```,```隔開
elasticsearch.host=127.0.0.1:9200
#### 使用組件 在spring管理的bean內直接自動注入組件內置的兩個工具服務:```ElasticsearchTemplate、ElasticsearchIndex```並調用相關api便可
@Service
public class CompletionSuggestServiceImpl implements CompletionSuggestService {
@Autowired
ElasticsearchTemplate<Book,String> elasticsearchTemplate;
#### 索引管理功能 ###### 元數據配置 用於定製es索引結構對應實體類的元數據
@ESMetaData(indexName = "index",indexType = "main4", number_of_shards = 5,number_of_replicas = 0)
包含的主要配置信息以及默認值以下
/**
###### 索引結構配置 用於定製es索引結構對應實體類的索引結構,以簡化建立索引工做。將相關注解配置於實體類field上,用於標識field對應elasticsearch索引結構字段的相關信息
@ESID
private String proposal_no;
@ESMapping(datatype = DataType.keyword_type)
private String risk_code;
@ESMapping(datatype = DataType.text_type)
private String risk_name;
@ESID
標識es主鍵(自動對應es索引數據_id字段),注意:主鍵的類型須要與
ElasticsearchTemplate```的第二泛型一致
/**
/**
若是對字段類型要求沒有那麼高,則不配置,組件能夠支持自動適配mapping ###### 根據配置信息自動建立索引結構mapping 項目啓動時,組件會自動識別es實體類上配置的```@ESMetaData```註解,若是對應的索引結構沒有建立,自動根據mapping註解配置建立相關索引結構。 若是實體類不在啓動類的包路徑下,如需啓用此功能,須要在啓動註解上配置實體類路徑。
@EnableESTools(entityPath = "com.*.esdemo.domain")
###### 手工建立或刪除索引結構
elasticsearchIndex.dropIndex(Main2.class);
elasticsearchIndex.createIndex(Main2.class);
###### 判斷索引是否存在
/**
elasticsearchIndex.exists(Main2.class)
#### CRUD功能說明 ###### LowLevelClient查詢 這種狀況一般適用於直接發JSON報文查詢或操做es服務端,本方法並無作太多的封裝,基本保留了原生的出入參
//自動注入工具類
@Autowired
ElasticsearchTemplate elasticsearchTemplate;
//執行查詢
Request request = new Request("GET","/esdemo");
request.setEntity(new NStringEntity("{"query":{"match_all":{"boost":1.0}}}",ContentType.APPLICATION_JSON));
Response response = elasticsearchTemplate.request(request);
RequestLine requestLine = response.getRequestLine();
HttpHost host = response.getHost();
int statusCode = response.getStatusLine().getStatusCode();
Header[] headers = response.getHeaders();
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println(responseBody);
###### 新增索引數據 如無特殊說明下面查詢都默認注入了工具類,工具類第一泛型是要操做的es索引結構的類,第二泛型是索引對應主鍵的類
@Autowired
ElasticsearchTemplate<Main2,String> elasticsearchTemplate;
Main2類型的主鍵是String
@ESMetaData(indexName = "index",indexType = "main", number_of_shards = 5,number_of_replicas = 0)
public class Main2 implements Serializable {
private static final long serialVersionUID = 1L;
@ESID
private String proposal_no;
Main2 main = new Main2();
main.setProposal_no("main2");
main.setAppli_code("123");
main.setAppli_name("456");
elasticsearchTemplate.save(main);
###### 批量新增索引數據
List
Main2 main1 = new Main2();
main1.setProposal_no("main1");
main1.setAppli_code("123");
main1.setAppli_name("456");
Main2 main2 = new Main2();
main2.setProposal_no("main2");
main2.setAppli_code("123");
main2.setAppli_name("456");
Main2 main3 = new Main2();
main3.setProposal_no("main3");
main3.setAppli_code("123");
main3.setAppli_name("456");
list.add(main1);
list.add(main2);
list.add(main3);
elasticsearchTemplate.save(list);
###### 部分更新索引數據
Main2 main1 = new Main2();
main1.setProposal_no("main1");
main1.setInsured_code("123");
elasticsearchTemplate.update(main1);
###### 覆蓋更新索引數據
Main2 main1 = new Main2();
main1.setProposal_no("main1");
main1.setInsured_code("123");
elasticsearchTemplate.updateCover(main1);
部分更新相比於覆蓋更新的區別是,部分更新只會更新set了的字段值 ###### 刪除索引數據
//經過對象刪除,ID必須有值
Main2 main1 = new Main2();
main1.setProposal_no("main1");
main1.setInsured_code("123");
elasticsearchTemplate.delete(main1);
//經過ID刪除
elasticsearchTemplate.deleteById("main1",Main2.class);
###### 根據查詢條件刪除索引數據
elasticsearchTemplate.deleteByCondition(QueryBuilders.matchQuery("appli_name","2"),Main5.class);
###### 判斷索引數據是否存在
Main2 main1 = new Main2();
main1.setProposal_no("main1");
main1.setInsured_code("123");
boolean exists = elasticsearchTemplate.exists("main1",Main2.class);
System.out.println(exists);
###### 原生查詢 searchRequest是官方原生查詢輸入,此方法在工具沒法知足需求時使用
SearchRequest searchRequest = new SearchRequest(new String[]{"index"});
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(new MatchAllQueryBuilder());
searchSourceBuilder.from(0);
searchSourceBuilder.size(10);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = elasticsearchTemplate.search(searchRequest);
SearchHits hits = searchResponse.getHits();
SearchHit[] searchHits = hits.getHits();
for (SearchHit hit : searchHits) {
Main2 t = JsonUtils.string2Obj(hit.getSourceAsString(), Main2.class);
System.out.println(t);
}
###### 支持、查詢條件的定製查詢
/**
//這裏簡單經過matchall(全查詢)的方式進行演示
//QueryBuilder的用法會在單獨章節介紹
List
main2List.forEach(main2 -> System.out.println(main2));
###### 支持分頁、高亮、排序、查詢條件的定製查詢
/**
//定製分頁信息
int currentPage = 1;
int pageSize = 10;
//分頁
PageSortHighLight psh = new PageSortHighLight(currentPage,pageSize);
//排序字段,注意若是proposal_no是text類型會默認帶有keyword性質,須要拼接.keyword
String sorter = "proposal_no.keyword";
Sort.Order order = new Sort.Order(SortOrder.ASC,sorter);
psh.setSort(new Sort(order));
//定製高亮,若是定製了高亮,返回結果會自動替換字段值爲高亮內容
psh.setHighLight(new HighLight().field("risk_code"));
//能夠單獨定義高亮的格式
//new HighLight().setPreTag("");
//new HighLight().setPostTag("");
PageList
pageList = elasticsearchTemplate.search(new MatchAllQueryBuilder(), psh, Main2.class);
pageList.getList().forEach(main2 -> System.out.println(main2));
###### count查詢 結合查詢條件查詢結果的數據量
long count = elasticsearchTemplate.count(new MatchAllQueryBuilder(),Main2.class);
System.out.println(count);
###### scroll查詢
/**
/**
//默認scroll鏡像保留2小時
List
main2List.forEach(main2 -> System.out.println(main2));
//指定scroll鏡像保留5小時
//List
###### ~~模版查詢~~ 暫時沒法使用該方法,緣由爲官方API SearchTemplateRequestBuilder仍保留對transportClient 的依賴,但Migration Guide 中描述須要把transportClient遷移爲RestHighLevelClient ###### 搜索建議 搜索建議功能可以快速提示要搜索的內容(請參考百度搜索功能),搜索建議字段須要配置suggest屬性爲true
/**
List
list.forEach(main2 -> System.out.println(main2));
@ESMapping(suggest = true)
private String appli_name;
###### 根據ID查詢
/**
Main2 main2 = elasticsearchTemplate.getById("main2", Main2.class);
System.out.println(main2);
###### mget查詢
/**
String[] list = {"main2","main3"};
List
listResult.forEach(main -> System.out.println(main));
#### QueryBuilder經常使用用法展現 ###### 精準查詢
//精準查詢的字段須要設置keyword屬性(默認該屬性爲true),查詢時fieldname須要帶上.keyword
QueryBuilder queryBuilder = QueryBuilders.termQuery("appli_name.keyword","456");
List
list.forEach(main2 -> System.out.println(main2));
//若是field類型直接爲keyword能夠不用加.keyword
###### 短語查詢
//中國好男兒
//必須相鄰的查詢條件
QueryBuilder queryBuilder = QueryBuilders.matchPhraseQuery("appli_name","國好");
###### 相關度查詢
//中國好男兒
//slop設置爲2,中和男最多能移動兩次並完成匹配
QueryBuilder queryBuilder = QueryBuilders.matchPhraseQuery("appli_name","中男").slop(2);
###### 範圍查詢
QueryBuilder queryBuilder = QueryBuilders.rangeQuery("sum_premium").from(1).to(3);
###### 全文匹配
QueryBuilder queryBuilder = QueryBuilders.matchQuery("appli_name","中男兒");
minimumShouldMatch最少匹配參數
//"中 男 兒 美 麗 人 生"最少匹配詞語數量是75%,該查詢查不到信息
QueryBuilder queryBuilder = QueryBuilders.matchQuery("appli_name","中 男 兒 美 麗 人 生").minimumShouldMatch("75%");
match查詢集成fuzzy糾錯查詢
QueryBuilder queryBuilder = QueryBuilders.matchQuery("appli_name","spting");
((MatchQueryBuilder) queryBuilder).fuzziness(Fuzziness.AUTO);
match查詢設定查詢條件邏輯關係
//默認是OR
QueryBuilder queryBuilder = QueryBuilders.matchQuery("appli_name","spring sps").operator(Operator.AND);
###### fuzzy糾錯查詢
//原文是spring,查詢條件輸入爲spting也能查詢到結果
QueryBuilder queryBuilder = QueryBuilders.fuzzyQuery("appli_name","spting");
###### boost權重設置
//查詢結果appli_name爲spring的會被優先展現其次456,再次123
QueryBuilder queryBuilder1 = QueryBuilders.termQuery("appli_name.keyword","spring").boost(5);
QueryBuilder queryBuilder2 = QueryBuilders.termQuery("appli_name.keyword","456").boost(3);
QueryBuilder queryBuilder3 = QueryBuilders.termQuery("appli_name.keyword","123");
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.should(queryBuilder1).should(queryBuilder2).should(queryBuilder3);
###### prefix前綴查詢
//性能差,掃描整個倒排索引,前綴越短,要處理的doc越多,性能越差,儘量用長前綴搜索
//查詢appli_name字段值前綴爲1的內容
QueryBuilder queryBuilder = QueryBuilders.prefixQuery("appli_name","1");
###### wildcard通配符查詢
//性能較差不建議使用
//?:任意字符
//*:0個或任意多個字符
QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("appli_name","1?3");
###### regexp正則查詢
//性能較差不建議使用
QueryBuilder queryBuilder = QueryBuilders.regexpQuery("appli_name","[0-9].+");
//[0-9]:指定範圍內的數字
//[a-z]:指定範圍內的字母
//.:一個字符
//+:前面的正則表達式能夠出現一次或屢次
###### 組合邏輯查詢 組合邏輯查詢是多種查詢方式的邏輯組合,共有三種:與must、或should、非mustNot
//select * from Main2 where (appli_name = 'spring' or appli_name = '456') and risk_code = '0101' and proposal_no != '1234567'
QueryBuilder queryBuilder1 = QueryBuilders.termQuery("appli_name.keyword","spring");
QueryBuilder queryBuilder2 = QueryBuilders.termQuery("appli_name.keyword","456");
QueryBuilder queryBuilder3 = QueryBuilders.termQuery("risk_code","0101");
QueryBuilder queryBuilder4 = QueryBuilders.termQuery("proposal_no.keyword","1234567");
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
queryBuilder.should(queryBuilder1).should(queryBuilder2);
queryBuilder.must(queryBuilder3);
queryBuilder.mustNot(queryBuilder4);
###### 過濾器 > 過濾器查詢須要和布爾查詢結合使用,效果上和普通查詢沒有什麼區別 > 好比下面的例子must和filter的關係是而且 > 但過濾器查詢首先不會計算相關度評分,而普通查詢會去計算相關度評分,而且按照相關對進行排序,那麼若是你並不須要相關度評分就要優先選擇過濾器查詢 > 另外過濾器查詢內置了bitset的caching機制,可以很是大程度的提高查詢的性能,減小掃描倒排索引的概率,因此在平常開發中,咱們須要認真評估,積極使用過濾器查詢
//select * from Main2 where appli_name = '456' and risk_code = '0101'
QueryBuilder queryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.termQuery("appli_name.keyword","456"))
//下面若是會比較頻繁的做爲子集合,就比較適合經過filter來緩存
.filter(QueryBuilders.matchPhraseQuery("risk_code","0101"));
List
list.forEach(main2 -> System.out.println(main2));
> 更多QueryBuilder詳見https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.6/java-rest-high-query-builders.html ###### 按照多索引查詢說明 有兩種方式可供多索引查詢 1. 經過配置註解```searchIndexNames```,這種方式能夠在默認能查詢多索引的全部api中生效,若是配置此項,再相應的查詢方法將會查詢多個索引,並按照當前poji的字段結果進行返回,但因爲經過註解配置不靈活,因此若是不是特別肯定的場景並不建議這麼作。
@ESMetaData(indexName = "main5",indexType = "main5",searchIndexNames = {"main5","index"}, number_of_shards = 5,number_of_replicas = 0,printLog = false)
public class Main5 implements Serializable {
//查詢api調用不發生任何變化
2. 經過api傳入須要查詢的多個索引名稱,這種方式相比註解方式更加靈活可靠,若是涉及跨索引查詢的業務推薦使用這種方法,目前已經添加了普通查詢對應的多索引入參api,後續將添加聚合查詢的跨索引查詢
//傳入main五、main6做爲須要被2個索引範圍
List
System.out.println(list.size());
//查詢結果僅包含main6的字段結果
list.forEach(main6 -> System.out.println(main6));
這是一個新增的接口方法實例,均在最後添加了可變長入參的方式
/**
* 非分頁查詢(跨索引)
* 目前暫時傳入類類型
* @param queryBuilder
* @param clazz
* @return
* @throws Exception
*/
public List
==建議跨索引查詢時多索引之間儘可能字段重合度高== #### 聚合查詢 ###### 原生聚合查詢
/**
SumAggregationBuilder aggregation = AggregationBuilders.sum("agg").field("sum_amount");
Aggregations aggregations = elasticsearchTemplate.aggs(aggregation,null,Main2.class);
Sum agg = aggregations.get("agg");
double value = agg.getValue();
System.out.println(value);
> 更詳細用法請參考官方文檔https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.6/_metrics_aggregations.html > 官方全部聚合Builder請參考https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.6/java-rest-high-aggregation-builders.html ###### 普通聚合查詢
/**
double sum = elasticsearchTemplate.aggs("sum_premium", AggsType.sum,null,Main2.class);
double count = elasticsearchTemplate.aggs("sum_premium", AggsType.count,null,Main2.class);
double avg = elasticsearchTemplate.aggs("sum_premium", AggsType.avg,null,Main2.class);
double min = elasticsearchTemplate.aggs("sum_premium", AggsType.min,null,Main2.class);
//若是翻譯成sql:select max(sum_premium) from Main2
double max = elasticsearchTemplate.aggs("sum_premium", AggsType.max,null,Main2.class);
System.out.println("sum===="+sum);
System.out.println("count===="+count);
System.out.println("avg===="+avg);
System.out.println("min===="+min);
System.out.println("max===="+max);
- 分組普通聚合查詢
/**
//若是翻譯成sql:select appli_name,max(sum_premium) from Main2 group by appli_name
Map map = elasticsearchTemplate.aggs("sum_premium", AggsType.sum,null,Main2.class,"appli_name");
map.forEach((k,v) -> System.out.println(k+" "+v));
==默認按照聚合結果降序排序== - 下鑽(2層)聚合查詢
/**
//select appli_name,risk_code,sum(sumpremium) from Main2 group by appli_name,risk_code
List
list.forEach(down ->
{
System.out.println("1:"+down.getLevel_1_key());
System.out.println("2:"+down.getLevel_2_key() + " "+ down.getValue());
}
);
- 統計聚合查詢
/**
//此方法能夠一次查詢便返回針對metricName統計分析的sum、count、avg、min、max指標值
Stats stats = elasticsearchTemplate.statsAggs("sum_premium",null,Main2.class);
System.out.println("max:"+stats.getMax());
System.out.println("min:"+stats.getMin());
System.out.println("sum:"+stats.getSum());
System.out.println("count:"+stats.getCount());
System.out.println("avg:"+stats.getAvg());
- 分組統計聚合查詢
/**
和上一個方法相比,這個方法增長了分組的功能
Map<String,Stats> stats = elasticsearchTemplate.statsAggs("sum_premium",null,Main2.class,"risk_code");
stats.forEach((k,v) ->
{
System.out.println(k+" count:"+v.getCount()+" sum:"+v.getSum()+"...");
}
);
//select count(distinct proposal_no) from Main2
long value = elasticsearchTemplate.cardinality("proposal_no",null,Main2.class);
System.out.println(value);
- 百分比聚合查詢
/**
/**
百分比聚合即查詢統計字段50%的數據在什麼值之內,95%的數據在什麼值之內
//下面的例子是取sum_premium這個字段的TP50 TP95 TP99
Map map = elasticsearchTemplate.percentilesAggs("sum_premium",null,Main2.class);
map.forEach((k,v) ->
{
System.out.println(k+" "+v);
}
);
//輸出結果是:
50.0 3.5
95.0 6.0
99.0 6.0
//即50%的sum_premium在3.5如下
//即95%的sum_premium在6.0如下
//即99%的sum_premium在6.0如下
//也能夠自定義百分比段位
Map map = elasticsearchTemplate.percentilesAggs("sum_premium",null,Main2.class,10,20,30,50,60,90,99);
- 百分等級聚合查詢
/**
百分等級聚合即給定一個統計結果的段位,並查詢在段位範圍內出現的百分比是多少
//咱們給定一個sum_premium字段的統計段位1,4,5,9,即1如下、4如下、5如下、9如下
//最終獲取在上述範圍內數據出現的比百分
Map map = elasticsearchTemplate.percentileRanksAggs("sum_premium",null,Main2.class,1,4,5,9);
map.forEach((k,v) ->
{
System.out.println(k+" "+v);
}
);
//輸出結果爲:
8.333333333333332 1.0
58.333333333333336 4.0
75.0 5.0
100.0 9.0
//即8.3%的數據sum_premium字段值在1如下
//即58.3%的數據sum_premium字段值在4如下
//即75%的數據sum_premium字段值在5如下
//即100%的數據sum_premium字段值在9如下
- 過濾器聚合查詢
/**
過濾器聚合讓es的聚合功能很是的靈活,它能夠靈活定製分組規格
//如下的例子是以risk_code是0101爲1組,risk_code是0103或0104爲1組,求sum_premium在分組內的和
Map map = elasticsearchTemplate.filterAggs("sum_premium", AggsType.sum, null,Main2.class,
new FiltersAggregator.KeyedFilter("0101", QueryBuilders.matchPhraseQuery("risk_code", "0101")),
new FiltersAggregator.KeyedFilter("0103或104", QueryBuilders.matchQuery("risk_code", "0103 0104")));
map.forEach((k, v) ->
System.out.println(k + " " + v)
);
- 直方圖聚合查詢
/**
直方圖聚合是統計針對分組字段,每隔X的值統計一次度量值
//統計sum_premium的數值每3的倍數,統計一次proposal_no的個數
Map map = elasticsearchTemplate.histogramAggs("proposal_no", AggsType.count, null,Main2.class,"sum_premium",3);
map.forEach((k, v) ->
System.out.println(k + " " + v)
);
//輸出結果爲:
0.0 2
3.0 3
6.0 1
- 日期直方圖聚合查詢
/**
日期直方圖與直方圖相似,只是將分組的字段替換爲日期類型
//統計input_date每兩個小時sum_premium的金額總合
Map map = elasticsearchTemplate.dateHistogramAggs("sum_premium", AggsType.sum, null,Main2.class,"input_date", DateHistogramInterval.hours(2));
map.forEach((k, v) ->
System.out.println(k + " " + v)
);
###### 更多聚合查詢的方式 es支持的聚合方式遠不止於此,工具只是針對最經常使用的一部分查詢方式進行封裝,以減輕代碼量 例如咱們須要實現一個範圍聚合,能夠經過如下例子實現:
//以sum_premium的範圍分組,並統計sum_premium的數量
AggregationBuilder aggregation = AggregationBuilders.range("range").field("sum_premium").addUnboundedTo(1).addRange(1,4).addRange(4,100).addUnboundedFrom(100);
aggregation.subAggregation(AggregationBuilders.count("agg").field("proposal_no.keyword"));
Aggregations aggregations = elasticsearchTemplate.aggs(aggregation,null,Main2.class);
Range range = aggregations.get("range");
for (Range.Bucket entry : range.getBuckets()) {
ValueCount count = entry.getAggregations().get("agg");
long value = count.getValue();
System.out.println(entry.getKey() + " " + value);
}
> 更多聚合API用法詳見https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.6/java-rest-high-aggregation-builders.html ## 運維功能 ###### 打印請求es服務日誌 若是須要調試,須要獲取請求es的json報文,能夠配置es索引結構實體類註解的打印報文開關```printLog = true```
@ESMetaData(indexName = "index",indexType = "main4", number_of_shards = 5,number_of_replicas = 0,printLog = true)
public class Main2 implements Serializable {
此項配置默認爲關閉,開啓後僅僅支持幾個經常使用功能的日誌打印,若是須要支持更多的功能打印,請在相應位置添加以下代碼便可
if(metaData.isPrintLog()){
logger.info(searchSourceBuilder.toString());
}
```