本文繼續上文(Elasticsearch 入門實戰(5)--Java API Client 使用一(Index,Document,Ingest,SQL APIs))介紹 Java API Client,相關的環境及軟體資訊如下:CentOS 7.6.1810、Java 1.8.0_341(客戶端用)、Elasticsearch 8.13.4、elasticsearch-java 8.13.4。
1、Search APIs
1.1、Count API(查詢文件數量)
/** * 查詢文件數量 */ @Test public void count() throws IOException { //查詢該索引的所有文件數量 CountResponse response = client.count(builder -> builder.index(INDEX_NAME)); log.info("response={}", response); //透過 Lucene 查詢語法指定條件;8.13.4會報錯”contains unrecognized parameter: [q]“,因為 API 提交了請求 "{}",應該時不需要請求體 //response = client.count(builder -> builder.index(INDEX_NAME).q("name:杜甫")); log.info("response={}", response); //透過 "Query DSL" 指定條件 response = client.count(builder -> builder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .term(termQueryBuilder -> termQueryBuilder .field("name").value("杜甫") ) ) ); log.info("response={}", response); }
1.2、Search API(查詢文件)
1.2.1、query
1.2.1.1、term/terms 查詢
/** * term/terms 查詢,對輸入內容不做分詞處理 */ @Test public void searchTerm() throws IOException { SearchResponse<Map> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .term(termQueryBuilder -> termQueryBuilder .field("name").value("李白"))) .sort(sortOptionsBuilder -> sortOptionsBuilder .field(fieldSortBuilder -> fieldSortBuilder .field("age").order(SortOrder.Asc))) .source(sourceConfigBuilder -> sourceConfigBuilder .filter(sourceFilterBuilder -> sourceFilterBuilder .includes("age", "name"))) .from(0) .size(10) , Map.class); log.info("response={}", response); List<FieldValue> words = new ArrayList<>(); words.add(new FieldValue.Builder().stringValue("李白").build()); words.add(new FieldValue.Builder().stringValue("杜甫").build()); SearchResponse<Poet> response2 = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .terms(termsQueryBuilder -> termsQueryBuilder .field("name").terms(termsQueryFieldBuilder -> termsQueryFieldBuilder.value(words)))) .source(sourceConfigBuilder -> sourceConfigBuilder .filter(sourceFilterBuilder -> sourceFilterBuilder .excludes("about"))) .from(0) .size(10) , Poet.class); log.info("response2={}", response2); }
1.2.1.2、range 查詢
/** * range 查詢,範圍查詢 */ @Test public void searchRange() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .range(rangeQueryBuilder -> rangeQueryBuilder .field("age").gte(JsonData.of("20")).lt(JsonData.of("40")))) , Poet.class); log.info("response={}", response); }
1.2.1.3、exists 查詢
/** * exists 查詢,查詢對應欄位不為空的資料 */ @Test public void exists() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME).query(builder -> builder.exists(builder1 -> builder1.field("poems"))) , Poet.class); log.info("response={}", response); }
1.2.1.4、match 相關查詢
A、match
/** * match查詢,對輸入內容先分詞再查詢 */ @Test public void searchMatch() throws IOException { SearchResponse<Map> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .match(matchQueryBuilder -> matchQueryBuilder .field("success").query("思想"))) , Map.class); log.info("response={}", response); }
B、multi_match
/** * multi_match 查詢,多個欄位進行匹配。 */ @Test public void searchMultiMatch() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .multiMatch(multiMatchQueryBuilder -> multiMatchQueryBuilder .fields("about", "success").query("思想"))) , Poet.class); log.info("response={}", response); }
C、match_phrase
/** * match_phrase 查詢,類似 match,先把查詢字串分詞生成一個詞列表,查詢包含所有這些詞且這些詞在文件中出現次序一致的資料。 */ @Test public void searchMatchPhrase() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .matchPhrase(matchPhraseQueryBuilder -> matchPhraseQueryBuilder .field("success").query("偉大作家"))) , Poet.class); log.info("response={}", response); }
D、match_all
/** * match_all 查詢,查詢所有文件 */ @Test public void searchMatchAll() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .matchAll(matchAllQueryBuilder -> matchAllQueryBuilder)) , Poet.class); log.info("response={}", response); //不加請求體,也是一樣的效果,查詢所有文件。 response = client.search(searchRequestBuilder -> searchRequestBuilder.index(INDEX_NAME), Poet.class); log.info("response={}", response); }
E、match_none
/** * match_none 查詢,與 match_all 相反,返回 0 個文件。 */ @Test public void searchMatchNone() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .matchNone(matchAllQueryBuilder -> matchAllQueryBuilder)) , Poet.class); log.info("response={}", response); }
1.2.1.5、query_string 查詢
/** * query_string 查詢,可以同時實現多種查詢 */ @Test public void searchQueryString() throws IOException { //類似 match SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .defaultField("success").query("古典文學"))) , Poet.class); log.info("response={}", response); //類似 mulit_match response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .fields("about", "success").query("古典文學"))) , Poet.class); log.info("response={}", response); //類似 match_phrase response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .defaultField("success").query("\"文學作家\""))) , Poet.class); log.info(response.toString()); //帶運算子查詢,運算子兩邊的詞不再分詞 //查詢同時包含 ”文學“ 和 ”偉大“ 的文件 response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .fields("success").query("文學 AND 偉大"))) , Poet.class); log.info("response={}", response); //等同上一個查詢 response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .fields("success").query("文學 偉大").defaultOperator(Operator.And))) , Poet.class); log.info("response={}", response); //查詢 name 或 success 欄位包含"文學"和"偉大"這兩個單詞,或者包含"李白"這個單詞的文件。 response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .fields("name","success").query("(文學 AND 偉大) OR 高度"))) , Poet.class); log.info("response={}", response); }
1.2.1.6、simple_query_string 查詢
/** * simple_query_string 查詢,類似 query_string,主要區別如下: * 1、不支援 AND OR NOT,會當做字元處理;使用 + 代替 AND,| 代替 OR,- 代替 NOT * 2、會忽略錯誤的語法 */ @Test public void searchSimpleQueryString() throws IOException { //查詢同時包含 ”文學“ 和 ”偉大“ 的文件 SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .simpleQueryString(simpleQueryStringQueryBuilder -> simpleQueryStringQueryBuilder .fields("success").query("文學 + 偉大"))) , Poet.class); log.info("response={}", response); }
3.4.7、fuzzy 查詢
/** * 模糊查詢 */ @Test public void searchFuzzy() throws IOException { //全文查詢時使用模糊引數,先分詞再計算模糊選項。 SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .match(matchQueryBuilder -> matchQueryBuilder .field("success").query("思考").fuzziness("1"))) , Poet.class); log.info(response.toString()); //使用 fuzzy query,對輸入不分詞,直接計算模糊選項。 SearchResponse<Poet> response2 = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .fuzzy(fuzzyQueryBuilder -> fuzzyQueryBuilder .field("success").fuzziness("1").value("理想"))) , Poet.class); log.info(response2.toString()); }
1.2.1.8、wildcard 查詢
/** * wildcard 查詢,類似 SQL 語句中的 like;? 匹配一個字元,* 匹配多個字元 */ @Test public void searchWildcard() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder.wildcard(wildcardQueryBuilder -> wildcardQueryBuilder .field("name") .wildcard("李*"))) , Poet.class); log.info(response.toString()); }
1.2.1.9、bool 查詢
/** * bool 查詢,組合查詢 */ @Test public void searchBool() throws IOException { //查詢 success 包含 “思想” 且 age 在 [20-40] 之間的文件 SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .bool(boolQueryBuilder -> boolQueryBuilder .must(queryBuilder2 -> queryBuilder2 .match(matchQueryBuilder -> matchQueryBuilder .field("success").query("思想")) ) .must(queryBuilder2 -> queryBuilder2 .range(rangeQueryBuilder -> rangeQueryBuilder .field("age").gte(JsonData.of("20")).lt(JsonData.of("40"))) ) ) ) , Poet.class); log.info(response.toString()); //過濾出 success 包含 “思想” 且 age 在 [20-40] 之間的文件,不計算得分 SearchResponse<Poet> response2 = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .bool(boolQueryBuilder -> boolQueryBuilder .filter(queryBuilder2 -> queryBuilder2 .match(matchQueryBuilder -> matchQueryBuilder .field("success").query("思想")) ) .filter(queryBuilder2 -> queryBuilder2 .range(rangeQueryBuilder -> rangeQueryBuilder .field("age").gte(JsonData.of("20")).lt(JsonData.of("40"))) ) ) ) , Poet.class); log.info(response2.toString()); }
1.2.2、aggs 查詢
/** * aggs 查詢,聚合查詢 */ @Test public void searchAggs() throws IOException { //求和,類似 select sum(age) from poet-index SearchResponse response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .aggregations("age_sum", aggregationBuilder -> aggregationBuilder .sum(sumAggregationBuilder -> sumAggregationBuilder .field("age"))) , Poet.class); log.info(response.toString()); //類似 select count distinct(age) from poet-index response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .aggregations("age_count", aggregationBuilder -> aggregationBuilder .cardinality(cardinalityAggregationBuilder -> cardinalityAggregationBuilder.field("age"))) , Poet.class); log.info(response.toString()); //數量、最大、最小、平均、求和 response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .aggregations("age_stats", aggregationBuilder -> aggregationBuilder .stats(statsAggregationBuilder -> statsAggregationBuilder .field("age"))) , Poet.class); log.info(response.toString()); //select name,count(*) from poet-index group by name response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .aggregations("name_terms", aggregationBuilder -> aggregationBuilder .terms(termsAggregationBuilder -> termsAggregationBuilder .field("name"))) , Map.class); log.info(response.toString()); //select name,age,count(*) from poet-index group by name,age response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .aggregations("name_terms", aggregationBuilder -> aggregationBuilder .terms(termsAggregationBuilder -> termsAggregationBuilder .field("name") ) .aggregations("age_terms", aggregationBuilder2 -> aggregationBuilder2 .terms(termsAggregationBuilder -> termsAggregationBuilder .field("age") )) ) , Poet.class); log.info(response.toString()); //類似 select avg(age) from poet-index where name='李白' response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .bool(boolQueryBuilder -> boolQueryBuilder .filter(queryBuilder2 -> queryBuilder2 .term(termQueryBuilder -> termQueryBuilder .field("name").value("李白"))))) .aggregations("ave_age", aggregationBuilder -> aggregationBuilder .avg(averageAggregationBuilder -> averageAggregationBuilder.field("age"))) , Poet.class); log.info(response.toString()); }
1.2.3、suggest 查詢
/** * suggest 查詢,推薦查詢 */ @Test public void searchSuggest() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .suggest(suggesterBuilder -> suggesterBuilder .suggesters("success_suggest", fieldSuggesterBuilder -> fieldSuggesterBuilder .text("思考") .term(termSuggesterBuilder -> termSuggesterBuilder .field("success") .suggestMode(SuggestMode.Always) .minWordLength(2) ) ) ) , Poet.class); log.info(response.toString()); }
1.2.4、highlight
/** * 高亮顯示 */ @Test public void searchHighlight() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .match(matchQueryBuilder -> matchQueryBuilder .field("success").query("思想"))) .highlight(highlightBuilder -> highlightBuilder .preTags("<span color='red'>") .postTags("</span>") .fields("success", highlightFieldBuilder -> highlightFieldBuilder)) , Poet.class); log.info(response.toString()); }
2、完整程式碼
package com.abc.demo.es; import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch._types.FieldValue; import co.elastic.clients.elasticsearch._types.SortOrder; import co.elastic.clients.elasticsearch._types.SuggestMode; import co.elastic.clients.elasticsearch._types.query_dsl.Operator; import co.elastic.clients.elasticsearch.core.*; import co.elastic.clients.json.JsonData; import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.transport.rest_client.RestClientTransport; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.junit.After; import org.junit.Before; import org.junit.Test; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; @Slf4j public class ElasticsearchJavaCase2 { private static final String INDEX_NAME = "poet-index"; private ElasticsearchTransport transport; private ElasticsearchClient client; @Before public void before() { RestClient restClient = RestClient.builder( new HttpHost("10.49.196.10", 9200), new HttpHost("10.49.196.11", 9200), new HttpHost("10.49.196.12", 9200)).build(); ObjectMapper objectMapper = new ObjectMapper(); transport = new RestClientTransport(restClient, new JacksonJsonpMapper(objectMapper)); client = new ElasticsearchClient(transport); } @After public void after() throws IOException { transport.close(); } /** * 查詢文件數量 */ @Test public void count() throws IOException { //查詢該索引的所有文件數量 CountResponse response = client.count(builder -> builder.index(INDEX_NAME)); log.info("response={}", response); //透過 Lucene 查詢語法指定條件;8.13.4會報錯”contains unrecognized parameter: [q]“,因為 API 提交了請求 "{}",應該時不需要請求體 //response = client.count(builder -> builder.index(INDEX_NAME).q("name:杜甫")); log.info("response={}", response); //透過 "Query DSL" 指定條件 response = client.count(builder -> builder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .term(termQueryBuilder -> termQueryBuilder .field("name").value("杜甫") ) ) ); log.info("response={}", response); } /** * term/terms查詢,對輸入內容不做分詞處理 */ @Test public void searchTerm() throws IOException { SearchResponse<Map> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .term(termQueryBuilder -> termQueryBuilder .field("name").value("李白"))) .sort(sortOptionsBuilder -> sortOptionsBuilder .field(fieldSortBuilder -> fieldSortBuilder .field("age").order(SortOrder.Asc))) .source(sourceConfigBuilder -> sourceConfigBuilder .filter(sourceFilterBuilder -> sourceFilterBuilder .includes("age", "name"))) .from(0) .size(10) , Map.class); log.info("response={}", response); List<FieldValue> words = new ArrayList<>(); words.add(new FieldValue.Builder().stringValue("李白").build()); words.add(new FieldValue.Builder().stringValue("杜甫").build()); SearchResponse<Poet> response2 = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .terms(termsQueryBuilder -> termsQueryBuilder .field("name").terms(termsQueryFieldBuilder -> termsQueryFieldBuilder.value(words)))) .source(sourceConfigBuilder -> sourceConfigBuilder .filter(sourceFilterBuilder -> sourceFilterBuilder .excludes("about"))) .from(0) .size(10) , Poet.class); log.info("response2={}", response2); } /** * range(範圍)查詢 */ @Test public void searchRange() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .range(rangeQueryBuilder -> rangeQueryBuilder .field("age").gte(JsonData.of("20")).lt(JsonData.of("40")))) , Poet.class); log.info("response={}", response); } /** * exists 查詢,查詢對應欄位不為空的資料 */ @Test public void exists() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME).query(builder -> builder.exists(builder1 -> builder1.field("poems"))) , Poet.class); log.info("response={}", response); } /** * match查詢,對輸入內容先分詞再查詢 */ @Test public void searchMatch() throws IOException { SearchResponse<Map> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .match(matchQueryBuilder -> matchQueryBuilder .field("success").query("思想"))) , Map.class); log.info("response={}", response); } /** * multi_match 查詢,多個欄位進行匹配。 */ @Test public void searchMultiMatch() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .multiMatch(multiMatchQueryBuilder -> multiMatchQueryBuilder .fields("about", "success").query("思想"))) , Poet.class); log.info("response={}", response); } /** * match_phrase 查詢,類似 match,先把查詢字串分詞生成一個詞列表,查詢包含所有這些詞且這些詞在文件中出現次序一致的資料。 */ @Test public void searchMatchPhrase() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .matchPhrase(matchPhraseQueryBuilder -> matchPhraseQueryBuilder .field("success").query("偉大作家"))) , Poet.class); log.info("response={}", response); } /** * match_all 查詢,查詢所有文件 */ @Test public void searchMatchAll() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .matchAll(matchAllQueryBuilder -> matchAllQueryBuilder)) , Poet.class); log.info("response={}", response); //不加請求體,也是一樣的效果,查詢所有文件。 response = client.search(searchRequestBuilder -> searchRequestBuilder.index(INDEX_NAME), Poet.class); log.info("response={}", response); } /** * match_none 查詢,與 match_all 相反,返回 0 個文件。 */ @Test public void searchMatchNone() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .matchNone(matchAllQueryBuilder -> matchAllQueryBuilder)) , Poet.class); log.info("response={}", response); } /** * query_string 查詢,可以同時實現多種查詢 */ @Test public void searchQueryString() throws IOException { //類似 match SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .defaultField("success").query("古典文學"))) , Poet.class); log.info("response={}", response); //類似 mulit_match response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .fields("about", "success").query("古典文學"))) , Poet.class); log.info("response={}", response); //類似 match_phrase response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .defaultField("success").query("\"文學作家\""))) , Poet.class); log.info(response.toString()); //帶運算子查詢,運算子兩邊的詞不再分詞 //查詢同時包含 ”文學“ 和 ”偉大“ 的文件 response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .fields("success").query("文學 AND 偉大"))) , Poet.class); log.info("response={}", response); //等同上一個查詢 response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .fields("success").query("文學 偉大").defaultOperator(Operator.And))) , Poet.class); log.info("response={}", response); //查詢 name 或 success 欄位包含"文學"和"偉大"這兩個單詞,或者包含"李白"這個單詞的文件。 response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .queryString(queryStringQueryBuilder -> queryStringQueryBuilder .fields("name","success").query("(文學 AND 偉大) OR 高度"))) , Poet.class); log.info("response={}", response); } /** * simple_query_string 查詢,類似 query_string,主要區別如下: * 1、不支援 AND OR NOT,會當做字元處理;使用 + 代替 AND,| 代替 OR,- 代替 NOT * 2、會忽略錯誤的語法 */ @Test public void searchSimpleQueryString() throws IOException { //查詢同時包含 ”文學“ 和 ”偉大“ 的文件 SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .simpleQueryString(simpleQueryStringQueryBuilder -> simpleQueryStringQueryBuilder .fields("success").query("文學 + 偉大"))) , Poet.class); log.info("response={}", response); } /** * 模糊查詢 */ @Test public void searchFuzzy() throws IOException { //全文查詢時使用模糊引數,先分詞再計算模糊選項。 SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .match(matchQueryBuilder -> matchQueryBuilder .field("success").query("思考").fuzziness("1"))) , Poet.class); log.info(response.toString()); //使用 fuzzy query,對輸入不分詞,直接計算模糊選項。 SearchResponse<Poet> response2 = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .fuzzy(fuzzyQueryBuilder -> fuzzyQueryBuilder .field("success").fuzziness("1").value("理想"))) , Poet.class); log.info(response2.toString()); } /** * wildcard 查詢,類似 SQL 語句中的 like;? 匹配一個字元,* 匹配多個字元 */ @Test public void searchWildcard() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder.wildcard(wildcardQueryBuilder -> wildcardQueryBuilder .field("name") .wildcard("李*"))) , Poet.class); log.info(response.toString()); } /** * bool 查詢,組合查詢 */ @Test public void searchBool() throws IOException { //查詢 success 包含 “思想” 且 age 在 [20-40] 之間的文件 SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .bool(boolQueryBuilder -> boolQueryBuilder .must(queryBuilder2 -> queryBuilder2 .match(matchQueryBuilder -> matchQueryBuilder .field("success").query("思想")) ) .must(queryBuilder2 -> queryBuilder2 .range(rangeQueryBuilder -> rangeQueryBuilder .field("age").gte(JsonData.of("20")).lt(JsonData.of("40"))) ) ) ) , Poet.class); log.info(response.toString()); //過濾出 success 包含 “思想” 且 age 在 [20-40] 之間的文件,不計算得分 SearchResponse<Poet> response2 = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .bool(boolQueryBuilder -> boolQueryBuilder .filter(queryBuilder2 -> queryBuilder2 .match(matchQueryBuilder -> matchQueryBuilder .field("success").query("思想")) ) .filter(queryBuilder2 -> queryBuilder2 .range(rangeQueryBuilder -> rangeQueryBuilder .field("age").gte(JsonData.of("20")).lt(JsonData.of("40"))) ) ) ) , Poet.class); log.info(response2.toString()); } /** * aggs 查詢,聚合查詢 */ @Test public void searchAggs() throws IOException { //求和,類似 select sum(age) from poet-index SearchResponse response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .aggregations("age_sum", aggregationBuilder -> aggregationBuilder .sum(sumAggregationBuilder -> sumAggregationBuilder .field("age"))) , Poet.class); log.info(response.toString()); //類似 select count distinct(age) from poet-index response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .aggregations("age_count", aggregationBuilder -> aggregationBuilder .cardinality(cardinalityAggregationBuilder -> cardinalityAggregationBuilder.field("age"))) , Poet.class); log.info(response.toString()); //數量、最大、最小、平均、求和 response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .aggregations("age_stats", aggregationBuilder -> aggregationBuilder .stats(statsAggregationBuilder -> statsAggregationBuilder .field("age"))) , Poet.class); log.info(response.toString()); //select name,count(*) from poet-index group by name response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .aggregations("name_terms", aggregationBuilder -> aggregationBuilder .terms(termsAggregationBuilder -> termsAggregationBuilder .field("name"))) , Map.class); log.info(response.toString()); //select name,age,count(*) from poet-index group by name,age response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .aggregations("name_terms", aggregationBuilder -> aggregationBuilder .terms(termsAggregationBuilder -> termsAggregationBuilder .field("name") ) .aggregations("age_terms", aggregationBuilder2 -> aggregationBuilder2 .terms(termsAggregationBuilder -> termsAggregationBuilder .field("age") )) ) , Poet.class); log.info(response.toString()); //類似 select avg(age) from poet-index where name='李白' response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .bool(boolQueryBuilder -> boolQueryBuilder .filter(queryBuilder2 -> queryBuilder2 .term(termQueryBuilder -> termQueryBuilder .field("name").value("李白"))))) .aggregations("ave_age", aggregationBuilder -> aggregationBuilder .avg(averageAggregationBuilder -> averageAggregationBuilder.field("age"))) , Poet.class); log.info(response.toString()); } /** * suggest 查詢,推薦搜尋 */ @Test public void searchSuggest() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .suggest(suggesterBuilder -> suggesterBuilder .suggesters("success_suggest", fieldSuggesterBuilder -> fieldSuggesterBuilder .text("思考") .term(termSuggesterBuilder -> termSuggesterBuilder .field("success") .suggestMode(SuggestMode.Always) .minWordLength(2) ) ) ) , Poet.class); log.info(response.toString()); } /** * 高亮顯示 */ @Test public void searchHighlight() throws IOException { SearchResponse<Poet> response = client.search(searchRequestBuilder -> searchRequestBuilder .index(INDEX_NAME) .query(queryBuilder -> queryBuilder .match(matchQueryBuilder -> matchQueryBuilder .field("success").query("思想藝術"))) .highlight(highlightBuilder -> highlightBuilder .preTags("<span color='red'>") .postTags("</span>") .fields("success", highlightFieldBuilder -> highlightFieldBuilder)) , Poet.class); log.info(response.toString()); } @Data @AllArgsConstructor @NoArgsConstructor static class Poet { private Integer age; private String name; private String poems; private String about; /**成就*/ private String success; } }
詳細的 Elasticsearch Java API Client 使用說明,請參考官網文件:https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/index.html。