【搜尋系列】ES查詢常用例項演示
本文將作為es系列第三篇,結合常見的例項,來演示下如何通過 RestHighLevelClient
來實現es的各種查詢支援
I. 專案搭建
1. 專案依賴
本專案藉助 SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ IDEA
進行開發
開一個web服務用於測試
<dependencies> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency> </dependencies>
2. 配置資訊
配置檔案application.yml,注意下面的配置資訊,下面採用的是由我們自己來解析配置的方式
elasticsearch: host: localhost port: 9200 user: elastic pwd: test123 connTimeout: 3000 socketTimeout: 5000 connectionRequestTimeout: 500
II. 例項演示
0. 準備
在開始之前,先準備插入幾條資料,這裡會藉助上一篇CURD博文中的插入介面
在開始之前就準備兩條資料
@Component public class TermQueryDemo { private BasicCurdDemo basicCurdDemo; @Autowired private RestHighLevelClient client; @Autowired private RequestOptions requestOptions; private String TEST_ID = "11123-33345-66543-55231"; private String TEST_ID_2 = "11123-33345-66543-55232"; private String index = "term-demo"; public TermQueryDemo(BasicCurdDemo basicCurdDemo) throws IOException { this.basicCurdDemo = basicCurdDemo; Map<String, Object> doc = newMap("name", "一灰灰", "age", 10, "skills", Arrays.asList("java", "python"), "site", "blog.hhui.top"); basicCurdDemo.addDoc(index, doc, TEST_ID); doc = newMap("name", "二灰灰", "age", 16, "skills", Arrays.asList("js", "html")); basicCurdDemo.addDoc(index, doc, TEST_ID_2); } @PreDestroy public void remove() throws IOException { basicCurdDemo.delete(index, TEST_ID); basicCurdDemo.delete(index, TEST_ID_2); } }
1. 全量查詢
即查詢所有的文件,如藉助kibanan的控制檯,發起的請求形如
GET index/_search { "query": { "match_all": {} } }
於此對應的java實現如下
/** * 全量查詢 * * @throws IOException */ private void queryAll() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 查詢所有的文件 searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, requestOptions); System.out.println("mathAll: " + searchResponse.toString()); }
注意上面的實現:
SearchRequest SearchSourceBuilder client.search(searchRequest, requestOptions)
通常來說,實際的業務場景中,不太可能出現上面這種沒有任何限制的查全量資料,即便真的有查全量資料的case,更常見的是分頁查詢,如下
private void queryAll() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); int page = 1; //每頁記錄數 int size = 2; //計算出記錄起始下標 int from = (page - 1) * size; //起始記錄下標,從0開始 searchSourceBuilder.from(from); //每頁顯示的記錄數 searchSourceBuilder.size(size); // 根據age欄位進行倒排 searchSourceBuilder.sort(new FieldSortBuilder("age").order(SortOrder.DESC)); // 查詢所有的文件 searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest, requestOptions); System.out.println("mathAll: " + searchResponse.toString()); }
2. 根據Field值精確查詢
即es中常說的term查詢,具體實現如下
/** * term精確查詢 * * @throws IOException */ private void term() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); // termQuery: 精確查詢 // SpanTermQuery: 詞距查詢 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.termQuery("site", "blog.hhui.top")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("term: " + response.toString()); }
從上面的實現也可以看出,查詢的套路沒啥區別,無非就是 SearchSourceBuilder
中的引數構造不一樣;上面主要通過
-
QueryBuilders.termQuery("site", "blog.hhui.top")
來構建 term的查詢條件,表明查詢site=blog.hhui.top
的文件
中文查詢不到問題
在我們實際使用過程中,如果value為中文,在查詢時,可能會遇到命名有對應的資料,但是就查不到,主要原因就在於分詞,如對於中文的查詢,可以考慮下面這種方式
private void term2() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 對於中文查詢,需要注意分詞的場景, 如果直接使用 "name : 一灰灰" 的方式進行查詢,則啥也不會返回 // elasticsearch 裡預設的IK分詞器是會將每一箇中文都進行了分詞的切割,所以你直接想查一整個詞,或者一整句話是無返回結果的。 // 在此種情況下,我們可以通過指定 keyword 的方式來處理, 設定關鍵詞搜尋(不進行分詞) searchSourceBuilder.query(QueryBuilders.termQuery("name.keyword", "一灰灰")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("term2: " + response.toString()); }
3. Field值in查詢
另外一個常見的就是多值查詢,也就是我們常說的 field in (val1, val2...)
,這個對應的就是es中的 terms
查詢
/** * 相當於in查詢 * {"terms": { "name": ["一灰灰", "二灰灰] }} * * @throws IOException */ private void multTerm() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.termsQuery("name.keyword", "一灰灰", "二灰灰")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("term: " + response.toString()); }
4. 範圍查詢
對於數值型別的Field,同樣是支援比較、範圍查詢的,對應的是es中 range
/** * 範圍查詢 * { "range": { "age": { "gt":8, "lt": 12 } }} * * @throws IOException */ private void range() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.rangeQuery("age").gt(8).lt(12)); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("range: " + response.toString()); }
注意上面的查詢有條件
QueryBuilders.rangeQuery("age").gt(8).lt(12) age > 8 && age < 12
5. Field是否存在查詢
es不同於mysql的在於它的field可以動態新增,當我們希望查詢包含某個欄位的文件時,可以考慮 exists
/** * 根據欄位是否存在查詢 * * @throws IOException */ private void exists() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.existsQuery("site")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("exists: " + response.toString()); }
6. 模糊查詢
es作為搜尋引擎,更常見的是模糊匹配,比如match查詢
/** * 根據欄位匹配查詢 * * @throws IOException */ private void match() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.matchQuery("name", "灰")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("matchQuery: " + response.toString()); }
多Field中進行查詢
/** * 多欄位中查詢 * * @throws IOException */ private void multiMatch() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.multiMatchQuery("灰", "name", "site")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("multiMatchQuery: " + response.toString()); }
在es的語法支援中,除了match,還有一個 wildcard
,可以使用 ?
來代指單字元, *
來代指0..n字元
/** * 模糊查詢 ? 單字元 * 0..n字元 * * @throws IOException */ private void wild() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.wildcardQuery("site", "*top")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("wildcard: " + response.toString()); }
7. 正則匹配
private void regexp() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.regexpQuery("site", ".*hhui.*")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("regexpQuery: " + response.toString()); }
8. 字首查詢
private void prefix() throws IOException { SearchRequest searchRequest = new SearchRequest(index); searchRequest.types("_doc"); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(QueryBuilders.prefixQuery("site", "blog")); searchRequest.source(searchSourceBuilder); SearchResponse response = client.search(searchRequest, requestOptions); System.out.println("prefixQuery: " + response.toString()); }
9.小結
本文雖然介紹了一些常見的查詢case,但注意並不僅僅只有這些,比如
- 查詢指定Feild的內容
- 排序
- 分組聚合
- 多查詢條件組合:and/or
- 高亮
更多的使用例項,敬請期待…,歡迎感興趣的小夥伴,點贊收藏評論一波:stuck_out_tongue_closed_eyes:
III. 不能錯過的原始碼和相關知識點
0. 專案
系列博文
原始碼
- 工程: http://github.com/liuyueyi/spring-boot-demo
- 原始碼: http://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/142-search-es
1. 微信公眾號: 一灰灰Blog
盡信書則不如,以上內容,純屬一家之言,因個人能力有限,難免有疏漏和錯誤之處,如發現bug或者有更好的建議,歡迎批評指正,不吝感激
下面一灰灰的個人部落格,記錄所有學習和工作中的博文,歡迎大家前去逛逛
- 一灰灰Blog個人部落格 http://blog.hhui.top
- 一灰灰Blog-Spring專題部落格 http://spring.hhui.top
打賞 如果覺得我的文章對您有幫助,請隨意打賞。
- 基於MySql,Redis,Mq,ES的高可用方案解析
- 1w5字詳細介紹分散式系統的那些技術方案
- 程式設計師的浪漫:三十行程式碼實現用她的名字作幅畫
- 【WEB系列】內嵌Tomcat配置Accesslog日誌檔案生成位置原始碼探索
- 【搜尋系列】ES查詢常用例項演示
- 【搜尋系列】ES文件基本操作CURD例項演示
- 【搜尋系列】ES基本專案搭建
- Nosql儲存系統-叢集工作原理
- 例項演示,帶你瞭解終端神器ncat
- Redis:你真的會Redis麼,一文告訴你如何學習
- 常用設計模式彙總,告訴你如何學習設計模式
- 微服務閘道器:從對比到選型,由理論到實踐
- 【WEB系列】從0到1實現自定義web引數對映器
- SpringBoot系列Mybatis之批量插入的幾種姿勢
- SpringBoot系列Mybatis之ResultMap、ResultType返回結果使用姿勢
- 【DB系列】Mybatis之批量插入的幾種姿勢
- 【DB系列】Mybatis之ResultMap、ResultType返回結果使用姿勢
- 【中介軟體】Prometheus基於AOP實現埋點採集上報
- JDNI注入:RMI之繞過trustURLCodebase配置的注入例項演示三
- JDNI注入:RMI Reference引起的注入case二