Java實現(xiàn)Elasticsearch查詢當前索引全部數(shù)據(jù)的完整代碼
需求背景
通常情況下,Elasticsearch 為了提高查詢效率,對于不指定分頁查詢條數(shù)的查詢語句,默認會返回10條數(shù)據(jù)。那么這就會有一種情況,當你需要一次性返回 Elasticsearch 索引中的全部數(shù)據(jù)時,就無法實現(xiàn)了。這個時候你可能會考慮,比如我將每頁取值的size 設置的很大,這樣或許可以解決問題,但是數(shù)據(jù)量的上升你是無法控制的,最終會有一天數(shù)據(jù)量會超過你此時設置的最大 size,那么這就是一個雷點。并且如果一次查詢很大量數(shù)據(jù)的話,即便是 Elasticsearch 查詢效率高的索引結構可能也會導致查詢時長較長,甚至響應超時。那么是否有一種查詢效率高,且相對靈活的方式可以查詢 Elasticsearch 的索引中全部數(shù)據(jù)呢?答案是:有的。
通常情況
下面來看一下在不設置 size 大小的情況下,執(zhí)行 Elasticsearch 查詢語句默認返回幾條數(shù)據(jù),結果是默認返回 10條。執(zhí)行如下查詢命令
GET crm_meiqia_conversation/_search
返回結果如圖,這時我們看到返回了 10 條數(shù)據(jù)
此時如果你需要查詢更多數(shù)據(jù)的話,你就可以通過指定 size 大小來查詢更多數(shù)據(jù),比如執(zhí)行如下命令
GET crm_meiqia_conversation/_search { "size":20 }
執(zhí)行查詢語句后返回的結果如圖所示,索引查詢會返回你指定 size 大小的數(shù)據(jù)
很明顯,在一些特殊的場景下,想要一次性查詢指定條件下的所有數(shù)據(jù)改如何操作呢,下面就來基于 Java 實現(xiàn)查詢指定條件下的所有數(shù)據(jù)操作。
Java 實現(xiàn)查詢 Elasticsearch 全部數(shù)據(jù)
在具體講解如何通過 Java 實現(xiàn)查詢 Elasticsearch 全部數(shù)據(jù)之前,我們可以先來看一下我已經(jīng)實現(xiàn)之后的查詢效果。這里你可以看到滾動州已經(jīng)變得很小,這就是因為我查詢出了指定條件下的全部數(shù)據(jù)導致的,而不是默認的 10 條數(shù)據(jù)
而如果沒有實現(xiàn)查詢指定索引指定條件下的全部數(shù)據(jù)時,看到的效果應該是這樣的,默認只能一次性查詢 10 條數(shù)據(jù)返回
下面再來講一下如何通過 Java 實現(xiàn) 查詢 es 全部數(shù)據(jù),我們由淺入深來講解,首先來看一下默認查詢 es 10條數(shù)據(jù)的代碼,Java 通過如下 SearchRequestBuilder searchRequest = client.prepareSearch(indexProperties.getMeiqiaConversationIndex()).setTypes(indexProperties.getMeiqiaConversationType()).setQuery(query); 構造查詢 es 索引代碼,這種情況沒有設置 size 大小,默認的話就是查詢指定索引下 10條數(shù)據(jù),完整代碼如下:
public AjaxResult getMeiqiaUidList(MeiqiaConversation meiqiaConversation) { BoolQueryBuilder query = QueryBuilders.boolQuery(); BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //會話id Long convId = meiqiaConversation.getConvId(); if (convId != null) { boolQuery.filter(QueryBuilders.termQuery("convId",convId)); } //會話日期 String convStartDate = (String) meiqiaConversation.getParams().get("convStartDate"); String convEndDate = (String) meiqiaConversation.getParams().get("convEndDate"); if (StringUtils.isNotEmpty(convStartDate)) { Date date = DateUtils.stringToDate(convStartDate, DateUtils.SDF_YMDHMS); boolQuery.filter(QueryBuilders.rangeQuery("convStartDate").gte(date.getTime())); } if (StringUtil.isNotEmptyString(convEndDate)) { Date date = DateUtils.stringToDate(convEndDate, DateUtils.SDF_YMDHMS); boolQuery.filter(QueryBuilders.rangeQuery("convEndDate").lte(date.getTime())); } //會話日期 Date convStartDate2 = meiqiaConversation.getConvStartDate(); Date convEndDate2 = meiqiaConversation.getConvEndDate(); if (Objects.nonNull(convStartDate2)) { boolQuery.filter(QueryBuilders.rangeQuery("convStartDate").gte(convStartDate2.getTime())); } if (Objects.nonNull(convEndDate2)) { boolQuery.filter(QueryBuilders.rangeQuery("convEndDate").lte(convEndDate2.getTime())); } //學號 String uid = (String) meiqiaConversation.getParams().get("uid"); if (StringUtils.isNotEmpty(uid)) { if (uid.contains("#")) { String replace = uid.replace("#", ""); boolQuery.filter(QueryBuilders.termQuery("clientInfo.name",replace)); }else { boolQuery.filter(QueryBuilders.termQuery("clientInfo.uid",uid)); } } //客服工號 String agentId = (String) meiqiaConversation.getParams().get("agentId"); if (StringUtils.isNotEmpty(agentId)) { boolQuery.filter(QueryBuilders.termQuery("agentId",agentId)); } // 會話內(nèi)容 String content = (String) meiqiaConversation.getParams().get("content"); if (StringUtils.isNotEmpty(content)) { boolQuery.filter(QueryBuilders.matchPhrasePrefixQuery("convContent.content",content)); } query.must(boolQuery); // 初始化搜索請求構建器,用于構造搜索請求 SearchRequestBuilder searchRequest = client.prepareSearch(indexProperties.getMeiqiaConversationIndex()) // 設置搜索的類型 .setTypes(indexProperties.getMeiqiaConversationType()) // 設置查詢條件 .setQuery(query); // 使用SearchRequest獲取搜索響應 SearchResponse searchResponse = searchRequest.get(); // 初始化存儲所有搜索結果的列表 List<EsMeiqiaConversation> rows = new ArrayList<>(); // 格式化搜索響應中的數(shù)據(jù),并添加到rows列表中 List<EsMeiqiaConversation> list1 = formatMeiqiaDto(searchResponse); rows.addAll(list1); //記錄返回的uid name List<MeiqiaConversation> list = new ArrayList<>(); if (CollectionUtils.isNotEmpty(rows)) { //獲取 uid name Map<String, List<EsMeiqiaConversation>> collect = rows.stream().collect(Collectors.groupingBy(EsMeiqiaConversation::getClientUid, Collectors.toList())); Set<String> uids = collect.keySet(); for (String u : uids) { MeiqiaConversation conv = new MeiqiaConversation(); conv.setUid(u); //同一個uid 對應同一個 name List<EsMeiqiaConversation> esconv = collect.get(u); String name = esconv.get(0).getClientName(); conv.setName(name); list.add(conv); } } return AjaxResult.success(list); }
那么如何實現(xiàn) 一次查詢滿足條件的全部 es 數(shù)據(jù)呢,這就需要通過 scroll 實現(xiàn),在初始化索引查詢構造器時通過 SearchRequestBuilder searchRequest = client.prepareSearch(indexProperties.getMeiqiaConversationIndex()).setTypes(indexProperties.getMeiqiaConversationType()).setQuery(query).setSize(100).setScroll(TimeValue.timeValueMinutes(1)); 設置 scroll 參數(shù)來實現(xiàn),同時需要再后續(xù)增加再次查詢索引邏輯,將 scorllId 循環(huán)傳遞 獲取全部數(shù)據(jù),最終改造后的獲取全部數(shù)據(jù)的代碼如下
public AjaxResult getMeiqiaUidList(MeiqiaConversation meiqiaConversation) { BoolQueryBuilder query = QueryBuilders.boolQuery(); BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); //會話id Long convId = meiqiaConversation.getConvId(); if (convId != null) { boolQuery.filter(QueryBuilders.termQuery("convId",convId)); } //會話日期 String convStartDate = (String) meiqiaConversation.getParams().get("convStartDate"); String convEndDate = (String) meiqiaConversation.getParams().get("convEndDate"); if (StringUtils.isNotEmpty(convStartDate)) { Date date = DateUtils.stringToDate(convStartDate, DateUtils.SDF_YMDHMS); boolQuery.filter(QueryBuilders.rangeQuery("convStartDate").gte(date.getTime())); } if (StringUtil.isNotEmptyString(convEndDate)) { Date date = DateUtils.stringToDate(convEndDate, DateUtils.SDF_YMDHMS); boolQuery.filter(QueryBuilders.rangeQuery("convEndDate").lte(date.getTime())); } //會話日期 Date convStartDate2 = meiqiaConversation.getConvStartDate(); Date convEndDate2 = meiqiaConversation.getConvEndDate(); if (Objects.nonNull(convStartDate2)) { boolQuery.filter(QueryBuilders.rangeQuery("convStartDate").gte(convStartDate2.getTime())); } if (Objects.nonNull(convEndDate2)) { boolQuery.filter(QueryBuilders.rangeQuery("convEndDate").lte(convEndDate2.getTime())); } //學號 String uid = (String) meiqiaConversation.getParams().get("uid"); if (StringUtils.isNotEmpty(uid)) { if (uid.contains("#")) { String replace = uid.replace("#", ""); boolQuery.filter(QueryBuilders.termQuery("clientInfo.name",replace)); }else { boolQuery.filter(QueryBuilders.termQuery("clientInfo.uid",uid)); } } //客服工號 String agentId = (String) meiqiaConversation.getParams().get("agentId"); if (StringUtils.isNotEmpty(agentId)) { boolQuery.filter(QueryBuilders.termQuery("agentId",agentId)); } // 會話內(nèi)容 String content = (String) meiqiaConversation.getParams().get("content"); if (StringUtils.isNotEmpty(content)) { boolQuery.filter(QueryBuilders.matchPhrasePrefixQuery("convContent.content",content)); } query.must(boolQuery); // 初始化搜索請求構建器,用于構造搜索請求 SearchRequestBuilder searchRequest = client.prepareSearch(indexProperties.getMeiqiaConversationIndex()) // 設置搜索的類型 .setTypes(indexProperties.getMeiqiaConversationType()) // 設置查詢條件 .setQuery(query) // 設置返回結果的數(shù)量為100 .setSize(100) // 設置滾動查詢的時間間隔為1分鐘 .setScroll(TimeValue.timeValueMinutes(1)); // 使用SearchRequest獲取搜索響應 SearchResponse searchResponse = searchRequest.get(); // 初始化存儲所有搜索結果的列表 List<EsMeiqiaConversation> rows = new ArrayList<>(); // 格式化搜索響應中的數(shù)據(jù),并添加到rows列表中 List<EsMeiqiaConversation> list1 = formatMeiqiaDto(searchResponse); rows.addAll(list1); // 使用Scroll方式遍歷所有搜索結果 do { // 準備下一次Scroll搜索,設置滾動時間為1分鐘 // 將scorllId循環(huán)傳遞 獲取全部數(shù)據(jù) searchResponse = client.prepareSearchScroll(searchResponse.getScrollId()).setScroll(TimeValue.timeValueMinutes(1)).execute().actionGet(); // 格式化新一批搜索結果,并添加到rows列表中 List<EsMeiqiaConversation> list = formatMeiqiaDto(searchResponse); if (CollectionUtils.isNotEmpty(list)) { rows.addAll(list); } // 當搜索結果為空時,結束循環(huán) // 當searchHits的數(shù)組為空的時候結束循環(huán),至此數(shù)據(jù)全部讀取完畢 } while (searchResponse.getHits().getHits().length != 0); // 創(chuàng)建一個ClearScrollRequest實例,用于清除滾動查詢的會話。 ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); // 將上一次查詢返回的滾動ID添加到請求中,以便清除這個特定的會話。 // 這是必要的,因為ClearScrollRequest需要至少一個滾動ID才能執(zhí)行清除操作。 clearScrollRequest.addScrollId(searchResponse.getScrollId()); // 發(fā)送ClearScroll請求并獲取操作的結果。 // 這一步是必需的,因為它實際執(zhí)行了清除滾動會話的操作,并允許我們處理結果或任何異常。 client.clearScroll(clearScrollRequest).actionGet(); //記錄返回的uid name List<MeiqiaConversation> list = new ArrayList<>(); if (CollectionUtils.isNotEmpty(rows)) { //獲取 uid name Map<String, List<EsMeiqiaConversation>> collect = rows.stream().collect(Collectors.groupingBy(EsMeiqiaConversation::getClientUid, Collectors.toList())); Set<String> uids = collect.keySet(); for (String u : uids) { MeiqiaConversation conv = new MeiqiaConversation(); conv.setUid(u); //同一個uid 對應同一個 name List<EsMeiqiaConversation> esconv = collect.get(u); String name = esconv.get(0).getClientName(); conv.setName(name); list.add(conv); } } return AjaxResult.success(list); }
那么這段的核心代碼是增加了滾動查詢數(shù)據(jù)的操作,如圖所示
同時再執(zhí)行循環(huán)查詢時將 scrollId 循環(huán)傳遞,并將查詢結果 addAll 到當前l(fā)ist 的集合中
查詢結束之后,最后是清除滾動會話的操作
到這里關于 Java 實現(xiàn) es 查詢指定條件下的全部數(shù)據(jù)操作就結束了,整個操作過程比較容易理解,增加了 es 滾動查詢 scroll 操作來實現(xiàn)查詢 es 全部數(shù)據(jù)。
寫在最后
最后想要說的是,對于 es 查詢,通常情況下是不需要一次性查詢出當前索引所有條件下的數(shù)據(jù)的,畢竟數(shù)據(jù)量比較大,但是也有特殊的場景,這個時候不得不一次性查詢出所有的數(shù)據(jù),這就需要上文中用到的辦法了,希望對大家有幫助。
到此這篇關于Java實現(xiàn)Elasticsearch查詢當前索引全部數(shù)據(jù)的文章就介紹到這了,更多相關Java Elasticsearch查詢當前索引全部數(shù)據(jù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java利用FileUtils讀取數(shù)據(jù)和寫入數(shù)據(jù)到文件
這篇文章主要介紹了Java利用FileUtils讀取數(shù)據(jù)和寫入數(shù)據(jù)到文件,下面文章圍繞FileUtils的相關資料展開怎么讀取數(shù)據(jù)和寫入數(shù)據(jù)到文件的內(nèi)容,具有一定的參考價值,徐婭奧德小伙伴可以參考一下2021-12-12Spring?Boot如何配置yml配置文件定義集合、數(shù)組和Map
這篇文章主要介紹了Spring?Boot?優(yōu)雅配置yml配置文件定義集合、數(shù)組和Map,包括Spring?Boot?yml配置文件定義基本數(shù)據(jù)類型和引用數(shù)據(jù)類型的方式,需要的朋友可以參考下2023-10-10Java中的自動拆裝箱、基本類型的轉(zhuǎn)換、包裝類的緩存詳解
文章詳細介紹了Java中數(shù)據(jù)類型的拆裝箱、自動拆箱和裝箱,以及包裝類的緩存機制,包括基本數(shù)據(jù)類型的容量大小、轉(zhuǎn)換規(guī)則和自動類型轉(zhuǎn)換等2024-12-12Spring Boot中定時任務Cron表達式的終極指南最佳實踐記錄
本文詳細介紹了SpringBoot中定時任務的實現(xiàn)方法,特別是Cron表達式的使用技巧和高級用法,從基礎語法到復雜場景,從快速啟用到調(diào)試驗證,再到常見問題的解決,涵蓋了定時任務開發(fā)的全過程,感興趣的朋友一起看看吧2025-03-03詳解mybatis-plus的 mapper.xml 路徑配置的坑
這篇文章主要介紹了詳解mybatis-plus的 mapper.xml 路徑配置的坑,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-08-08JAVA加密算法- 非對稱加密算法(DH,RSA)的詳細介紹
這篇文章主要介紹了JAVA加密算法- 非對稱加密算法(DH,RSA),詳細介紹了DH,RSA的用法和示例,需要的朋友可以了解一下。2016-11-11